diff options
77 files changed, 9402 insertions, 9601 deletions
diff --git a/mk/build.mk b/mk/build.mk index 4f59b8b..78bdd91 100644 --- a/mk/build.mk +++ b/mk/build.mk @@ -42,7 +42,7 @@ bin/mds-registry: $(OBJ_mds-registry) obj/mds-base.o bin/libmdsserver.so else bin/mds-registry: $(OBJ_mds-registry) obj/mds-base.o endif - @printf '\e[00;01;31mLD\e[34m %s\e[00m\n' "$@"o + @printf '\e[00;01;31mLD\e[34m %s\e[00m\n' "$@" @mkdir -p $(shell dirname $@) $(CC) $(C_FLAGS) -o $@ $(LDS) $(LDS_mds-registry) $(OBJ_mds-registry) obj/mds-base.o @echo diff --git a/src/libmdsclient.h b/src/libmdsclient.h index 4a01e16..0bb1ddc 100644 --- a/src/libmdsclient.h +++ b/src/libmdsclient.h @@ -25,4 +25,3 @@ #endif - diff --git a/src/libmdsclient/address.c b/src/libmdsclient/address.c index baa9798..a50bbaf 100644 --- a/src/libmdsclient/address.c +++ b/src/libmdsclient/address.c @@ -40,13 +40,13 @@ * @param str The string * @return Whether a string is a radix-10 non-negative integer */ -__attribute__((nonnull)) -static int is_pzinteger(const char* restrict str) +static int __attribute__((nonnull)) +is_pzinteger(const char *restrict str) { - for (; *str; str++) - if (('0' > *str) || (*str > '9')) - return 0; - return 1; + for (; *str; str++) + if ('0' > *str || *str > '9') + return 0; + return 1; } @@ -64,32 +64,32 @@ static int is_pzinteger(const char* restrict str) * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2). * @throws ENAMETOOLONG The filename of the target socket is too long */ -__attribute__((nonnull, format(gnu_printf, 3, 4))) -static int set_af_unix(struct sockaddr** restrict out_address, ssize_t* pathlen, const char* format, ...) -#define set_af_unix(a, f, ...) ((set_af_unix)(a, &pathlen, f "%zn", __VA_ARGS__, &pathlen)) +static int __attribute__((nonnull, format(gnu_printf, 3, 4))) +set_af_unix(struct sockaddr **restrict out_address, ssize_t *pathlen, const char *format, ...) +#define set_af_unix(a, f, ...) ((set_af_unix)(a, &pathlen, f "%zn", __VA_ARGS__, &pathlen)) { - struct sockaddr_un* address; - size_t maxlen; - va_list args; - - address = malloc(sizeof(struct sockaddr_un)); - *out_address = (struct sockaddr*)address; - if (address == NULL) - return -1; - - maxlen = sizeof(address->sun_path) / sizeof(address->sun_path[0]); - - va_start(args, format); - - address->sun_family = AF_UNIX; - vsnprintf(address->sun_path, maxlen, format, args); - - va_end(args); - - if ((size_t)*pathlen > maxlen) - return errno = ENAMETOOLONG, -1; - - return 0; + struct sockaddr_un *address; + size_t maxlen; + va_list args; + + address = malloc(sizeof(struct sockaddr_un)); + *out_address = (struct sockaddr*)address; + if (!address) + return -1; + + maxlen = sizeof(address->sun_path) / sizeof(address->sun_path[0]); + + va_start(args, format); + + address->sun_family = AF_UNIX; + vsnprintf(address->sun_path, maxlen, format, args); + + va_end(args); + + if ((size_t)*pathlen > maxlen) + return errno = ENAMETOOLONG, -1; + + return 0; } @@ -112,36 +112,36 @@ static int set_af_unix(struct sockaddr** restrict out_address, ssize_t* pathlen, * @throws ENOMEM Out of memory. Possibly, the application hit the * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2). */ -__attribute__((nonnull)) -static int set_af_inet(struct sockaddr** restrict out_address, socklen_t* restrict out_address_len, - int* restrict out_gai_error, int* restrict out_domain, int address_family, - const char* restrict host, const char* restrict port) +static int __attribute__((nonnull)) +set_af_inet(struct sockaddr **restrict out_address, socklen_t *restrict out_address_len, + int *restrict out_gai_error, int *restrict out_domain, int address_family, + const char *restrict host, const char *restrict port) { - struct addrinfo hints; - struct addrinfo* result; - int saved_errno; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = address_family; - - *out_gai_error = getaddrinfo(host, port, &hints, &result); - if (*out_gai_error) - return 0; - - *out_address = malloc(result->ai_addrlen); - if (*out_address == NULL) - return saved_errno = errno, freeaddrinfo(result), errno = saved_errno, -1; - memcpy(*out_address, result->ai_addr, result->ai_addrlen); - - *out_address_len = result->ai_addrlen; - *out_domain = - result->ai_family == AF_UNSPEC ? PF_UNSPEC : - result->ai_family == AF_INET ? PF_INET : - result->ai_family == AF_INET6 ? PF_INET6 : - result->ai_family; - - freeaddrinfo(result); - return 0; + struct addrinfo hints; + struct addrinfo *result; + int saved_errno; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = address_family; + + *out_gai_error = getaddrinfo(host, port, &hints, &result); + if (*out_gai_error) + return 0; + + *out_address = malloc(result->ai_addrlen); + if (!*out_address) + return saved_errno = errno, freeaddrinfo(result), errno = saved_errno, -1; + memcpy(*out_address, result->ai_addr, result->ai_addrlen); + + *out_address_len = result->ai_addrlen; + *out_domain = + result->ai_family == AF_UNSPEC ? PF_UNSPEC : + result->ai_family == AF_INET ? PF_INET : + result->ai_family == AF_INET6 ? PF_INET6 : + result->ai_family; + + freeaddrinfo(result); + return 0; } @@ -157,91 +157,100 @@ static int set_af_inet(struct sockaddr** restrict out_address, socklen_t* restri * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2). * @throws ENAMETOOLONG The filename of the target socket is too long */ -int libmds_parse_display_address(const char* restrict display, libmds_display_address_t* restrict address) +int +libmds_parse_display_address(const char *restrict display, libmds_display_address_t *restrict address) { - ssize_t pathlen = 0; - char* host; - char* port; - char* params; - size_t i = 0; - char c; - int esc = 0; - int colesc = 0; - - address->domain = -1; - address->type = -1; - address->protocol = -1; - address->address = NULL; - address->address_len = 0; - address->gai_error = 0; - - if (strchr(display, ':') == NULL) - return 0; - - if (*display == ':') - { - address->domain = PF_UNIX; - address->type = SOCK_STREAM; - address->protocol = 0; - address->address_len = sizeof(struct sockaddr_un); - - if (strstr(display, ":file:") == display) - return set_af_unix(&(address->address), "%s", display + 6); - else if (display[1] && is_pzinteger(display + 1)) - return set_af_unix(&(address->address), "%s/%s.socket", - MDS_RUNTIME_ROOT_DIRECTORY, display + 1); - return 0; - } - - host = alloca((strlen(display) + 1) * sizeof(char)); - - if (*display == '[') - colesc = 1, i++; - for (; (c = display[i]); i++) - if (esc) host[pathlen++] = c, esc = 0; - else if (c == '\\') esc = 1; - else if (c == ']') - if (colesc) { i++; break; } - else host[pathlen++] = c; - else if (c == ':') - if (colesc) host[pathlen++] = c; - else break; - else host[pathlen++] = c; - if (esc || (display[i++] != ':')) - return 0; - host[pathlen++] = '\0'; - - port = host + pathlen; - memcpy(port, display + i, (strlen(display) + 1 - i) * sizeof(char)); - params = strchr(port, ':'); - if (params != NULL) - *params++ = '\0'; - -#define param_test(f, n, a, b, c) \ - ((n >= 3) && (!strcasecmp(params, a ":" b ":" c))) || \ - ((n >= 2) && (!strcasecmp(params, a ":" b))) || \ - ((n >= 1) && (!strcasecmp(params, a))) || \ - (f == NULL ? 0 : !strcasecmp(params, f)) -#define set(d, t, p) \ - address->domain = (d), address->type = (t), address->protocol = (p) - - if (params == NULL) set(PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - else if (param_test("ip/tcp", 1, "ip", "stream", "tcp")) set(PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - else if (param_test("ipv4/tcp", 1, "ipv4", "stream", "tcp")) set(PF_INET, SOCK_STREAM, IPPROTO_TCP); - else if (param_test("ipv6/tcp", 1, "ipv6", "stream", "tcp")) set(PF_INET6, SOCK_STREAM, IPPROTO_TCP); - else if (param_test("inet/tcp", 1, "inet", "stream", "tcp")) set(PF_INET, SOCK_STREAM, IPPROTO_TCP); - else if (param_test("inet6/tcp", 1, "inet6", "stream", "tcp")) set(PF_INET6, SOCK_STREAM, IPPROTO_TCP); - else - return 0; - + ssize_t pathlen = 0; + char *host; + char *port; + char *params; + size_t i = 0; + char c; + int esc = 0; + int colesc = 0; + + address->domain = -1; + address->type = -1; + address->protocol = -1; + address->address = NULL; + address->address_len = 0; + address->gai_error = 0; + + if (!strchr(display, ':')) + return 0; + + if (*display == ':') { + address->domain = PF_UNIX; + address->type = SOCK_STREAM; + address->protocol = 0; + address->address_len = sizeof(struct sockaddr_un); + + if (strstr(display, ":file:") == display) + return set_af_unix(&(address->address), "%s", display + 6); + else if (display[1] && is_pzinteger(display + 1)) + return set_af_unix(&(address->address), "%s/%s.socket", + MDS_RUNTIME_ROOT_DIRECTORY, display + 1); + return 0; + } + + host = alloca((strlen(display) + 1) * sizeof(char)); + + if (*display == '[') + colesc = 1, i++; + for (; (c = display[i]); i++) { + if (esc) { + host[pathlen++] = c; + esc = 0; + } else if (c == '\\') { + esc = 1; + } else if (c == ']') { + if (colesc) + { i++; break; } + else + host[pathlen++] = c; + } else if (c == ':') { + if (colesc) + host[pathlen++] = c; + else + break; + } else { + host[pathlen++] = c; + } + } + if (esc || display[i++] != ':') + return 0; + host[pathlen++] = '\0'; + + port = host + pathlen; + memcpy(port, display + i, (strlen(display) + 1 - i) * sizeof(char)); + params = strchr(port, ':'); + if (params) + *params++ = '\0'; + +#define param_test(f, n, a, b, c)\ + ((n >= 3 && !strcasecmp(params, a ":" b ":" c)) ||\ + (n >= 2 && !strcasecmp(params, a ":" b)) ||\ + (n >= 1 && !strcasecmp(params, a)) ||\ + (!f ? 0 : !strcasecmp(params, f))) +#define set(d, t, p)\ + (address->domain = (d), address->type = (t), address->protocol = (p)) + + if (!params) set(PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + else if (param_test("ip/tcp", 1, "ip", "stream", "tcp")) set(PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + else if (param_test("ipv4/tcp", 1, "ipv4", "stream", "tcp")) set(PF_INET, SOCK_STREAM, IPPROTO_TCP); + else if (param_test("ipv6/tcp", 1, "ipv6", "stream", "tcp")) set(PF_INET6, SOCK_STREAM, IPPROTO_TCP); + else if (param_test("inet/tcp", 1, "inet", "stream", "tcp")) set(PF_INET, SOCK_STREAM, IPPROTO_TCP); + else if (param_test("inet6/tcp", 1, "inet6", "stream", "tcp")) set(PF_INET6, SOCK_STREAM, IPPROTO_TCP); + else + return 0; + #undef set #undef param_test - - return set_af_inet(&(address->address), &(address->address_len), - &(address->gai_error), &(address->domain), - address->domain == PF_UNSPEC ? AF_UNSPEC : - address->domain == PF_INET ? AF_INET : - address->domain == PF_INET6 ? AF_INET6 : - address->domain, host, port); -} + return set_af_inet(&(address->address), &(address->address_len), + &(address->gai_error), &(address->domain), + address->domain == PF_UNSPEC ? AF_UNSPEC : + address->domain == PF_INET ? AF_INET : + address->domain == PF_INET6 ? AF_INET6 : + address->domain, host, port); +} diff --git a/src/libmdsclient/address.h b/src/libmdsclient/address.h index 7d9089e..dab95db 100644 --- a/src/libmdsclient/address.h +++ b/src/libmdsclient/address.h @@ -27,50 +27,50 @@ */ typedef struct libmds_display_address { - /** - * The domain (protocol family), that is - * the first argument for socket(2), a - * value whose constant is prefixed PF_; - * -1 if not detected - */ - int domain; - - /** - * The socket type, that is the second - * argument for socket(2), a value whose - * constant is prefixed SOCK_; -1 if not - * detected - */ - int type; - - /** - * The protocol, that is the third - * argument for socket(2), a value whose - * constant is affixed PROTO_ (zero - * for the default); -1 if not detected - */ - int protocol; - - /** - * The address, `NULL` if not detected, - * you are responsible for freeing this - */ - struct sockaddr* address; - - /** - * The size of `address`, may be set - * even if `address` is `NULL` - */ - socklen_t address_len; - - /** - * Code for an error that has occured - * when parsing the address, whose - * description can be retrieved using - * `gia_strerror`, zero if none - */ - int gai_error; - + /** + * The domain (protocol family), that is + * the first argument for socket(2), a + * value whose constant is prefixed PF_; + * -1 if not detected + */ + int domain; + + /** + * The socket type, that is the second + * argument for socket(2), a value whose + * constant is prefixed SOCK_; -1 if not + * detected + */ + int type; + + /** + * The protocol, that is the third + * argument for socket(2), a value whose + * constant is affixed PROTO_ (zero + * for the default); -1 if not detected + */ + int protocol; + + /** + * The address, `NULL` if not detected, + * you are responsible for freeing this + */ + struct sockaddr *address; + + /** + * The size of `address`, may be set + * even if `address` is `NULL` + */ + socklen_t address_len; + + /** + * Code for an error that has occured + * when parsing the address, whose + * description can be retrieved using + * `gia_strerror`, zero if none + */ + int gai_error; + } libmds_display_address_t; @@ -87,8 +87,7 @@ typedef struct libmds_display_address * @throws ENAMETOOLONG The filename of the target socket is too long */ __attribute__((nonnull)) -int libmds_parse_display_address(const char* restrict display, libmds_display_address_t* restrict address); +int libmds_parse_display_address(const char *restrict display, libmds_display_address_t *restrict address); #endif - diff --git a/src/libmdsclient/comm.c b/src/libmdsclient/comm.c index c4ba23c..572ffb2 100644 --- a/src/libmdsclient/comm.c +++ b/src/libmdsclient/comm.c @@ -25,7 +25,7 @@ -#define min(a, b) ((a) < (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) @@ -40,17 +40,17 @@ * @throws ENOMEM See pthread_mutex_init(3) * @throws EPERM See pthread_mutex_init(3) */ -int libmds_connection_initialise(libmds_connection_t* restrict this) +int libmds_connection_initialise(libmds_connection_t *restrict this) { - this->socket_fd = -1; - this->message_id = UINT32_MAX; - this->client_id = NULL; - this->mutex_initialised = 0; - errno = pthread_mutex_init(&(this->mutex), NULL); - if (errno) - return -1; - this->mutex_initialised = 1; - return 0; + this->socket_fd = -1; + this->message_id = UINT32_MAX; + this->client_id = NULL; + this->mutex_initialised = 0; + errno = pthread_mutex_init(&(this->mutex), NULL); + if (errno) + return -1; + this->mutex_initialised = 1; + return 0; } @@ -65,12 +65,13 @@ int libmds_connection_initialise(libmds_connection_t* restrict this) * @throws EAGAIN See pthread_mutex_init(3) * @throws EPERM See pthread_mutex_init(3) */ -libmds_connection_t* libmds_connection_create(void) +libmds_connection_t * +libmds_connection_create(void) { - libmds_connection_t* rc = malloc(sizeof(libmds_connection_t)); - if (rc == NULL) - return NULL; - return libmds_connection_initialise(rc) ? NULL : rc; + libmds_connection_t *rc = malloc(sizeof(libmds_connection_t)); + if (!rc) + return NULL; + return libmds_connection_initialise(rc) ? NULL : rc; } @@ -79,25 +80,24 @@ libmds_connection_t* libmds_connection_create(void) * * @param this The connection descriptor, may be `NULL` */ -void libmds_connection_destroy(libmds_connection_t* restrict this) +void +libmds_connection_destroy(libmds_connection_t *restrict this) { - if (this == NULL) - return; - - if (this->socket_fd >= 0) - { - close(this->socket_fd); /* TODO Linux closes the filedescriptor on EINTR, but POSIX does not require that. */ - this->socket_fd = -1; - } - - free(this->client_id); - this->client_id = NULL; - - if (this->mutex_initialised) - { - this->mutex_initialised = 0; - pthread_mutex_destroy(&(this->mutex)); /* Can return EBUSY. */ - } + if (!this) + return; + + if (this->socket_fd >= 0) { + close(this->socket_fd); /* TODO Linux closes the filedescriptor on EINTR, but POSIX does not require that. */ + this->socket_fd = -1; + } + + free(this->client_id); + this->client_id = NULL; + + if (this->mutex_initialised) { + this->mutex_initialised = 0; + pthread_mutex_destroy(&(this->mutex)); /* Can return EBUSY. */ + } } @@ -107,10 +107,11 @@ void libmds_connection_destroy(libmds_connection_t* restrict this) * * @param this The connection descriptor, may be `NULL` */ -void libmds_connection_free(libmds_connection_t* restrict this) +void +libmds_connection_free(libmds_connection_t *restrict this) { - libmds_connection_destroy(this); - free(this); + libmds_connection_destroy(this); + free(this); } @@ -137,36 +138,37 @@ void libmds_connection_free(libmds_connection_t* restrict this) * @throws Any error specified for socket(2) * @throws Any error specified for connect(2), except EINTR */ -int libmds_connection_establish(libmds_connection_t* restrict this, const char** restrict display) +int +libmds_connection_establish(libmds_connection_t *restrict this, const char **restrict display) { - libmds_display_address_t addr; - int saved_errno; - - addr.address = NULL; - - if (*display == NULL) - *display = getenv("MDS_DISPLAY"); - - if ((*display == NULL) || (strchr(*display, ':') == NULL)) - goto efault; - - if (libmds_parse_display_address(*display, &addr) < 0) - goto fail; - - if (libmds_connection_establish_address(this, &addr) < 0) - goto fail; - - free(addr.address); - return 0; - - efault: - free(addr.address); - return errno = EFAULT, -1; - - fail: - saved_errno = errno; - free(addr.address); - return errno = saved_errno, -1; + libmds_display_address_t addr; + int saved_errno; + + addr.address = NULL; + + if (!*display) + *display = getenv("MDS_DISPLAY"); + + if (!*display || !strchr(*display, ':')) + goto efault; + + if (libmds_parse_display_address(*display, &addr) < 0) + goto fail; + + if (libmds_connection_establish_address(this, &addr) < 0) + goto fail; + + free(addr.address); + return 0; + +efault: + free(addr.address); + return errno = EFAULT, -1; + +fail: + saved_errno = errno; + free(addr.address); + return errno = saved_errno, -1; } @@ -186,28 +188,29 @@ int libmds_connection_establish(libmds_connection_t* restrict this, const char** * @throws Any error specified for socket(2) * @throws Any error specified for connect(2), except EINTR */ -int libmds_connection_establish_address(libmds_connection_t* restrict this, - const libmds_display_address_t* restrict address) +int +libmds_connection_establish_address(libmds_connection_t *restrict this, + const libmds_display_address_t *restrict address) { - if (address->domain < 0) goto efault; - if (address->type < 0) goto efault; - if (address->protocol < 0) goto efault; - if (address->address == NULL) goto efault; - - this->socket_fd = socket(address->domain, address->type, address->protocol); - if (this->socket_fd < 0) - goto fail; - - while (connect(this->socket_fd, address->address, address->address_len)) - if (errno != EINTR) - goto fail; - - return 0; - - efault: - errno = EFAULT; - fail: - return -1; + if (address->domain < 0) goto efault; + if (address->type < 0) goto efault; + if (address->protocol < 0) goto efault; + if (!address->address) goto efault; + + this->socket_fd = socket(address->domain, address->type, address->protocol); + if (this->socket_fd < 0) + goto fail; + + while (connect(this->socket_fd, address->address, address->address_len)) + if (errno != EINTR) + goto fail; + + return 0; + +efault: + errno = EFAULT; +fail: + return -1; } @@ -234,19 +237,20 @@ int libmds_connection_establish_address(libmds_connection_t* restrict this, * @throws ENOTSOCK See send(2) * @throws See pthread_mutex_lock(3) */ -size_t libmds_connection_send(libmds_connection_t* restrict this, const char* restrict message, size_t length) +size_t +libmds_connection_send(libmds_connection_t *restrict this, const char *restrict message, size_t length) { - int saved_errno; - size_t r; - - if (libmds_connection_lock(this)) - return 0; - - r = libmds_connection_send_unlocked(this, message, length, 1); - - saved_errno = errno; - (void) libmds_connection_unlock(this); - return errno = saved_errno, r; + int saved_errno; + size_t r; + + if (libmds_connection_lock(this)) + return 0; + + r = libmds_connection_send_unlocked(this, message, length, 1); + + saved_errno = errno; + (void) libmds_connection_unlock(this); + return errno = saved_errno, r; } @@ -274,36 +278,33 @@ size_t libmds_connection_send(libmds_connection_t* restrict this, const char* re * @throws ENOTCONN See send(2) * @throws ENOTSOCK See send(2) */ -size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const char* restrict message, - size_t length, int continue_on_interrupt) +size_t +libmds_connection_send_unlocked(libmds_connection_t *restrict this, const char *restrict message, + size_t length, int continue_on_interrupt) { - size_t block_size = length; - size_t sent = 0; - ssize_t just_sent; - - errno = 0; - while (length > 0) - if ((just_sent = send(this->socket_fd, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0) - { - if (errno == EPIPE) - errno = ECONNRESET; - if (errno == EMSGSIZE) - { - block_size >>= 1; - if (block_size == 0) - return sent; - } - else if ((errno == EINTR) && continue_on_interrupt) - continue; - else - return sent; - } - else - { - sent += (size_t)just_sent; - length -= (size_t)just_sent; - } - - return sent; -} + size_t block_size = length; + size_t sent = 0; + ssize_t just_sent; + errno = 0; + while (length > 0) { + if ((just_sent = send(this->socket_fd, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0) { + if (errno == EPIPE) + errno = ECONNRESET; + if (errno == EMSGSIZE) { + block_size >>= 1; + if (!block_size) + return sent; + } else if (errno == EINTR && continue_on_interrupt) { + continue; + } else { + return sent; + } + } else { + sent += (size_t)just_sent; + length -= (size_t)just_sent; + } + } + + return sent; +} diff --git a/src/libmdsclient/comm.h b/src/libmdsclient/comm.h index a162d0a..b726f2e 100644 --- a/src/libmdsclient/comm.h +++ b/src/libmdsclient/comm.h @@ -35,37 +35,37 @@ */ typedef struct libmds_connection { - /** - * The file descriptor of the socket - * connected to the display server, - * -1 if not connected - */ - int socket_fd; - - /** - * The ID of the _previous_ message - */ - uint32_t message_id; - - /** - * The client ID, `NULL` if anonymous - */ - char* client_id; - - /** - * Mutex used to hinder concurrent modification - * and concurrent message passing - * - * This mutex is a fast mutex, a thread may not - * lock it more than once - */ - pthread_mutex_t mutex; - - /** - * Whether `mutex` is initialised - */ - int mutex_initialised; - + /** + * The file descriptor of the socket + * connected to the display server, + * -1 if not connected + */ + int socket_fd; + + /** + * The ID of the _previous_ message + */ + uint32_t message_id; + + /** + * The client ID, `NULL` if anonymous + */ + char *client_id; + + /** + * Mutex used to hinder concurrent modification + * and concurrent message passing + * + * This mutex is a fast mutex, a thread may not + * lock it more than once + */ + pthread_mutex_t mutex; + + /** + * Whether `mutex` is initialised + */ + int mutex_initialised; + } libmds_connection_t; @@ -81,7 +81,7 @@ typedef struct libmds_connection * @throws EPERM See pthread_mutex_init(3) */ __attribute__((nonnull)) -int libmds_connection_initialise(libmds_connection_t* restrict this); +int libmds_connection_initialise(libmds_connection_t *restrict this); /** * Allocate and initialise a connection descriptor @@ -94,14 +94,14 @@ int libmds_connection_initialise(libmds_connection_t* restrict this); * @throws EAGAIN See pthread_mutex_init(3) * @throws EPERM See pthread_mutex_init(3) */ -libmds_connection_t* libmds_connection_create(void); +libmds_connection_t *libmds_connection_create(void); /** * Release all resources held by a connection descriptor * * @param this The connection descriptor, may be `NULL` */ -void libmds_connection_destroy(libmds_connection_t* restrict this); +void libmds_connection_destroy(libmds_connection_t *restrict this); /** * Release all resources held by a connection descriptor, @@ -109,7 +109,7 @@ void libmds_connection_destroy(libmds_connection_t* restrict this); * * @param this The connection descriptor, may be `NULL` */ -void libmds_connection_free(libmds_connection_t* restrict this); +void libmds_connection_free(libmds_connection_t *restrict this); /** * Connect to the display server @@ -135,7 +135,7 @@ void libmds_connection_free(libmds_connection_t* restrict this); * @throws Any error specified for connect(2), except EINTR */ __attribute__((nonnull)) -int libmds_connection_establish(libmds_connection_t* restrict this, const char** restrict display); +int libmds_connection_establish(libmds_connection_t *restrict this, const char **restrict display); /** * Connect to the display server @@ -153,8 +153,8 @@ int libmds_connection_establish(libmds_connection_t* restrict this, const char** * @throws Any error specified for connect(2), except EINTR */ __attribute__((nonnull)) -int libmds_connection_establish_address(libmds_connection_t* restrict this, - const libmds_display_address_t* restrict address); +int libmds_connection_establish_address(libmds_connection_t *restrict this, + const libmds_display_address_t *restrict address); /** * Wrapper for `libmds_connection_send_unlocked` that locks @@ -180,7 +180,7 @@ int libmds_connection_establish_address(libmds_connection_t* restrict this, * @throws See pthread_mutex_lock(3) */ __attribute__((nonnull)) -size_t libmds_connection_send(libmds_connection_t* restrict this, const char* restrict message, size_t length); +size_t libmds_connection_send(libmds_connection_t *restrict this, const char *restrict message, size_t length); /** * Send a message to the display server, without locking the @@ -207,8 +207,8 @@ size_t libmds_connection_send(libmds_connection_t* restrict this, const char* re * @throws ENOTSOCK See send(2) */ __attribute__((nonnull)) -size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const char* restrict message, - size_t length, int continue_on_interrupt); +size_t libmds_connection_send_unlocked(libmds_connection_t *restrict this, const char *restrict message, + size_t length, int continue_on_interrupt); /** * Lock the connection descriptor for being modified, @@ -220,8 +220,8 @@ size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const * * @throws See pthread_mutex_lock(3) */ -#define libmds_connection_lock(this) \ - (errno = pthread_mutex_lock(&((this)->mutex)), (errno ? 0 : -1)) +#define libmds_connection_lock(this)\ + (errno = pthread_mutex_lock(&((this)->mutex)), (errno ? 0 : -1)) /** * Lock the connection descriptor for being modified, @@ -233,8 +233,8 @@ size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const * * @throws See pthread_mutex_trylock(3) */ -#define libmds_connection_trylock(this) \ - (errno = pthread_mutex_trylock(&((this)->mutex)), (errno ? 0 : -1)) +#define libmds_connection_trylock(this)\ + (errno = pthread_mutex_trylock(&((this)->mutex)), (errno ? 0 : -1)) /** * Lock the connection descriptor for being modified, @@ -248,8 +248,8 @@ size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const * * @throws See pthread_mutex_timedlock(3) */ -#define libmds_connection_timedlock(this, deadline) \ - (errno = pthread_mutex_timedlock(&((this)->mutex), deadline), (errno ? 0 : -1)) +#define libmds_connection_timedlock(this, deadline)\ + (errno = pthread_mutex_timedlock(&((this)->mutex), deadline), (errno ? 0 : -1)) /** * Undo the action of `libmds_connection_lock`, `libmds_connection_trylock` @@ -261,24 +261,24 @@ size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const * * @throws See pthread_mutex_unlock(3) */ -#define libmds_connection_unlock(this) \ - (errno = pthread_mutex_unlock(&((this)->mutex)), (errno ? 0 : -1)) +#define libmds_connection_unlock(this)\ + (errno = pthread_mutex_unlock(&((this)->mutex)), (errno ? 0 : -1)) /** * Arguments for `libmds_compose` to compose the `Client ID`-header * * @param this: libmds_connection_t* The connection descriptor, must not be `NULL` */ -#define LIBMDS_HEADER_CLIENT_ID(this) \ - "?Client ID: %s", (this)->client_id != NULL, (this)->client_id +#define LIBMDS_HEADER_CLIENT_ID(this)\ + "?Client ID: %s", (this)->client_id != NULL, (this)->client_id /** * Arguments for `libmds_compose` to compose the `Message ID`-header * * @param this: libmds_connection_t* The connection descriptor, must not be `NULL` */ -#define LIBMDS_HEADER_MESSAGE_ID(this) \ - "Message ID: %"PRIu32, (this)->message_id +#define LIBMDS_HEADER_MESSAGE_ID(this)\ + "Message ID: %" PRIu32, (this)->message_id /** * Arguments for `libmds_compose` to compose the standard headers: @@ -286,10 +286,8 @@ size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const * * @param this: libmds_connection_t* The connection descriptor, must not be `NULL` */ -#define LIBMDS_HEADERS_STANDARD(this) \ - LIBMDS_HEADER_CLIENT_ID(this), LIBMDS_HEADER_MESSAGE_ID(this) - +#define LIBMDS_HEADERS_STANDARD(this)\ + LIBMDS_HEADER_CLIENT_ID(this), LIBMDS_HEADER_MESSAGE_ID(this) #endif - diff --git a/src/libmdsclient/inbound.c b/src/libmdsclient/inbound.c index ccff51e..4b74b58 100644 --- a/src/libmdsclient/inbound.c +++ b/src/libmdsclient/inbound.c @@ -28,8 +28,8 @@ #include <assert.h> -#define try(INSTRUCTION) if ((r = INSTRUCTION) < 0) return r -#define static_strlen(str) (sizeof(str) / sizeof(char) - 1) +#define try(INSTRUCTION) do { if ((r = INSTRUCTION) < 0) return r; } while (0) +#define static_strlen(str) (sizeof(str) / sizeof(char) - 1) @@ -44,18 +44,19 @@ * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_message_initialise(libmds_message_t* restrict this) +int +libmds_message_initialise(libmds_message_t *restrict this) { - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->buffer_size = 128; - this->buffer_ptr = 0; - this->stage = 0; - this->flattened = 0; - this->buffer = malloc(this->buffer_size * sizeof(char)); - return this->buffer == NULL ? -1 : 0; + this->headers = NULL; + this->header_count = 0; + this->payload = NULL; + this->payload_size = 0; + this->buffer_size = 128; + this->buffer_ptr = 0; + this->stage = 0; + this->flattened = 0; + this->buffer = malloc(this->buffer_size * sizeof(char)); + return this->buffer == NULL ? -1 : 0; } @@ -64,20 +65,20 @@ int libmds_message_initialise(libmds_message_t* restrict this) * * @param this The message */ -void libmds_message_destroy(libmds_message_t* restrict this) +void +libmds_message_destroy(libmds_message_t *restrict this) { - if (this->flattened == 0) - { - free(this->headers), this->headers = NULL; - free(this->buffer), this->buffer = NULL; - } + if (!this->flattened) { + free(this->headers), this->headers = NULL; + free(this->buffer), this->buffer = NULL; + } } /** * Release all resources in a message, should * be done even if initialisation fails -* + * * @param this The message * @param pool Message allocation pool, may be `NULL` * @return The duplicate, you do not need to call `libmds_message_destroy` @@ -88,36 +89,37 @@ void libmds_message_destroy(libmds_message_t* restrict this) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -libmds_message_t* libmds_message_duplicate(libmds_message_t* restrict this, libmds_mpool_t* restrict pool) +libmds_message_t * +libmds_message_duplicate(libmds_message_t *restrict this, libmds_mpool_t *restrict pool) { - size_t flattened_size, reused, i, n = this->header_count; - libmds_message_t* rc; - - flattened_size = sizeof(libmds_message_t) + this->buffer_off * sizeof(char) + n * sizeof(void*); - repoll: - reused = 0; - rc = pool == NULL ? NULL : libmds_mpool_poll(pool); - if (rc != NULL) - if ((reused = rc->flattened) < flattened_size) - { - free(rc); - goto repoll; - } - if ((rc == NULL) && (rc = malloc(flattened_size), rc == NULL)) - return NULL; - - *rc = *this; - rc->flattened = reused ? reused : flattened_size; - rc->buffer_size = this->buffer_off; - - rc->buffer = ((char*)rc) + sizeof(libmds_message_t) / sizeof(char); - rc->headers = rc->header_count ? (char**)(void*)(rc->buffer + this->buffer_off) : NULL; - rc->payload = rc->payload_size ? (rc->buffer + (size_t)(this->payload - this->buffer)) : NULL; - for (i = 0; i < n; i++) - rc->headers[i] = rc->buffer + (size_t)(this->headers[i] - this->buffer); - - memcpy(rc->buffer, this->buffer, this->buffer_off * sizeof(char)); - return rc; + size_t flattened_size, reused, i, n = this->header_count; + libmds_message_t *rc; + + flattened_size = sizeof(libmds_message_t) + this->buffer_off * sizeof(char) + n * sizeof(void*); +repoll: + reused = 0; + rc = !pool ? NULL : libmds_mpool_poll(pool); + if (rc) { + if ((reused = rc->flattened) < flattened_size) { + free(rc); + goto repoll; + } + } + if (!rc && !(rc = malloc(flattened_size))) + return NULL; + + *rc = *this; + rc->flattened = reused ? reused : flattened_size; + rc->buffer_size = this->buffer_off; + + rc->buffer = ((char*)rc) + sizeof(libmds_message_t) / sizeof(char); + rc->headers = rc->header_count ? (char**)(void*)(rc->buffer + this->buffer_off) : NULL; + rc->payload = rc->payload_size ? (rc->buffer + (size_t)(this->payload - this->buffer)) : NULL; + for (i = 0; i < n; i++) + rc->headers[i] = rc->buffer + (size_t)(this->headers[i] - this->buffer); + + memcpy(rc->buffer, this->buffer, this->buffer_off * sizeof(char)); + return rc; } @@ -128,73 +130,71 @@ libmds_message_t* libmds_message_duplicate(libmds_message_t* restrict this, libm * @param allow_modified_nul Whether Modified UTF-8 is allowed, which allows a two-byte encoding for NUL * @return Zero if good, -1 on encoding error */ -__attribute__((nonnull, warn_unused_result)) /* Cannibalised from <libmdsserver/util.h>. */ -static int verify_utf8(const char* string, int allow_modified_nul) +static int __attribute__((nonnull, warn_unused_result)) /* Cannibalised from <libmdsserver/util.h>. */ +verify_utf8(const char *string, int allow_modified_nul) { - static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; - static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; - long bytes = 0, read_bytes = 0, bits = 0, c, character; - - /* min bits max bits - 0....... 0 7 - 110..... 10...... 8 11 - 1110.... 10...... 10...... 12 16 - 11110... 10...... 10...... 10...... 17 21 - 111110.. 10...... 10...... 10...... 10...... 22 26 - 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 - */ - - while ((c = (long)(*string++))) - if (read_bytes == 0) - { - /* First byte of the character. */ - - if ((c & 0x80) == 0x00) - /* Single-byte character. */ - continue; - - if ((c & 0xC0) == 0x80) - /* Single-byte character marked as multibyte, or - a non-first byte in a multibyte character. */ - return -1; - - /* Multibyte character. */ - while ((c & 0x80)) - bytes++, c <<= 1; - read_bytes = 1; - character = c & 0x7F; - if (bytes > 6) - /* 31-bit characters can be encoded with 6-bytes, - and UTF-8 does not cover higher code points. */ - return -1; - } - else - { - /* Not first byte of the character. */ - - if ((c & 0xC0) != 0x80) - /* Beginning of new character before a - multibyte character has ended. */ - return -1; - - character = (character << 6) | (c & 0x7F); - - if (++read_bytes < bytes) - /* Not at last byte yet. */ - continue; - - /* Check that the character is not unnecessarily long. */ - while (character) - character >>= 1, bits++; - bits = ((bits == 0) && (bytes == 2) && allow_modified_nul) ? 8 : bits; - if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) - return -1; - - read_bytes = bytes = bits = 0; - } - - /* Make sure we did not stop at the middle of a multibyte character. */ - return read_bytes == 0 ? 0 : -1; + static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; + static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; + long bytes = 0, read_bytes = 0, bits = 0, c, character; + + /* min bits max bits + 0....... 0 7 + 110..... 10...... 8 11 + 1110.... 10...... 10...... 12 16 + 11110... 10...... 10...... 10...... 17 21 + 111110.. 10...... 10...... 10...... 10...... 22 26 + 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 + */ + + while ((c = (long)(*string++))) { + if (!read_bytes) { + /* First byte of the character. */ + + if (!(c & 0x80)) + /* Single-byte character. */ + continue; + + if ((c & 0xC0) == 0x80) + /* Single-byte character marked as multibyte, or + a non-first byte in a multibyte character. */ + return -1; + + /* Multibyte character. */ + while ((c & 0x80)) + bytes++, c <<= 1; + read_bytes = 1; + character = c & 0x7F; + if (bytes > 6) + /* 31-bit characters can be encoded with 6-bytes, + and UTF-8 does not cover higher code points. */ + return -1; + } else { + /* Not first byte of the character. */ + + if ((c & 0xC0) != 0x80) + /* Beginning of new character before a + multibyte character has ended. */ + return -1; + + character = (character << 6) | (c & 0x7F); + + if (++read_bytes < bytes) + /* Not at last byte yet. */ + continue; + + /* Check that the character is not unnecessarily long. */ + while (character) + character >>= 1, bits++; + bits = ((bits == 0) && (bytes == 2) && allow_modified_nul) ? 8 : bits; + if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) + return -1; + + read_bytes = bytes = bits = 0; + } + } + + /* Make sure we did not stop at the middle of a multibyte character. */ + return read_bytes == 0 ? 0 : -1; } @@ -209,14 +209,14 @@ static int verify_utf8(const char* string, int allow_modified_nul) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -__attribute__((nonnull, warn_unused_result)) -static int extend_headers(libmds_message_t* restrict this, size_t extent) +static int __attribute__((nonnull, warn_unused_result)) +extend_headers(libmds_message_t *restrict this, size_t extent) { - char** new_headers = realloc(this->headers, (this->header_count + extent) * sizeof(char*)); - if (new_headers == NULL) - return -1; - this->headers = new_headers; - return 0; + char **new_headers = realloc(this->headers, (this->header_count + extent) * sizeof(char *)); + if (!new_headers) + return -1; + this->headers = new_headers; + return 0; } @@ -230,19 +230,19 @@ static int extend_headers(libmds_message_t* restrict this, size_t extent) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -__attribute__((nonnull, warn_unused_result)) -static int extend_buffer(libmds_message_t* restrict this, int shift) +static int __attribute__((nonnull, warn_unused_result)) +extend_buffer(libmds_message_t *restrict this, int shift) { - size_t i, n = this->header_count; - char* new_buf = realloc(this->buffer, (this->buffer_size << shift) * sizeof(char)); - if (new_buf == NULL) - return -1; - if (new_buf != this->buffer) - for (i = 0; i < n; i++) - this->headers[i] = new_buf + (size_t)(this->headers[i] - this->buffer); - this->buffer = new_buf; - this->buffer_size <<= shift; - return 0; + size_t i, n = this->header_count; + char *new_buf = realloc(this->buffer, (this->buffer_size << shift) * sizeof(char)); + if (!new_buf) + return -1; + if (new_buf != this->buffer) + for (i = 0; i < n; i++) + this->headers[i] = new_buf + (size_t)(this->headers[i] - this->buffer); + this->buffer = new_buf; + this->buffer_size <<= shift; + return 0; } /** @@ -250,22 +250,22 @@ static int extend_buffer(libmds_message_t* restrict this, int shift) * * @param this The message */ -__attribute__((nonnull)) -static void reset_message(libmds_message_t* restrict this) +static void __attribute__((nonnull)) +reset_message(libmds_message_t *restrict this) { - size_t overrun = this->buffer_ptr - this->buffer_off; - - if (overrun) - memmove(this->buffer, this->buffer + this->buffer_off, overrun * sizeof(char)); - this->buffer_ptr -= this->buffer_off; - this->buffer_off = 0; - - free(this->headers); - this->headers = NULL; - this->header_count = 0; - - this->payload = NULL; - this->payload_size = 0; + size_t overrun = this->buffer_ptr - this->buffer_off; + + if (overrun) + memmove(this->buffer, this->buffer + this->buffer_off, overrun * sizeof(char)); + this->buffer_ptr -= this->buffer_off; + this->buffer_off = 0; + + free(this->headers); + this->headers = NULL; + this->header_count = 0; + + this->payload = NULL; + this->payload_size = 0; } @@ -275,29 +275,29 @@ static void reset_message(libmds_message_t* restrict this) * @param this The message * @return Zero on success, negative on error (malformated message: unrecoverable state) */ -__attribute__((pure, nonnull, warn_unused_result)) -static int get_payload_length(libmds_message_t* restrict this) +static int __attribute__((pure, nonnull, warn_unused_result)) +get_payload_length(libmds_message_t *restrict this) { - char* header; - size_t i; - - for (i = 0; i < this->header_count; i++) - if (strstr(this->headers[i], "Length: ") == this->headers[i]) - { - /* Store the message length. */ - header = this->headers[i] + static_strlen("Length: "); - this->payload_size = (size_t)atoll(header); - - /* Do not except a length that is not correctly formated. */ - for (; *header; header++) - if ((*header < '0') || ('9' < *header)) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Stop searching for the ‘Length’ header, we have found and parsed it. */ - break; - } - - return 0; + char *header; + size_t i; + + for (i = 0; i < this->header_count; i++) { + if (strstr(this->headers[i], "Length: ") == this->headers[i]) { + /* Store the message length. */ + header = this->headers[i] + static_strlen("Length: "); + this->payload_size = (size_t)atoll(header); + + /* Do not except a length that is not correctly formated. */ + for (; *header; header++) + if (*header < '0' || '9' < *header) + return -2; /* Malformated value, enters unrecoverable state. */ + + /* Stop searching for the ‘Length’ header, we have found and parsed it. */ + break; + } + } + + return 0; } @@ -308,21 +308,21 @@ static int get_payload_length(libmds_message_t* restrict this) * @param length The length of the header * @return Zero if valid, negative if invalid (malformated message: unrecoverable state) */ -__attribute__((pure, nonnull, warn_unused_result)) -static int validate_header(const char* header, size_t length) +static int __attribute__((pure, nonnull, warn_unused_result)) +validate_header(const char *header, size_t length) { - char* p = memchr(header, ':', length * sizeof(char)); - - if (verify_utf8(header, 0) < 0) - /* Either the string is not UTF-8, or your are under an UTF-8 attack, - let's just call this unrecoverable because the client will not correct. */ - return -2; - - if ((p == NULL) || /* Buck you, rawmemchr should not segfault the program. */ - (p[1] != ' ')) /* Also an invalid format. ' ' is mandated after the ':'. */ - return -2; - - return 0; + char *p = memchr(header, ':', length * sizeof(char)); + + if (verify_utf8(header, 0) < 0) + /* Either the string is not UTF-8, or your are under an UTF-8 attack, + let's just call this unrecoverable because the client will not correct. */ + return -2; + + if (!p || /* Buck you, rawmemchr should not segfault the program. */ + (p[1] != ' ')) /* Also an invalid format. ' ' is mandated after the ':'. */ + return -2; + + return 0; } @@ -336,28 +336,28 @@ static int validate_header(const char* header, size_t length) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -__attribute__((nonnull)) -static int initialise_payload(libmds_message_t* restrict this) +static int __attribute__((nonnull)) +initialise_payload(libmds_message_t *restrict this) { - int shift = 0; - - /* Skip over the \n (end of empty line) we found from the buffer. */ - this->buffer_off++; - - /* Get the length of the payload. */ - if (get_payload_length(this) < 0) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Reallocate the buffer if it is too small. */ - while (this->buffer_off + this->payload_size > this->buffer_size << shift) - shift++; - if (shift ? (extend_buffer(this, shift) < 0) : 0) - return -1; - - /* Set pointer to payload. */ - this->payload = this->buffer + this->buffer_off; - - return 0; + int shift = 0; + + /* Skip over the \n (end of empty line) we found from the buffer. */ + this->buffer_off++; + + /* Get the length of the payload. */ + if (get_payload_length(this) < 0) + return -2; /* Malformated value, enters unrecoverable state. */ + + /* Reallocate the buffer if it is too small. */ + while (this->buffer_off + this->payload_size > this->buffer_size << shift) + shift++; + if (shift ? (extend_buffer(this, shift) < 0) : 0) + return -1; + + /* Set pointer to payload. */ + this->payload = this->buffer + this->buffer_off; + + return 0; } @@ -371,28 +371,28 @@ static int initialise_payload(libmds_message_t* restrict this) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -__attribute__((nonnull, warn_unused_result)) -static int store_header(libmds_message_t* restrict this, size_t length) +static int __attribute__((nonnull, warn_unused_result)) +store_header(libmds_message_t *restrict this, size_t length) { - char* header; - - /* Get pointer to header in buffer. */ - header = this->buffer + this->buffer_off; - /* NUL-terminate the header. */ - header[length - 1] = '\0'; - - /* Update read offset. */ - this->buffer += length; - - /* Make sure the the header syntax is correct so that - the program does not need to care about it. */ - if (validate_header(header, length)) - return -2; - - /* Store the header in the header list. */ - this->headers[this->header_count++] = header; - - return 0; + char *header; + + /* Get pointer to header in buffer. */ + header = this->buffer + this->buffer_off; + /* NUL-terminate the header. */ + header[length - 1] = '\0'; + + /* Update read offset. */ + this->buffer += length; + + /* Make sure the the header syntax is correct so that + the program does not need to care about it. */ + if (validate_header(header, length)) + return -2; + + /* Store the header in the header list. */ + this->headers[this->header_count++] = header; + + return 0; } @@ -407,36 +407,35 @@ static int store_header(libmds_message_t* restrict this, size_t length) * RLIMIT_DATA limit described in getrlimit(2). * @throws Any error specified for recv(3) */ -__attribute__((nonnull)) -static int continue_read(libmds_message_t* restrict this, int fd) +static int __attribute__((nonnull)) +continue_read(libmds_message_t *restrict this, int fd) { - size_t n; - ssize_t got; - int r; - - /* Figure out how much space we have left in the read buffer. */ - n = this->buffer_size - this->buffer_ptr; - - /* If we do not have too much left, */ - if (n < 128) - { - /* grow the buffer, */ - try (extend_buffer(this, 1)); + size_t n; + ssize_t got; + int r; + + /* Figure out how much space we have left in the read buffer. */ + n = this->buffer_size - this->buffer_ptr; + + /* If we do not have too much left, */ + if (n < 128) { + /* grow the buffer, */ + try (extend_buffer(this, 1)); - /* and recalculate how much space we have left. */ - n = this->buffer_size - this->buffer_ptr; - } - - /* Then read from the socket. */ - errno = 0; - got = recv(fd, this->buffer + this->buffer_ptr, n, 0); - this->buffer_ptr += (size_t)(got < 0 ? 0 : got); - if (errno) - return -1; - if (got == 0) - return errno = ECONNRESET, -1; - - return 0; + /* and recalculate how much space we have left. */ + n = this->buffer_size - this->buffer_ptr; + } + + /* Then read from the socket. */ + errno = 0; + got = recv(fd, this->buffer + this->buffer_ptr, n, 0); + this->buffer_ptr += (size_t)(got < 0 ? 0 : got); + if (errno) + return -1; + if (!got) + return errno = ECONNRESET, -1; + + return 0; } @@ -457,77 +456,71 @@ static int continue_read(libmds_message_t* restrict this, int fd) * RLIMIT_DATA limit described in getrlimit(2). * @throws Any error specified for recv(3) */ -int libmds_message_read(libmds_message_t* restrict this, int fd) +int +libmds_message_read(libmds_message_t *restrict this, int fd) { - size_t header_commit_buffer = 0; - int r; - - /* If we are at stage 2, we are done and it is time to start over. - This is important because the function could have been interrupted. */ - if (this->stage == 2) - { - reset_message(this); - this->stage = 0; - } - - /* Read from file descriptor until we have a full message. */ - for (;;) - { - char* p; - size_t length; - - /* Stage 0: headers. */ - /* Read all headers that we have stored into the read buffer. */ - while ((this->stage == 0) && - ((p = memchr(this->buffer + this->buffer_off, '\n', - (this->buffer_ptr - this->buffer_off) * sizeof(char))) != NULL)) - if ((length = (size_t)(p - (this->buffer + this->buffer_off)))) - { - /* We have found a header. */ - - /* On every eighth header found with this function call, - we prepare the header list for eight more headers so - that it does not need to be reallocated again and again. */ - if (header_commit_buffer == 0) - try (extend_headers(this, header_commit_buffer = 8)); - - /* Store header. */ - try (store_header(this, length + 1)); - header_commit_buffer -= 1; - } - else - { - /* We have found an empty line, i.e. the end of the headers. */ - - /* Make sure the full payload fits the buffer, and set - * the payload buffer pointer. */ - try (initialise_payload(this)); - - /* Mark end of stage, next stage is getting the payload. */ - this->stage = 1; - } - - - /* Stage 1: payload. */ - if ((this->stage == 1) && (this->buffer_ptr - this->buffer_off >= this->payload_size)) - { - /* If we have filled the payload (or there was no payload), - mark the end of this stage, i.e. that the message is - complete, and return with success. */ - this->stage = 2; - - /* Mark the end of the message. */ - this->buffer_off += this->payload_size; - - return 0; + size_t header_commit_buffer = 0; + int r; + char *p; + size_t length; + + /* If we are at stage 2, we are done and it is time to start over. + This is important because the function could have been interrupted. */ + if (this->stage == 2) { + reset_message(this); + this->stage = 0; + } + + /* Read from file descriptor until we have a full message. */ + for (;;) { + /* Stage 0: headers. */ + /* Read all headers that we have stored into the read buffer. */ + while (!this->stage && ((p = memchr(this->buffer + this->buffer_off, '\n', + (this->buffer_ptr - this->buffer_off) * sizeof(char))))) { + if ((length = (size_t)(p - (this->buffer + this->buffer_off)))) { + /* We have found a header. */ + + /* On every eighth header found with this function call, + we prepare the header list for eight more headers so + that it does not need to be reallocated again and again. */ + if (!header_commit_buffer) + try (extend_headers(this, header_commit_buffer = 8)); + + /* Store header. */ + try (store_header(this, length + 1)); + header_commit_buffer -= 1; + } else { + /* We have found an empty line, i.e. the end of the headers. */ + + /* Make sure the full payload fits the buffer, and set + * the payload buffer pointer. */ + try (initialise_payload(this)); + + /* Mark end of stage, next stage is getting the payload. */ + this->stage = 1; + } + } + + + /* Stage 1: payload. */ + if (this->stage == 1 && this->buffer_ptr - this->buffer_off >= this->payload_size) { + /* If we have filled the payload (or there was no payload), + mark the end of this stage, i.e. that the message is + complete, and return with success. */ + this->stage = 2; + + /* Mark the end of the message. */ + this->buffer_off += this->payload_size; + + return 0; + } + + + /* If stage 1 was not completed. */ + + /* Continue reading from the socket into the buffer. */ + try (continue_read(this, fd)); } - - - /* If stage 1 was not completed. */ - - /* Continue reading from the socket into the buffer. */ - try (continue_read(this, fd)); - } } @@ -541,29 +534,30 @@ int libmds_message_read(libmds_message_t* restrict this, int fd) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_mspool_initialise(libmds_mspool_t* restrict this) +int +libmds_mspool_initialise(libmds_mspool_t *restrict this) { - int stage = 0, saved_errno; - this->size = 1; - this->head = 0; - this->tail = 0; - this->spooled_bytes = 0; - this->spool_limit_bytes = 4 << 10; - this->spool_limit_messages = 8; - this->please_post = 0; - this->messages = malloc(sizeof(libmds_message_t*)); - if (this->messages == NULL) - return -1; - if (sem_init(&(this->lock), 0, 1) < 0) goto fail; else stage++; - if (sem_init(&(this->semaphore), 0, 0) < 0) goto fail; else stage++; - if (sem_init(&(this->wait_semaphore), 0, 0) < 0) goto fail; - return 0; + int stage = 0, saved_errno; + this->size = 1; + this->head = 0; + this->tail = 0; + this->spooled_bytes = 0; + this->spool_limit_bytes = 4 << 10; + this->spool_limit_messages = 8; + this->please_post = 0; + this->messages = malloc(sizeof(libmds_message_t*)); + if (!this->messages) + return -1; + if (sem_init(&(this->lock), 0, 1) < 0) goto fail; else stage++; + if (sem_init(&(this->semaphore), 0, 0) < 0) goto fail; else stage++; + if (sem_init(&(this->wait_semaphore), 0, 0) < 0) goto fail; + return 0; fail: - saved_errno = errno; - if (stage >= 1) sem_destroy(&(this->lock)); - if (stage >= 2) sem_destroy(&(this->semaphore)); - free(this->messages), this->messages = NULL; - return errno = saved_errno, -1; + saved_errno = errno; + if (stage >= 1) sem_destroy(&(this->lock)); + if (stage >= 2) sem_destroy(&(this->semaphore)); + free(this->messages), this->messages = NULL; + return errno = saved_errno, -1; } @@ -572,17 +566,18 @@ int libmds_mspool_initialise(libmds_mspool_t* restrict this) * * @param this The message spool */ -void libmds_mspool_destroy(libmds_mspool_t* restrict this) +void +libmds_mspool_destroy(libmds_mspool_t *restrict this) { - if (this->messages == NULL) - return; - while (this->tail < this->head) - free(this->messages[this->tail++]); - sem_destroy(&(this->lock)); - sem_destroy(&(this->semaphore)); - sem_destroy(&(this->wait_semaphore)); - free(this->messages); - this->messages = NULL; + if (!this->messages) + return; + while (this->tail < this->head) + free(this->messages[this->tail++]); + sem_destroy(&(this->lock)); + sem_destroy(&(this->semaphore)); + sem_destroy(&(this->wait_semaphore)); + free(this->messages); + this->messages = NULL; } @@ -597,61 +592,59 @@ void libmds_mspool_destroy(libmds_mspool_t* restrict this) * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_mspool_spool(libmds_mspool_t* restrict this, libmds_message_t* restrict message) +int +libmds_mspool_spool(libmds_mspool_t *restrict this, libmds_message_t *restrict message) { - libmds_message_t** new; - int saved_errno; - - start_over: - /* Lock. */ - if (sem_wait(&(this->lock)) < 0) - return -1; - - /* Block if spool is full. */ - if ((this->spooled_bytes >= this->spool_limit_bytes) || - (this->head - this->tail >= this->spool_limit_messages)) - { - this->please_post++; - if ((sem_post(&(this->lock)) < 0) || (sem_wait(&(this->wait_semaphore)) < 0)) - return this->please_post--, -1; - goto start_over; - } - - /* Rebase if the tail has come too far. */ - if (this->tail << 1 > this->size) - { - memmove(this->messages, this->messages + this->tail, - (this->head - this->tail) * sizeof(sizeof(libmds_message_t*))); - this->head -= this->tail, this->tail = 0; - } - - /* Grow the spool if necessary. */ - if (this->size == this->head) - { - new = realloc(this->messages, (this->size << 1) * sizeof(libmds_message_t*)); - if (new == NULL) - goto fail; - this->messages = new; - this->size <<= 1; - } - - /* Spool. */ - this->spooled_bytes += message->flattened; - this->messages[this->head++] = message; - - /* Signal. */ - if (sem_post(&(this->semaphore)) < 0) - goto fail; - - /* Unlock. */ - if (sem_post(&(this->lock)) < 0) - return -1; - - return 0; - fail: - saved_errno = errno; - sem_post(&(this->lock)); - return errno = saved_errno, -1; + libmds_message_t **new; + int saved_errno; + +start_over: + /* Lock. */ + if (sem_wait(&(this->lock)) < 0) + return -1; + + /* Block if spool is full. */ + if ((this->spooled_bytes >= this->spool_limit_bytes) || + (this->head - this->tail >= this->spool_limit_messages)) { + this->please_post++; + if (sem_post(&this->lock) < 0 || sem_wait(&this->wait_semaphore) < 0) + return this->please_post--, -1; + goto start_over; + } + + /* Rebase if the tail has come too far. */ + if (this->tail << 1 > this->size) { + memmove(this->messages, this->messages + this->tail, + (this->head - this->tail) * sizeof(sizeof(libmds_message_t *))); + this->head -= this->tail, this->tail = 0; + } + + /* Grow the spool if necessary. */ + if (this->size == this->head) { + new = realloc(this->messages, (this->size << 1) * sizeof(libmds_message_t *)); + if (!new) + goto fail; + this->messages = new; + this->size <<= 1; + } + + /* Spool. */ + this->spooled_bytes += message->flattened; + this->messages[this->head++] = message; + + /* Signal. */ + if (sem_post(&(this->semaphore)) < 0) + goto fail; + + /* Unlock. */ + if (sem_post(&(this->lock)) < 0) + return -1; + + return 0; +fail: + saved_errno = errno; + sem_post(&(this->lock)); + return errno = saved_errno, -1; } @@ -661,38 +654,38 @@ int libmds_mspool_spool(libmds_mspool_t* restrict this, libmds_message_t* restri * @param this The message spool, must not be empty * @return A spooled message, `NULL`on error, `errno` will be set accordingly */ -static inline libmds_message_t* mspool_poll(libmds_mspool_t* restrict this) +static inline libmds_message_t * +mspool_poll(libmds_mspool_t *restrict this) { - libmds_message_t* msg; - - /* Lock. */ - if (sem_wait(&(this->lock)) < 0) - return sem_post(&(this->semaphore)), NULL; - - /* Fetch message. */ - assert(this->tail < this->head); - msg = this->messages[this->tail++]; - this->spooled_bytes -= msg->flattened; - - /* Unblock spooler, takes effect when this->lock is unlocked. */ - if (this->please_post) - { - if (sem_post(&(this->wait_semaphore)) < 0) - perror("libmsdclient"); - else - this->please_post--; - } - - /* Unlock. */ - if (sem_post(&(this->lock)) < 0) - goto fail; - - return msg; - fail: - sem_post(&(this->semaphore)); - this->messages[--(this->tail)] = msg; - this->spooled_bytes += msg->flattened; - return NULL; + libmds_message_t *msg; + + /* Lock. */ + if (sem_wait(&(this->lock)) < 0) + return sem_post(&(this->semaphore)), NULL; + + /* Fetch message. */ + assert(this->tail < this->head); + msg = this->messages[this->tail++]; + this->spooled_bytes -= msg->flattened; + + /* Unblock spooler, takes effect when this->lock is unlocked. */ + if (this->please_post) { + if (sem_post(&(this->wait_semaphore)) < 0) + perror("libmsdclient"); + else + this->please_post--; + } + + /* Unlock. */ + if (sem_post(&(this->lock)) < 0) + goto fail; + + return msg; +fail: + sem_post(&(this->semaphore)); + this->messages[--(this->tail)] = msg; + this->spooled_bytes += msg->flattened; + return NULL; } @@ -704,13 +697,14 @@ static inline libmds_message_t* mspool_poll(libmds_mspool_t* restrict this) * * @throws EINTR If interrupted */ -libmds_message_t* libmds_mspool_poll(libmds_mspool_t* restrict this) +libmds_message_t * +libmds_mspool_poll(libmds_mspool_t *restrict this) { - /* Wait until there is a message available. */ - if (sem_wait(&(this->semaphore)) < 0) - return NULL; - - return mspool_poll(this); + /* Wait until there is a message available. */ + if (sem_wait(&(this->semaphore)) < 0) + return NULL; + + return mspool_poll(this); } @@ -728,16 +722,16 @@ libmds_message_t* libmds_mspool_poll(libmds_mspool_t* restrict this) * @throws EINVAL If `deadline->tv_nsecs` is outside [0, 1 milliard[ * @throws ETIMEDOUT If the time specified `deadline` passed and the spool was till empty */ -libmds_message_t* libmds_mspool_poll_try(libmds_mspool_t* restrict this, - const struct timespec* restrict deadline) +libmds_message_t * +libmds_mspool_poll_try(libmds_mspool_t *restrict this, const struct timespec *restrict deadline) { - /* Is a message available? */ - if ((deadline == NULL) && (sem_trywait(&(this->semaphore)) < 0)) - return NULL; - if ((deadline != NULL) && (sem_timedwait(&(this->semaphore), deadline) < 0)) - return NULL; - - return mspool_poll(this); + /* Is a message available? */ + if (!deadline && sem_trywait(&this->semaphore) < 0) + return NULL; + if (deadline && sem_timedwait(&this->semaphore, deadline) < 0) + return NULL; + + return mspool_poll(this); } @@ -752,21 +746,22 @@ libmds_message_t* libmds_mspool_poll_try(libmds_mspool_t* restrict this, * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_mpool_initialise(libmds_mpool_t* restrict this, size_t size) +int +libmds_mpool_initialise(libmds_mpool_t *restrict this, size_t size) { - int saved_errno; - this->size = size; - this->tip = 0; - this->messages = malloc(size * sizeof(libmds_message_t*)); - if (this->messages == NULL) - return -1; - if (sem_init(&(this->lock), 0, 1) < 0) - goto fail; - return 0; - fail: - saved_errno = errno; - free(this->messages), this->messages = NULL; - return errno = saved_errno, -1; + int saved_errno; + this->size = size; + this->tip = 0; + this->messages = malloc(size * sizeof(libmds_message_t*)); + if (!this->messages) + return -1; + if (sem_init(&this->lock, 0, 1) < 0) + goto fail; + return 0; +fail: + saved_errno = errno; + free(this->messages), this->messages = NULL; + return errno = saved_errno, -1; } @@ -776,15 +771,16 @@ int libmds_mpool_initialise(libmds_mpool_t* restrict this, size_t size) * * @param this The message allocation pool */ -void libmds_mpool_destroy(libmds_mpool_t* restrict this) +void +libmds_mpool_destroy(libmds_mpool_t *restrict this) { - if (this->messages == NULL) - return; - while (this->tip--) - free(this->messages[this->tip]); - sem_destroy(&(this->lock)); - free(this->messages); - this->messages = NULL; + if (!this->messages) + return; + while (this->tip--) + free(this->messages[this->tip]); + sem_destroy(&this->lock); + free(this->messages); + this->messages = NULL; } @@ -797,32 +793,32 @@ void libmds_mpool_destroy(libmds_mpool_t* restrict this) * or `libmds_mspool_poll_try`) * @return Zero on success, -1 on error, `errno` will be set accordingly */ -int libmds_mpool_offer(libmds_mpool_t* restrict this, libmds_message_t* restrict message) +int +libmds_mpool_offer(libmds_mpool_t *restrict this, libmds_message_t *restrict message) { - /* Discard if pool is full. */ - if (this->tip == this->size) - return free(message), 0; - - /* Lock. */ - if (sem_wait(&(this->lock)) < 0) - return -1; - - /* Discard if pool is still full. */ - if (this->tip == this->size) - { - free(message); - goto unlock; - } - - /* Pool allocation. */ - this->messages[this->tip++] = message; - - unlock: - /* Unlock. */ - if (sem_post(&(this->lock)) < 0) - return -1; - - return 0; + /* Discard if pool is full. */ + if (this->tip == this->size) + return free(message), 0; + + /* Lock. */ + if (sem_wait(&this->lock) < 0) + return -1; + + /* Discard if pool is still full. */ + if (this->tip == this->size) { + free(message); + goto unlock; + } + + /* Pool allocation. */ + this->messages[this->tip++] = message; + +unlock: + /* Unlock. */ + if (sem_post(&this->lock) < 0) + return -1; + + return 0; } @@ -834,26 +830,27 @@ int libmds_mpool_offer(libmds_mpool_t* restrict this, libmds_message_t* restrict * are available. If `NULL` is returned, `errno` is set to zero, * if the pool was empty, otherwise `errno` will describe the error. */ -libmds_message_t* libmds_mpool_poll(libmds_mpool_t* restrict this) +libmds_message_t * +libmds_mpool_poll(libmds_mpool_t *restrict this) { - libmds_message_t* msg = NULL; - - /* Is the pool empty? Return nothing. */ - if (this->tip == 0) - return errno = 0, NULL; - - /* Lock. */ - if (sem_wait(&(this->lock)) < 0) - return NULL; - - /* Do we have a message? Take it */ - if (this->tip) - msg = this->messages[--(this->tip)]; - - /* Unlock. */ - if (sem_post(&(this->lock)) < 0) - return this->tip--, NULL; - - return errno = 0, msg; + libmds_message_t *msg = NULL; + + /* Is the pool empty? Return nothing. */ + if (!this->tip) + return errno = 0, NULL; + + /* Lock. */ + if (sem_wait(&this->lock) < 0) + return NULL; + + /* Do we have a message? Take it */ + if (this->tip) + msg = this->messages[--(this->tip)]; + + /* Unlock. */ + if (sem_post(&this->lock) < 0) + return this->tip--, NULL; + + return errno = 0, msg; } diff --git a/src/libmdsclient/inbound.h b/src/libmdsclient/inbound.h index 2599225..538e198 100644 --- a/src/libmdsclient/inbound.h +++ b/src/libmdsclient/inbound.h @@ -31,64 +31,64 @@ */ typedef struct libmds_message { - /** - * The headers in the message, each element in this list - * as an unparsed header, it consists of both the header - * name and its associated value, joined by ": ". A header - * cannot be `NULL` but `headers` itself is `NULL` if there - * are no headers. The "Length" header is included in this list. - */ - char** headers; - - /** - * The number of headers in the message - */ - size_t header_count; - - /** - * The payload of the message, `NULL` if none (of zero-length) - */ - char* payload; - - /** - * The size of the payload - */ - size_t payload_size; - - /** - * Internal buffer for the reading function (internal data) - */ - char* buffer; - - /** - * The size allocated to `buffer` (internal data) - */ - size_t buffer_size; - - /** - * The number of bytes used in `buffer` (internal data) - */ - size_t buffer_ptr; - - /** - * The number of bytes read from `buffer` (internal data) - */ - size_t buffer_off; - - /** - * Zero unless the structure is flattend, otherwise - * the size of the object (internal data) - * - * Flattened means that all pointers are subpointers - * of the object itself - */ - size_t flattened; - - /** - * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) - */ - int stage; - + /** + * The headers in the message, each element in this list + * as an unparsed header, it consists of both the header + * name and its associated value, joined by ": ". A header + * cannot be `NULL` but `headers` itself is `NULL` if there + * are no headers. The "Length" header is included in this list. + */ + char **headers; + + /** + * The number of headers in the message + */ + size_t header_count; + + /** + * The payload of the message, `NULL` if none (of zero-length) + */ + char *payload; + + /** + * The size of the payload + */ + size_t payload_size; + + /** + * Internal buffer for the reading function (internal data) + */ + char *buffer; + + /** + * The size allocated to `buffer` (internal data) + */ + size_t buffer_size; + + /** + * The number of bytes used in `buffer` (internal data) + */ + size_t buffer_ptr; + + /** + * The number of bytes read from `buffer` (internal data) + */ + size_t buffer_off; + + /** + * Zero unless the structure is flattend, otherwise + * the size of the object (internal data) + * + * Flattened means that all pointers are subpointers + * of the object itself + */ + size_t flattened; + + /** + * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) + */ + int stage; + } libmds_message_t; @@ -97,79 +97,79 @@ typedef struct libmds_message */ typedef struct libmds_mspool { - /** - * Array of messages (internal data) - */ - libmds_message_t** messages; - - /** - * The number of elements the current - * allocation of `messages` can hold (internal data) - */ - size_t size; - - /** - * Push end (internal data) - */ - size_t head; - - /** - * Poll end (internal data) - */ - size_t tail; - - /** - * The total size of all spooled messages - * (internal data) - */ - size_t spooled_bytes; - - /** - * Do not spool additional messages if - * `spooled_bytes` is equal to or exceeds - * to value - */ - size_t spool_limit_bytes; - - /** - * Do not spool more than this amount - * of messages - */ - size_t spool_limit_messages; - - /** - * If non-zero, `wait_semaphore` shall - * be incremented when a message is - * polled (internal data) - */ - int please_post; - - /* POSIX semaphores are lighter weight than XSI semaphores, so we use POSIX here. */ - - /** - * Binary semaphore used to lock the spool whilst - * manipulating it (internal data) - */ - sem_t lock; - - /** - * Semaphore used to signal addition of messages. - * Each time a message is spooled, this semaphore - * is increased, the polling thread decreases the - * semaphore before despooling a message, causing - * it to block when the spool is empty - * (internal data) - */ - sem_t semaphore; - - /** - * If the spool is full, the semaphore is acquired - * so that the spool function blocks, it is then - * posted when a message is polled so that the - * spool function may try again (internal data) - */ - sem_t wait_semaphore; - + /** + * Array of messages (internal data) + */ + libmds_message_t **messages; + + /** + * The number of elements the current + * allocation of `messages` can hold (internal data) + */ + size_t size; + + /** + * Push end (internal data) + */ + size_t head; + + /** + * Poll end (internal data) + */ + size_t tail; + + /** + * The total size of all spooled messages + * (internal data) + */ + size_t spooled_bytes; + + /** + * Do not spool additional messages if + * `spooled_bytes` is equal to or exceeds + * to value + */ + size_t spool_limit_bytes; + + /** + * Do not spool more than this amount + * of messages + */ + size_t spool_limit_messages; + + /** + * If non-zero, `wait_semaphore` shall + * be incremented when a message is + * polled (internal data) + */ + int please_post; + + /* POSIX semaphores are lighter weight than XSI semaphores, so we use POSIX here. */ + + /** + * Binary semaphore used to lock the spool whilst + * manipulating it (internal data) + */ + sem_t lock; + + /** + * Semaphore used to signal addition of messages. + * Each time a message is spooled, this semaphore + * is increased, the polling thread decreases the + * semaphore before despooling a message, causing + * it to block when the spool is empty + * (internal data) + */ + sem_t semaphore; + + /** + * If the spool is full, the semaphore is acquired + * so that the spool function blocks, it is then + * posted when a message is polled so that the + * spool function may try again (internal data) + */ + sem_t wait_semaphore; + } libmds_mspool_t; @@ -178,28 +178,28 @@ typedef struct libmds_mspool */ typedef struct libmds_mpool { - /** - * Array of messages (internal data) - */ - libmds_message_t** messages; - - /** - * The number of elements the current - * allocation of 'messages` can hold (internal data) - */ - size_t size; - - /** - * The tip of the stack (internal data) - */ - volatile size_t tip; - - /** - * Binary semaphore used to lock the pool - * whilst manipulating it (internal data) - */ - sem_t lock; - + /** + * Array of messages (internal data) + */ + libmds_message_t **messages; + + /** + * The number of elements the current + * allocation of 'messages` can hold (internal data) + */ + size_t size; + + /** + * The tip of the stack (internal data) + */ + volatile size_t tip; + + /** + * Binary semaphore used to lock the pool + * whilst manipulating it (internal data) + */ + sem_t lock; + } libmds_mpool_t; @@ -216,7 +216,7 @@ typedef struct libmds_mpool * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull, warn_unused_result)) -int libmds_message_initialise(libmds_message_t* restrict this); +int libmds_message_initialise(libmds_message_t *restrict this); /** * Release all resources in a message @@ -224,7 +224,7 @@ int libmds_message_initialise(libmds_message_t* restrict this); * @param this The message */ __attribute__((nonnull)) -void libmds_message_destroy(libmds_message_t* restrict this); +void libmds_message_destroy(libmds_message_t *restrict this); /** * Release all resources in a message, should @@ -241,7 +241,7 @@ void libmds_message_destroy(libmds_message_t* restrict this); * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull(1), malloc, warn_unused_result)) -libmds_message_t* libmds_message_duplicate(libmds_message_t* restrict this, libmds_mpool_t* restrict pool); +libmds_message_t *libmds_message_duplicate(libmds_message_t *restrict this, libmds_mpool_t *restrict pool); /** * Read the next message from a file descriptor @@ -261,7 +261,7 @@ libmds_message_t* libmds_message_duplicate(libmds_message_t* restrict this, libm * @throws Any error specified for recv(3) */ __attribute__((nonnull, warn_unused_result)) -int libmds_message_read(libmds_message_t* restrict this, int fd); +int libmds_message_read(libmds_message_t *restrict this, int fd); @@ -275,7 +275,7 @@ int libmds_message_read(libmds_message_t* restrict this, int fd); * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull, warn_unused_result)) -int libmds_mspool_initialise(libmds_mspool_t* restrict this); +int libmds_mspool_initialise(libmds_mspool_t *restrict this); /** * Destroy a message spool, deallocate its resources @@ -283,7 +283,7 @@ int libmds_mspool_initialise(libmds_mspool_t* restrict this); * @param this The message spool */ __attribute__((nonnull)) -void libmds_mspool_destroy(libmds_mspool_t* restrict this); +void libmds_mspool_destroy(libmds_mspool_t *restrict this); /** * Spool a message @@ -297,7 +297,7 @@ void libmds_mspool_destroy(libmds_mspool_t* restrict this); * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull, warn_unused_result)) -int libmds_mspool_spool(libmds_mspool_t* restrict this, libmds_message_t* restrict message); +int libmds_mspool_spool(libmds_mspool_t *restrict this, libmds_message_t *restrict message); /** * Poll a message from a spool, wait if empty @@ -308,7 +308,7 @@ int libmds_mspool_spool(libmds_mspool_t* restrict this, libmds_message_t* restri * @throws EINTR If interrupted */ __attribute__((nonnull, warn_unused_result, malloc)) -libmds_message_t* libmds_mspool_poll(libmds_mspool_t* restrict this); +libmds_message_t *libmds_mspool_poll(libmds_mspool_t *restrict this); /** * Poll a message from a spool, wait for a limited time @@ -325,8 +325,8 @@ libmds_message_t* libmds_mspool_poll(libmds_mspool_t* restrict this); * @throws ETIMEDOUT If the time specified `deadline` passed and the spool was till empty */ __attribute__((nonnull(1), warn_unused_result, malloc)) -libmds_message_t* libmds_mspool_poll_try(libmds_mspool_t* restrict this, - const struct timespec* restrict deadline); +libmds_message_t *libmds_mspool_poll_try(libmds_mspool_t *restrict this, + const struct timespec *restrict deadline); @@ -341,7 +341,7 @@ libmds_message_t* libmds_mspool_poll_try(libmds_mspool_t* restrict this, * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull, warn_unused_result)) -int libmds_mpool_initialise(libmds_mpool_t* restrict this, size_t size); +int libmds_mpool_initialise(libmds_mpool_t *restrict this, size_t size); /** * Destroy a pool of reusable message allocations, @@ -350,7 +350,7 @@ int libmds_mpool_initialise(libmds_mpool_t* restrict this, size_t size); * @param this The message allocation pool */ __attribute__((nonnull)) -void libmds_mpool_destroy(libmds_mpool_t* restrict this); +void libmds_mpool_destroy(libmds_mpool_t *restrict this); /** * Add a message allocation to a pool @@ -362,7 +362,7 @@ void libmds_mpool_destroy(libmds_mpool_t* restrict this); * @return Zero on success, -1 on error, `errno` will be set accordingly */ __attribute__((nonnull, warn_unused_result)) -int libmds_mpool_offer(libmds_mpool_t* restrict this, libmds_message_t* restrict message); +int libmds_mpool_offer(libmds_mpool_t *restrict this, libmds_message_t *restrict message); /** * Fetch a message allocation from a pool @@ -373,9 +373,8 @@ int libmds_mpool_offer(libmds_mpool_t* restrict this, libmds_message_t* restrict * if the pool was empty, otherwise `errno` will describe the error. */ __attribute__((nonnull, warn_unused_result, malloc)) -libmds_message_t* libmds_mpool_poll(libmds_mpool_t* restrict this); +libmds_message_t *libmds_mpool_poll(libmds_mpool_t *restrict this); #endif - diff --git a/src/libmdsclient/libmdsclient.pc.in b/src/libmdsclient/libmdsclient.pc.in index 1d00c8f..630eee8 100644 --- a/src/libmdsclient/libmdsclient.pc.in +++ b/src/libmdsclient/libmdsclient.pc.in @@ -6,4 +6,3 @@ Description: Library for mds-clients Version: @VERSION@ Libs: -L${libdir} -lmdsclient @LIBS@ Cflags: -I${includedir} @CFLAGS@ - diff --git a/src/libmdsclient/proto-util.c b/src/libmdsclient/proto-util.c index 49ed887..8fd43bc 100644 --- a/src/libmdsclient/proto-util.c +++ b/src/libmdsclient/proto-util.c @@ -32,7 +32,7 @@ * it is beneficial to sort them. */ #ifndef LIBMDS_HEADERS_SORT_THRESHOLD -# define LIBMDS_HEADERS_SORT_THRESHOLD 100 /* XXX: Value is chosen at random */ +# define LIBMDS_HEADERS_SORT_THRESHOLD 100 /* XXX: Value is chosen at random */ #endif /** @@ -44,7 +44,7 @@ * a header array. */ #ifndef LIBMDS_HEADERS_COPY_THRESHOLD -# define LIBMDS_HEADERS_COPY_THRESHOLD 10 /* XXX: Value is chosen at random */ +# define LIBMDS_HEADERS_COPY_THRESHOLD 10 /* XXX: Value is chosen at random */ #endif /** @@ -56,7 +56,7 @@ * is is either full binary or full linear. */ #ifndef LIBMDS_HEADERS_BINSEARCH_THRESHOLD -# define LIBMDS_HEADERS_BINSEARCH_THRESHOLD 1000 /* XXX: Value is chosen at semirandom */ +# define LIBMDS_HEADERS_BINSEARCH_THRESHOLD 1000 /* XXX: Value is chosen at semirandom */ #endif @@ -69,21 +69,21 @@ * @param header_b The header that may not include a value * @return Same syntax as strcmp(3) */ -static int headercmp(const char* header_a, const char* header_b) +static int +headercmp(const char *header_a, const char *header_b) { - int a, b; - for (;;) - { - a = (int)*header_a++; - b = (int)*header_b++; - - if ((a == ':') && (*header_a == ' ')) - return 0 - b; - if ((a == 0) || (b == 0)) - return a - b; - if (a - b) - return a - b; - } + int a, b; + for (;;) { + a = (int)*header_a++; + b = (int)*header_b++; + + if (a == ':' && *header_a == ' ') + return 0 - b; + if (!a || !b) + return a - b; + if (a - b) + return a - b; + } } @@ -96,28 +96,28 @@ static int headercmp(const char* header_a, const char* header_b) * @param strp_b Pointer to the second string * @return Will return `strcmp(*strp_a, *strp_b)`, see strcmp(3) */ -static int headerpcmp(const void* headerp_a, const void* headerp_b) +static int +headerpcmp(const void *headerp_a, const void *headerp_b) { - const char* header_a = *(char* const*)headerp_a; - const char* header_b = *(char* const*)headerp_b; - int a, b, az, bz; - - for (;;) - { - a = (int)*header_a++; - b = (int)*header_b++; - az = (a == ':') && (*header_a == ' '); - bz = (b == ':') && (*header_b == ' '); - - if (az) - return 0 - !(bz || (b == 0)); - if (bz) - return a - 0; - if ((a == 0) || (b == 0)) - return a - b; - if (a - b) - return a - b; - } + const char *header_a = *(char *const *)headerp_a; + const char *header_b = *(char *const *)headerp_b; + int a, b, az, bz; + + for (;;) { + a = (int)*header_a++; + b = (int)*header_b++; + az = a == ':' && *header_a == ' '; + bz = b == ':' && *header_b == ' '; + + if (az) + return 0 - !(bz || !b); + if (bz) + return a - 0; + if (!a || !b) + return a - b; + if (a - b) + return a - b; + } } @@ -145,17 +145,18 @@ static int headerpcmp(const void* headerp_a, const void* headerp_b) * @throws ENOMEM Out of memory, Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_headers_cherrypick(char** restrict headers, size_t header_count, size_t* restrict found, - libmds_cherrypick_optimisation_t optimisation, ...) +int +libmds_headers_cherrypick(char **restrict headers, size_t header_count, size_t *restrict found, + libmds_cherrypick_optimisation_t optimisation, ...) { - va_list args; - int r, saved_errno; - va_start(args, optimisation); - r = libmds_headers_cherrypick_v(headers, header_count, found, optimisation, args); - saved_errno = errno; - va_end(args); - errno = saved_errno; - return r; + va_list args; + int r, saved_errno; + va_start(args, optimisation); + r = libmds_headers_cherrypick_v(headers, header_count, found, optimisation, args); + saved_errno = errno; + va_end(args); + errno = saved_errno; + return r; } @@ -177,17 +178,18 @@ int libmds_headers_cherrypick(char** restrict headers, size_t header_count, size * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_linear_unsorted(char** restrict headers, size_t header_count, ...) +size_t +libmds_headers_cherrypick_linear_unsorted(char **restrict headers, size_t header_count, ...) { - va_list args; - size_t r; - int saved_errno; - va_start(args, header_count); - r = libmds_headers_cherrypick_linear_unsorted_v(headers, header_count, args); - saved_errno = errno; - va_end(args); - errno = saved_errno; - return r; + va_list args; + size_t r; + int saved_errno; + va_start(args, header_count); + r = libmds_headers_cherrypick_linear_unsorted_v(headers, header_count, args); + saved_errno = errno; + va_end(args); + errno = saved_errno; + return r; } @@ -209,17 +211,17 @@ size_t libmds_headers_cherrypick_linear_unsorted(char** restrict headers, size_t * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_linear_sorted(char** restrict headers, size_t header_count, ...) +size_t libmds_headers_cherrypick_linear_sorted(char **restrict headers, size_t header_count, ...) { - va_list args; - size_t r; - int saved_errno; - va_start(args, header_count); - r = libmds_headers_cherrypick_linear_sorted_v(headers, header_count, args); - saved_errno = errno; - va_end(args); - errno = saved_errno; - return r; + va_list args; + size_t r; + int saved_errno; + va_start(args, header_count); + r = libmds_headers_cherrypick_linear_sorted_v(headers, header_count, args); + saved_errno = errno; + va_end(args); + errno = saved_errno; + return r; } @@ -241,17 +243,18 @@ size_t libmds_headers_cherrypick_linear_sorted(char** restrict headers, size_t h * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_binary_unsorted(char** restrict headers, size_t header_count, ...) +size_t +libmds_headers_cherrypick_binary_unsorted(char **restrict headers, size_t header_count, ...) { - va_list args; - size_t r; - int saved_errno; - va_start(args, header_count); - r = libmds_headers_cherrypick_binary_unsorted_v(headers, header_count, args); - saved_errno = errno; - va_end(args); - errno = saved_errno; - return r; + va_list args; + size_t r; + int saved_errno; + va_start(args, header_count); + r = libmds_headers_cherrypick_binary_unsorted_v(headers, header_count, args); + saved_errno = errno; + va_end(args); + errno = saved_errno; + return r; } @@ -274,17 +277,18 @@ size_t libmds_headers_cherrypick_binary_unsorted(char** restrict headers, size_t * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_binary_sorted(char** restrict headers, size_t header_count, ...) +size_t +libmds_headers_cherrypick_binary_sorted(char **restrict headers, size_t header_count, ...) { - va_list args; - size_t r; - int saved_errno; - va_start(args, header_count); - r = libmds_headers_cherrypick_binary_sorted_v(headers, header_count, args); - saved_errno = errno; - va_end(args); - errno = saved_errno; - return r; + va_list args; + size_t r; + int saved_errno; + va_start(args, header_count); + r = libmds_headers_cherrypick_binary_sorted_v(headers, header_count, args); + saved_errno = errno; + va_end(args); + errno = saved_errno; + return r; } @@ -312,58 +316,55 @@ size_t libmds_headers_cherrypick_binary_sorted(char** restrict headers, size_t h * @throws ENOMEM Out of memory, Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_headers_cherrypick_v(char** restrict headers, size_t header_count, size_t* restrict found, - libmds_cherrypick_optimisation_t optimisation, va_list args) +int +libmds_headers_cherrypick_v(char **restrict headers, size_t header_count, size_t *restrict found, + libmds_cherrypick_optimisation_t optimisation, va_list args) { - char** headers_ = headers; - size_t found_; - libmds_cherrypick_optimisation_t sorted; - - if (found != NULL) - *found = 0; - - optimisation ^= sorted = optimisation & ARGS_SORTED; - - if (optimisation == DO_NOT_SORT) - { - if (header_count >= LIBMDS_HEADERS_SORT_THRESHOLD + LIBMDS_HEADERS_COPY_THRESHOLD) - { - headers_ = malloc(header_count * sizeof(char*)); - if (headers_ == NULL) - return -1; - memcpy(headers_, headers, header_count * sizeof(char*)); - libmds_headers_sort(headers_, header_count); - optimisation = SORTED; + char **headers_ = headers; + size_t found_; + libmds_cherrypick_optimisation_t sorted; + + if (found) + *found = 0; + + optimisation ^= sorted = optimisation & ARGS_SORTED; + + if (optimisation == DO_NOT_SORT) { + if (header_count >= LIBMDS_HEADERS_SORT_THRESHOLD + LIBMDS_HEADERS_COPY_THRESHOLD) { + headers_ = malloc(header_count * sizeof(char*)); + if (!headers_) + return -1; + memcpy(headers_, headers, header_count * sizeof(char*)); + libmds_headers_sort(headers_, header_count); + optimisation = SORTED; + } + } else if (optimisation == SORT) { + if (header_count >= LIBMDS_HEADERS_SORT_THRESHOLD) { + libmds_headers_sort(headers_, header_count); + optimisation = SORTED; + } + } + + if (optimisation != SORTED) { + found_ = libmds_headers_cherrypick_linear_unsorted_v(headers_, header_count, args); + } else if (header_count < LIBMDS_HEADERS_BINSEARCH_THRESHOLD) { + if (sorted) + found_ = libmds_headers_cherrypick_linear_sorted_v(headers_, header_count, args); + else + found_ = libmds_headers_cherrypick_linear_unsorted_v(headers_, header_count, args); + } else if (sorted) { + found_ = libmds_headers_cherrypick_binary_sorted_v(headers_, header_count, args); + } else { + found_ = libmds_headers_cherrypick_binary_unsorted_v(headers_, header_count, args); } - } - else if (optimisation == SORT) - if (header_count >= LIBMDS_HEADERS_SORT_THRESHOLD) - { - libmds_headers_sort(headers_, header_count); - optimisation = SORTED; - } - - if (optimisation != SORTED) - found_ = libmds_headers_cherrypick_linear_unsorted_v(headers_, header_count, args); - else if (header_count < LIBMDS_HEADERS_BINSEARCH_THRESHOLD) - { - if (sorted) - found_ = libmds_headers_cherrypick_linear_sorted_v(headers_, header_count, args); - else - found_ = libmds_headers_cherrypick_linear_unsorted_v(headers_, header_count, args); - } - else if (sorted) - found_ = libmds_headers_cherrypick_binary_sorted_v(headers_, header_count, args); - else - found_ = libmds_headers_cherrypick_binary_unsorted_v(headers_, header_count, args); - - if (found != NULL) - *found = found_; - - if (headers_ != headers) - free(headers_); - - return 0; + + if (found) + *found = found_; + + if (headers_ != headers) + free(headers_); + + return 0; } @@ -385,29 +386,29 @@ int libmds_headers_cherrypick_v(char** restrict headers, size_t header_count, si * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_linear_unsorted_v(char** restrict headers, size_t header_count, va_list args) +size_t +libmds_headers_cherrypick_linear_unsorted_v(char **restrict headers, size_t header_count, va_list args) { - const char* header; - char** value_out; - size_t found = 0, i; - - for (;;) - { - header = va_arg(args, const char*); - if (header == NULL) - return found; - - value_out = va_arg(args, char**); - *value_out = NULL; - - for (i = 0; i < header_count; i++) - if (!headercmp(headers[i], header)) - { - *value_out = strstr(headers[i], ": ") + 2; - found++; - break; - } - } + const char *header; + char **value_out; + size_t found = 0, i; + + for (;;) { + header = va_arg(args, const char*); + if (!header) + return found; + + value_out = va_arg(args, char**); + *value_out = NULL; + + for (i = 0; i < header_count; i++) { + if (!headercmp(headers[i], header)) { + *value_out = strstr(headers[i], ": ") + 2; + found++; + break; + } + } + } } @@ -431,35 +432,33 @@ size_t libmds_headers_cherrypick_linear_unsorted_v(char** restrict headers, size * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_linear_sorted_v(char** restrict headers, size_t header_count, va_list args) +size_t +libmds_headers_cherrypick_linear_sorted_v(char **restrict headers, size_t header_count, va_list args) { - const char* header; - char** value_out; - size_t found = 0, i = 0; - int r; - - for (;;) - { - header = va_arg(args, const char*); - if (header == NULL) - return found; - - value_out = va_arg(args, char**); - *value_out = NULL; - - for (; i < header_count; i++) - { - r = headercmp(headers[i], header); - if (r == 0) - { - *value_out = strstr(headers[i], ": ") + 2; - found++, i++; - break; - } - if (r > 0) - break; + const char *header; + char **value_out; + size_t found = 0, i = 0; + int r; + + for (;;) { + header = va_arg(args, const char*); + if (!header) + return found; + + value_out = va_arg(args, char**); + *value_out = NULL; + + for (; i < header_count; i++) { + r = headercmp(headers[i], header); + if (!r) { + *value_out = strstr(headers[i], ": ") + 2; + found++, i++; + break; + } + if (r > 0) + break; + } } - } } @@ -481,26 +480,26 @@ size_t libmds_headers_cherrypick_linear_sorted_v(char** restrict headers, size_t * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_binary_unsorted_v(char** restrict headers, size_t header_count, va_list args) +size_t +libmds_headers_cherrypick_binary_unsorted_v(char **restrict headers, size_t header_count, va_list args) { - const char* header; - char** value_out; - void* found_element; - size_t found = 0; - - for (;;) - { - header = va_arg(args, const char*); - if (header == NULL) - return found; - - value_out = va_arg(args, char**); - *value_out = NULL; - - found_element = bsearch(&header, headers, header_count, sizeof(char*), headerpcmp); - if (found_element != NULL) - *value_out = strstr(*(char**)found_element, ": ") + 2, found++; - } + const char *header; + char **value_out; + void *found_element; + size_t found = 0; + + for (;;) { + header = va_arg(args, const char*); + if (!header) + return found; + + value_out = va_arg(args, char**); + *value_out = NULL; + + found_element = bsearch(&header, headers, header_count, sizeof(char*), headerpcmp); + if (found_element) + *value_out = strstr(*(char**)found_element, ": ") + 2, found++; + } } @@ -523,35 +522,34 @@ size_t libmds_headers_cherrypick_binary_unsorted_v(char** restrict headers, size * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_binary_sorted_v(char** restrict headers, size_t header_count, va_list args) +size_t +libmds_headers_cherrypick_binary_sorted_v(char **restrict headers, size_t header_count, va_list args) { - const char* header; - char** value_out; - void* found_element; - size_t found = 0; - size_t offset = 0; - - /* I sincerely doubt even this amount of optimisation is needed, - * so there is no need for even faster algorithms, keep in mind - * that the overhead increases with faster algorithms. */ - - for (;;) - { - header = va_arg(args, const char*); - if (header == NULL) - return found; - - value_out = va_arg(args, char**); - *value_out = NULL; - - found_element = bsearch(&header, headers + offset, header_count - offset, sizeof(char*), headerpcmp); - if (found_element != NULL) - { - offset = (size_t)((char**)found_element - headers); - *value_out = strstr(*(char**)found_element, ": ") + 2; - found++; + const char *header; + char **value_out; + void *found_element; + size_t found = 0; + size_t offset = 0; + + /* I sincerely doubt even this amount of optimisation is needed, + * so there is no need for even faster algorithms, keep in mind + * that the overhead increases with faster algorithms. */ + + for (;;) { + header = va_arg(args, const char*); + if (!header) + return found; + + value_out = va_arg(args, char**); + *value_out = NULL; + + found_element = bsearch(&header, headers + offset, header_count - offset, sizeof(char *), headerpcmp); + if (found_element) { + offset = (size_t)((char **)found_element - headers); + *value_out = strstr(*(char **)found_element, ": ") + 2; + found++; + } } - } } @@ -562,9 +560,10 @@ size_t libmds_headers_cherrypick_binary_sorted_v(char** restrict headers, size_t * @param headers The array of headers * @param headr_count The number of elements in `headers` */ -void libmds_headers_sort(char** restrict headers, size_t header_count) +void +libmds_headers_sort(char **restrict headers, size_t header_count) { - qsort(headers, header_count, sizeof(char*), headerpcmp); + qsort(headers, header_count, sizeof(char *), headerpcmp); } @@ -610,17 +609,18 @@ void libmds_headers_sort(char** restrict headers, size_t header_count) * @throws ENOMEM Out of memory, Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_compose(char** restrict buffer, size_t* restrict buffer_size, size_t* restrict length, - const char* restrict payload, const size_t* restrict payload_length, ...) +int +libmds_compose(char **restrict buffer, size_t *restrict buffer_size, size_t *restrict length, + const char *restrict payload, const size_t *restrict payload_length, ...) { - va_list args; - int r, saved_errno; - va_start(args, payload_length); - r = libmds_compose_v(buffer, buffer_size, length, payload, payload_length, args); - saved_errno = errno; - va_end(args); - errno = saved_errno; - return r; + va_list args; + int r, saved_errno; + va_start(args, payload_length); + r = libmds_compose_v(buffer, buffer_size, length, payload, payload_length, args); + saved_errno = errno; + va_end(args); + errno = saved_errno; + return r; } @@ -666,105 +666,106 @@ int libmds_compose(char** restrict buffer, size_t* restrict buffer_size, size_t* * @throws ENOMEM Out of memory, Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_compose_v(char** restrict buffer, size_t* restrict buffer_size, size_t* restrict length, - const char* restrict payload, const size_t* restrict payload_length, va_list args) +int +libmds_compose_v(char **restrict buffer, size_t *restrict buffer_size, size_t *restrict length, + const char *restrict payload, const size_t *restrict payload_length, va_list args) { - char* buf = *buffer; - size_t bufsize = *buffer_size; - size_t len = 0; - int part_len; - char* part_msg; - size_t payload_len = 0; - const char* format; - int include; - int saved_errno; - - *length = 0; - - if (payload != NULL) - payload_len = payload_length == NULL ? strlen(payload) : *payload_length; - - if (bufsize == 0) - { - bufsize = 128; - buf = realloc(buf, bufsize * sizeof(char)); - if (buf == NULL) - return -1; - } - - for (;;) - { - format = va_arg(args, const char*); - if (format == NULL) - break; - - include = 1; - if (*format == '?') - { - include = va_arg(args, int); - format++; + char *buf = *buffer; + size_t bufsize = *buffer_size; + size_t len = 0; + int part_len; + char *part_msg; + size_t payload_len = 0; + const char* format; + int include; + int saved_errno; + + *length = 0; + + if (payload) + payload_len = payload_length == NULL ? strlen(payload) : *payload_length; + + if (!bufsize) { + bufsize = 128; + buf = realloc(buf, bufsize * sizeof(char)); + if (!buf) + return -1; } - + + for (;;) { + format = va_arg(args, const char*); + if (!format) + break; + + include = 1; + if (*format == '?') { + include = va_arg(args, int); + format++; + } + +#if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat-nonliteral" # pragma GCC diagnostic ignored "-Wsuggest-attribute=format" - part_len = vasprintf(&part_msg, format, args); - /* XXX vbprintf in slibc will be a nice replacement for this horror. */ +#endif + part_len = vasprintf(&part_msg, format, args); + /* XXX vbprintf in slibc will be a nice replacement for this horror. */ +#if defined(__GNUC__) # pragma GCC diagnostic pop +#endif + + if (!include) { + if (part_len >= 0) + free(part_msg); + continue; + } + + if (part_len < 0) + return -1; - if (include == 0) - { - if (part_len >= 0) - free(part_msg); - continue; + if (len + (size_t)part_len >= bufsize) { + *buffer_size = bufsize; + *buffer = buf; + do + bufsize <<= 1; + while (len + (size_t)part_len >= bufsize); + buf = realloc(buf, bufsize * sizeof(char)); + if (!buf) + return saved_errno = errno, free(part_msg), errno = saved_errno, -1; + } + + memcpy(buf + len, part_msg, ((size_t)part_len) * sizeof(char)); + len += (size_t)part_len; + buf[len++] = '\n'; + free(part_msg); } - - if (part_len < 0) - return -1; - - if (len + (size_t)part_len >= bufsize) - { - *buffer_size = bufsize; - *buffer = buf; - do - bufsize <<= 1; - while (len + (size_t)part_len >= bufsize); - buf = realloc(buf, bufsize * sizeof(char)); - if (buf == NULL) - return saved_errno = errno, free(part_msg), errno = saved_errno, -1; + +#define LENGTH_LEN \ + (payload_len > 0 ? ((sizeof("Length: \n") / sizeof(char) - 1) + 3 * sizeof(size_t)) : 0) + + if (len + LENGTH_LEN + 1 + payload_len + 1 > bufsize) { + *buffer_size = bufsize; + *buffer = buf; + bufsize = len + LENGTH_LEN + 1 + payload_len + 1; + buf = realloc(buf, bufsize * sizeof(char)); + if (!buf) + return -1; } - - memcpy(buf + len, part_msg, ((size_t)part_len) * sizeof(char)); - len += (size_t)part_len; - buf[len++] = '\n'; - free(part_msg); - } - -#define LENGTH_LEN \ - (payload_len > 0 ? ((sizeof("Length: \n") / sizeof(char) - 1) + 3 * sizeof(size_t)) : 0) - if (len + LENGTH_LEN + 1 + payload_len + 1 > bufsize) - { - *buffer_size = bufsize; - *buffer = buf; - bufsize = len + LENGTH_LEN + 1 + payload_len + 1; - buf = realloc(buf, bufsize * sizeof(char)); - if (buf == NULL) - return -1; - } + #undef LENGTH_LEN - - if (payload_len > 0) - sprintf(buf + len, "Length: %zu\n%n", payload_len, &part_len), - len += (size_t)part_len; - buf[len++] = '\n'; - if (payload_len > 0) - memcpy(buf + len, payload, payload_len * sizeof(char)), - len += payload_len; - - *buffer_size = bufsize; - *buffer = buf; - *length = len; - return 0; + + if (payload_len > 0) + sprintf(buf + len, "Length: %zu\n%n", payload_len, &part_len), + len += (size_t)part_len; + buf[len++] = '\n'; + if (payload_len > 0) + memcpy(buf + len, payload, payload_len * sizeof(char)), + len += payload_len; + + *buffer_size = bufsize; + *buffer = buf; + *length = len; + return 0; } @@ -789,28 +790,28 @@ int libmds_compose_v(char** restrict buffer, size_t* restrict buffer_size, size_ * there are no free message ID:s. * @throws Any error that `test` may throw. */ -int libmds_next_message_id(uint32_t* restrict message_id, - int (*test)(uint32_t message_id, void* data), void* data) +int +libmds_next_message_id(uint32_t *restrict message_id, + int (*test)(uint32_t message_id, void *data), void *data) { - uint32_t id = *message_id; - uint32_t first_test; - int r; - - id = id == UINT32_MAX ? 0 : (id + 1); - if (test != NULL) - for (first_test = id;;) - { - r = test(id, data); - if (r < 0) - return -1; - if (r) - break; + uint32_t id = *message_id; + uint32_t first_test; + int r; + id = id == UINT32_MAX ? 0 : (id + 1); - if (id == first_test) - return errno = EAGAIN, -1; - } - - *message_id = id; - return 0; -} + if (test) { + for (first_test = id;;) { + r = test(id, data); + if (r < 0) + return -1; + if (r) + break; + id = id == UINT32_MAX ? 0 : (id + 1); + if (id == first_test) + return errno = EAGAIN, -1; + } + } + *message_id = id; + return 0; +} diff --git a/src/libmdsclient/proto-util.h b/src/libmdsclient/proto-util.h index 2d38441..26f862c 100644 --- a/src/libmdsclient/proto-util.h +++ b/src/libmdsclient/proto-util.h @@ -31,58 +31,57 @@ */ typedef enum libmds_cherrypick_optimisation { - /** - * No optimisation is allowed, in particular this - * means that the array of headers may not be reordered. - * The function may still create a copy of the header - * array and sort the copy. - * - * Cannot be combined with `SORT` or `SORTED` - * - * This option is guaranteed to always have the value 0 - */ - DO_NOT_SORT = 0, - - /** - * `libmds_headers_cherrypick` is allowed to - * sort the header array. There is no guarantee - * that the header array will be sorted. - * - * Cannot be combined with `DO_NOT_SORT` or `SORTED` - */ - SORT = 1, - - /** - * Informs `libmds_headers_cherrypick` that the header - * array already is sorted. `libmds_headers_cherrypick` - * can use this information to optimise its procedure. - * But this also means that the header array will not - * be reordered. - * - * Cannot be combined with `DO_NOT_SORT` or `SORT` - */ - SORTED = 2, - - - /** - * The list of requested headers is not sorted - * in ascending order - * - * Cannot be combined with `ARGS_SORTED` - * - * This option is guaranteed to always have the value 0 - */ - ARGS_UNSORTED = 0, - - /** - * The list of requested headers is sorted in - * ascending order - * - * Cannot be combined with `ARGS_UNSORTED` - */ - ARGS_SORTED = 4, - - + /** + * No optimisation is allowed, in particular this + * means that the array of headers may not be reordered. + * The function may still create a copy of the header + * array and sort the copy. + * + * Cannot be combined with `SORT` or `SORTED` + * + * This option is guaranteed to always have the value 0 + */ + DO_NOT_SORT = 0, + + /** + * `libmds_headers_cherrypick` is allowed to + * sort the header array. There is no guarantee + * that the header array will be sorted. + * + * Cannot be combined with `DO_NOT_SORT` or `SORTED` + */ + SORT = 1, + + /** + * Informs `libmds_headers_cherrypick` that the header + * array already is sorted. `libmds_headers_cherrypick` + * can use this information to optimise its procedure. + * But this also means that the header array will not + * be reordered. + * + * Cannot be combined with `DO_NOT_SORT` or `SORT` + */ + SORTED = 2, + + + /** + * The list of requested headers is not sorted + * in ascending order + * + * Cannot be combined with `ARGS_SORTED` + * + * This option is guaranteed to always have the value 0 + */ + ARGS_UNSORTED = 0, + + /** + * The list of requested headers is sorted in + * ascending order + * + * Cannot be combined with `ARGS_UNSORTED` + */ + ARGS_SORTED = 4, + } libmds_cherrypick_optimisation_t; @@ -111,8 +110,8 @@ typedef enum libmds_cherrypick_optimisation * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((sentinel)) -int libmds_headers_cherrypick(char** restrict headers, size_t header_count, size_t* restrict found, - libmds_cherrypick_optimisation_t optimisation, ...); +int libmds_headers_cherrypick(char **restrict headers, size_t header_count, size_t *restrict found, + libmds_cherrypick_optimisation_t optimisation, ...); /** * Cherrypick headers from a message, @@ -133,8 +132,8 @@ int libmds_headers_cherrypick(char** restrict headers, size_t header_count, size * @return The number of found headers of those that were requested */ __attribute__((sentinel)) -size_t libmds_headers_cherrypick_linear_unsorted(char** restrict headers, size_t header_count, ...); -#define libmds_headers_cherrypick_linear_unsorted libmds_headers_cherrypick_linear_unsorted +size_t libmds_headers_cherrypick_linear_unsorted(char **restrict headers, size_t header_count, ...); +#define libmds_headers_cherrypick_linear_unsorted libmds_headers_cherrypick_linear_unsorted /** * Cherrypick headers from a message, @@ -157,8 +156,8 @@ size_t libmds_headers_cherrypick_linear_unsorted(char** restrict headers, size_t * @return The number of found headers of those that were requested */ __attribute__((sentinel)) -size_t libmds_headers_cherrypick_linear_sorted(char** restrict headers, size_t header_count, ...); -#define libmds_headers_cherrypick_linear_sorted libmds_headers_cherrypick_linear_sorted +size_t libmds_headers_cherrypick_linear_sorted(char **restrict headers, size_t header_count, ...); +#define libmds_headers_cherrypick_linear_sorted libmds_headers_cherrypick_linear_sorted /** * Cherrypick headers from a message, @@ -179,8 +178,8 @@ size_t libmds_headers_cherrypick_linear_sorted(char** restrict headers, size_t h * @return The number of found headers of those that were requested */ __attribute__((sentinel)) -size_t libmds_headers_cherrypick_binary_unsorted(char** restrict headers, size_t header_count, ...); -#define libmds_headers_cherrypick_binary_unsorted libmds_headers_cherrypick_binary_unsorted +size_t libmds_headers_cherrypick_binary_unsorted(char **restrict headers, size_t header_count, ...); +#define libmds_headers_cherrypick_binary_unsorted libmds_headers_cherrypick_binary_unsorted /** * Cherrypick headers from a message, @@ -202,8 +201,8 @@ size_t libmds_headers_cherrypick_binary_unsorted(char** restrict headers, size_t * @return The number of found headers of those that were requested */ __attribute__((sentinel)) -size_t libmds_headers_cherrypick_binary_sorted(char** restrict headers, size_t header_count, ...); -#define libmds_headers_cherrypick_binary_unsorted libmds_headers_cherrypick_binary_unsorted +size_t libmds_headers_cherrypick_binary_sorted(char **restrict headers, size_t header_count, ...); +#define libmds_headers_cherrypick_binary_unsorted libmds_headers_cherrypick_binary_unsorted /** * Cherrypick headers from a message @@ -229,8 +228,8 @@ size_t libmds_headers_cherrypick_binary_sorted(char** restrict headers, size_t h * @throws ENOMEM Out of memory. Possibly, the process hit the RLIMIT_AS or * RLIMIT_DATA limit described in getrlimit(2). */ -int libmds_headers_cherrypick_v(char** restrict headers, size_t header_count, size_t* restrict found, - libmds_cherrypick_optimisation_t optimisation, va_list args); +int libmds_headers_cherrypick_v(char **restrict headers, size_t header_count, size_t *restrict found, + libmds_cherrypick_optimisation_t optimisation, va_list args); /** * Cherrypick headers from a message, @@ -250,8 +249,8 @@ int libmds_headers_cherrypick_v(char** restrict headers, size_t header_count, si * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_linear_unsorted_v(char** restrict headers, size_t header_count, va_list args); -#define libmds_headers_cherrypick_linear_unsorted_v libmds_headers_cherrypick_linear_unsorted_v +size_t libmds_headers_cherrypick_linear_unsorted_v(char **restrict headers, size_t header_count, va_list args); +#define libmds_headers_cherrypick_linear_unsorted_v libmds_headers_cherrypick_linear_unsorted_v /** * Cherrypick headers from a message, @@ -273,8 +272,8 @@ size_t libmds_headers_cherrypick_linear_unsorted_v(char** restrict headers, size * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_linear_sorted_v(char** restrict headers, size_t header_count, va_list args); -#define libmds_headers_cherrypick_linear_sorted_v libmds_headers_cherrypick_linear_sorted_v +size_t libmds_headers_cherrypick_linear_sorted_v(char **restrict headers, size_t header_count, va_list args); +#define libmds_headers_cherrypick_linear_sorted_v libmds_headers_cherrypick_linear_sorted_v /** * Cherrypick headers from a message, @@ -294,8 +293,8 @@ size_t libmds_headers_cherrypick_linear_sorted_v(char** restrict headers, size_t * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_binary_unsorted_v(char** restrict headers, size_t header_count, va_list args); -#define libmds_headers_cherrypick_binary_unsorted_v libmds_headers_cherrypick_binary_unsorted_v +size_t libmds_headers_cherrypick_binary_unsorted_v(char **restrict headers, size_t header_count, va_list args); +#define libmds_headers_cherrypick_binary_unsorted_v libmds_headers_cherrypick_binary_unsorted_v /** * Cherrypick headers from a message, @@ -316,8 +315,8 @@ size_t libmds_headers_cherrypick_binary_unsorted_v(char** restrict headers, size * more headers in the list, it should be terminated with a `NULL`. * @return The number of found headers of those that were requested */ -size_t libmds_headers_cherrypick_binary_sorted_v(char** restrict headers, size_t header_count, va_list args); -#define libmds_headers_cherrypick_binary_sorted_v libmds_headers_cherrypick_binary_sorted_v +size_t libmds_headers_cherrypick_binary_sorted_v(char **restrict headers, size_t header_count, va_list args); +#define libmds_headers_cherrypick_binary_sorted_v libmds_headers_cherrypick_binary_sorted_v /** * Sort the a header array, this is what `libmds_headers_cherrypick` @@ -326,7 +325,7 @@ size_t libmds_headers_cherrypick_binary_sorted_v(char** restrict headers, size_t * @param headers The array of headers * @param headr_count The number of elements in `headers` */ -void libmds_headers_sort(char** restrict headers, size_t header_count); +void libmds_headers_sort(char **restrict headers, size_t header_count); /** * Compose a message @@ -371,8 +370,8 @@ void libmds_headers_sort(char** restrict headers, size_t header_count); * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull(1, 2, 3), sentinel)) -int libmds_compose(char** restrict buffer, size_t* restrict buffer_size, size_t* restrict length, - const char* restrict payload, const size_t* restrict payload_length, ...); +int libmds_compose(char **restrict buffer, size_t *restrict buffer_size, size_t *restrict length, + const char *restrict payload, const size_t *restrict payload_length, ...); /** * Compose a message @@ -417,8 +416,8 @@ int libmds_compose(char** restrict buffer, size_t* restrict buffer_size, size_t* * RLIMIT_DATA limit described in getrlimit(2). */ __attribute__((nonnull(1, 2, 3))) -int libmds_compose_v(char** restrict buffer, size_t* restrict buffer_size, size_t* restrict length, - const char* restrict payload, const size_t* restrict payload_length, va_list args); +int libmds_compose_v(char **restrict buffer, size_t *restrict buffer_size, size_t *restrict length, + const char *restrict payload, const size_t *restrict payload_length, va_list args); /** * Increase the message ID counter @@ -442,9 +441,7 @@ int libmds_compose_v(char** restrict buffer, size_t* restrict buffer_size, size_ * @throws Any error that `test` may throw. */ __attribute__((nonnull(1))) -int libmds_next_message_id(uint32_t* restrict message_id, int (*test)(uint32_t message_id, void* data), - void* data); +int libmds_next_message_id(uint32_t *restrict message_id, int (*test)(uint32_t message_id, void *data), void *data); #endif - diff --git a/src/libmdsserver/client-list.h b/src/libmdsserver/client-list.h index 339f7c7..fcd9923 100644 --- a/src/libmdsserver/client-list.h +++ b/src/libmdsserver/client-list.h @@ -25,28 +25,28 @@ -#define CLIENT_LIST_T_VERSION 0 +#define CLIENT_LIST_T_VERSION 0 /** * Dynamic array of client ID:s */ typedef struct client_list { - /** - * The size of the array - */ - size_t capacity; - - /** - * The index after the last used index - */ - size_t size; - - /** - * Stored client ID:s - */ - uint64_t* clients; - + /** + * The size of the array + */ + size_t capacity; + + /** + * The index after the last used index + */ + size_t size; + + /** + * Stored client ID:s + */ + uint64_t *clients; + } client_list_t; @@ -59,7 +59,7 @@ typedef struct client_list * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int client_list_create(client_list_t* restrict this, size_t capacity); +int client_list_create(client_list_t *restrict this, size_t capacity); /** * Release all resources in a client list, should @@ -68,7 +68,7 @@ int client_list_create(client_list_t* restrict this, size_t capacity); * @param this The client list */ __attribute__((nonnull)) -void client_list_destroy(client_list_t* restrict this); +void client_list_destroy(client_list_t *restrict this); /** * Clone a client list @@ -78,7 +78,7 @@ void client_list_destroy(client_list_t* restrict this); * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int client_list_clone(const client_list_t* restrict this, client_list_t* restrict out); +int client_list_clone(const client_list_t *restrict this, client_list_t *restrict out); /** * Add a client to the list @@ -88,7 +88,7 @@ int client_list_clone(const client_list_t* restrict this, client_list_t* restric * @return Non-zero on error, `errno` will be set accordingly */ __attribute__((nonnull)) -int client_list_add(client_list_t* restrict this, uint64_t client); +int client_list_add(client_list_t *restrict this, uint64_t client); /** * Remove a client from the list, once @@ -97,7 +97,7 @@ int client_list_add(client_list_t* restrict this, uint64_t client); * @param client The client to remove */ __attribute__((nonnull)) -void client_list_remove(client_list_t* restrict this, uint64_t client); +void client_list_remove(client_list_t *restrict this, uint64_t client); /** * Calculate the buffer size need to marshal a client list @@ -106,7 +106,7 @@ void client_list_remove(client_list_t* restrict this, uint64_t client); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t client_list_marshal_size(const client_list_t* restrict this); +size_t client_list_marshal_size(const client_list_t *restrict this); /** * Marshals a client list @@ -115,7 +115,7 @@ size_t client_list_marshal_size(const client_list_t* restrict this); * @param data Output buffer for the marshalled data */ __attribute__((nonnull)) -void client_list_marshal(const client_list_t* restrict this, char* restrict data); +void client_list_marshal(const client_list_t *restrict this, char *restrict data); /** * Unmarshals a client list @@ -126,8 +126,7 @@ void client_list_marshal(const client_list_t* restrict this, char* restrict data * Destroy the list on error. */ __attribute__((nonnull)) -int client_list_unmarshal(client_list_t* restrict this, char* restrict data); +int client_list_unmarshal(client_list_t *restrict this, char *restrict data); #endif - diff --git a/src/libmdsserver/config.h.in b/src/libmdsserver/config.h.in index a1242f7..d018366 100644 --- a/src/libmdsserver/config.h.in +++ b/src/libmdsserver/config.h.in @@ -22,152 +22,128 @@ /** * The name under which this package is installed */ -#define PKGNAME "@PKGNAME@" - +#define PKGNAME "@PKGNAME@" /** * The directory where all servers are installed */ -#define LIBEXECDIR "@LIBEXECDIR@" - +#define LIBEXECDIR "@LIBEXECDIR@" /** * The system's directory for non-persistent temporary files */ -#define TMPDIR "@TMPDIR@" - +#define TMPDIR "@TMPDIR@" /** * The system's directory for runtime data */ -#define RUNDIR "@RUNDIR@" - +#define RUNDIR "@RUNDIR@" /** * The system's directory for site-specific configurations */ -#define SYSCONFDIR "@SYSCONFDIR@" - +#define SYSCONFDIR "@SYSCONFDIR@" /** * The system's directory for pseudo-devices */ -#define DEVDIR "@DEVDIR@" - +#define DEVDIR "@DEVDIR@" /** * Pathname pattern for virtual terminals */ -#define VT_PATH_PATTERN "@VT_PATH_PATTERN@" - +#define VT_PATH_PATTERN "@VT_PATH_PATTERN@" /** * The root directory of all runtime data stored by mds */ -#define MDS_RUNTIME_ROOT_DIRECTORY "@MDS_RUNTIME_ROOT_DIRECTORY@" - +#define MDS_RUNTIME_ROOT_DIRECTORY "@MDS_RUNTIME_ROOT_DIRECTORY@" /** * The root directory of temporarily stored data stored by mds servers */ -#define MDS_STORAGE_ROOT_DIRECTORY "@MDS_STORAGE_ROOT_DIRECTORY@" - +#define MDS_STORAGE_ROOT_DIRECTORY "@MDS_STORAGE_ROOT_DIRECTORY@" /** * The user ID for the root user */ -#define ROOT_USER_UID @ROOT_USER_UID@ - +#define ROOT_USER_UID @ROOT_USER_UID@ /** * The group ID for the root group */ -#define ROOT_GROUP_GID @ROOT_GROUP_GID@ - +#define ROOT_GROUP_GID @ROOT_GROUP_GID@ /** * The group ID for the nobody group */ -#define NOBODY_GROUP_GID @NOBODY_GROUP_GID@ +#define NOBODY_GROUP_GID @NOBODY_GROUP_GID@ /* These three names above are redundant, but that is to avoid errors. */ - /** * The byte length of the authentication token */ -#define TOKEN_LENGTH @TOKEN_LENGTH@ - +#define TOKEN_LENGTH @TOKEN_LENGTH@ /** * Random number generator to use for generating a token */ -#define TOKEN_RANDOM "@TOKEN_RANDOM@" - +#define TOKEN_RANDOM "@TOKEN_RANDOM@" /** * The path of the symlink to the executed command */ -#define SELF_EXE "@SELF_EXE@" - +#define SELF_EXE "@SELF_EXE@" /** * The path to the directory with symlinks to each file that is open */ -#define SELF_FD "@SELF_FD@" - +#define SELF_FD "@SELF_FD@" /** * Pattern for the names of shared object to which states are marshalled */ -#define SHM_PATH_PATTERN "@SHM_PATH_PATTERN@" - +#define SHM_PATH_PATTERN "@SHM_PATH_PATTERN@" /** * The maximum number of command line arguments to allow */ -#define ARGC_LIMIT @ARGC_LIMIT@ - +#define ARGC_LIMIT @ARGC_LIMIT@ /** * The number of additional arguments a libexec server may have */ -#define LIBEXEC_ARGC_EXTRA_LIMIT @LIBEXEC_ARGC_EXTRA_LIMIT@ - +#define LIBEXEC_ARGC_EXTRA_LIMIT @LIBEXEC_ARGC_EXTRA_LIMIT@ /** * The maximum number of display allowed on the system */ -#define DISPLAY_MAX @DISPLAY_MAX@ - +#define DISPLAY_MAX @DISPLAY_MAX@ /** * The name of the environment variable that * indicates the index of the display */ -#define DISPLAY_ENV "@DISPLAY_ENV@" - +#define DISPLAY_ENV "@DISPLAY_ENV@" /** * The name of the environment variable that * indicates the display server's process group */ -#define PGROUP_ENV "@PGROUP_ENV@" - +#define PGROUP_ENV "@PGROUP_ENV@" /** * The minimum time that most have elapsed * for respawning to be allowed */ -#define RESPAWN_TIME_LIMIT_SECONDS @RESPAWN_TIME_LIMIT_SECONDS@ - +#define RESPAWN_TIME_LIMIT_SECONDS @RESPAWN_TIME_LIMIT_SECONDS@ /** * The dot-prefixless basename of the initrc * file that the master server executes */ -#define INITRC_FILE "@INITRC_FILE@" +#define INITRC_FILE "@INITRC_FILE@" #endif - diff --git a/src/libmdsserver/fd-table.h b/src/libmdsserver/fd-table.h index 19d1f99..b611b43 100644 --- a/src/libmdsserver/fd-table.h +++ b/src/libmdsserver/fd-table.h @@ -25,43 +25,43 @@ -#define FD_TABLE_T_VERSION 0 +#define FD_TABLE_T_VERSION 0 /** * Value lookup table optimised for file descriptors as keys */ typedef struct fd_table { - /** - * The table's capacity, i.e. how many entries that can be stored, - * in total, before its internal table needs to grow - */ - size_t capacity; - - /** - * The number of entries stored in the table - */ - size_t size; - - /** - * Map from keys to values - */ - size_t* values; - - /** - * Map from keys to whether that are in used, bit-packed - */ - uint64_t* used; - - /** - * Check whether two values are equal - * - * If this function pointer is `NULL`, the identity is used - * - * Be aware, this variable cannot be marshalled - */ - compare_func* value_comparator; - + /** + * The table's capacity, i.e. how many entries that can be stored, + * in total, before its internal table needs to grow + */ + size_t capacity; + + /** + * The number of entries stored in the table + */ + size_t size; + + /** + * Map from keys to values + */ + size_t *values; + + /** + * Map from keys to whether that are in used, bit-packed + */ + uint64_t *used; + + /** + * Check whether two values are equal + * + * If this function pointer is `NULL`, the identity is used + * + * Be aware, this variable cannot be marshalled + */ + compare_func *value_comparator; + } fd_table_t; @@ -74,7 +74,7 @@ typedef struct fd_table * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity); +int fd_table_create_tuned(fd_table_t *restrict this, size_t initial_capacity); /** * Create a fd table @@ -82,8 +82,8 @@ int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity); * @param this:fd_table_t* Memory slot in which to store the new fd table * @return :int Non-zero on error, `errno` will have been set accordingly */ -#define fd_table_create(this) \ - fd_table_create_tuned(this, 16) +#define fd_table_create(this)\ + fd_table_create_tuned(this, 16) /** * Release all resources in a fd table, should @@ -94,7 +94,7 @@ int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity); * @param values_freer Function that frees a value, `NULL` if value should not be freed */ __attribute__((nonnull(1))) -void fd_table_destroy(fd_table_t* restrict this, free_func* key_freer, free_func* value_freer); +void fd_table_destroy(fd_table_t *restrict this, free_func *key_freer, free_func *value_freer); /** * Check whether a value is stored in the table @@ -104,7 +104,7 @@ void fd_table_destroy(fd_table_t* restrict this, free_func* key_freer, free_func * @return Whether the value is stored in the table */ __attribute__((pure, nonnull)) -int fd_table_contains_value(const fd_table_t* restrict this, size_t value); +int fd_table_contains_value(const fd_table_t *restrict this, size_t value); /** * Check whether a key is used in the table @@ -114,7 +114,7 @@ int fd_table_contains_value(const fd_table_t* restrict this, size_t value); * @return Whether the key is used */ __attribute__((pure, nonnull)) -int fd_table_contains_key(const fd_table_t* restrict this, int key); +int fd_table_contains_key(const fd_table_t *restrict this, int key); /** * Look up a value in the table @@ -124,7 +124,7 @@ int fd_table_contains_key(const fd_table_t* restrict this, int key); * @return The value associated with the key, 0 if the key was not used */ __attribute__((pure, nonnull)) -size_t fd_table_get(const fd_table_t* restrict this, int key); +size_t fd_table_get(const fd_table_t *restrict this, int key); /** * Add an entry to the table @@ -136,7 +136,7 @@ size_t fd_table_get(const fd_table_t* restrict this, int key); * 0 will also be returned on error, check the `errno` variable. */ __attribute__((nonnull)) -size_t fd_table_put(fd_table_t* restrict this, int key, size_t value); +size_t fd_table_put(fd_table_t *restrict this, int key, size_t value); /** * Remove an entry in the table @@ -146,7 +146,7 @@ size_t fd_table_put(fd_table_t* restrict this, int key, size_t value); * @return The previous value associated with the key, 0 if the key was not used */ __attribute__((nonnull)) -size_t fd_table_remove(fd_table_t* restrict this, int key); +size_t fd_table_remove(fd_table_t *restrict this, int key); /** * Remove all entries in the table @@ -154,7 +154,7 @@ size_t fd_table_remove(fd_table_t* restrict this, int key); * @param this The fd table */ __attribute__((nonnull)) -void fd_table_clear(fd_table_t* restrict this); +void fd_table_clear(fd_table_t *restrict this); /** * Calculate the buffer size need to marshal a fd table @@ -163,7 +163,7 @@ void fd_table_clear(fd_table_t* restrict this); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t fd_table_marshal_size(const fd_table_t* restrict this); +size_t fd_table_marshal_size(const fd_table_t *restrict this); /** * Marshals a fd table @@ -172,7 +172,7 @@ size_t fd_table_marshal_size(const fd_table_t* restrict this); * @param data Output buffer for the marshalled data */ __attribute__((nonnull)) -void fd_table_marshal(const fd_table_t* restrict this, char* restrict data); +void fd_table_marshal(const fd_table_t *restrict this, char *restrict data); /** * Unmarshals a fd table @@ -184,8 +184,7 @@ void fd_table_marshal(const fd_table_t* restrict this, char* restrict data); * Destroy the table on error. */ __attribute__((nonnull(1, 2))) -int fd_table_unmarshal(fd_table_t* restrict this, char* restrict data, remap_func* remapper); +int fd_table_unmarshal(fd_table_t *restrict this, char *restrict data, remap_func *remapper); #endif - diff --git a/src/libmdsserver/hash-help.h b/src/libmdsserver/hash-help.h index 21676f3..0b51bb8 100644 --- a/src/libmdsserver/hash-help.h +++ b/src/libmdsserver/hash-help.h @@ -29,16 +29,16 @@ * @param str The string * @return The hash of the string */ -__attribute__((pure)) -static inline size_t string_hash(const char* str) +static inline size_t __attribute__((pure)) +string_hash(const char *str) { - size_t hash = 0; - - if (str != NULL) - while (*str != '\0') - hash = hash * 31 + (size_t)(unsigned char)*str++; - - return hash; + size_t hash = 0; + + if (str) + while (*str != '\0') + hash = hash * 31 + (size_t)(unsigned char)*str++; + + return hash; } @@ -49,15 +49,14 @@ static inline size_t string_hash(const char* str) * @param str_b The second string * @return Whether the strings are equals */ -__attribute__((pure)) -static inline int string_comparator(char* str_a, char* str_b) +static inline int __attribute__((pure)) +string_comparator(char *str_a, char *str_b) { - if ((str_a != NULL) && (str_b != NULL) && (str_a != str_b)) - return !strcmp((char*)str_a, (char*)str_b); - else - return str_a == str_b; + if (str_a && str_b && str_a != str_b) + return !strcmp(str_a, str_b); + else + return str_a == str_b; } #endif - diff --git a/src/libmdsserver/hash-list.h b/src/libmdsserver/hash-list.h index 1381e4e..a376209 100644 --- a/src/libmdsserver/hash-list.h +++ b/src/libmdsserver/hash-list.h @@ -592,4 +592,3 @@ T##_unmarshal(T##_t* restrict this, char* restrict data)\ #endif - diff --git a/src/libmdsserver/hash-table.h b/src/libmdsserver/hash-table.h index 1a3a26c..5ccdefe 100644 --- a/src/libmdsserver/hash-table.h +++ b/src/libmdsserver/hash-table.h @@ -23,33 +23,33 @@ -#define HASH_TABLE_T_VERSION 0 +#define HASH_TABLE_T_VERSION 0 /** * Hash table entry */ typedef struct hash_entry { - /** - * A key - */ - size_t key; - - /** - * The value associated with the key - */ - size_t value; - - /** - * The truncated hash value of the key - */ - size_t hash; - - /** - * The next entry in the bucket - */ - struct hash_entry* next; - + /** + * A key + */ + size_t key; + + /** + * The value associated with the key + */ + size_t value; + + /** + * The truncated hash value of the key + */ + size_t hash; + + /** + * The next entry in the bucket + */ + struct hash_entry *next; + } hash_entry_t; @@ -58,61 +58,61 @@ typedef struct hash_entry */ typedef struct hash_table { - /** - * The table's capacity, i.e. the number of buckets - */ - size_t capacity; - - /** - * Entry buckets - */ - hash_entry_t** buckets; - - /** - * When, in the ratio of entries comparied to the capacity, to grow the table - */ - float load_factor; - - /** - * When, in the number of entries, to grow the table - */ - size_t threshold; - - /** - * The number of entries stored in the table - */ - size_t size; - - /** - * Check whether two values are equal - * - * If this function pointer is `NULL`, the identity is used - * - * Be aware, this variable cannot be marshalled - */ - compare_func* value_comparator; - - /** - * Check whether two keys are equal - * - * If this function pointer is `NULL`, the identity is used - * - * Be aware, this variable cannot be marshalled - */ - compare_func* key_comparator; - - /** - * Calculate the hash of a key - * - * If this function pointer is `NULL`, the identity hash is used - * - * Be aware, this variable cannot be marshalled - * - * @param key The key - * @return The hash of the key - */ - hash_func* hasher; - + /** + * The table's capacity, i.e. the number of buckets + */ + size_t capacity; + + /** + * Entry buckets + */ + hash_entry_t **buckets; + + /** + * When, in the ratio of entries comparied to the capacity, to grow the table + */ + float load_factor; + + /** + * When, in the number of entries, to grow the table + */ + size_t threshold; + + /** + * The number of entries stored in the table + */ + size_t size; + + /** + * Check whether two values are equal + * + * If this function pointer is `NULL`, the identity is used + * + * Be aware, this variable cannot be marshalled + */ + compare_func *value_comparator; + + /** + * Check whether two keys are equal + * + * If this function pointer is `NULL`, the identity is used + * + * Be aware, this variable cannot be marshalled + */ + compare_func *key_comparator; + + /** + * Calculate the hash of a key + * + * If this function pointer is `NULL`, the identity hash is used + * + * Be aware, this variable cannot be marshalled + * + * @param key The key + * @return The hash of the key + */ + hash_func *hasher; + } hash_table_t; @@ -126,7 +126,7 @@ typedef struct hash_table * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_capacity, float load_factor); +int hash_table_create_fine_tuned(hash_table_t *restrict this, size_t initial_capacity, float load_factor); /** * Create a hash table @@ -135,8 +135,8 @@ int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_cap * @param initial_capacity:size_t The initial capacity of the table * @return :int Non-zero on error, `errno` will have been set accordingly */ -#define hash_table_create_tuned(this, initial_capacity) \ - hash_table_create_fine_tuned(this, initial_capacity, 0.75f) +#define hash_table_create_tuned(this, initial_capacity)\ + hash_table_create_fine_tuned(this, initial_capacity, 0.75f) /** * Create a hash table @@ -144,8 +144,8 @@ int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_cap * @param this:hash_table_t* Memory slot in which to store the new hash table * @return :int Non-zero on error, `errno` will have been set accordingly */ -#define hash_table_create(this) \ - hash_table_create_tuned(this, 16) +#define hash_table_create(this)\ + hash_table_create_tuned(this, 16) /** * Release all resources in a hash table, should @@ -156,7 +156,7 @@ int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_cap * @param values_freer Function that frees a value, `NULL` if value should not be freed */ __attribute__((nonnull(1))) -void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_func* value_freer); +void hash_table_destroy(hash_table_t *restrict this, free_func *key_freer, free_func *value_freer); /** * Check whether a value is stored in the table @@ -166,7 +166,7 @@ void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_ * @return Whether the value is stored in the table */ __attribute__((pure, nonnull)) -int hash_table_contains_value(const hash_table_t* restrict this, size_t value); +int hash_table_contains_value(const hash_table_t *restrict this, size_t value); /** * Check whether a key is used in the table @@ -176,7 +176,7 @@ int hash_table_contains_value(const hash_table_t* restrict this, size_t value); * @return Whether the key is used */ __attribute__((pure, nonnull)) -int hash_table_contains_key(const hash_table_t* restrict this, size_t key); +int hash_table_contains_key(const hash_table_t *restrict this, size_t key); /** * Look up a value in the table @@ -186,7 +186,7 @@ int hash_table_contains_key(const hash_table_t* restrict this, size_t key); * @return The value associated with the key, 0 if the key was not used */ __attribute__((pure, nonnull)) -size_t hash_table_get(const hash_table_t* restrict this, size_t key); +size_t hash_table_get(const hash_table_t *restrict this, size_t key); /** * Look up an entry in the table @@ -196,7 +196,7 @@ size_t hash_table_get(const hash_table_t* restrict this, size_t key); * @return The entry associated with the key, `NULL` if the key was not used */ __attribute__((pure, nonnull)) -hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key); +hash_entry_t *hash_table_get_entry(const hash_table_t *restrict this, size_t key); /** * Add an entry to the table @@ -208,7 +208,7 @@ hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key * 0 will also be returned on error, check the `errno` variable. */ __attribute__((nonnull)) -size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value); +size_t hash_table_put(hash_table_t *restrict this, size_t key, size_t value); /** * Remove an entry in the table @@ -218,7 +218,7 @@ size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value); * @return The previous value associated with the key, 0 if the key was not used */ __attribute__((nonnull)) -size_t hash_table_remove(hash_table_t* restrict this, size_t key); +size_t hash_table_remove(hash_table_t *restrict this, size_t key); /** * Remove all entries in the table @@ -226,7 +226,7 @@ size_t hash_table_remove(hash_table_t* restrict this, size_t key); * @param this The hash table */ __attribute__((nonnull)) -void hash_table_clear(hash_table_t* restrict this); +void hash_table_clear(hash_table_t *restrict this); /** * Wrapper for `for` keyword that iterates over entry element in a hash table @@ -235,9 +235,9 @@ void hash_table_clear(hash_table_t* restrict this); * @param i:size_t The variable to store the buckey index in at each iteration * @param entry:hash_entry_t* The variable to store the entry in at each iteration */ -#define foreach_hash_table_entry(this, i, entry) \ - for (i = 0; i < (this).capacity; i++) \ - for (entry = (this).buckets[i]; entry != NULL; entry = entry->next) +#define foreach_hash_table_entry(this, i, entry)\ + for (i = 0; i < (this).capacity; i++)\ + for (entry = (this).buckets[i]; entry; entry = entry->next) /** * Calculate the buffer size need to marshal a hash table @@ -246,7 +246,7 @@ void hash_table_clear(hash_table_t* restrict this); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t hash_table_marshal_size(const hash_table_t* restrict this); +size_t hash_table_marshal_size(const hash_table_t *restrict this); /** * Marshals a hash table @@ -255,7 +255,7 @@ size_t hash_table_marshal_size(const hash_table_t* restrict this); * @param data Output buffer for the marshalled data */ __attribute__((nonnull)) -void hash_table_marshal(const hash_table_t* restrict this, char* restrict data); +void hash_table_marshal(const hash_table_t *restrict this, char *restrict data); /** * Unmarshals a hash table @@ -267,8 +267,7 @@ void hash_table_marshal(const hash_table_t* restrict this, char* restrict data); * Destroy the table on error. */ __attribute__((nonnull(1, 2))) -int hash_table_unmarshal(hash_table_t* restrict this, char* restrict data, remap_func* remapper); +int hash_table_unmarshal(hash_table_t *restrict this, char *restrict data, remap_func *remapper); #endif - diff --git a/src/libmdsserver/libmdsserver.pc.in b/src/libmdsserver/libmdsserver.pc.in index 4b463af..ddaa591 100644 --- a/src/libmdsserver/libmdsserver.pc.in +++ b/src/libmdsserver/libmdsserver.pc.in @@ -6,4 +6,3 @@ Description: Library for mds-servers Version: @VERSION@ Libs: -L${libdir} -lmdsserver @LIBS@ Cflags: -I${includedir} @CFLAGS@ - diff --git a/src/libmdsserver/linked-list.h b/src/libmdsserver/linked-list.h index 6a8ff2d..1d0cabb 100644 --- a/src/libmdsserver/linked-list.h +++ b/src/libmdsserver/linked-list.h @@ -46,63 +46,63 @@ /** * Sentinel value indicating that the position is unused */ -#define LINKED_LIST_UNUSED (-((ssize_t)(SIZE_MAX >> 1)) - 1) +#define LINKED_LIST_UNUSED (-((ssize_t)(SIZE_MAX >> 1)) - 1) -#define LINKED_LIST_T_VERSION 0 +#define LINKED_LIST_T_VERSION 0 /** * Linear array sentinel doubly linked list class */ typedef struct linked_list { - /** - * The size of the arrays - */ - size_t capacity; - - /** - * The index after the last used index in - * `values` and `next` - */ - size_t end; - - /** - * Head of the stack of reusable positions - */ - size_t reuse_head; - - /** - * Stack of indices than are no longer in use - */ - ssize_t* reusable; - - /** - * The value stored in each node - */ - size_t* values; - - /** - * The next node for each node, `edge` if the current - * node is the last node, and `LINKED_LIST_UNUSED` - * if there is no node on this position - */ - ssize_t* next; - - /** - * The previous node for each node, `edge` if - * the current node is the first node, and - * `LINKED_LIST_UNUSED` if there is no node - * on this position - */ - ssize_t* previous; - - /** - * The sentinel node in the list - */ - ssize_t edge; - + /** + * The size of the arrays + */ + size_t capacity; + + /** + * The index after the last used index in + * `values` and `next` + */ + size_t end; + + /** + * Head of the stack of reusable positions + */ + size_t reuse_head; + + /** + * Stack of indices than are no longer in use + */ + ssize_t *reusable; + + /** + * The value stored in each node + */ + size_t *values; + + /** + * The next node for each node, `edge` if the current + * node is the last node, and `LINKED_LIST_UNUSED` + * if there is no node on this position + */ + ssize_t *next; + + /** + * The previous node for each node, `edge` if + * the current node is the first node, and + * `LINKED_LIST_UNUSED` if there is no node + * on this position + */ + ssize_t *previous; + + /** + * The sentinel node in the list + */ + ssize_t edge; + } linked_list_t; @@ -115,7 +115,7 @@ typedef struct linked_list * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int linked_list_create(linked_list_t* restrict this, size_t capacity); +int linked_list_create(linked_list_t *restrict this, size_t capacity); /** * Release all resources in a linked list, should @@ -124,7 +124,7 @@ int linked_list_create(linked_list_t* restrict this, size_t capacity); * @param this The linked list */ __attribute__((nonnull)) -void linked_list_destroy(linked_list_t* restrict this); +void linked_list_destroy(linked_list_t *restrict this); /** * Clone a linked list @@ -134,7 +134,7 @@ void linked_list_destroy(linked_list_t* restrict this); * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int linked_list_clone(const linked_list_t* restrict this, linked_list_t* restrict out); +int linked_list_clone(const linked_list_t *restrict this, linked_list_t *restrict out); /** * Pack the list so that there are no reusable @@ -151,7 +151,7 @@ int linked_list_clone(const linked_list_t* restrict this, linked_list_t* restric * @return Non-zero on error, `errno` will have been set accordingly */ __attribute__((nonnull)) -int linked_list_pack(linked_list_t* restrict this); +int linked_list_pack(linked_list_t *restrict this); /** * Insert a value in the beginning of the list @@ -161,8 +161,8 @@ int linked_list_pack(linked_list_t* restrict this); * @return :ssize_t The node that has been created and inserted, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -#define linked_list_insert_beginning(this, value) \ - (linked_list_insert_after(this, value, this->edge)) +#define linked_list_insert_beginning(this, value)\ + (linked_list_insert_after(this, value, this->edge)) /** * Remove the node at the beginning of the list @@ -170,8 +170,8 @@ int linked_list_pack(linked_list_t* restrict this); * @param this:linked_list_t* The list * @return :ssize_t The node that has been removed */ -#define linked_list_remove_beginning(this) \ - (linked_list_remove_after(this, this->edge)) +#define linked_list_remove_beginning(this)\ + (linked_list_remove_after(this, this->edge)) /** * Insert a value after a specified, reference, node @@ -183,7 +183,7 @@ int linked_list_pack(linked_list_t* restrict this); * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ __attribute__((nonnull)) -ssize_t linked_list_insert_after(linked_list_t* restrict this, size_t value, ssize_t predecessor); +ssize_t linked_list_insert_after(linked_list_t *restrict this, size_t value, ssize_t predecessor); /** * Remove the node after a specified, reference, node @@ -193,7 +193,7 @@ ssize_t linked_list_insert_after(linked_list_t* restrict this, size_t value, ssi * @return The node that has been removed */ __attribute__((nonnull)) -ssize_t linked_list_remove_after(linked_list_t* restrict this, ssize_t predecessor); +ssize_t linked_list_remove_after(linked_list_t *restrict this, ssize_t predecessor); /** * Insert a value before a specified, reference, node @@ -205,7 +205,7 @@ ssize_t linked_list_remove_after(linked_list_t* restrict this, ssize_t predecess * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ __attribute__((nonnull)) -ssize_t linked_list_insert_before(linked_list_t* restrict this, size_t value, ssize_t successor); +ssize_t linked_list_insert_before(linked_list_t *restrict this, size_t value, ssize_t successor); /** * Remove the node before a specified, reference, node @@ -215,7 +215,7 @@ ssize_t linked_list_insert_before(linked_list_t* restrict this, size_t value, ss * @return The node that has been removed */ __attribute__((nonnull)) -ssize_t linked_list_remove_before(linked_list_t* restrict this, ssize_t successor); +ssize_t linked_list_remove_before(linked_list_t *restrict this, ssize_t successor); /** * Remove the node from the list @@ -224,7 +224,7 @@ ssize_t linked_list_remove_before(linked_list_t* restrict this, ssize_t successo * @param node The node to remove */ __attribute__((nonnull)) -void linked_list_remove(linked_list_t* restrict this, ssize_t node); +void linked_list_remove(linked_list_t *restrict this, ssize_t node); /** * Insert a value in the end of the list @@ -234,8 +234,8 @@ void linked_list_remove(linked_list_t* restrict this, ssize_t node); * @return :ssize_t The node that has been created and inserted, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -#define linked_list_insert_end(this, value) \ - (linked_list_insert_before((this), (value), (this)->edge)) +#define linked_list_insert_end(this, value)\ + (linked_list_insert_before((this), (value), (this)->edge)) /** * Remove the node at the end of the list @@ -243,8 +243,8 @@ void linked_list_remove(linked_list_t* restrict this, ssize_t node); * @param this:linked_list_t* The list * @return :ssize_t The node that has been removed */ -#define linked_list_remove_end(this) \ - (linked_list_remove_before((this), (this)->edge)) +#define linked_list_remove_end(this)\ + (linked_list_remove_before((this), (this)->edge)) /** * Calculate the buffer size need to marshal a linked list @@ -253,7 +253,7 @@ void linked_list_remove(linked_list_t* restrict this, ssize_t node); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t linked_list_marshal_size(const linked_list_t* restrict this); +size_t linked_list_marshal_size(const linked_list_t *restrict this); /** * Marshals a linked list @@ -262,7 +262,7 @@ size_t linked_list_marshal_size(const linked_list_t* restrict this); * @param data Output buffer for the marshalled data */ __attribute__((nonnull)) -void linked_list_marshal(const linked_list_t* restrict this, char* restrict data); +void linked_list_marshal(const linked_list_t *restrict this, char *restrict data); /** * Unmarshals a linked list @@ -273,7 +273,7 @@ void linked_list_marshal(const linked_list_t* restrict this, char* restrict data * Destroy the list on error. */ __attribute__((nonnull)) -int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data); +int linked_list_unmarshal(linked_list_t *restrict this, char *restrict data); /** * Wrapper for `for` keyword that iterates over each element in a linked list @@ -281,8 +281,8 @@ int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data); * @param list:linked_list_t The linked list * @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], node != (list).edge;) +#define foreach_linked_list_node(list, node)\ + for (node = (list).edge; node = (list).next[node], node != (list).edge;) /** * Print the content of the list @@ -291,8 +291,7 @@ int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data); * @param output Output file */ __attribute__((nonnull)) -void linked_list_dump(linked_list_t* restrict this, FILE* restrict output); +void linked_list_dump(linked_list_t *restrict this, FILE *restrict output); #endif - diff --git a/src/libmdsserver/macro-bits.h b/src/libmdsserver/macro-bits.h index abfb34a..2d1dbf5 100644 --- a/src/libmdsserver/macro-bits.h +++ b/src/libmdsserver/macro-bits.h @@ -31,7 +31,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atoz(str) ((size_t)atol(str)) +#define atoz(str) ((size_t)atol(str)) /** * Convert the beginning of a `const char*` to an `ssize_t` @@ -39,7 +39,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atosz(str) ((ssize_t)atol(str)) +#define atosz(str) ((ssize_t)atol(str)) /** * Convert the beginning of a `const char*` to a `short int` @@ -47,7 +47,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atoh(str) ((short)atol(str)) +#define atoh(str) ((short)atol(str)) /** * Convert the beginning of a `const char*` to an `unsigned short int` @@ -55,7 +55,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atouh(str) ((unsigned short)atol(str)) +#define atouh(str) ((unsigned short)atol(str)) /** * Convert the beginning of a `const char*` to an `unsigned int` @@ -63,7 +63,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atou(str) ((unsigned int)atoi(str)) +#define atou(str) ((unsigned int)atoi(str)) /** * Convert the beginning of a `const char*` to an `unsigned long int` @@ -71,7 +71,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atoul(str) ((unsigned long)atol(str)) +#define atoul(str) ((unsigned long)atol(str)) /** * Convert the beginning of a `const char*` to an `unsigned long long int` @@ -79,7 +79,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -#define atoull(str) ((unsigned long long)atoll(str)) +#define atoull(str) ((unsigned long long)atoll(str)) /** * Convert the beginning of a `const char*` to an `int8_t` @@ -87,7 +87,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define ato8(str) ((int8_t)atoi(str)) +#define ato8(str) ((int8_t)atoi(str)) /** * Convert the beginning of a `const char*` to an `uint8_t` @@ -95,7 +95,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atou8(str) ((uint8_t)atou(str)) +#define atou8(str) ((uint8_t)atou(str)) /** * Convert the beginning of a `const char*` to an `int16_t` @@ -103,7 +103,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define ato16(str) ((int16_t)atoi(str)) +#define ato16(str) ((int16_t)atoi(str)) /** * Convert the beginning of a `const char*` to an `uint16_t` @@ -111,7 +111,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atou16(str) ((uint16_t)atou(str)) +#define atou16(str) ((uint16_t)atou(str)) #if UINT_MAX == UINT32_MAX /** @@ -120,7 +120,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define ato32(str) ((int32_t)atoi(str)) +# define ato32(str) ((int32_t)atoi(str)) /** * Convert the beginning of a `const char*` to an `uint32_t` @@ -128,7 +128,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atou32(str) ((uint32_t)atou(str)) +# define atou32(str) ((uint32_t)atou(str)) #else /** * Convert the beginning of a `const char*` to an `int32_t` @@ -136,7 +136,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define ato32(str) ((int32_t)atol(str)) +# define ato32(str) ((int32_t)atol(str)) /** * Convert the beginning of a `const char*` to an `uint32_t` @@ -144,7 +144,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atou32(str) ((uint32_t)atoul(str)) +# define atou32(str) ((uint32_t)atoul(str)) #endif #if ULONG_MAX == UINT64_MAX @@ -154,7 +154,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define ato64(str) ((int64_t)atol(str)) +# define ato64(str) ((int64_t)atol(str)) /** * Convert the beginning of a `const char*` to an `uint64_t` @@ -162,7 +162,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atou64(str) ((uint64_t)atoul(str)) +# define atou64(str) ((uint64_t)atoul(str)) #else /** * Convert the beginning of a `const char*` to an `int64_t` @@ -170,7 +170,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define ato64(str) ((int64_t)atoll(str)) +# define ato64(str) ((int64_t)atoll(str)) /** * Convert the beginning of a `const char*` to an `uint64_t` @@ -178,7 +178,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atou64(str) ((uint64_t)atoull(str)) +# define atou64(str) ((uint64_t)atoull(str)) #endif /** @@ -187,7 +187,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atoj(str) ((intmax_t)atou64(str)) +#define atoj(str) ((intmax_t)atou64(str)) /** * Convert the beginning of a `const char*` to an `uintmax_t` @@ -195,8 +195,7 @@ * @param str:const char* The string that begins with an integer * @return The integer at the beginning of the string */ -# define atouj(str) ((uintmax_t)atou64(str)) +#define atouj(str) ((uintmax_t)atou64(str)) #endif - diff --git a/src/libmdsserver/macros.h b/src/libmdsserver/macros.h index 14ce80b..3621268 100644 --- a/src/libmdsserver/macros.h +++ b/src/libmdsserver/macros.h @@ -729,8 +729,8 @@ * * @param str:const char* The argument passed to `perror` */ -#define xperror(str) \ - (errno ? perror(str), errno = 0 : 0) +#define xperror(str)\ + (errno ? perror(str), errno = 0 : 0) /** @@ -738,17 +738,17 @@ * * @param ... The condition */ -#define fail_if(...) \ - do \ - if (__VA_ARGS__) \ - { \ - int _fail_if_saved_errno = errno; \ - if ((errno != EMSGSIZE) && (errno != ECONNRESET) && (errno != EINTR)) \ - fprintf(stderr, "failure at %s:%i\n", __FILE__, __LINE__); \ - errno = _fail_if_saved_errno; \ - goto fail; \ - } \ - while (0) +#define fail_if(...)\ + do {\ + int _fail_if_saved_errno;\ + if (__VA_ARGS__) {\ + _fail_if_saved_errno = errno;\ + if (errno != EMSGSIZE && errno != ECONNRESET && errno != EINTR)\ + fprintf(stderr, "failure at %s:%i\n", __FILE__, __LINE__);\ + errno = _fail_if_saved_errno;\ + goto fail;\ + }\ + } while (0) /** @@ -757,8 +757,8 @@ * @param condition The condition * @param instructions The instruction (semicolon-terminated) */ -#define exit_if(condition, instructions) \ - do { if (condition) { instructions return 1; } } while (0) +#define exit_if(condition, instructions)\ + do { if (condition) { instructions return 1; } } while (0) /** @@ -769,8 +769,8 @@ * the compiler you are using, you may want to edit this * macro. */ -#define STREND(str) \ - (strchr(str, '\0')) +#define STREND(str)\ + (strchr(str, '\0')) /** @@ -778,7 +778,7 @@ * Quick, free up all your unused memory or kill yourself! */ #ifndef SIGDANGER -# define SIGDANGER (SIGRTMIN + 1) +# define SIGDANGER (SIGRTMIN + 1) #endif @@ -787,7 +787,7 @@ * about the server's state or statistics */ #ifndef SIGINFO -# define SIGINFO (SIGRTMIN + 2) +# define SIGINFO (SIGRTMIN + 2) #endif @@ -796,7 +796,7 @@ * into an updated binary */ #ifndef SIGUPDATE -# define SIGUPDATE SIGUSR1 +# define SIGUPDATE SIGUSR1 #endif @@ -804,8 +804,8 @@ * Normal signal handlers should place this macro * at the top of the function */ -#define SIGHANDLER_START \ - int sighandler_saved_errno = errno +#define SIGHANDLER_START\ + int sighandler_saved_errno = errno /** @@ -813,9 +813,8 @@ * at the bottom of the function, or just before * any `return` */ -#define SIGHANDLER_END \ - (errno = sighandler_saved_errno) +#define SIGHANDLER_END\ + (errno = sighandler_saved_errno) #endif - diff --git a/src/libmdsserver/mds-message.h b/src/libmdsserver/mds-message.h index 68c3c86..a2254e7 100644 --- a/src/libmdsserver/mds-message.h +++ b/src/libmdsserver/mds-message.h @@ -22,63 +22,63 @@ #include <stddef.h> -#define MDS_MESSAGE_T_VERSION 0 +#define MDS_MESSAGE_T_VERSION 0 /** * Message passed between a server and a client or between two of either */ typedef struct mds_message { - /** - * The headers in the message, each element in this list - * as an unparsed header, it consists of both the header - * name and its associated value, joined by ": ". A header - * cannot be `NULL` (unless its memory allocation failed,) - * but `headers` itself is `NULL` if there are no headers. - * The "Length" header should be included in this list. - */ - char** headers; - - /** - * The number of headers in the message - */ - size_t header_count; - - /** - * The payload of the message, `NULL` if none (of zero-length) - */ - char* payload; - - /** - * The size of the payload - */ - size_t payload_size; - - /** - * How much of the payload that has been stored (internal data) - */ - size_t payload_ptr; - - /** - * Internal buffer for the reading function (internal data) - */ - char* buffer; - - /** - * The size allocated to `buffer` (internal data) - */ - size_t buffer_size; - - /** - * The number of bytes used in `buffer` (internal data) - */ - size_t buffer_ptr; - - /** - * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) - */ - int stage; - + /** + * The headers in the message, each element in this list + * as an unparsed header, it consists of both the header + * name and its associated value, joined by ": ". A header + * cannot be `NULL` (unless its memory allocation failed,) + * but `headers` itself is `NULL` if there are no headers. + * The "Length" header should be included in this list. + */ + char **headers; + + /** + * The number of headers in the message + */ + size_t header_count; + + /** + * The payload of the message, `NULL` if none (of zero-length) + */ + char *payload; + + /** + * The size of the payload + */ + size_t payload_size; + + /** + * How much of the payload that has been stored (internal data) + */ + size_t payload_ptr; + + /** + * Internal buffer for the reading function (internal data) + */ + char *buffer; + + /** + * The size allocated to `buffer` (internal data) + */ + size_t buffer_size; + + /** + * The number of bytes used in `buffer` (internal data) + */ + size_t buffer_ptr; + + /** + * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) + */ + int stage; + } mds_message_t; @@ -91,7 +91,7 @@ typedef struct mds_message * Destroy the message on error. */ __attribute__((nonnull)) -int mds_message_initialise(mds_message_t* restrict this); +int mds_message_initialise(mds_message_t *restrict this); /** * Zero initialise a message slot @@ -99,7 +99,7 @@ int mds_message_initialise(mds_message_t* restrict this); * @param this Memory slot in which to store the new message */ __attribute__((nonnull)) -void mds_message_zero_initialise(mds_message_t* restrict this); +void mds_message_zero_initialise(mds_message_t *restrict this); /** * Release all resources in a message, should @@ -108,7 +108,7 @@ void mds_message_zero_initialise(mds_message_t* restrict this); * @param this The message */ __attribute__((nonnull)) -void mds_message_destroy(mds_message_t* restrict this); +void mds_message_destroy(mds_message_t *restrict this); /** * Extend the header list's allocation @@ -118,7 +118,7 @@ void mds_message_destroy(mds_message_t* restrict this); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int mds_message_extend_headers(mds_message_t* restrict this, size_t extent); +int mds_message_extend_headers(mds_message_t *restrict this, size_t extent); /** * Read the next message from a file descriptor @@ -134,7 +134,7 @@ int mds_message_extend_headers(mds_message_t* restrict this, size_t extent); * which is a state that cannot be recovered from. */ __attribute__((nonnull)) -int mds_message_read(mds_message_t* restrict this, int fd); +int mds_message_read(mds_message_t *restrict this, int fd); /** * Get the required allocation size for `data` of the @@ -144,7 +144,7 @@ int mds_message_read(mds_message_t* restrict this, int fd); * @return The size of the message when marshalled */ __attribute__((pure, nonnull)) -size_t mds_message_marshal_size(const mds_message_t* restrict this); +size_t mds_message_marshal_size(const mds_message_t *restrict this); /** * Marshal a message for state serialisation @@ -153,7 +153,7 @@ size_t mds_message_marshal_size(const mds_message_t* restrict this); * @param data Output buffer for the marshalled data */ __attribute__((nonnull)) -void mds_message_marshal(const mds_message_t* restrict this, char* restrict data); +void mds_message_marshal(const mds_message_t *restrict this, char *restrict data); /** * Unmarshal a message for state deserialisation @@ -164,7 +164,7 @@ void mds_message_marshal(const mds_message_t* restrict this, char* restrict data * Destroy the message on error. */ __attribute__((nonnull)) -int mds_message_unmarshal(mds_message_t* restrict this, char* restrict data); +int mds_message_unmarshal(mds_message_t *restrict this, char *restrict data); /** * Get the required allocation size for `data` of the @@ -174,7 +174,7 @@ int mds_message_unmarshal(mds_message_t* restrict this, char* restrict data); * @return The size of the message when marshalled */ __attribute__((pure, nonnull)) -size_t mds_message_compose_size(const mds_message_t* restrict this); +size_t mds_message_compose_size(const mds_message_t *restrict this); /** * Marshal a message for communication @@ -183,8 +183,7 @@ size_t mds_message_compose_size(const mds_message_t* restrict this); * @param data Output buffer for the marshalled data */ __attribute__((nonnull)) -void mds_message_compose(const mds_message_t* restrict this, char* restrict data); +void mds_message_compose(const mds_message_t *restrict this, char *restrict data); #endif - diff --git a/src/libmdsserver/table-common.h b/src/libmdsserver/table-common.h index 850358a..1fb95d9 100644 --- a/src/libmdsserver/table-common.h +++ b/src/libmdsserver/table-common.h @@ -56,4 +56,3 @@ typedef size_t remap_func(size_t obj); #endif - diff --git a/src/libmdsserver/util.h b/src/libmdsserver/util.h index acb8d5e..2bcad50 100644 --- a/src/libmdsserver/util.h +++ b/src/libmdsserver/util.h @@ -26,14 +26,14 @@ #ifndef __USE_GNU -__attribute__((pure, nonnull)) -static inline void* rawmemchr(const void* str, int chr) +static inline void *__attribute__((pure, nonnull)) +rawmemchr(const void *str, int chr) { - intptr_t str_address = (intptr_t)str; - void* str_nonconst = (void*)str_address; - char* s = str_nonconst; - while ((int)*s++ != chr); - return s - 1; + intptr_t str_address = (intptr_t)str; + void *str_nonconst = (void*)str_address; + char *s = str_nonconst; + while ((int)*s++ != chr); + return s - 1; } #endif @@ -45,7 +45,7 @@ static inline void* rawmemchr(const void* str, int chr) * @return The client ID integer */ __attribute__((pure, nonnull)) -uint64_t parse_client_id(const char* str); +uint64_t parse_client_id(const char *str); /** * Read an environment variable, but handle it as undefined if empty @@ -54,7 +54,7 @@ uint64_t parse_client_id(const char* str); * @return The environment variable's value, `NULL` if empty or not defined */ __attribute__((nonnull)) -char* getenv_nonempty(const char* var); +char *getenv_nonempty(const char *var); /** * Prepare the server so that it can reexec into @@ -88,7 +88,7 @@ int prepare_reexec(void); * @param argv The command line arguments * @param reexeced Whether the server has previously been re-exec:ed */ -void reexec_server(int argc, char** argv, int reexeced); +void reexec_server(int argc, char **argv, int reexeced); /** * Set up a signal trap. @@ -112,7 +112,7 @@ int xsigaction(int signo, void (*function)(int signo)); * @param length The length of the message * @return The number of bytes that have been sent (even on error) */ -size_t send_message(int socket, const char* message, size_t length); +size_t send_message(int socket, const char *message, size_t length); /** * A version of `atoi` that is strict about the syntax and bounds @@ -124,7 +124,7 @@ size_t send_message(int socket, const char* message, size_t length); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoi(const char* str, int* value, int min, int max); +int strict_atoi(const char *str, int *value, int min, int max); /** * A version of `atoj` that is strict about the syntax and bounds @@ -136,7 +136,7 @@ int strict_atoi(const char* str, int* value, int min, int max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoj(const char* str, intmax_t* value, intmax_t min, intmax_t max); +int strict_atoj(const char *str, intmax_t *value, intmax_t min, intmax_t max); /** * A version of `atouj` that is strict about the syntax and bounds @@ -148,7 +148,7 @@ int strict_atoj(const char* str, intmax_t* value, intmax_t min, intmax_t max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atouj(const char* str, uintmax_t* value, uintmax_t min, uintmax_t max); +int strict_atouj(const char *str, uintmax_t *value, uintmax_t min, uintmax_t max); /** * A version of `atoh` that is strict about the syntax and bounds @@ -160,7 +160,7 @@ int strict_atouj(const char* str, uintmax_t* value, uintmax_t min, uintmax_t max * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoh(const char* str, short int* value, int min, int max); +int strict_atoh(const char *str, short int *value, int min, int max); /** * A version of `atouh` that is strict about the syntax and bounds @@ -172,7 +172,7 @@ int strict_atoh(const char* str, short int* value, int min, int max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atouh(const char* str, unsigned short int* value, unsigned int min, unsigned int max); +int strict_atouh(const char *str, unsigned short int *value, unsigned int min, unsigned int max); /** * A version of `atou` that is strict about the syntax and bounds @@ -184,7 +184,7 @@ int strict_atouh(const char* str, unsigned short int* value, unsigned int min, u * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atou(const char* str, unsigned int* value, unsigned int min, unsigned int max); +int strict_atou(const char *str, unsigned int *value, unsigned int min, unsigned int max); /** * A version of `atol` that is strict about the syntax and bounds @@ -196,7 +196,7 @@ int strict_atou(const char* str, unsigned int* value, unsigned int min, unsigned * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atol(const char* str, long int* value, long int min, long int max); +int strict_atol(const char *str, long int *value, long int min, long int max); /** * A version of `atoul` that is strict about the syntax and bounds @@ -208,7 +208,7 @@ int strict_atol(const char* str, long int* value, long int min, long int max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoul(const char* str, unsigned long int* value, unsigned long int min, unsigned long int max); +int strict_atoul(const char *str, unsigned long int *value, unsigned long int min, unsigned long int max); /** * A version of `atoll` that is strict about the syntax and bounds @@ -220,7 +220,7 @@ int strict_atoul(const char* str, unsigned long int* value, unsigned long int mi * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoll(const char* str, long long int* value, long long int min, long long int max); +int strict_atoll(const char *str, long long int *value, long long int min, long long int max); /** * A version of `atoull` that is strict about the syntax and bounds @@ -232,8 +232,8 @@ int strict_atoll(const char* str, long long int* value, long long int min, long * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoull(const char* str, unsigned long long int* value, - unsigned long long int min, unsigned long long int max); +int strict_atoull(const char *str, unsigned long long int *value, + unsigned long long int min, unsigned long long int max); /** * A version of `atoz` that is strict about the syntax and bounds @@ -245,7 +245,7 @@ int strict_atoull(const char* str, unsigned long long int* value, * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atoz(const char* str, size_t* value, size_t min, size_t max); +int strict_atoz(const char *str, size_t *value, size_t min, size_t max); /** * A version of `atosz` that is strict about the syntax and bounds @@ -257,7 +257,7 @@ int strict_atoz(const char* str, size_t* value, size_t min, size_t max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atosz(const char* str, ssize_t* value, ssize_t min, ssize_t max); +int strict_atosz(const char *str, ssize_t *value, ssize_t min, ssize_t max); /** * A version of `ato8` that is strict about the syntax and bounds @@ -269,7 +269,7 @@ int strict_atosz(const char* str, ssize_t* value, ssize_t min, ssize_t max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_ato8(const char* str, int8_t* value, int min, int max); +int strict_ato8(const char *str, int8_t *value, int min, int max); /** * A version of `atou8` that is strict about the syntax and bounds @@ -281,7 +281,7 @@ int strict_ato8(const char* str, int8_t* value, int min, int max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atou8(const char* str, uint8_t* value, int min, int max); +int strict_atou8(const char *str, uint8_t *value, int min, int max); /** * A version of `ato16` that is strict about the syntax and bounds @@ -293,7 +293,7 @@ int strict_atou8(const char* str, uint8_t* value, int min, int max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_ato16(const char* str, int16_t* value, int min, int max); +int strict_ato16(const char *str, int16_t *value, int min, int max); /** * A version of `atou16` that is strict about the syntax and bounds @@ -305,7 +305,7 @@ int strict_ato16(const char* str, int16_t* value, int min, int max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atou16(const char* str, uint16_t* value, unsigned int min, unsigned int max); +int strict_atou16(const char *str, uint16_t *value, unsigned int min, unsigned int max); /** * A version of `ato32` that is strict about the syntax and bounds @@ -317,7 +317,7 @@ int strict_atou16(const char* str, uint16_t* value, unsigned int min, unsigned i * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_ato32(const char* str, int32_t* value, int32_t min, int32_t max); +int strict_ato32(const char *str, int32_t *value, int32_t min, int32_t max); /** * A version of `atou32` that is strict about the syntax and bounds @@ -329,7 +329,7 @@ int strict_ato32(const char* str, int32_t* value, int32_t min, int32_t max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atou32(const char* str, uint32_t* value, uint32_t min, uint32_t max); +int strict_atou32(const char *str, uint32_t *value, uint32_t min, uint32_t max); /** * A version of `ato64` that is strict about the syntax and bounds @@ -341,7 +341,7 @@ int strict_atou32(const char* str, uint32_t* value, uint32_t min, uint32_t max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_ato64(const char* str, int64_t* value, int64_t min, int64_t max); +int strict_ato64(const char *str, int64_t *value, int64_t min, int64_t max); /** * A version of `atou64` that is strict about the syntax and bounds @@ -353,7 +353,7 @@ int strict_ato64(const char* str, int64_t* value, int64_t min, int64_t max); * @return Zero on success, -1 on syntax error */ __attribute__((nonnull)) -int strict_atou64(const char* str, uint64_t* value, uint64_t min, uint64_t max); +int strict_atou64(const char *str, uint64_t *value, uint64_t min, uint64_t max); /** * Send a buffer into a file and ignore interruptions @@ -363,7 +363,7 @@ int strict_atou64(const char* str, uint64_t* value, uint64_t min, uint64_t max); * @param length The length of the buffer * @return Zero on success, -1 on error */ -int full_write(int fd, const char* buffer, size_t length); +int full_write(int fd, const char *buffer, size_t length); /** * Read a file completely and ignore interruptions @@ -372,7 +372,7 @@ int full_write(int fd, const char* buffer, size_t length); * @param length Output parameter for the length of the file, may be `NULL` * @return The content of the file, you will need to free it. `NULL` on error */ -char* full_read(int fd, size_t* length); +char *full_read(int fd, size_t *length); /** * Send a full message even if interrupted @@ -382,7 +382,7 @@ char* full_read(int fd, size_t* length); * @param length The length of the message * @return Zero on success, -1 on error */ -int full_send(int socket, const char* message, size_t length); +int full_send(int socket, const char *message, size_t length); /** * Check whether a string begins with a specific string, @@ -395,7 +395,7 @@ int full_send(int socket, const char* message, size_t length); * @return Whether the `haystack` begins with `needle` */ __attribute__((pure, nonnull)) -int startswith_n(const char* haystack, const char* needle, size_t haystack_n, size_t needle_n); +int startswith_n(const char *haystack, const char *needle, size_t haystack_n, size_t needle_n); /** * Wrapper around `waitpid` that never returns on an interruption unless @@ -406,7 +406,7 @@ int startswith_n(const char* haystack, const char* needle, size_t haystack_n, si * @param options See description of `options` in the documentation for `waitpid` * @return See the documentation for `waitpid` */ -pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options); +pid_t uninterruptable_waitpid(pid_t pid, int *restrict status, int options); /** * Check whether a NUL-terminated string is encoded in UTF-8 @@ -416,7 +416,7 @@ pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options); * @return Zero if good, -1 on encoding error */ __attribute__((pure, nonnull)) -int verify_utf8(const char* string, int allow_modified_nul); +int verify_utf8(const char *string, int allow_modified_nul); /** * Construct an error message to be sent to a client @@ -444,10 +444,10 @@ int verify_utf8(const char* string, int allow_modified_nul); * @return The length of the message, zero on error */ __attribute__((nonnull(1, 2, 3, 7, 8))) -size_t construct_error_message(const char* restrict recv_client_id, const char* restrict recv_message_id, - const char* restrict recv_command, int custom, int errnum, - const char* restrict message, char** restrict send_buffer, - size_t* restrict send_buffer_size, uint32_t message_id); +size_t construct_error_message(const char *restrict recv_client_id, const char *restrict recv_message_id, + const char *restrict recv_command, int custom, int errnum, + const char *restrict message, char **restrict send_buffer, + size_t *restrict send_buffer_size, uint32_t message_id); /** * Send an error message @@ -476,11 +476,10 @@ size_t construct_error_message(const char* restrict recv_client_id, const char* * @return Zero on success, -1 on error */ __attribute__((nonnull(1, 2, 3, 7, 8))) -int send_error(const char* restrict recv_client_id, const char* restrict recv_message_id, - const char* restrict recv_command, int custom, int errnum, const char* restrict message, - char** restrict send_buffer, size_t* restrict send_buffer_size, uint32_t message_id, - int socket_fd); +int send_error(const char *restrict recv_client_id, const char *restrict recv_message_id, + const char *restrict recv_command, int custom, int errnum, const char *restrict message, + char **restrict send_buffer, size_t *restrict send_buffer_size, uint32_t message_id, + int socket_fd); #endif - diff --git a/src/mds-base.c b/src/mds-base.c index 8581282..f983b7f 100644 --- a/src/mds-base.c +++ b/src/mds-base.c @@ -44,7 +44,7 @@ int argc = 0; /** * Command line arguments */ -char** argv = NULL; +char **argv = NULL; /** * Whether the server has been respawn @@ -75,7 +75,7 @@ int on_init_fork = 0; * Command the run (`NULL` for none) when * the server has been properly initialised */ -char* on_init_sh = NULL; +char *on_init_sh = NULL; /** * The thread that runs the master loop @@ -112,51 +112,48 @@ int socket_fd = -1; * * @return Non-zero on error */ -int __attribute__((weak)) parse_cmdline(void) +int __attribute__((weak)) +parse_cmdline(void) { - int i; - + int i, v; + char *arg; + #if (LIBEXEC_ARGC_EXTRA_LIMIT < 2) # error LIBEXEC_ARGC_EXTRA_LIMIT is too small, need at least 2. #endif - - - /* 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; + + /* Parse command line arguments. */ + for (i = 1; i < argc; i++) { + arg = argv[i]; + 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 (strequals(arg, "--re-exec")) { /* Re-exec state-marshal. */ + is_reexec = 1; + } else if (startswith(arg, "--alarm=")) { /* Schedule an alarm signal for forced abort. */ + alarm(min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ + } else if (strequals(arg, "--on-init-fork")) { /* Fork process when initialised. */ + on_init_fork = 1; + } else if (startswith(arg, "--on-init-sh=")) { /* Run a command when initialised. */ + on_init_sh = arg + strlen("--on-init-sh="); + } else if (strequals(arg, "--immortal")) { /* I return to serve. */ + is_immortal = 1; + } + } + if (is_reexec) { + is_respawn = 1; + eprint("re-exec performed."); } - else if (strequals(arg, "--re-exec")) /* Re-exec state-marshal. */ - is_reexec = 1; - else if (startswith(arg, "--alarm=")) /* Schedule an alarm signal for forced abort. */ - alarm(min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ - else if (strequals(arg, "--on-init-fork")) /* Fork process when initialised. */ - on_init_fork = 1; - else if (startswith(arg, "--on-init-sh=")) /* Run a command when initialised. */ - on_init_sh = arg + strlen("--on-init-sh="); - else if (strequals(arg, "--immortal")) /* I return to serve. */ - is_immortal = 1; - } - if (is_reexec) - { - is_respawn = 1; - eprint("re-exec performed."); - } - - /* Check that mandatory arguments have been specified. */ - if (server_characteristics.require_respawn_info) - exit_if (is_respawn < 0, - eprintf("missing state argument, require either %s or %s.", - "--initial-spawn", "--respawn");); - return 0; + + /* Check that mandatory arguments have been specified. */ + if (server_characteristics.require_respawn_info) + exit_if (is_respawn < 0, + eprintf("missing state argument, require either %s or %s.", + "--initial-spawn", "--respawn");); + return 0; } @@ -165,30 +162,31 @@ int __attribute__((weak)) parse_cmdline(void) * * @return Non-zero on error */ -int __attribute__((weak)) connect_to_display(void) +int __attribute__((weak)) +connect_to_display(void) { - char* display; - char pathname[PATH_MAX]; - struct sockaddr_un address; - - display = getenv("MDS_DISPLAY"); - exit_if ((display == NULL) || (strchr(display, ':') == NULL), - eprint("MDS_DISPLAY has not set.");); - exit_if (display[0] != ':', - eprint("remote mds sessions are not supported.");); - xsnprintf(pathname, "%s/%s.socket", MDS_RUNTIME_ROOT_DIRECTORY, display + 1); - address.sun_family = AF_UNIX; - strcpy(address.sun_path, pathname); - fail_if ((socket_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0); - fail_if (connect(socket_fd, (struct sockaddr*)(&address), sizeof(address)) < 0); - - return 0; - - fail: - xperror(*argv); - if (socket_fd >= 0) - xclose(socket_fd); - return 1; + char *display; + char pathname[PATH_MAX]; + struct sockaddr_un address; + + display = getenv("MDS_DISPLAY"); + exit_if (!display || !strchr(display, ':'), + eprint("MDS_DISPLAY has not set.");); + exit_if (display[0] != ':', + eprint("remote mds sessions are not supported.");); + xsnprintf(pathname, "%s/%s.socket", MDS_RUNTIME_ROOT_DIRECTORY, display + 1); + address.sun_family = AF_UNIX; + strcpy(address.sun_path, pathname); + fail_if ((socket_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0); + fail_if (connect(socket_fd, (struct sockaddr*)(&address), sizeof(address)) < 0); + + return 0; + +fail: + xperror(*argv); + if (socket_fd >= 0) + xclose(socket_fd); + return 1; } @@ -201,45 +199,44 @@ int __attribute__((weak)) connect_to_display(void) */ static int server_initialised_fork_for_safety(void) { - unsigned pending_alarm = alarm(0); /* Disable the alarm. */ - pid_t pid = fork(); - int status; - - fail_if (pid == (pid_t)-1); - if (pid == 0) - /* Reinstate the alarm for the child. */ - alarm(pending_alarm); - else - { - /* SIGDANGER cannot hurt the parent process. */ - if (xsigaction(SIGDANGER, SIG_IGN) < 0) - { - xperror(*argv); - eprint("WARNING! parent process failed to sig up ignoring of SIGDANGER."); - } - - /* Wait for the child process to die. */ - if (uninterruptable_waitpid(pid, &status, 0) == (pid_t)-1) - { - xperror(*argv); - kill(pid, SIGABRT); - sleep(5); + unsigned pending_alarm = alarm(0); /* Disable the alarm. */ + pid_t pid = fork(); + int status; + + fail_if (pid == (pid_t)-1); + if (!pid) { + /* Reinstate the alarm for the child. */ + alarm(pending_alarm); + } else { + /* SIGDANGER cannot hurt the parent process. */ + if (xsigaction(SIGDANGER, SIG_IGN) < 0) { + xperror(*argv); + eprint("WARNING! parent process failed to sig up ignoring of SIGDANGER."); + } + + /* Wait for the child process to die. */ + if (uninterruptable_waitpid(pid, &status, 0) == (pid_t)-1) { + xperror(*argv); + kill(pid, SIGABRT); + sleep(5); + } + + /* Clean up after us. */ + fork_cleanup(status); + + /* Die like the child. */ + if (WIFEXITED(status)) + exit(WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + raise(WTERMSIG(status)); + exit(1); } - - /* Clean up after us. */ - fork_cleanup(status); - - /* Die like the child. */ - if (WIFEXITED(status)) exit(WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) raise(WTERMSIG(status)); - exit(1); - } - - return 0; - fail: - xperror(*argv); - eprint("while forking for safety."); - return -1; + + return 0; +fail: + xperror(*argv); + eprint("while forking for safety."); + return -1; } @@ -250,49 +247,48 @@ static int server_initialised_fork_for_safety(void) * * @return Zero on success, -1 on error */ -int __attribute__((weak)) server_initialised(void) +int __attribute__((weak)) +server_initialised(void) { - pid_t r; - int saved_errno; - - if (on_init_fork && (r = fork())) - { - fail_if (r == (pid_t)-1); - exit(0); - } - - if (on_init_sh != NULL) - if (system(on_init_sh) == -1) - { - saved_errno = errno; - if (system(NULL)) - { - errno = 0; - eprint("no shell is available."); - return -1; - } - else - { - errno = saved_errno; - xperror(*argv); - eprint("while running shell at completed initialisation."); - return -1; - } - } - - if (server_characteristics.fork_for_safety) - return server_initialised_fork_for_safety(); - - return 0; - fail: - xperror(*argv); - eprint("while forking at completed initialisation."); - return -1; + pid_t r; + int saved_errno; + + if (on_init_fork && (r = fork())) { + fail_if (r == (pid_t)-1); + exit(0); + } + + if (on_init_sh) { + if (system(on_init_sh) == -1) { + saved_errno = errno; + if (system(NULL)) { + errno = 0; + eprint("no shell is available."); + return -1; + } else { + errno = saved_errno; + xperror(*argv); + eprint("while running shell at completed initialisation."); + return -1; + } + } + } + + if (server_characteristics.fork_for_safety) + return server_initialised_fork_for_safety(); + + return 0; +fail: + xperror(*argv); + eprint("while forking at completed initialisation."); + return -1; } +#if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wsuggest-attribute=const" +#endif /** * This function should be implemented by the actual server implementation * if the server is multi-threaded @@ -301,11 +297,14 @@ int __attribute__((weak)) server_initialised(void) * * @param signo The signal */ -void __attribute__((weak)) signal_all(int signo) +void __attribute__((weak)) +signal_all(int signo) { - (void) signo; + (void) signo; } +#if defined(__GNUC__) # pragma GCC diagnostic pop +#endif /** @@ -314,12 +313,13 @@ void __attribute__((weak)) signal_all(int signo) * * @param signo The signal that has been received */ -static void __attribute__((const)) received_noop(int signo) +static void __attribute__((const)) +received_noop(int signo) { - (void) signo; - /* This function is used rather than `SIG_IGN` because we - * want blocking functions to return with `errno` set to - * `EINTR` rather than continue blocking. */ + (void) signo; + /* This function is used rather than `SIG_IGN` because we + * want blocking functions to return with `errno` set to + * `EINTR` rather than continue blocking. */ } @@ -332,17 +332,17 @@ static void __attribute__((const)) received_noop(int signo) * * @param signo The signal that has been received */ -void __attribute__((weak)) received_reexec(int signo) +void __attribute__((weak)) +received_reexec(int signo) { - SIGHANDLER_START; - (void) signo; - if (reexecing == 0) - { - reexecing = terminating = 1; - eprint("re-exec signal received."); - signal_all(signo); - } - SIGHANDLER_END; + SIGHANDLER_START; + if (!reexecing) { + reexecing = terminating = 1; + eprint("re-exec signal received."); + signal_all(signo); + } + SIGHANDLER_END; + (void) signo; } @@ -354,17 +354,17 @@ void __attribute__((weak)) received_reexec(int signo) * * @param signo The signal that has been received */ -void __attribute__((weak)) received_terminate(int signo) +void __attribute__((weak)) +received_terminate(int signo) { - SIGHANDLER_START; - (void) signo; - if (terminating == 0) - { - terminating = 1; - eprint("terminate signal received."); - signal_all(signo); - } - SIGHANDLER_END; + SIGHANDLER_START; + if (!terminating) { + terminating = 1; + eprint("terminate signal received."); + signal_all(signo); + } + SIGHANDLER_END; + (void) signo; } @@ -377,16 +377,16 @@ void __attribute__((weak)) received_terminate(int signo) * * @param signo The signal that has been received */ -void __attribute__((weak)) received_danger(int signo) +void __attribute__((weak)) +received_danger(int signo) { - SIGHANDLER_START; - (void) signo; - if (danger == 0) - { - danger = 1; - eprint("danger signal received."); - } - SIGHANDLER_END; + SIGHANDLER_START; + if (!danger) { + danger = 1; + eprint("danger signal received."); + } + SIGHANDLER_END; + (void) signo; } @@ -397,13 +397,18 @@ void __attribute__((weak)) received_danger(int signo) * * @param signo The signal that has been received */ +#if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wsuggest-attribute=const" -void __attribute__((weak)) received_info(int signo) +#endif +void __attribute__((weak)) +received_info(int signo) { - (void) signo; + (void) signo; } +#if defined(__GNUC__) # pragma GCC diagnostic pop +#endif /** @@ -411,47 +416,48 @@ void __attribute__((weak)) received_info(int signo) * * @return Non-zero on error */ -static int base_unmarshal(void) +static int +base_unmarshal(void) { - pid_t pid = getpid(); - int reexec_fd, r; - char shm_path[NAME_MAX + 1]; - char* state_buf; - char* state_buf_; - - /* Acquire access to marshalled data. */ - xsnprintf(shm_path, SHM_PATH_PATTERN, (intmax_t)pid); - reexec_fd = shm_open(shm_path, O_RDONLY, S_IRWXU); - fail_if (reexec_fd < 0); /* Critical. */ - - /* Read the state file. */ - fail_if ((state_buf = state_buf_ = full_read(reexec_fd, NULL)) == NULL); - - /* Release resources. */ - xclose(reexec_fd); - shm_unlink(shm_path); - - - /* Unmarshal state. */ - - /* Get the marshal protocal version. Not needed, there is only the one version right now. */ - /* buf_get(state_buf_, int, 0, MDS_BASE_VARS_VERSION); */ - buf_next(state_buf_, int, 1); - - buf_get_next(state_buf_, int, socket_fd); - r = unmarshal_server(state_buf_); - - - /* Release resources. */ - free(state_buf); - - /* Recover after failure. */ - fail_if (r && reexec_failure_recover()); - - return 0; - fail: - xperror(*argv); - return 1; + pid_t pid = getpid(); + int reexec_fd, r; + char shm_path[NAME_MAX + 1]; + char *state_buf; + char *state_buf_; + + /* Acquire access to marshalled data. */ + xsnprintf(shm_path, SHM_PATH_PATTERN, (intmax_t)pid); + reexec_fd = shm_open(shm_path, O_RDONLY, S_IRWXU); + fail_if (reexec_fd < 0); /* Critical. */ + + /* Read the state file. */ + fail_if (!(state_buf = state_buf_ = full_read(reexec_fd, NULL))); + + /* Release resources. */ + xclose(reexec_fd); + shm_unlink(shm_path); + + + /* Unmarshal state. */ + + /* Get the marshal protocal version. Not needed, there is only the one version right now. */ + /* buf_get(state_buf_, int, 0, MDS_BASE_VARS_VERSION); */ + buf_next(state_buf_, int, 1); + + buf_get_next(state_buf_, int, socket_fd); + r = unmarshal_server(state_buf_); + + + /* Release resources. */ + free(state_buf); + + /* Recover after failure. */ + fail_if (r && reexec_failure_recover()); + + return 0; +fail: + xperror(*argv); + return 1; } @@ -461,40 +467,41 @@ static int base_unmarshal(void) * @param reexec_fd The file descriptor of the file into which the state shall be saved * @return Non-zero on error */ -static int base_marshal(int reexec_fd) +static int +base_marshal(int reexec_fd) { - size_t state_n; - char* state_buf; - char* state_buf_; - - /* Calculate the size of the state data when it is marshalled. */ - state_n = 2 * sizeof(int); - state_n += marshal_server_size(); - - /* Allocate a buffer for all data. */ - fail_if (xbmalloc(state_buf = state_buf_, state_n)); - - - /* Marshal the state of the server. */ - - /* Tell the new version of the program what version of the program it is marshalling. */ - buf_set_next(state_buf_, int, MDS_BASE_VARS_VERSION); - - /* Store the state. */ - buf_set_next(state_buf_, int, socket_fd); - 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); - return 0; - - fail: - xperror(*argv); - free(state_buf); - return 1; + size_t state_n; + char *state_buf; + char *state_buf_; + + /* Calculate the size of the state data when it is marshalled. */ + state_n = 2 * sizeof(int); + state_n += marshal_server_size(); + + /* Allocate a buffer for all data. */ + fail_if (xbmalloc(state_buf = state_buf_, state_n)); + + + /* Marshal the state of the server. */ + + /* Tell the new version of the program what version of the program it is marshalling. */ + buf_set_next(state_buf_, int, MDS_BASE_VARS_VERSION); + + /* Store the state. */ + buf_set_next(state_buf_, int, socket_fd); + 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); + return 0; + +fail: + xperror(*argv); + free(state_buf); + return 1; } @@ -504,30 +511,30 @@ static int base_marshal(int reexec_fd) * This function only returns on error, * in which case the error will have been printed. */ -static void perform_reexec(void) +static void +perform_reexec(void) { - pid_t pid = getpid(); - int reexec_fd; - char shm_path[NAME_MAX + 1]; - - /* 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); - fail_if (reexec_fd < 0); - fail_if (base_marshal(reexec_fd) < 0); - xclose(reexec_fd); - reexec_fd = -1; - - /* Re-exec the server. */ - reexec_server(argc, argv, is_reexec); - - fail: - xperror(*argv); - if (reexec_fd >= 0) - { - xclose(reexec_fd); - shm_unlink(shm_path); - } + pid_t pid = getpid(); + int reexec_fd; + char shm_path[NAME_MAX + 1]; + + /* 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); + fail_if (reexec_fd < 0); + fail_if (base_marshal(reexec_fd) < 0); + xclose(reexec_fd); + reexec_fd = -1; + + /* Re-exec the server. */ + reexec_server(argc, argv, is_reexec); + +fail: + xperror(*argv); + if (reexec_fd >= 0) { + xclose(reexec_fd); + shm_unlink(shm_path); + } } @@ -538,80 +545,77 @@ static void perform_reexec(void) * @param argv_ Command line arguments * @return Non-zero on error */ -int main(int argc_, char** argv_) +int +main(int argc_, char **argv_) { - argc = argc_; - argv = argv_; - - - if (server_characteristics.require_privileges == 0) - /* Drop privileges like it's hot. */ - if (drop_privileges()) - fail_if (1); - - - /* Use /proc/self/exe when re:exec-ing */ - if (prepare_reexec()) - xperror(*argv); - - - /* 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. */ - fail_if (parse_cmdline()); - - - /* Store the current thread so it can be killed from elsewhere. */ - master_thread = pthread_self(); - - /* Set up signal traps for all especially handled signals. */ - trap_signals(); - - - /* Initialise the server. */ - fail_if (preinitialise_server()); - - if (is_reexec == 0) - { - if (server_characteristics.require_display) - /* Connect to the display. */ - fail_if (connect_to_display()); - - /* Initialise the server. */ - fail_if (initialise_server()); - } - else - { - /* Unmarshal the server's saved state. */ - fail_if (base_unmarshal()); - } - - /* Initialise the server. */ - fail_if (postinitialise_server()); - - - /* Run the server. */ - fail_if (master_loop()); - - - /* Re-exec server if signal to re-exec. */ - if (reexecing) - { - perform_reexec(); - fail_if (1); - } - - xclose(socket_fd); - return 0; - - - fail: - xperror(*argv); - if (socket_fd >= 0) - xclose(socket_fd); - return 1; + argc = argc_; + argv = argv_; + + + if (!server_characteristics.require_privileges) + /* Drop privileges like it's hot. */ + if (drop_privileges()) + fail_if (1); + + + /* Use /proc/self/exe when re:exec-ing */ + if (prepare_reexec()) + xperror(*argv); + + + /* 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. */ + fail_if (parse_cmdline()); + + + /* Store the current thread so it can be killed from elsewhere. */ + master_thread = pthread_self(); + + /* Set up signal traps for all especially handled signals. */ + trap_signals(); + + + /* Initialise the server. */ + fail_if (preinitialise_server()); + + if (!is_reexec) { + if (server_characteristics.require_display) + /* Connect to the display. */ + fail_if (connect_to_display()); + + /* Initialise the server. */ + fail_if (initialise_server()); + } else { + /* Unmarshal the server's saved state. */ + fail_if (base_unmarshal()); + } + + /* Initialise the server. */ + fail_if (postinitialise_server()); + + + /* Run the server. */ + fail_if (master_loop()); + + + /* Re-exec server if signal to re-exec. */ + if (reexecing) { + perform_reexec(); + fail_if (1); + } + + xclose(socket_fd); + return 0; + + +fail: + xperror(*argv); + if (socket_fd >= 0) + xclose(socket_fd); + return 1; } @@ -625,19 +629,20 @@ int main(int argc_, char** argv_) * * @param signo The signal that has been received */ -static void commit_suicide(int signo) +static void +commit_suicide(int signo) { - (void) signo; - - eprint("SIGDANGER received, process is killing itself to free memory."); - - /* abort(), but on the process rather than the thread. */ - xsigaction(SIGABRT, SIG_DFL); - kill(getpid(), SIGABRT); - - /* Just in case. */ - xperror(*argv); - _exit(1); + eprint("SIGDANGER received, process is killing itself to free memory."); + + /* abort(), but on the process rather than the thread. */ + xsigaction(SIGABRT, SIG_DFL); + kill(getpid(), SIGABRT); + + /* Just in case. */ + xperror(*argv); + _exit(1); + + (void) signo; } @@ -646,33 +651,34 @@ static void commit_suicide(int signo) * * @return Non-zero on error */ -int trap_signals(void) +int +trap_signals(void) { - /* Make the server update without all slaves dying on SIGUPDATE. */ - fail_if (xsigaction(SIGUPDATE, received_reexec) < 0); - - /* Implement clean exit on SIGTERM. */ - fail_if (xsigaction(SIGTERM, received_terminate) < 0); - - /* Implement clean exit on SIGINT. */ - fail_if (xsigaction(SIGINT, received_terminate) < 0); - - /* Implement silent interruption on SIGRTMIN. */ - fail_if (xsigaction(SIGRTMIN, received_noop) < 0); - - /* Implement death on SIGDANGER or ignoral of SIGDANGER. */ - if (server_characteristics.danger_is_deadly && !is_immortal) - fail_if (xsigaction(SIGDANGER, commit_suicide) < 0); - else - fail_if (xsigaction(SIGDANGER, received_danger) < 0); - - /* Implement support of SIGINFO. */ - fail_if (xsigaction(SIGINFO, received_info) < 0); - - return 0; - fail: - xperror(*argv); - return 1; + /* Make the server update without all slaves dying on SIGUPDATE. */ + fail_if (xsigaction(SIGUPDATE, received_reexec) < 0); + + /* Implement clean exit on SIGTERM. */ + fail_if (xsigaction(SIGTERM, received_terminate) < 0); + + /* Implement clean exit on SIGINT. */ + fail_if (xsigaction(SIGINT, received_terminate) < 0); + + /* Implement silent interruption on SIGRTMIN. */ + fail_if (xsigaction(SIGRTMIN, received_noop) < 0); + + /* Implement death on SIGDANGER or ignoral of SIGDANGER. */ + if (server_characteristics.danger_is_deadly && !is_immortal) + fail_if (xsigaction(SIGDANGER, commit_suicide) < 0); + else + fail_if (xsigaction(SIGDANGER, received_danger) < 0); + + /* Implement support of SIGINFO. */ + fail_if (xsigaction(SIGINFO, received_info) < 0); + + return 0; +fail: + xperror(*argv); + return 1; } @@ -687,9 +693,9 @@ int trap_signals(void) * * @param status The status the child died with */ -void __attribute__((weak)) fork_cleanup(int status) +void __attribute__((weak)) +fork_cleanup(int status) { - (void) status; - fprintf(stderr, "Something is wrong, `fork_cleanup` has been called but not reimplemented."); + fprintf(stderr, "Something is wrong, `fork_cleanup` has been called but not reimplemented."); + (void) status; } - diff --git a/src/mds-base.h b/src/mds-base.h index 121efb9..df96031 100644 --- a/src/mds-base.h +++ b/src/mds-base.h @@ -32,53 +32,53 @@ */ typedef struct server_characteristics { - /** - * Setting this to zero will cause the server to drop privileges as a security precaution - */ - unsigned require_privileges : 1; - - /** - * Setting this to non-zero will cause the server to connect to the display - */ - unsigned require_display : 1; - - /** - * Setting this to non-zero will cause the server to refuse to - * start unless either --initial-spawn or --respawn is used - */ - unsigned require_respawn_info : 1; - - /** - * Setting this to non-zero will cause the server to refuse to - * start if there are too many command line arguments - */ - unsigned sanity_check_argc : 1; - - /** - * Setting this to non-zero will cause the server to place - * itself in a fork of itself when initialised. This can be - * used to let the server clean up fatal stuff after itself - * if it crashes. When the child exits, no matter how it - * exits, the parent will call `fork_cleanup` and then - * die it the same manner as the child. - */ - unsigned fork_for_safety : 1; - - /** - * Setting this to non-zero without setting a signal action - * for `SIGDANGER` will cause the server to die if `SIGDANGER` - * is received. It is safe to set both `danger_is_deadly` and - * `fork_for_safety` to non-zero, during the call of - * `server_initialised` the signal handler for `SIGDANGER` - * in the parent process will be set to `SIG_IGN` independently - * of the value of `danger_is_deadly` if `fork_for_safety` - * is set to non-zero. - * - * This setting will be treated as set to zero if - * --immortal is used. - */ - unsigned danger_is_deadly : 1; - + /** + * Setting this to zero will cause the server to drop privileges as a security precaution + */ + unsigned require_privileges : 1; + + /** + * Setting this to non-zero will cause the server to connect to the display + */ + unsigned require_display : 1; + + /** + * Setting this to non-zero will cause the server to refuse to + * start unless either --initial-spawn or --respawn is used + */ + unsigned require_respawn_info : 1; + + /** + * Setting this to non-zero will cause the server to refuse to + * start if there are too many command line arguments + */ + unsigned sanity_check_argc : 1; + + /** + * Setting this to non-zero will cause the server to place + * itself in a fork of itself when initialised. This can be + * used to let the server clean up fatal stuff after itself + * if it crashes. When the child exits, no matter how it + * exits, the parent will call `fork_cleanup` and then + * die it the same manner as the child. + */ + unsigned fork_for_safety : 1; + + /** + * Setting this to non-zero without setting a signal action + * for `SIGDANGER` will cause the server to die if `SIGDANGER` + * is received. It is safe to set both `danger_is_deadly` and + * `fork_for_safety` to non-zero, during the call of + * `server_initialised` the signal handler for `SIGDANGER` + * in the parent process will be set to `SIG_IGN` independently + * of the value of `danger_is_deadly` if `fork_for_safety` + * is set to non-zero. + * + * This setting will be treated as set to zero if + * --immortal is used. + */ + unsigned danger_is_deadly : 1; + } __attribute__((packed)) server_characteristics_t; @@ -100,7 +100,7 @@ extern int argc; /** * Command line arguments */ -extern char** argv; +extern char **argv; /** * Whether the server has been respawn @@ -298,7 +298,7 @@ extern size_t marshal_server_size(void); * @return Non-zero on error */ __attribute__((nonnull)) -extern int marshal_server(char* state_buf); +extern int marshal_server(char *state_buf); /** * This function should be implemented by the actual server implementation @@ -313,7 +313,7 @@ extern int marshal_server(char* state_buf); * @return Non-zero on error */ __attribute__((nonnull)) -extern int unmarshal_server(char* state_buf); +extern int unmarshal_server(char *state_buf); /** * This function should be implemented by the actual server implementation @@ -349,4 +349,3 @@ void fork_cleanup(int status); /* __attribute__((weak)) */ #endif - diff --git a/src/mds-clipboard.c b/src/mds-clipboard.c index 5d54f79..1872269 100644 --- a/src/mds-clipboard.c +++ b/src/mds-clipboard.c @@ -30,7 +30,7 @@ -#define MDS_CLIPBOARD_VARS_VERSION 0 +#define MDS_CLIPBOARD_VARS_VERSION 0 @@ -40,15 +40,14 @@ * * This tells the server-base how to behave */ -server_characteristics_t server_characteristics = - { - .require_privileges = 0, - .require_display = 1, - .require_respawn_info = 1, - .sanity_check_argc = 1, - .fork_for_safety = 0, - .danger_is_deadly = 1 - }; +server_characteristics_t server_characteristics = { + .require_privileges = 0, + .require_display = 1, + .require_respawn_info = 1, + .sanity_check_argc = 1, + .fork_for_safety = 0, + .danger_is_deadly = 1 +}; @@ -80,7 +79,7 @@ static size_t clipboard_used[CLIPBOARD_LEVELS] = { 0, 0, 0 }; /** * The entries in each clipstack */ -static clipitem_t* clipboard[CLIPBOARD_LEVELS]; +static clipitem_t *clipboard[CLIPBOARD_LEVELS]; @@ -91,8 +90,8 @@ static clipitem_t* clipboard[CLIPBOARD_LEVELS]; * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** @@ -101,9 +100,10 @@ static clipitem_t* clipboard[CLIPBOARD_LEVELS]; * * @return Non-zero on error */ -int __attribute__((const)) preinitialise_server(void) +int __attribute__((const)) +preinitialise_server(void) { - return 0; + return 0; } @@ -115,48 +115,47 @@ int __attribute__((const)) preinitialise_server(void) */ int initialise_server(void) { - ssize_t i = 0; - int stage = 0; - const char* const message = - "Command: intercept\n" - "Message ID: 0\n" - "Length: 33\n" - "\n" - "Command: clipboard\n" - "Client closed\n"; - - fail_if (full_send(message, strlen(message))); - - if (is_respawn) - { - const char* const crash_message = - "Command: clipboard-info\n" - "Event: crash\n" - "Message ID: 1\n" - "\n"; - - fail_if (full_send(crash_message, strlen(crash_message))); - message_id++; - } - - stage++; - fail_if (server_initialised() < 0); - stage++; - fail_if (mds_message_initialise(&received)); - - for (i = 0; i < CLIPBOARD_LEVELS; i++) - fail_if (xcalloc(clipboard[i], clipboard_size[i], clipitem_t)); - - return 0; - - fail: - xperror(*argv); - if (stage == 0) return 1; - mds_message_destroy(&received); - if (stage == 1) return 1; - while (i--) - free(clipboard[i]); - return 1; + ssize_t i = 0; + int stage = 0; + const char* const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 33\n" + "\n" + "Command: clipboard\n" + "Client closed\n"; + + fail_if (full_send(message, strlen(message))); + + if (is_respawn) { + const char* const crash_message = + "Command: clipboard-info\n" + "Event: crash\n" + "Message ID: 1\n" + "\n"; + + fail_if (full_send(crash_message, strlen(crash_message))); + message_id++; + } + + stage++; + fail_if (server_initialised() < 0); + stage++; + fail_if (mds_message_initialise(&received)); + + for (i = 0; i < CLIPBOARD_LEVELS; i++) + fail_if (xcalloc(clipboard[i], clipboard_size[i], clipitem_t)); + + return 0; + +fail: + xperror(*argv); + if (stage == 0) return 1; + mds_message_destroy(&received); + if (stage == 1) return 1; + while (i--) + free(clipboard[i]); + return 1; } @@ -166,17 +165,18 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - if (connected) - return 0; - - fail_if (reconnect_to_display()); - connected = 1; - return 0; - fail: - mds_message_destroy(&received); - return 1; + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; +fail: + mds_message_destroy(&received); + return 1; } @@ -188,25 +188,27 @@ int postinitialise_server(void) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t i, j, rc = 2 * sizeof(int) + sizeof(uint32_t) + mds_message_marshal_size(&received); - rc += 2 * CLIPBOARD_LEVELS * sizeof(size_t); - for (i = 0; i < CLIPBOARD_LEVELS; i++) - for (j = 0; j < clipboard_used[i]; j++) - { - clipitem_t clip = clipboard[i][j]; - rc += sizeof(size_t) + sizeof(time_t) + sizeof(long) + sizeof(uint64_t) + sizeof(int); - rc += clip.length * sizeof(char); - } - return rc; + size_t i, j, rc = 2 * sizeof(int) + sizeof(uint32_t) + mds_message_marshal_size(&received); + clipitem_t clip; + rc += 2 * CLIPBOARD_LEVELS * sizeof(size_t); + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + for (j = 0; j < clipboard_used[i]; j++) { + clip = clipboard[i][j]; + rc += sizeof(size_t) + sizeof(time_t) + sizeof(long) + sizeof(uint64_t) + sizeof(int); + rc += clip.length * sizeof(char); + } + } + return rc; } /** * `memset`, but the compiler does not know that */ -void* (* volatile mds_clipboard_my_explicit_memset)(void* s, int c, size_t n) = memset; +void *(*volatile mds_clipboard_my_explicit_memset)(void *s, int c, size_t n) = memset; /** @@ -215,10 +217,11 @@ void* (* volatile mds_clipboard_my_explicit_memset)(void* s, int c, size_t n) = * @param s The memory area * @param n The number of bytes to write */ -static inline void wipe_and_free(void* s, size_t n) +static inline void +wipe_and_free(void *s, size_t n) { - if (s != NULL) - free(mds_clipboard_my_explicit_memset(s, 0, n)); + if (s) + free(mds_clipboard_my_explicit_memset(s, 0, n)); } @@ -228,54 +231,54 @@ static inline void wipe_and_free(void* s, size_t n) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - size_t i, j; - - buf_set_next(state_buf, int, MDS_CLIPBOARD_VARS_VERSION); - buf_set_next(state_buf, int, connected); - buf_set_next(state_buf, uint32_t, message_id); - mds_message_marshal(&received, state_buf); - - /* Removed entires from the clipboard that may not be marshalled. */ - for (i = 0; i < CLIPBOARD_LEVELS; i++) - for (j = 0; j < clipboard_used[i]; j++) - { - clipitem_t clip = clipboard[i][j]; - - if (clip.autopurge == CLIPITEM_AUTOPURGE_NEVER) - continue; - - wipe_and_free(clip.content, clip.length * sizeof(char)); - - memmove(clipboard[i] + j, clipboard[i] + j + 1, (clipboard_used[i] - j - 1) * sizeof(clipitem_t)); - clipboard_used[i]--; - j--; - } - - /* Marshal clipboard. */ - for (i = 0; i < CLIPBOARD_LEVELS; i++) - { - buf_set_next(state_buf, size_t, clipboard_size[i]); - buf_set_next(state_buf, size_t, clipboard_used[i]); - for (j = 0; j < clipboard_used[i]; j++) - { - clipitem_t clip = clipboard[i][j]; - buf_set_next(state_buf, size_t, clip.length); - buf_set_next(state_buf, time_t, clip.dethklok.tv_sec); - buf_set_next(state_buf, long, clip.dethklok.tv_nsec); - buf_set_next(state_buf, uint64_t, clip.client); - buf_set_next(state_buf, int, clip.autopurge); - memcpy(state_buf, clip.content, clip.length * sizeof(char)); - state_buf += clip.length; - - free(clip.content); + size_t i, j; + clipitem_t clip; + + buf_set_next(state_buf, int, MDS_CLIPBOARD_VARS_VERSION); + buf_set_next(state_buf, int, connected); + buf_set_next(state_buf, uint32_t, message_id); + mds_message_marshal(&received, state_buf); + + /* Removed entires from the clipboard that may not be marshalled. */ + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + for (j = 0; j < clipboard_used[i]; j++) { + clip = clipboard[i][j]; + + if (clip.autopurge == CLIPITEM_AUTOPURGE_NEVER) + continue; + + wipe_and_free(clip.content, clip.length * sizeof(char)); + + memmove(clipboard[i] + j, clipboard[i] + j + 1, (clipboard_used[i] - j - 1) * sizeof(clipitem_t)); + clipboard_used[i]--; + j--; + } } - free(clipboard[i]); - } - - mds_message_destroy(&received); - return 0; + + /* Marshal clipboard. */ + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + buf_set_next(state_buf, size_t, clipboard_size[i]); + buf_set_next(state_buf, size_t, clipboard_used[i]); + for (j = 0; j < clipboard_used[i]; j++) { + clip = clipboard[i][j]; + buf_set_next(state_buf, size_t, clip.length); + buf_set_next(state_buf, time_t, clip.dethklok.tv_sec); + buf_set_next(state_buf, long, clip.dethklok.tv_nsec); + buf_set_next(state_buf, uint64_t, clip.client); + buf_set_next(state_buf, int, clip.autopurge); + memcpy(state_buf, clip.content, clip.length * sizeof(char)); + state_buf += clip.length; + + free(clip.content); + } + free(clipboard[i]); + } + + mds_message_destroy(&received); + return 0; } @@ -289,51 +292,51 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - size_t i, j; - - for (i = 0; i < CLIPBOARD_LEVELS; i++) - clipboard[i] = NULL; - - /* buf_get_next(state_buf, int, MDS_CLIPBOARD_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)); - - for (i = 0; i < CLIPBOARD_LEVELS; i++) - { - buf_get_next(state_buf, size_t, clipboard_size[i]); - buf_get_next(state_buf, size_t, clipboard_used[i]); - fail_if (xcalloc(clipboard[i], clipboard_size[i], clipitem_t)); - - for (j = 0; j < clipboard_used[i]; j++) - { - clipitem_t* clip = clipboard[i] + j; - buf_get_next(state_buf, size_t, clip->length); - buf_get_next(state_buf, time_t, clip->dethklok.tv_sec); - buf_get_next(state_buf, long, clip->dethklok.tv_nsec); - buf_get_next(state_buf, uint64_t, clip->client); - buf_get_next(state_buf, int, clip->autopurge); - fail_if (xmemdup(clip->content, state_buf, clip->length, char)); - state_buf += clip->length; + size_t i, j; + clipitem_t *clip; + + for (i = 0; i < CLIPBOARD_LEVELS; i++) + clipboard[i] = NULL; + + /* buf_get_next(state_buf, int, MDS_CLIPBOARD_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)); + + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + buf_get_next(state_buf, size_t, clipboard_size[i]); + buf_get_next(state_buf, size_t, clipboard_used[i]); + fail_if (xcalloc(clipboard[i], clipboard_size[i], clipitem_t)); + + for (j = 0; j < clipboard_used[i]; j++) { + clip = clipboard[i] + j; + buf_get_next(state_buf, size_t, clip->length); + buf_get_next(state_buf, time_t, clip->dethklok.tv_sec); + buf_get_next(state_buf, long, clip->dethklok.tv_nsec); + buf_get_next(state_buf, uint64_t, clip->client); + buf_get_next(state_buf, int, clip->autopurge); + fail_if (xmemdup(clip->content, state_buf, clip->length, char)); + state_buf += clip->length; + } } - } - - return 0; - fail: - xperror(*argv); - mds_message_destroy(&received); - for (i = 0; i < CLIPBOARD_LEVELS; i++) - if (clipboard[i] != NULL) - { - for (j = 0; j < clipboard_used[i]; j++) - free(clipboard[i][j].content); - free(clipboard[i]); - } - abort(); - return -1; + + return 0; +fail: + xperror(*argv); + mds_message_destroy(&received); + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + if (clipboard[i] != NULL) { + for (j = 0; j < clipboard_used[i]; j++) + free(clipboard[i][j].content); + free(clipboard[i]); + } + } + abort(); + return -1; } @@ -343,9 +346,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } @@ -354,57 +358,55 @@ int __attribute__((const)) reexec_failure_recover(void) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - int rc = 1, r; - size_t i, j; - - while (!reexecing && !terminating) - { - if (danger) - { - danger = 0; - clipboard_danger(); - } - - 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; + int rc = 1, r; + size_t i, j; + + while (!reexecing && !terminating) { + if (danger) { + danger = 0; + clipboard_danger(); + } + + 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; } - 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; + + rc = 0; + goto done; fail: - xperror(*argv); + xperror(*argv); done: - if (!rc && reexecing) - return 0; - mds_message_destroy(&received); - for (i = 0; i < CLIPBOARD_LEVELS; i++) - if (clipboard[i] != NULL) - { - for (j = 0; j < clipboard_used[i]; j++) - wipe_and_free(clipboard[i][j].content, clipboard[i][j].length); - free(clipboard[i]); - } - return rc; + if (!rc && reexecing) + return 0; + mds_message_destroy(&received); + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + if (clipboard[i] != NULL) { + for (j = 0; j < clipboard_used[i]; j++) + wipe_and_free(clipboard[i][j].content, clipboard[i][j].length); + free(clipboard[i]); + } + } + return rc; } @@ -413,90 +415,85 @@ int master_loop(void) * * @return Zero on success, -1 on error */ -int handle_message(void) +int +handle_message(void) { - /* Fetch message headers. */ - - const char* recv_client_id = "0:0"; - const char* recv_message_id = NULL; - const char* recv_length = NULL; - const char* recv_level = NULL; - const char* recv_action = NULL; - const char* recv_size = NULL; - const char* recv_index = "0"; - const char* recv_time_to_live = "forever"; - const char* recv_client_closed = NULL; - size_t i; - int level; - -#define __get_header(storage, header) \ - (startswith(received.headers[i], header)) \ - storage = received.headers[i] + strlen(header) - - for (i = 0; i < received.header_count; i++) - { - if __get_header(recv_client_id, "Client ID: "); - else if __get_header(recv_message_id, "Message ID: "); - else if __get_header(recv_length, "Length: "); - else if __get_header(recv_action, "Action: "); - else if __get_header(recv_level, "Level: "); - else if __get_header(recv_size, "Size: "); - else if __get_header(recv_index, "Index: "); - else if __get_header(recv_time_to_live, "Time to live: "); - else if __get_header(recv_client_closed, "Client closed: "); - } - + /* Fetch message headers. */ + + const char *recv_client_id = "0:0"; + const char *recv_message_id = NULL; + const char *recv_length = NULL; + const char *recv_level = NULL; + const char *recv_action = NULL; + const char *recv_size = NULL; + const char *recv_index = "0"; + const char *recv_time_to_live = "forever"; + const char *recv_client_closed = NULL; + size_t i; + int level; + +#define __get_header(storage, header)\ + (startswith(received.headers[i], header))\ + storage = received.headers[i] + strlen(header) + + for (i = 0; i < received.header_count; i++) { + if __get_header(recv_client_id, "Client ID: "); + else if __get_header(recv_message_id, "Message ID: "); + else if __get_header(recv_length, "Length: "); + else if __get_header(recv_action, "Action: "); + else if __get_header(recv_level, "Level: "); + else if __get_header(recv_size, "Size: "); + else if __get_header(recv_index, "Index: "); + else if __get_header(recv_time_to_live, "Time to live: "); + else if __get_header(recv_client_closed, "Client closed: "); + } + #undef __get_header - - - /* Validate headers and take appropriate action. */ - - if (recv_message_id == NULL) - return eprint("received message without ID, ignoring, master server is misbehaving."), 0; - - if (recv_client_closed) - { - if (strequals(recv_client_closed, "0:0")) + + /* Validate headers and take appropriate action. */ + + if (!recv_message_id) + return eprint("received message without ID, ignoring, master server is misbehaving."), 0; + + if (recv_client_closed) { + if (strequals(recv_client_closed, "0:0")) + return 0; + return clipboard_death(recv_client_closed); + } + + if (!recv_action) + return eprint("received message without any action, ignoring."), 0; + if (!recv_level) + return eprint("received message without specified clipboard level, ignoring."), 0; + level = atoi(recv_level); + if ((level < 0) || (CLIPBOARD_LEVELS <= level)) + return eprint("received message without invalid clipboard level, ignoring."), 0; + if (strequals(recv_client_id, "0:0")) + if (strequals(recv_action, "read") || strequals(recv_action, "get-size")) + return eprint("received information request from an anonymous client, ignoring."), 0; + + if (strequals(recv_action, "add")) { + if (recv_length == NULL) + return eprint("received request for adding a clipboard entry " + "but did not receive any content, ignoring."), 0; + if ((strequals(recv_client_id, "0:0")) && startswith(recv_time_to_live, "until-death")) + return eprint("received request new clipboard entry with autopurge upon " + "client close from an anonymous client, ignoring."), 0; + return clipboard_add(level, recv_time_to_live, recv_client_id); + } else if (strequals(recv_action, "read")) { + return clipboard_read(level, atoz(recv_index), recv_client_id, recv_message_id); + } else if (strequals(recv_action, "clear")) { + return clipboard_clear(level); + } else if (strequals(recv_action, "set-size")) { + if (recv_size == NULL) + return eprint("received request for clipboard resizing without a new size, ignoring."), 0; + return clipboard_set_size(level, atoz(recv_size)); + } else if (strequals(recv_action, "get-size")) { + return clipboard_get_size(level, recv_client_id, recv_message_id); + } + + eprint("received message with invalid action, ignoring."); return 0; - return clipboard_death(recv_client_closed); - } - - if (recv_action == NULL) - return eprint("received message without any action, ignoring."), 0; - if (recv_level == NULL) - return eprint("received message without specified clipboard level, ignoring."), 0; - level = atoi(recv_level); - if ((level < 0) || (CLIPBOARD_LEVELS <= level)) - return eprint("received message without invalid clipboard level, ignoring."), 0; - if (strequals(recv_client_id, "0:0")) - if (strequals(recv_action, "read") || strequals(recv_action, "get-size")) - return eprint("received information request from an anonymous client, ignoring."), 0; - - if (strequals(recv_action, "add")) - { - if (recv_length == NULL) - return eprint("received request for adding a clipboard entry " - "but did not receive any content, ignoring."), 0; - if ((strequals(recv_client_id, "0:0")) && startswith(recv_time_to_live, "until-death")) - return eprint("received request new clipboard entry with autopurge upon" - " client close from an anonymous client, ignoring."), 0; - return clipboard_add(level, recv_time_to_live, recv_client_id); - } - else if (strequals(recv_action, "read")) - return clipboard_read(level, atoz(recv_index), recv_client_id, recv_message_id); - else if (strequals(recv_action, "clear")) - return clipboard_clear(level); - else if (strequals(recv_action, "set-size")) - { - if (recv_size == NULL) - return eprint("received request for clipboard resizing without a new size, ignoring."), 0; - return clipboard_set_size(level, atoz(recv_size)); - } - else if (strequals(recv_action, "get-size")) - return clipboard_get_size(level, recv_client_id, recv_message_id); - - eprint("received message with invalid action, ignoring."); - return 0; } @@ -505,14 +502,14 @@ int handle_message(void) * * @param entry The clipboard entry to free */ -__attribute__((nonnull)) -static inline void free_clipboard_entry(clipitem_t* entry) +static inline void __attribute__((nonnull)) +free_clipboard_entry(clipitem_t *entry) { - if (entry->autopurge == CLIPITEM_AUTOPURGE_NEVER) - free(entry->content); - else - wipe_and_free(entry->content, entry->length); - entry->content = NULL; + if (entry->autopurge == CLIPITEM_AUTOPURGE_NEVER) + free(entry->content); + else + wipe_and_free(entry->content, entry->length); + entry->content = NULL; } @@ -523,36 +520,37 @@ static inline void free_clipboard_entry(clipitem_t* entry) * @param index The index in the clipstack of the removed entry * @return Zero on success, -1 on error, `errno` will be set accordingly */ -static int clipboard_notify_pop(int level, size_t index) +static int +clipboard_notify_pop(int level, size_t index) { - size_t size = clipboard_size[level]; - size_t used = clipboard_used[level]; - char message[10 + 3 * (sizeof(int) + 3 * sizeof(size_t)) + - sizeof("Command: clipboard-info\n" - "Event: crash\n" - "Message ID: \n" - "Level: \n" - "Popped: \n" - "Size: \n" - "Used: \n" - "\n") / sizeof(char)]; - - sprintf(message, - "Command: clipboard-info\n" - "Event: crash\n" - "Message ID: %" PRIu32 "\n" - "Level: %i\n" - "Popped: %zu\n" - "Size: %zu\n" - "Used: %zu\n" - "\n", - message_id, level, index, size, used); - - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - fail_if (full_send(message, strlen(message)) ? -1 : 0); - return 0; - fail: - return -1; + size_t size = clipboard_size[level]; + size_t used = clipboard_used[level]; + char message[10 + 3 * (sizeof(int) + 3 * sizeof(size_t)) + + sizeof("Command: clipboard-info\n" + "Event: crash\n" + "Message ID: \n" + "Level: \n" + "Popped: \n" + "Size: \n" + "Used: \n" + "\n") / sizeof(char)]; + + sprintf(message, + "Command: clipboard-info\n" + "Event: crash\n" + "Message ID: %" PRIu32 "\n" + "Level: %i\n" + "Popped: %zu\n" + "Size: %zu\n" + "Used: %zu\n" + "\n", + message_id, level, index, size, used); + + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + fail_if (full_send(message, strlen(message)) ? -1 : 0); + return 0; +fail: + return -1; } @@ -563,44 +561,43 @@ static int clipboard_notify_pop(int level, size_t index) * @param client_id The ID of the client that has newly closed, `NULL` if none * @return Zero on success, -1 on error */ -static int clipboard_purge(int level, const char* client_id) +static int +clipboard_purge(int level, const char *client_id) { - uint64_t client = client_id ? parse_client_id(client_id) : 0; - struct timespec now; - size_t i; - - fail_if (monotone(&now)); - - for (i = 0; i < clipboard_used[level]; i++) - { - clipitem_t* clip = clipboard[level] + i; - if ((clip->autopurge & CLIPITEM_AUTOPURGE_UPON_DEATH)) - { - if (clip->client == client) - goto removed; + uint64_t client = client_id ? parse_client_id(client_id) : 0; + struct timespec now; + clipitem_t *clip; + size_t i; + + fail_if (monotone(&now)); + + for (i = 0; i < clipboard_used[level]; i++) { + clip = clipboard[level] + i; + if ((clip->autopurge & CLIPITEM_AUTOPURGE_UPON_DEATH)) { + if (clip->client == client) + goto removed; + } + if ((clip->autopurge & CLIPITEM_AUTOPURGE_UPON_CLOCK)) { + if (clip->dethklok.tv_sec > now.tv_sec) + goto removed; + if (clip->dethklok.tv_sec == now.tv_sec) + if (clip->dethklok.tv_nsec >= now.tv_nsec) + goto removed; + } + + continue; + removed: + free_clipboard_entry(clipboard[level] + i); + clipboard_used[level]--; + fail_if (clipboard_notify_pop(level, i)); + memmove(clipboard[level] + i, clipboard[level] + i + 1, (clipboard_used[level] - i) * sizeof(clipitem_t)); + i--; } - if ((clip->autopurge & CLIPITEM_AUTOPURGE_UPON_CLOCK)) - { - if (clip->dethklok.tv_sec > now.tv_sec) - goto removed; - if (clip->dethklok.tv_sec == now.tv_sec) - if (clip->dethklok.tv_nsec >= now.tv_nsec) - goto removed; - } - - continue; - removed: - free_clipboard_entry(clipboard[level] + i); - clipboard_used[level]--; - fail_if (clipboard_notify_pop(level, i)); - memmove(clipboard[level] + i, clipboard[level] + i + 1, (clipboard_used[level] - i) * sizeof(clipitem_t)); - i--; - } - - return 0; - fail: - xperror(*argv); - return -1; + + return 0; +fail: + xperror(*argv); + return -1; } @@ -609,14 +606,15 @@ static int clipboard_purge(int level, const char* client_id) * * @return Zero on success, -1 on error */ -int clipboard_danger(void) +int +clipboard_danger(void) { - int i; - for (i = 0; i < CLIPBOARD_LEVELS; i++) - fail_if (clipboard_purge(i, NULL)); - return 0; - fail: - return -1; + int i; + for (i = 0; i < CLIPBOARD_LEVELS; i++) + fail_if (clipboard_purge(i, NULL)); + return 0; +fail: + return -1; } @@ -626,14 +624,15 @@ int clipboard_danger(void) * @param recv_client_id The ID of the client * @return Zero on success, -1 on error */ -int clipboard_death(const char* recv_client_id) +int +clipboard_death(const char *recv_client_id) { - int i; - for (i = 0; i < CLIPBOARD_LEVELS; i++) - fail_if (clipboard_purge(i, recv_client_id)); - return 0; - fail: - return -1; + int i; + for (i = 0; i < CLIPBOARD_LEVELS; i++) + fail_if (clipboard_purge(i, recv_client_id)); + return 0; +fail: + return -1; } @@ -645,53 +644,50 @@ int clipboard_death(const char* recv_client_id) * @param recv_client_id The ID of the client * @return Zero on success, -1 on error */ -int clipboard_add(int level, const char* time_to_live, const char* recv_client_id) +int +clipboard_add(int level, const char *time_to_live, const char *recv_client_id) { - int autopurge = CLIPITEM_AUTOPURGE_UPON_CLOCK; - uint64_t client = parse_client_id(recv_client_id); - clipitem_t new_clip; - - fail_if (clipboard_purge(level, NULL)); - - if (strequals(time_to_live, "forever")) - autopurge = CLIPITEM_AUTOPURGE_NEVER; - else if (strequals(time_to_live, "until-death")) - autopurge = CLIPITEM_AUTOPURGE_UPON_DEATH; - else if (startswith(time_to_live, "until-death ")) - { - autopurge = CLIPITEM_AUTOPURGE_UPON_DEATH_OR_CLOCK; - time_to_live += strlen("until-death "); - } - - if ((autopurge & CLIPITEM_AUTOPURGE_UPON_CLOCK)) - { - struct timespec dethklok; - fail_if (monotone(&dethklok)); - dethklok.tv_sec += (time_t)atoll(time_to_live); - /* It should really be `atol`, but we want to be future-proof. */ - new_clip.dethklok = dethklok; - } - else - { - new_clip.dethklok.tv_sec = 0; - new_clip.dethklok.tv_nsec = 0; - } - - new_clip.client = client; - new_clip.autopurge = autopurge; - new_clip.length = received.payload_size; - - fail_if (xmemdup(new_clip.content, received.payload, new_clip.length, char)); - - if (clipboard_used[level] == clipboard_size[level]) - free_clipboard_entry(clipboard[level] + clipboard_used[level] - 1); - memmove(clipboard[level] + 1, clipboard[level], (clipboard_used[level] - 1) * sizeof(clipitem_t)); - clipboard[level][0] = new_clip; - - return 0; - fail: - xperror(*argv); - return -1; + int autopurge = CLIPITEM_AUTOPURGE_UPON_CLOCK; + uint64_t client = parse_client_id(recv_client_id); + clipitem_t new_clip; + struct timespec dethklok; + + fail_if (clipboard_purge(level, NULL)); + + if (strequals(time_to_live, "forever")) { + autopurge = CLIPITEM_AUTOPURGE_NEVER; + } else if (strequals(time_to_live, "until-death")) { + autopurge = CLIPITEM_AUTOPURGE_UPON_DEATH; + } else if (startswith(time_to_live, "until-death ")) { + autopurge = CLIPITEM_AUTOPURGE_UPON_DEATH_OR_CLOCK; + time_to_live += strlen("until-death "); + } + + if ((autopurge & CLIPITEM_AUTOPURGE_UPON_CLOCK)) { + fail_if (monotone(&dethklok)); + dethklok.tv_sec += (time_t)atoll(time_to_live); + /* It should really be `atol`, but we want to be future-proof. */ + new_clip.dethklok = dethklok; + } else { + new_clip.dethklok.tv_sec = 0; + new_clip.dethklok.tv_nsec = 0; + } + + new_clip.client = client; + new_clip.autopurge = autopurge; + new_clip.length = received.payload_size; + + fail_if (xmemdup(new_clip.content, received.payload, new_clip.length, char)); + + if (clipboard_used[level] == clipboard_size[level]) + free_clipboard_entry(clipboard[level] + clipboard_used[level] - 1); + memmove(clipboard[level] + 1, clipboard[level], (clipboard_used[level] - 1) * sizeof(clipitem_t)); + clipboard[level][0] = new_clip; + + return 0; +fail: + xperror(*argv); + return -1; } @@ -704,72 +700,72 @@ int clipboard_add(int level, const char* time_to_live, const char* recv_client_i * @param recv_message_id The message ID of the received message * @return Zero on success, -1 on error */ -int clipboard_read(int level, size_t index, const char* recv_client_id, const char* recv_message_id) +int +clipboard_read(int level, size_t index, const char *recv_client_id, const char *recv_message_id) { - char* message = NULL; - clipitem_t* clip = NULL; - size_t n; - - fail_if (clipboard_purge(level, NULL)); - - if (clipboard_used[level] == 0) - { - n = sizeof("To: \n" - "In response to: \n" - "Message ID: \n" - "Origin command: clipboard\n" - "\n") / sizeof(char); - n += strlen(recv_client_id) + strlen(recv_message_id) + 10; - - fail_if (xmalloc(message, n, char)); - - sprintf(message, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Origin command: clipboard\n" - "\n", - recv_client_id, recv_message_id, message_id); - - goto send; - } - - if (index >= clipboard_used[level]) - index = clipboard_used[level] - 1; - - clip = clipboard[level] + index; - - n = sizeof("To: \n" - "In response to: \n" - "Message ID: \n" - "Origin command: clipboard\n" - "Length: \n" - "\n") / sizeof(char); - n += strlen(recv_client_id) + strlen(recv_message_id) + 10 + 3 * sizeof(size_t); - - fail_if (xmalloc(message, n, char)); - - sprintf(message, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Origin command: clipboard\n" - "Length: %zu\n" - "\n", - recv_client_id, recv_message_id, message_id, clip->length); - - send: - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - fail_if (full_send(message, strlen(message))); - if (clip != NULL) - fail_if (full_send(clip->content, clip->length)); - - free(message); - return 0; - fail: - xperror(*argv); - free(message); - return errno = 0, -1; + char *message = NULL; + clipitem_t *clip = NULL; + size_t n; + + fail_if (clipboard_purge(level, NULL)); + + if (clipboard_used[level] == 0) { + n = sizeof("To: \n" + "In response to: \n" + "Message ID: \n" + "Origin command: clipboard\n" + "\n") / sizeof(char); + n += strlen(recv_client_id) + strlen(recv_message_id) + 10; + + fail_if (xmalloc(message, n, char)); + + sprintf(message, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Origin command: clipboard\n" + "\n", + recv_client_id, recv_message_id, message_id); + + goto send; + } + + if (index >= clipboard_used[level]) + index = clipboard_used[level] - 1; + + clip = clipboard[level] + index; + + n = sizeof("To: \n" + "In response to: \n" + "Message ID: \n" + "Origin command: clipboard\n" + "Length: \n" + "\n") / sizeof(char); + n += strlen(recv_client_id) + strlen(recv_message_id) + 10 + 3 * sizeof(size_t); + + fail_if (xmalloc(message, n, char)); + + sprintf(message, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Origin command: clipboard\n" + "Length: %zu\n" + "\n", + recv_client_id, recv_message_id, message_id, clip->length); + +send: + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + fail_if (full_send(message, strlen(message))); + if (clip) + fail_if (full_send(clip->content, clip->length)); + + free(message); + return 0; +fail: + xperror(*argv); + free(message); + return errno = 0, -1; } @@ -779,13 +775,14 @@ int clipboard_read(int level, size_t index, const char* recv_client_id, const ch * @param level The clipboard level * @return Zero on success, -1 on error */ -int clipboard_clear(int level) +int +clipboard_clear(int level) { - size_t i; - for (i = 0; i < clipboard_used[level]; i++) - free_clipboard_entry(clipboard[level] + i); - clipboard_used[level] = 0; - return 0; + size_t i; + for (i = 0; i < clipboard_used[level]; i++) + free_clipboard_entry(clipboard[level] + i); + clipboard_used[level] = 0; + return 0; } @@ -796,37 +793,36 @@ int clipboard_clear(int level) * @param size The new clipstack size * @return Zero on success, -1 on error */ -int clipboard_set_size(int level, size_t size) +int +clipboard_set_size(int level, size_t size) { - size_t i; - fail_if (clipboard_purge(level, NULL)); - - if (size < clipboard_size[level]) - { - size_t old_used = clipboard_used[level]; - if (size < old_used) - { - clipboard_used[level] = size; - for (i = size; i < old_used; i++) - free_clipboard_entry(clipboard[level] + i); + size_t i, old_used; + clipitem_t* old; + + fail_if (clipboard_purge(level, NULL)); + + if (size < clipboard_size[level]) { + old_used = clipboard_used[level]; + if (size < old_used) { + clipboard_used[level] = size; + for (i = size; i < old_used; i++) + free_clipboard_entry(clipboard[level] + i); + } } - } - - if (size != clipboard_size[level]) - { - clipitem_t* old = clipboard[level]; - if (xrealloc(clipboard[level], size, clipitem_t)) - { - clipboard[level] = old; - fail_if (1); + + if (size != clipboard_size[level]) { + old = clipboard[level]; + if (xrealloc(clipboard[level], size, clipitem_t)) { + clipboard[level] = old; + fail_if (1); + } + clipboard_size[level] = size; } - clipboard_size[level] = size; - } - - return 0; - fail: - xperror(*argv); - return -1; + + return 0; +fail: + xperror(*argv); + return -1; } @@ -838,43 +834,44 @@ int clipboard_set_size(int level, size_t size) * @param recv_message_id The message ID of the received message * @return Zero on success, -1 on error */ -int clipboard_get_size(int level, const char* recv_client_id, const char* recv_message_id) +int +clipboard_get_size(int level, const char *recv_client_id, const char *recv_message_id) { - char* message = NULL; - size_t n; - - fail_if (clipboard_purge(level, NULL)); - - n = sizeof("To: \n" - "In response to: \n" - "Message ID: \n" - "Origin command: clipboard\n" - "Size: \n" - "Used: \n" - "\n") / sizeof(char); - n += strlen(recv_client_id) + strlen(recv_message_id) + 10 + 2 * 3 * sizeof(size_t); - - fail_if (xmalloc(message, n, char)); - sprintf(message, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Origin command: clipboard\n" - "Size: %zu\n" - "Used: %zu\n" - "\n", - recv_client_id, recv_message_id, message_id, clipboard_size[level], clipboard_used[level]); - - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - - fail_if (full_send(message, strlen(message))); - - free(message); - return 0; - fail: - xperror(*argv); - free(message); - return errno = 0, -1; + char *message = NULL; + size_t n; + + fail_if (clipboard_purge(level, NULL)); + + n = sizeof("To: \n" + "In response to: \n" + "Message ID: \n" + "Origin command: clipboard\n" + "Size: \n" + "Used: \n" + "\n") / sizeof(char); + n += strlen(recv_client_id) + strlen(recv_message_id) + 10 + 2 * 3 * sizeof(size_t); + + fail_if (xmalloc(message, n, char)); + sprintf(message, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Origin command: clipboard\n" + "Size: %zu\n" + "Used: %zu\n" + "\n", + recv_client_id, recv_message_id, message_id, clipboard_size[level], clipboard_used[level]); + + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + + fail_if (full_send(message, strlen(message))); + + free(message); + return 0; +fail: + xperror(*argv); + free(message); + return errno = 0, -1; } @@ -885,47 +882,45 @@ int clipboard_get_size(int level, const char* recv_client_id, const char* recv_m * * @param signo The signal that has been received */ -void received_info(int signo) +void +received_info(int signo) { - SIGHANDLER_START; - clipitem_t clipitem; - size_t i, j, n; - struct timespec now; - (void) signo; - if (monotone(&now) < 0) - iprint("(unable to get current time)"); - else - iprintf("current time: %ji.%09li", (intmax_t)(now.tv_sec), (long)(now.tv_nsec)); - iprintf("next message ID: %" PRIu32, message_id); - iprintf("connected: %s", connected ? "yes" : "no"); - for (i = 0; i < CLIPBOARD_LEVELS; i++) - { - n = clipboard_used[i]; - iprintf("clipstack %zu: allocated: %zu", i, clipboard_size[i]); - iprintf("clipstack %zu: used: %zu", i, n); - for (j = 0; j < n; j++) - { - clipitem = clipboard[i][j]; - iprintf("clipstack %zu: item %zu:", i, j); - iprintf(" autopurge: %s", - clipitem.autopurge == CLIPITEM_AUTOPURGE_NEVER ? "as needed" : - clipitem.autopurge == CLIPITEM_AUTOPURGE_UPON_DEATH ? "upon death or as needed" : - clipitem.autopurge == CLIPITEM_AUTOPURGE_UPON_CLOCK ? "timeout or as needed" : - clipitem.autopurge == CLIPITEM_AUTOPURGE_UPON_DEATH_OR_CLOCK ? "upon death, timeout or as needed" : - "unrecognised rule, something is wrong here!"); - iprintf(" client: %" PRIu32 ":%" PRIu32, - (uint32_t)(clipitem.client >> 32), - (uint32_t)(clipitem.client)); - if (clipitem.autopurge & CLIPITEM_AUTOPURGE_UPON_CLOCK) - iprintf(" timeout: %ji.%09li", - (intmax_t)(clipitem.dethklok.tv_sec), - (long)(clipitem.dethklok.tv_nsec)); - iprintf(" butes: %zu", clipitem.length); - iprintf(" content (possibily truncated): %.*s", - (int)strnlen(clipitem.content, clipitem.length > 50 ? (size_t)50 : clipitem.length), - clipitem.content); + SIGHANDLER_START; + clipitem_t clipitem; + size_t i, j, n; + struct timespec now; + if (monotone(&now) < 0) + iprint("(unable to get current time)"); + else + iprintf("current time: %ji.%09li", (intmax_t)(now.tv_sec), (long)(now.tv_nsec)); + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + for (i = 0; i < CLIPBOARD_LEVELS; i++) { + n = clipboard_used[i]; + iprintf("clipstack %zu: allocated: %zu", i, clipboard_size[i]); + iprintf("clipstack %zu: used: %zu", i, n); + for (j = 0; j < n; j++) { + clipitem = clipboard[i][j]; + iprintf("clipstack %zu: item %zu:", i, j); + iprintf(" autopurge: %s", + clipitem.autopurge == CLIPITEM_AUTOPURGE_NEVER ? "as needed" : + clipitem.autopurge == CLIPITEM_AUTOPURGE_UPON_DEATH ? "upon death or as needed" : + clipitem.autopurge == CLIPITEM_AUTOPURGE_UPON_CLOCK ? "timeout or as needed" : + clipitem.autopurge == CLIPITEM_AUTOPURGE_UPON_DEATH_OR_CLOCK ? "upon death, timeout or as needed" : + "unrecognised rule, something is wrong here!"); + iprintf(" client: %" PRIu32 ":%" PRIu32, + (uint32_t)(clipitem.client >> 32), + (uint32_t)(clipitem.client)); + if (clipitem.autopurge & CLIPITEM_AUTOPURGE_UPON_CLOCK) + iprintf(" timeout: %ji.%09li", + (intmax_t)(clipitem.dethklok.tv_sec), + (long)(clipitem.dethklok.tv_nsec)); + iprintf(" butes: %zu", clipitem.length); + iprintf(" content (possibily truncated): %.*s", + (int)strnlen(clipitem.content, clipitem.length > 50 ? (size_t)50 : clipitem.length), + clipitem.content); + } } - } - SIGHANDLER_END; + SIGHANDLER_END; + (void) signo; } - diff --git a/src/mds-clipboard.h b/src/mds-clipboard.h index 5c13d25..e35d5cc 100644 --- a/src/mds-clipboard.h +++ b/src/mds-clipboard.h @@ -54,38 +54,38 @@ */ typedef struct clipitem { - /** - * The stored content - */ - char* content; - - /** - * The length of the stored content - */ - size_t length; - - /** - * Time of planned death if `autopurge` is `CLIPITEM_AUTOPURGE_UPON_CLOCK` - */ - struct timespec dethklok; - - /** - * The client that issued the inclusion of this entry - */ - uint64_t client; - - /** - * Rule for automatic deletion - */ - int autopurge; - + /** + * The stored content + */ + char *content; + + /** + * The length of the stored content + */ + size_t length; + + /** + * Time of planned death if `autopurge` is `CLIPITEM_AUTOPURGE_UPON_CLOCK` + */ + struct timespec dethklok; + + /** + * The client that issued the inclusion of this entry + */ + uint64_t client; + + /** + * Rule for automatic deletion + */ + int autopurge; + } clipitem_t; /** * The number of levels in the clipboard */ -#define CLIPBOARD_LEVELS 3 +#define CLIPBOARD_LEVELS 3 @@ -110,7 +110,7 @@ int clipboard_danger(void); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int clipboard_death(const char* recv_client_id); +int clipboard_death(const char *recv_client_id); /** * Add a new entry to the clipboard @@ -121,7 +121,7 @@ int clipboard_death(const char* recv_client_id); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int clipboard_add(int level, const char* time_to_live, const char* recv_client_id); +int clipboard_add(int level, const char *time_to_live, const char *recv_client_id); /** * Read an entry to the clipboard @@ -133,7 +133,7 @@ int clipboard_add(int level, const char* time_to_live, const char* recv_client_i * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int clipboard_read(int level, size_t index, const char* recv_client_id, const char* recv_message_id); +int clipboard_read(int level, size_t index, const char *recv_client_id, const char *recv_message_id); /** * Clear a clipstack @@ -161,8 +161,7 @@ int clipboard_set_size(int level, size_t size); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int clipboard_get_size(int level, const char* recv_client_id, const char* recv_message_id); +int clipboard_get_size(int level, const char *recv_client_id, const char *recv_message_id); #endif - diff --git a/src/mds-colour.c b/src/mds-colour.c index f7a5722..6823f78 100644 --- a/src/mds-colour.c +++ b/src/mds-colour.c @@ -34,7 +34,7 @@ -#define MDS_COLOUR_VARS_VERSION 0 +#define MDS_COLOUR_VARS_VERSION 0 @@ -44,15 +44,14 @@ * * 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 - }; +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 +}; @@ -74,7 +73,7 @@ static int connected = 1; /** * Buffer for sending messages */ -static char* send_buffer = NULL; +static char *send_buffer = NULL; /** * The size allocated to `send_buffer` divided by `sizeof(char)` @@ -90,13 +89,13 @@ static colour_list_t colours; * Textual list of all colours that can be sent * to clients upon query. This list only includes names. */ -static char* colour_list_buffer_without_values = NULL; +static char *colour_list_buffer_without_values = NULL; /** * Textual list of all colours that can be sent * to clients upon query. This list include value. */ -static char* colour_list_buffer_with_values = NULL; +static char *colour_list_buffer_with_values = NULL; /** * The length of the message in `colour_list_buffer_without_values` @@ -121,8 +120,8 @@ static size_t colour_list_buffer_with_values_length = 0; * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** * Send an error message, message ID will be incremented @@ -145,10 +144,10 @@ static size_t colour_list_buffer_with_values_length = 0; * be omitted * @return Zero on success, -1 on error */ -#define send_error(recv_client_id, recv_message_id, recv_command, custom, errnum, message) \ - ((send_error)(recv_client_id, recv_message_id, recv_command, custom, errnum, \ - message, &send_buffer, &send_buffer_size, message_id, socket_fd) \ - ? -1 : ((message_id = message_id == INT32_MAX ? 0 : (message_id + 1)), 0)) +#define send_error(recv_client_id, recv_message_id, recv_command, custom, errnum, message)\ + ((send_error)(recv_client_id, recv_message_id, recv_command, custom, errnum,\ + message, &send_buffer, &send_buffer_size, message_id, socket_fd)\ + ? -1 : ((message_id = message_id == INT32_MAX ? 0 : (message_id + 1)), 0)) /** @@ -157,9 +156,10 @@ static size_t colour_list_buffer_with_values_length = 0; * * @return Non-zero on error */ -int __attribute__((const)) preinitialise_server(void) +int __attribute__((const)) +preinitialise_server(void) { - return 0; + return 0; } @@ -169,29 +169,30 @@ int __attribute__((const)) preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +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 (colour_list_create(&colours, 64) < 0); stage++; - fail_if (mds_message_initialise(&received)); - - return 0; - fail: - xperror(*argv); - if (stage >= 2) colour_list_destroy(&colours); - if (stage >= 1) mds_message_destroy(&received); - return 1; + 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 (colour_list_create(&colours, 64) < 0); stage++; + fail_if (mds_message_initialise(&received)); + + return 0; +fail: + xperror(*argv); + if (stage >= 2) colour_list_destroy(&colours); + if (stage >= 1) mds_message_destroy(&received); + return 1; } @@ -201,20 +202,21 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - colours.freer = colour_list_entry_free; - colours.hasher = string_hash; - - if (connected) - return 0; - - fail_if (reconnect_to_display()); - connected = 1; - return 0; - fail: - mds_message_destroy(&received); - return 1; + colours.freer = colour_list_entry_free; + colours.hasher = string_hash; + + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; +fail: + mds_message_destroy(&received); + return 1; } @@ -226,12 +228,13 @@ int postinitialise_server(void) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t rc = 2 * sizeof(int) + sizeof(uint32_t); - rc += mds_message_marshal_size(&received); - rc += colour_list_marshal_size(&colours); - return rc; + size_t rc = 2 * sizeof(int) + sizeof(uint32_t); + rc += mds_message_marshal_size(&received); + rc += colour_list_marshal_size(&colours); + return rc; } @@ -241,20 +244,21 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +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); - state_buf += mds_message_marshal_size(&received) / sizeof(char*); - - colour_list_marshal(&colours, state_buf); - - mds_message_destroy(&received); - colour_list_destroy(&colours); - return 0; + 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); + state_buf += mds_message_marshal_size(&received) / sizeof(char*); + + colour_list_marshal(&colours, state_buf); + + mds_message_destroy(&received); + colour_list_destroy(&colours); + return 0; } @@ -268,27 +272,28 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - int stage = 0; - - /* 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)); - state_buf += mds_message_marshal_size(&received) / sizeof(char*); - stage++; - - fail_if (colour_list_unmarshal(&colours, state_buf)); - - return 0; - fail: - xperror(*argv); - if (stage >= 0) mds_message_destroy(&received); - if (stage >= 1) colour_list_destroy(&colours); - return -1; + int stage = 0; + + /* 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)); + state_buf += mds_message_marshal_size(&received) / sizeof(char*); + stage++; + + fail_if (colour_list_unmarshal(&colours, state_buf)); + + return 0; +fail: + xperror(*argv); + if (stage >= 0) mds_message_destroy(&received); + if (stage >= 1) colour_list_destroy(&colours); + return -1; } @@ -298,9 +303,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } @@ -309,60 +315,58 @@ int __attribute__((const)) reexec_failure_recover(void) * * @return Non-zero on error */ -int master_loop(void) +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; - colour_list_pack(&colours); - free(colour_list_buffer_without_values), - colour_list_buffer_without_values = NULL; - free(colour_list_buffer_with_values), - colour_list_buffer_with_values = NULL; + int rc = 1, r; + + while (!reexecing && !terminating) { + if (danger) { + danger = 0; + free(send_buffer); + send_buffer = NULL; + send_buffer_size = 0; + colour_list_pack(&colours); + free(colour_list_buffer_without_values); + colour_list_buffer_without_values = NULL; + free(colour_list_buffer_with_values); + colour_list_buffer_with_values = NULL; + } + + if (!(r = mds_message_read(&received, socket_fd))) + if (!(r = handle_message())) + 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; } - - 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; + + rc = 0; + goto done; +fail: + xperror(*argv); +done: + if (rc || !reexecing) { + mds_message_destroy(&received); + colour_list_destroy(&colours); } - 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); - colour_list_destroy(&colours); - } - free(send_buffer); - free(colour_list_buffer_without_values); - free(colour_list_buffer_with_values); - return rc; + free(send_buffer); + free(colour_list_buffer_without_values); + free(colour_list_buffer_with_values); + return rc; } @@ -371,61 +375,60 @@ int master_loop(void) * * @return Zero on success, -1 on error */ -int handle_message(void) +int +handle_message(void) { - const char* recv_command = NULL; - const char* recv_client_id = "0:0"; - const char* recv_message_id = NULL; - const char* recv_include_values = NULL; - const char* recv_name = NULL; - const char* recv_remove = NULL; - const char* recv_bytes = NULL; - const char* recv_red = NULL; - const char* recv_green = NULL; - const char* recv_blue = NULL; - size_t i; - -#define __get_header(storage, header) \ - (startswith(received.headers[i], header)) \ - storage = received.headers[i] + strlen(header) - - for (i = 0; i < received.header_count; i++) - { - if __get_header(recv_command, "Command: "); - else if __get_header(recv_client_id, "Client ID: "); - else if __get_header(recv_message_id, "Message ID: "); - else if __get_header(recv_include_values, "Include values: "); - else if __get_header(recv_name, "Name: "); - else if __get_header(recv_remove, "Remove: "); - else if __get_header(recv_bytes, "Bytes: "); - else if __get_header(recv_red, "Red: "); - else if __get_header(recv_green, "Green: "); - else if __get_header(recv_blue, "Blue: "); - } - + const char *recv_command = NULL; + const char *recv_client_id = "0:0"; + const char *recv_message_id = NULL; + const char *recv_include_values = NULL; + const char *recv_name = NULL; + const char *recv_remove = NULL; + const char *recv_bytes = NULL; + const char *recv_red = NULL; + const char *recv_green = NULL; + const char *recv_blue = NULL; + size_t i; + +#define __get_header(storage, header)\ + (startswith(received.headers[i], header))\ + storage = received.headers[i] + strlen(header) + + for (i = 0; i < received.header_count; i++) { + if __get_header(recv_command, "Command: "); + else if __get_header(recv_client_id, "Client ID: "); + else if __get_header(recv_message_id, "Message ID: "); + else if __get_header(recv_include_values, "Include values: "); + else if __get_header(recv_name, "Name: "); + else if __get_header(recv_remove, "Remove: "); + else if __get_header(recv_bytes, "Bytes: "); + else if __get_header(recv_red, "Red: "); + else if __get_header(recv_green, "Green: "); + else if __get_header(recv_blue, "Blue: "); + } + #undef __get_header - - if (recv_message_id == NULL) - { - eprint("received message without ID, ignoring, master server is misbehaving."); - return 0; - } - - if (recv_command == NULL) - return 0; /* How did that get here, no matter, just ignore it? */ - -#define t(expr) do { fail_if (expr); return 0; } while (0) - if (strequals(recv_command, "list-colours")) - t (handle_list_colours(recv_client_id, recv_message_id, recv_include_values)); - if (strequals(recv_command, "get-colour")) - t (handle_get_colour(recv_client_id, recv_message_id, recv_name)); - if (strequals(recv_command, "set-colour")) - t (handle_set_colour(recv_name, recv_remove, recv_bytes, recv_red, recv_green, recv_blue)); + + if (!recv_message_id) { + eprint("received message without ID, ignoring, master server is misbehaving."); + return 0; + } + + if (!recv_command) + return 0; /* How did that get here, no matter, just ignore it? */ + +#define t(expr) do { fail_if (expr); return 0; } while (0) + if (strequals(recv_command, "list-colours")) + t (handle_list_colours(recv_client_id, recv_message_id, recv_include_values)); + if (strequals(recv_command, "get-colour")) + t (handle_get_colour(recv_client_id, recv_message_id, recv_name)); + if (strequals(recv_command, "set-colour")) + t (handle_set_colour(recv_name, recv_remove, recv_bytes, recv_red, recv_green, recv_blue)); #undef t - - return 0; /* How did that get here, no matter, just ignore it? */ - fail: - return -1; + + return 0; /* How did that get here, no matter, just ignore it? */ +fail: + return -1; } @@ -436,31 +439,32 @@ int handle_message(void) * * @return Zero on success, -1 on error */ -static int create_colour_list_buffer_without_values(void) +static int +create_colour_list_buffer_without_values(void) { - size_t i, length = 1; - colour_list_entry_t* entry; - char* temp; - int saved_errno; - - foreach_hash_list_entry (colours, i, entry) - length += strlen(entry->key) + 1; - - fail_if (yrealloc(temp, colour_list_buffer_without_values, length, char)); - temp = colour_list_buffer_without_values; - colour_list_buffer_without_values_length = length - 1; - - *temp = '\0'; - foreach_hash_list_entry (colours, i, entry) - temp = stpcpy(temp, entry->key++), *temp++ = '\n'; - *temp = '\0'; - - return 0; - fail: - saved_errno = errno; - free(colour_list_buffer_without_values); - colour_list_buffer_without_values = NULL; - return errno = saved_errno, -1; + size_t i, length = 1; + colour_list_entry_t *entry; + char *temp; + int saved_errno; + + foreach_hash_list_entry (colours, i, entry) + length += strlen(entry->key) + 1; + + fail_if (yrealloc(temp, colour_list_buffer_without_values, length, char)); + temp = colour_list_buffer_without_values; + colour_list_buffer_without_values_length = length - 1; + + *temp = '\0'; + foreach_hash_list_entry (colours, i, entry) + temp = stpcpy(temp, entry->key++), *temp++ = '\n'; + *temp = '\0'; + + return 0; +fail: + saved_errno = errno; + free(colour_list_buffer_without_values); + colour_list_buffer_without_values = NULL; + return errno = saved_errno, -1; } @@ -471,36 +475,39 @@ static int create_colour_list_buffer_without_values(void) * * @return Zero on success, -1 on error */ -static int create_colour_list_buffer_with_values(void) +static int +create_colour_list_buffer_with_values(void) { - size_t i, length = 1; - ssize_t part_length; - colour_list_entry_t* entry; - char* temp; - int saved_errno; - - foreach_hash_list_entry (colours, i, entry) - snprintf(NULL, 0, "%i %"PRIu64" %"PRIu64" %"PRIu64" %s\n%zn", - entry->value.bytes, entry->value.red, entry->value.green, - entry->value.blue, entry->key, &part_length), - length += (size_t)part_length; - - fail_if (yrealloc(temp, colour_list_buffer_with_values, length, char)); - temp = colour_list_buffer_with_values; - colour_list_buffer_with_values_length = length - 1; - - foreach_hash_list_entry (colours, i, entry) - sprintf(temp, "%i %"PRIu64" %"PRIu64" %"PRIu64" %s\n%zn", - entry->value.bytes, entry->value.red, entry->value.green, - entry->value.blue, entry->key, &part_length), - temp += (size_t)part_length; - - return 0; - fail: - saved_errno = errno; - free(colour_list_buffer_with_values); - colour_list_buffer_with_values = NULL; - return errno = saved_errno, -1; + size_t i, length = 1; + ssize_t part_length; + colour_list_entry_t* entry; + char* temp; + int saved_errno; + + foreach_hash_list_entry (colours, i, entry) { + snprintf(NULL, 0, "%i %"PRIu64" %"PRIu64" %"PRIu64" %s\n%zn", + entry->value.bytes, entry->value.red, entry->value.green, + entry->value.blue, entry->key, &part_length); + length += (size_t)part_length; + } + + fail_if (yrealloc(temp, colour_list_buffer_with_values, length, char)); + temp = colour_list_buffer_with_values; + colour_list_buffer_with_values_length = length - 1; + + foreach_hash_list_entry (colours, i, entry) { + sprintf(temp, "%i %"PRIu64" %"PRIu64" %"PRIu64" %s\n%zn", + entry->value.bytes, entry->value.red, entry->value.green, + entry->value.blue, entry->key, &part_length); + temp += (size_t)part_length; + } + + return 0; +fail: + saved_errno = errno; + free(colour_list_buffer_with_values); + colour_list_buffer_with_values = NULL; + return errno = saved_errno, -1; } @@ -513,68 +520,65 @@ static int create_colour_list_buffer_with_values(void) * @param recv_include_values The value of the `Include values`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_list_colours(const char* recv_client_id, const char* recv_message_id, - const char* recv_include_values) +int +handle_list_colours(const char *recv_client_id, const char *recv_message_id, const char *recv_include_values) { - int include_values = 0; - char* payload; - size_t payload_length; - size_t length; - char* temp; - - if (strequals(recv_client_id, "0:0")) - return eprint("got a query from an anonymous client, ignoring."), 0; - - if (recv_include_values == NULL) include_values = 0; - else if (strequals(recv_include_values, "yes")) include_values = 1; - else if (strequals(recv_include_values, "no")) include_values = 0; - else - { - fail_if (send_error(recv_client_id, recv_message_id, "list-colours", 0, EPROTO, NULL)); - return 0; - } - - if ((colour_list_buffer_with_values == NULL) && include_values) - fail_if (create_colour_list_buffer_with_values()); - else if ((colour_list_buffer_without_values == NULL) && !include_values) - fail_if (create_colour_list_buffer_without_values()); - - payload = include_values - ? colour_list_buffer_with_values - : colour_list_buffer_without_values; - - payload_length = include_values - ? colour_list_buffer_with_values_length - : colour_list_buffer_without_values_length; - - length = sizeof("To: \n" - "In response to: \n" - "Message ID: \n" - "Origin command: list-colours\n" - "\n") / sizeof(char); - length += strlen(recv_client_id) + strlen(recv_message_id) + 10 + payload_length; - - if (length > send_buffer_size) - { - fail_if (yrealloc(temp, send_buffer, length, char)); - send_buffer_size = length; - } - - sprintf(send_buffer, - "To: %s\n" - "In response to: %s\n" - "Message ID: %"PRIu32"\n" - "Origin command: list-colours\n" - "\n%zn", - recv_client_id, recv_message_id, message_id, - (ssize_t*)&length); - memcpy(send_buffer + length, payload, payload_length * sizeof(char)); - length += payload_length; - - fail_if (full_send(send_buffer, length)); - return 0; - fail: - return -1; + int include_values = 0; + char *payload; + size_t payload_length; + size_t length; + char *temp; + + if (strequals(recv_client_id, "0:0")) + return eprint("got a query from an anonymous client, ignoring."), 0; + + if (!recv_include_values) include_values = 0; + else if (strequals(recv_include_values, "yes")) include_values = 1; + else if (strequals(recv_include_values, "no")) include_values = 0; + else { + fail_if (send_error(recv_client_id, recv_message_id, "list-colours", 0, EPROTO, NULL)); + return 0; + } + + if ((colour_list_buffer_with_values == NULL) && include_values) + fail_if (create_colour_list_buffer_with_values()); + else if ((colour_list_buffer_without_values == NULL) && !include_values) + fail_if (create_colour_list_buffer_without_values()); + + payload = include_values + ? colour_list_buffer_with_values + : colour_list_buffer_without_values; + + payload_length = include_values + ? colour_list_buffer_with_values_length + : colour_list_buffer_without_values_length; + + length = sizeof("To: \n" + "In response to: \n" + "Message ID: \n" + "Origin command: list-colours\n" + "\n") / sizeof(char); + length += strlen(recv_client_id) + strlen(recv_message_id) + 10 + payload_length; + + if (length > send_buffer_size) { + fail_if (yrealloc(temp, send_buffer, length, char)); + send_buffer_size = length; + } + + sprintf(send_buffer, + "To: %s\n" + "In response to: %s\n" + "Message ID: %"PRIu32"\n" + "Origin command: list-colours\n" + "\n%zn", + recv_client_id, recv_message_id, message_id, (ssize_t*)&length); + memcpy(send_buffer + length, payload, payload_length * sizeof(char)); + length += payload_length; + + fail_if (full_send(send_buffer, length)); + return 0; +fail: + return -1; } @@ -587,63 +591,61 @@ int handle_list_colours(const char* recv_client_id, const char* recv_message_id, * @param recv_name The value of the `Name`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_get_colour(const char* recv_client_id, const char* recv_message_id, const char* recv_name) +int +handle_get_colour(const char *recv_client_id, const char *recv_message_id, const char *recv_name) { - colour_t colour; - size_t length; - char* temp; - - if (strequals(recv_client_id, "0:0")) - return eprint("got a query from an anonymous client, ignoring."), 0; - - if (recv_name == NULL) - { - fail_if (send_error(recv_client_id, recv_message_id, "get-colour", 0, EPROTO, NULL)); - return 0; - } - - if (!colour_list_get(&colours, recv_name, &colour)) - { - fail_if (send_error(recv_client_id, recv_message_id, "get-colour", 1, -1, "not defined")); - return 0; - } - - length = sizeof("To: \n" - "In response to: \n" - "Message ID: \n" - "Origin command: get-colour\n" - "Bytes: \n" - "Red: \n" - "Green; \n" - "Blue: \n" - "\n") / sizeof(char); - length += strlen(recv_client_id) + strlen(recv_message_id) + 10 + 1 + 3 * 3 * (size_t)(colour.bytes); + colour_t colour; + size_t length; + char *temp; - if (length > send_buffer_size) - { - fail_if (yrealloc(temp, send_buffer, length, char)); - send_buffer_size = length; - } - - sprintf(send_buffer, - "To: %s\n" - "In response to: %s\n" - "Message ID: %"PRIu32"\n" - "Origin command: get-colour\n" - "Bytes: %i\n" - "Red: %"PRIu64"\n" - "Green; %"PRIu64"\n" - "Blue: %"PRIu64"\n" - "\n", - recv_client_id, recv_message_id, message_id, colour.bytes, - colour.red, colour.green, colour.blue); - - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - fail_if (full_send(send_buffer, (size_t)length)); - return 0; - fail: - return -1; + if (strequals(recv_client_id, "0:0")) + return eprint("got a query from an anonymous client, ignoring."), 0; + + if (!recv_name) { + fail_if (send_error(recv_client_id, recv_message_id, "get-colour", 0, EPROTO, NULL)); + return 0; + } + + if (!colour_list_get(&colours, recv_name, &colour)) { + fail_if (send_error(recv_client_id, recv_message_id, "get-colour", 1, -1, "not defined")); + return 0; + } + + length = sizeof("To: \n" + "In response to: \n" + "Message ID: \n" + "Origin command: get-colour\n" + "Bytes: \n" + "Red: \n" + "Green; \n" + "Blue: \n" + "\n") / sizeof(char); + length += strlen(recv_client_id) + strlen(recv_message_id) + 10 + 1 + 3 * 3 * (size_t)(colour.bytes); + + if (length > send_buffer_size) { + fail_if (yrealloc(temp, send_buffer, length, char)); + send_buffer_size = length; + } + + sprintf(send_buffer, + "To: %s\n" + "In response to: %s\n" + "Message ID: %"PRIu32"\n" + "Origin command: get-colour\n" + "Bytes: %i\n" + "Red: %"PRIu64"\n" + "Green: %"PRIu64"\n" + "Blue: %"PRIu64"\n" + "\n", + recv_client_id, recv_message_id, message_id, colour.bytes, + colour.red, colour.green, colour.blue); + + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + + fail_if (full_send(send_buffer, (size_t)length)); + return 0; +fail: + return -1; } @@ -659,52 +661,52 @@ int handle_get_colour(const char* recv_client_id, const char* recv_message_id, c * @param recv_blue The value of the `Blue`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_set_colour(const char* recv_name, const char* recv_remove, const char* recv_bytes, - const char* recv_red, const char* recv_green, const char* recv_blue) +int +handle_set_colour(const char *recv_name, const char *recv_remove, const char *recv_bytes, + const char *recv_red, const char *recv_green, const char *recv_blue) { - uint64_t limit = UINT64_MAX; - int remove_colour = 0; - colour_t colour; - int bytes; - - if (recv_remove == NULL) remove_colour = 0; - else if (strequals(recv_remove, "yes")) remove_colour = 1; - else if (strequals(recv_remove, "no")) remove_colour = 0; - else - return eprint("got an invalid value on the Remove-header, ignoring."), 0; - - if (recv_name == NULL) - return eprint("did not get all required headers, ignoring."), 0; - - if (remove_colour == 0) - { - if ((recv_bytes == NULL) || (recv_red == NULL) || (recv_green == NULL) || (recv_blue == NULL)) - return eprint("did not get all required headers, ignoring."), 0; - - if (strict_atoi(recv_bytes, &bytes, 1, 8)) - return eprint("got an invalid value on the Bytes-header, ignoring."), 0; - if ((bytes != 1) && (bytes != 2) && (bytes != 4) && (bytes != 8)) - return eprint("got an invalid value on the Bytes-header, ignoring."), 0; - - if (bytes < 8) - limit = (((uint64_t)1) << (bytes * 8)) - 1; - - colour.bytes = bytes; - if (strict_atou64(recv_red, &(colour.red), 0, limit)) - return eprint("got an invalid value on the Red-header, ignoring."), 0; - if (strict_atou64(recv_green, &(colour.green), 0, limit)) - return eprint("got an invalid value on the Green-header, ignoring."), 0; - if (strict_atou64(recv_blue, &(colour.blue), 0, limit)) - return eprint("got an invalid value on the Blue-header, ignoring."), 0; - - fail_if (set_colour(recv_name, &colour)); - } - else - fail_if (set_colour(recv_name, NULL)); - - return 0; - fail: - return -1; + uint64_t limit = UINT64_MAX; + int remove_colour = 0; + colour_t colour; + int bytes; + + if (!recv_remove) remove_colour = 0; + else if (strequals(recv_remove, "yes")) remove_colour = 1; + else if (strequals(recv_remove, "no")) remove_colour = 0; + else + return eprint("got an invalid value on the Remove-header, ignoring."), 0; + + if (!recv_name) + return eprint("did not get all required headers, ignoring."), 0; + + if (!remove_colour) { + if (!recv_bytes || !recv_red || !recv_green || !recv_blue) + return eprint("did not get all required headers, ignoring."), 0; + + if (strict_atoi(recv_bytes, &bytes, 1, 8)) + return eprint("got an invalid value on the Bytes-header, ignoring."), 0; + if ((bytes != 1) && (bytes != 2) && (bytes != 4) && (bytes != 8)) + return eprint("got an invalid value on the Bytes-header, ignoring."), 0; + + if (bytes < 8) + limit = ((uint64_t)1 << (bytes * 8)) - 1; + + colour.bytes = bytes; + if (strict_atou64(recv_red, &(colour.red), 0, limit)) + return eprint("got an invalid value on the Red-header, ignoring."), 0; + if (strict_atou64(recv_green, &(colour.green), 0, limit)) + return eprint("got an invalid value on the Green-header, ignoring."), 0; + if (strict_atou64(recv_blue, &(colour.blue), 0, limit)) + return eprint("got an invalid value on the Blue-header, ignoring."), 0; + + fail_if (set_colour(recv_name, &colour)); + } else { + fail_if (set_colour(recv_name, NULL)); + } + + return 0; +fail: + return -1; } @@ -715,13 +717,14 @@ int handle_set_colour(const char* recv_name, const char* recv_remove, const char * @param colour_b The other colour * @return 1 if the colours are equal, 0 otherwise */ -static inline int colourequals(const colour_t* colour_a, const colour_t* colour_b) +static inline int +colourequals(const colour_t *colour_a, const colour_t *colour_b) { - size_t rc = (size_t)(colour_a->bytes - colour_b->bytes); - rc |= colour_a->red - colour_b->red; - rc |= colour_a->green - colour_b->green; - rc |= colour_a->blue - colour_b->blue; - return !rc; + size_t rc = (size_t)(colour_a->bytes - colour_b->bytes); + rc |= colour_a->red - colour_b->red; + rc |= colour_a->green - colour_b->green; + rc |= colour_a->blue - colour_b->blue; + return !rc; } @@ -733,59 +736,57 @@ static inline int colourequals(const colour_t* colour_a, const colour_t* colour_ * @return Zero on success, -1 on error, removal of * non-existent colour does not constitute an error */ -int set_colour(const char* name, const colour_t* colour) +int +set_colour(const char *name, const colour_t *colour) { - char* name_ = NULL; - int found; - colour_t old_colour; - int saved_errno; - - /* Find out whether the colour is already defined, - and retrieve its value. This is required so we - can broadcast the proper event. */ - found = colour_list_get(&colours, name, &old_colour); - - if (colour == NULL) - { - /* We have been asked to remove the colour. */ - - /* If the colour does not exist, there is no - point in removing it, and an event should - not be broadcasted. */ - if (found == 0) + char *name_ = NULL; + int found; + colour_t old_colour; + int saved_errno; + + /* Find out whether the colour is already defined, + and retrieve its value. This is required so we + can broadcast the proper event. */ + found = colour_list_get(&colours, name, &old_colour); + + if (!colour) { + /* We have been asked to remove the colour. */ + + /* If the colour does not exist, there is no + point in removing it, and an event should + not be broadcasted. */ + if (!found) + return 0; + + /* Remove the colour. */ + colour_list_remove(&colours, name); + + /* Broadcast update event. */ + fail_if (broadcast_update("colour-removed", name, NULL, "yes")); + } else { + /* We have been asked to add or modify the colour. */ + + /* `colour_list_put` will store the name of the colour, + so we have to make a copy that will not disappear. */ + fail_if (xstrdup_nn(name_, name)); + + /* Add or modify the colour. */ + fail_if (colour_list_put(&colours, name_, colour)); + + /* Broadcast update event. */ + if (!found) + fail_if (broadcast_update("colour-added", name, colour, "yes")); + else if (!colourequals(colour, &old_colour)) + fail_if (broadcast_update("colour-changed", name, colour, "yes")); + } + return 0; - - /* Remove the colour. */ - colour_list_remove(&colours, name); - - /* Broadcast update event. */ - fail_if (broadcast_update("colour-removed", name, NULL, "yes")); - } - else - { - /* We have been asked to add or modify the colour. */ - - /* `colour_list_put` will store the name of the colour, - so we have to make a copy that will not disappear. */ - fail_if (xstrdup_nn(name_, name)); - - /* Add or modify the colour. */ - fail_if (colour_list_put(&colours, name_, colour)); - - /* Broadcast update event. */ - if (found == 0) - fail_if (broadcast_update("colour-added", name, colour, "yes")); - else if (!colourequals(colour, &old_colour)) - fail_if (broadcast_update("colour-changed", name, colour, "yes")); - } - - return 0; - fail: - saved_errno = errno; - /* On failure, `colour_list_put` does not - free the colour name we gave it. */ - free(name_); - return errno = saved_errno, -1; +fail: + saved_errno = errno; + /* On failure, `colour_list_put` does not + free the colour name we gave it. */ + free(name_); + return errno = saved_errno, -1; } @@ -798,61 +799,63 @@ int set_colour(const char* name, const colour_t* colour) * @param last_update The value on the `Last update`-header * @return Zero on success, -1 on error */ -int broadcast_update(const char* event, const char* name, const colour_t* colour, const char* last_update) +int +broadcast_update(const char *event, const char *name, const colour_t *colour, const char *last_update) { - ssize_t part_length; - size_t length; - char* temp; - - free(colour_list_buffer_without_values), colour_list_buffer_without_values = NULL; - free(colour_list_buffer_with_values), colour_list_buffer_with_values = NULL; - - length = sizeof("Command: \nMessage ID: \nName: \nLast update: \n\n") / sizeof(char) - 1; - length += strlen(event) + 10 + strlen(name) + strlen(last_update); - - if (colour != NULL) - { - length += sizeof("Bytes: \nRed: \nBlue: \nGreen: \n") / sizeof(char) - 1; - length += 1 + 3 * 3 * (size_t)(colour->bytes); - } - - if (++length > send_buffer_size) - { - fail_if (yrealloc(temp, send_buffer, length, char)); - send_buffer_size = length; - } - - length = 0; - - sprintf(send_buffer + length, - "Command: %s\n" - "Message ID: %"PRIu32"\n" - "Name: %s\n%zn", - event, message_id, name, &part_length), - length += (size_t)part_length; - - if (colour != NULL) - sprintf(send_buffer + length, - "Bytes: %i\n" - "Red: %"PRIu64"\n" - "Blue: %"PRIu64"\n" - "Green: %"PRIu64"\n%zn", - colour->bytes, colour->red, colour->green, - colour->blue, &part_length), - length += (size_t)part_length; - - sprintf(send_buffer + length, - "Last update: %s\n" - "\n%zn", - last_update, &part_length), - length += (size_t)part_length; - - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - fail_if (full_send(send_buffer, length)); - return 0; - fail: - return -1; + ssize_t part_length; + size_t length; + char *temp; + + free(colour_list_buffer_without_values); + colour_list_buffer_without_values = NULL; + free(colour_list_buffer_with_values); + colour_list_buffer_with_values = NULL; + + length = sizeof("Command: \nMessage ID: \nName: \nLast update: \n\n") / sizeof(char) - 1; + length += strlen(event) + 10 + strlen(name) + strlen(last_update); + + if (colour) { + length += sizeof("Bytes: \nRed: \nBlue: \nGreen: \n") / sizeof(char) - 1; + length += 1 + 3 * 3 * (size_t)(colour->bytes); + } + + if (++length > send_buffer_size) { + fail_if (yrealloc(temp, send_buffer, length, char)); + send_buffer_size = length; + } + + length = 0; + + sprintf(send_buffer + length, + "Command: %s\n" + "Message ID: %"PRIu32"\n" + "Name: %s\n%zn", + event, message_id, name, &part_length); + length += (size_t)part_length; + + if (colour) { + sprintf(send_buffer + length, + "Bytes: %i\n" + "Red: %"PRIu64"\n" + "Blue: %"PRIu64"\n" + "Green: %"PRIu64"\n%zn", + colour->bytes, colour->red, colour->green, + colour->blue, &part_length); + length += (size_t)part_length; + } + + sprintf(send_buffer + length, + "Last update: %s\n" + "\n%zn", + last_update, &part_length); + length += (size_t)part_length; + + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + + fail_if (full_send(send_buffer, length)); + return 0; +fail: + return -1; } @@ -865,20 +868,20 @@ int broadcast_update(const char* event, const char* name, const colour_t* colour */ void received_info(int signo) { - SIGHANDLER_START; - size_t i; - colour_list_entry_t* entry; - (void) signo; - iprintf("next message ID: %" PRIu32, message_id); - iprintf("connected: %s", connected ? "yes" : "no"); - iprintf("send buffer size: %zu bytes", send_buffer_size); - iprint("DEFINED COLOURS (bytes red green blue name-hash name)"); - foreach_hash_list_entry (colours, i, entry) - iprintf("%i %"PRIu64" %"PRIu64" %"PRIu64" %zu %s", - entry->value.bytes, entry->value.red, entry->value.green, - entry->value.blue, entry->key_hash, entry->key); - iprint("END DEFINED COLOURS"); - SIGHANDLER_END; + SIGHANDLER_START; + size_t i; + colour_list_entry_t *entry; + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + iprintf("send buffer size: %zu bytes", send_buffer_size); + iprint("DEFINED COLOURS (bytes red green blue name-hash name)"); + foreach_hash_list_entry (colours, i, entry) + iprintf("%i %"PRIu64" %"PRIu64" %"PRIu64" %zu %s", + entry->value.bytes, entry->value.red, entry->value.green, + entry->value.blue, entry->key_hash, entry->key); + iprint("END DEFINED COLOURS"); + SIGHANDLER_END; + (void) signo; } @@ -889,9 +892,10 @@ void received_info(int signo) * @param key_b The second key, will never be `NULL` * @return Whether the keys are equal */ -static inline int colour_list_key_comparer(const char* key_a, const char* key_b) +static inline int +colour_list_key_comparer(const char *key_a, const char *key_b) { - return !strcmp(key_a, key_b); + return !strcmp(key_a, key_b); } @@ -901,9 +905,10 @@ static inline int colour_list_key_comparer(const char* key_a, const char* key_b) * @param entry The entry, will never be `NULL`, any only used entries will be passed * @return The marshal-size of the entry's key and value */ -static inline size_t colour_list_submarshal_size(const colour_list_entry_t* entry) +static inline size_t +colour_list_submarshal_size(const colour_list_entry_t *entry) { - return sizeof(colour_t) + (strlen(entry->key) + 1) * sizeof(char); + return sizeof(colour_t) + (strlen(entry->key) + 1) * sizeof(char); } @@ -914,13 +919,14 @@ static inline size_t colour_list_submarshal_size(const colour_list_entry_t* entr * @param data The buffer where the entry's key and value will be stored * @return The marshal-size of the entry's key and value */ -static inline size_t colour_list_submarshal(const colour_list_entry_t* entry, char* restrict data) +static inline size_t +colour_list_submarshal(const colour_list_entry_t *entry, char *restrict data) { - size_t n = (strlen(entry->key) + 1) * sizeof(char); - memcpy(data, &(entry->value), sizeof(colour_t)); - data += sizeof(colour_t) / sizeof(char); - memcpy(data, entry->key, n); - return sizeof(colour_t) + n; + size_t n = (strlen(entry->key) + 1) * sizeof(char); + memcpy(data, &(entry->value), sizeof(colour_t)); + data += sizeof(colour_t) / sizeof(char); + memcpy(data, entry->key, n); + return sizeof(colour_t) + n; } @@ -931,18 +937,19 @@ static inline size_t colour_list_submarshal(const colour_list_entry_t* entry, ch * @param data The buffer where the entry's key and value is stored * @return The number of read bytes, zero on error */ -static inline size_t colour_list_subunmarshal(colour_list_entry_t* entry, char* restrict data) +static inline size_t +colour_list_subunmarshal(colour_list_entry_t *entry, char *restrict data) { - size_t n = 0; - memcpy(&(entry->value), data, sizeof(colour_t)); - data += sizeof(colour_t) / sizeof(char); - while (data[n++]); - n *= sizeof(char); - fail_if (xbmalloc(entry->key, n)); - memcpy(entry->key, data, n); - return sizeof(colour_t) + n; - fail: - return 0; + size_t n = 0; + memcpy(&(entry->value), data, sizeof(colour_t)); + data += sizeof(colour_t) / sizeof(char); + while (data[n++]); + n *= sizeof(char); + fail_if (xbmalloc(entry->key, n)); + memcpy(entry->key, data, n); + return sizeof(colour_t) + n; +fail: + return 0; } @@ -951,8 +958,8 @@ static inline size_t colour_list_subunmarshal(colour_list_entry_t* entry, char* * * @param entry The entry */ -void colour_list_entry_free(colour_list_entry_t* entry) +void +colour_list_entry_free(colour_list_entry_t *entry) { - free(entry->key); + free(entry->key); } - diff --git a/src/mds-colour.h b/src/mds-colour.h index 2043242..bb2fdbc 100644 --- a/src/mds-colour.h +++ b/src/mds-colour.h @@ -32,27 +32,27 @@ */ typedef struct colour { - /** - * The value of the red channel - */ - uint64_t red; - - /** - * The value of the green channel - */ - uint64_t green; - - /** - * The value of the blue channel - */ - uint64_t blue; - - /** - * The number of bytes with which - * each channel is encoded - */ - int bytes; - + /** + * The value of the red channel + */ + uint64_t red; + + /** + * The value of the green channel + */ + uint64_t green; + + /** + * The value of the blue channel + */ + uint64_t blue; + + /** + * The number of bytes with which + * each channel is encoded + */ + int bytes; + } colour_t; @@ -73,8 +73,8 @@ int handle_message(void); * @param recv_include_values The value of the `Include values`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_list_colours(const char* recv_client_id, const char* recv_message_id, - const char* recv_include_values); +int handle_list_colours(const char *recv_client_id, const char *recv_message_id, + const char *recv_include_values); /** * Handle the received message after it has been @@ -85,7 +85,7 @@ int handle_list_colours(const char* recv_client_id, const char* recv_message_id, * @param recv_name The value of the `Name`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_get_colour(const char* recv_client_id, const char* recv_message_id, const char* recv_name); +int handle_get_colour(const char *recv_client_id, const char *recv_message_id, const char *recv_name); /** * Handle the received message after it has been @@ -99,8 +99,8 @@ int handle_get_colour(const char* recv_client_id, const char* recv_message_id, c * @param recv_blue The value of the `Blue`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_set_colour(const char* recv_name, const char* recv_remove, const char* recv_bytes, - const char* recv_red, const char* recv_green, const char* recv_blue); +int handle_set_colour(const char *recv_name, const char *recv_remove, const char *recv_bytes, + const char *recv_red, const char *recv_green, const char *recv_blue); /** * Add, remove or modify a colour @@ -110,7 +110,8 @@ int handle_set_colour(const char* recv_name, const char* recv_remove, const char * @return Zero on success, -1 on error, removal of * non-existent colour does not constitute an error */ -int set_colour(const char* name, const colour_t* colour) __attribute__((nonnull(1))); +__attribute__((nonnull(1))) +int set_colour(const char* name, const colour_t *colour); /** * Broadcast a colour list update event @@ -121,11 +122,12 @@ int set_colour(const char* name, const colour_t* colour) __attribute__((nonnull( * @param last_update The value on the `Last update`-header * @return Zero on success, -1 on error */ -int broadcast_update(const char* event, const char* name, const colour_t* colour, - const char* last_update) __attribute__((nonnull(1, 2, 4))); +__attribute__((nonnull(1, 2, 4))) +int broadcast_update(const char *event, const char *name, const colour_t *colour, + const char *last_update); -CREATE_HASH_LIST_SUBCLASS(colour_list, char* restrict, const char* restrict, colour_t) +CREATE_HASH_LIST_SUBCLASS(colour_list, char *restrict, const char *restrict, colour_t) /** @@ -133,7 +135,7 @@ CREATE_HASH_LIST_SUBCLASS(colour_list, char* restrict, const char* restrict, col * * @param entry The entry */ -void colour_list_entry_free(colour_list_entry_t* entry); +void colour_list_entry_free(colour_list_entry_t *entry); #endif diff --git a/src/mds-echo.c b/src/mds-echo.c index 66d3b14..a47f45a 100644 --- a/src/mds-echo.c +++ b/src/mds-echo.c @@ -40,15 +40,14 @@ * * 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 = 1 - }; +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 = 1 +}; @@ -70,7 +69,7 @@ static int connected = 1; /** * Buffer for message echoing */ -static char* echo_buffer = NULL; +static char *echo_buffer = NULL; /** * The size allocated to `echo_buffer` divided by `sizeof(char)` @@ -86,8 +85,8 @@ static size_t echo_buffer_size = 0; * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** @@ -96,9 +95,10 @@ static size_t echo_buffer_size = 0; * * @return Non-zero on error */ -int __attribute__((const)) preinitialise_server(void) +int __attribute__((const)) +preinitialise_server(void) { - return 0; + return 0; } @@ -108,26 +108,27 @@ int __attribute__((const)) preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +int +initialise_server(void) { - int stage = 0; - const char* const message = - "Command: intercept\n" - "Message ID: 0\n" - "Length: 14\n" - "\n" - "Command: echo\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; + int stage = 0; + const char* const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 14\n" + "\n" + "Command: echo\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; } @@ -137,17 +138,18 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - if (connected) - return 0; - - fail_if (reconnect_to_display()); - connected = 1; - return 0; - fail: - mds_message_destroy(&received); - return 1; + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; +fail: + mds_message_destroy(&received); + return 1; } @@ -159,9 +161,10 @@ int postinitialise_server(void) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - return 2 * sizeof(int) + sizeof(uint32_t) + mds_message_marshal_size(&received); + return 2 * sizeof(int) + sizeof(uint32_t) + mds_message_marshal_size(&received); } @@ -171,15 +174,16 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - buf_set_next(state_buf, int, MDS_ECHO_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; + buf_set_next(state_buf, int, MDS_ECHO_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; } @@ -193,18 +197,19 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - /* buf_get_next(state_buf, int, MDS_ECHO_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; + /* buf_get_next(state_buf, int, MDS_ECHO_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; } @@ -214,9 +219,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } @@ -225,43 +231,42 @@ int __attribute__((const)) reexec_failure_recover(void) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - int rc = 1, r; - - while (!reexecing && !terminating) - { - if (r = mds_message_read(&received, socket_fd), r == 0) - if (r = echo_message(), r == 0) - continue; - - if (r == -2) - { - eprint("corrupt message received, aborting."); - goto done; + int rc = 1, r; + + while (!reexecing && !terminating) { + if (!(r = mds_message_read(&received, socket_fd))) + if (!(r = echo_message())) + 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; } - 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(echo_buffer); - return rc; + + rc = 0; + goto done; +fail: + xperror(*argv); +done: + if (rc || !reexecing) + mds_message_destroy(&received); + free(echo_buffer); + return rc; } @@ -271,74 +276,73 @@ int master_loop(void) * @return Zero on success -1 on error or interruption, * errno will be set accordingly */ -int echo_message(void) +int +echo_message(void) { - char* old_buffer = NULL; - const char* recv_client_id = NULL; - const char* recv_message_id = NULL; - const char* recv_length = NULL; - size_t i, n; - int saved_errno; - - /* Fetch headers. */ - -#define __get_header(storage, header, skip) \ - (startswith(received.headers[i], header)) \ - storage = received.headers[i] + skip * strlen(header) - - for (i = 0; i < received.header_count; i++) - { - if __get_header(recv_client_id, "Client ID: ", 1); - else if __get_header(recv_message_id, "Message ID: ", 1); - else if __get_header(recv_length, "Length: ", 0); - else - continue; - - /* Stop fetch headers if we have found everything we want. */ - if (recv_client_id && recv_message_id && recv_length) - break; - } - + char *old_buffer = NULL; + const char *recv_client_id = NULL; + const char *recv_message_id = NULL; + const char *recv_length = NULL; + size_t i, n; + int saved_errno; + + /* Fetch headers. */ + +#define __get_header(storage, header, skip)\ + (startswith(received.headers[i], header))\ + storage = received.headers[i] + skip * strlen(header) + + for (i = 0; i < received.header_count; i++) { + if __get_header(recv_client_id, "Client ID: ", 1); + else if __get_header(recv_message_id, "Message ID: ", 1); + else if __get_header(recv_length, "Length: ", 0); + else + continue; + + /* Stop fetch headers if we have found everything we want. */ + if (recv_client_id && recv_message_id && recv_length) + break; + } + #undef __get_header + + /* Validate headers. */ + if (!recv_client_id || strequals(recv_client_id, "0:0")) + return eprint("received message from anonymous sender, ignoring."), 0; + else if (!recv_message_id) + return eprint("received message without ID, ignoring, master server is misbehaving."), 0; + + /* Construct echo message headers. */ + + n = sizeof("To: \nIn response to: \nMessage ID: \nOrigin command: echo\n\n") / sizeof(char); + n += strlen(recv_client_id) + strlen(recv_message_id) + 3 * sizeof(uint32_t); + if (recv_length) + n += strlen(recv_length) + 1; + + if ((echo_buffer_size < n) || (echo_buffer_size * 4 > n)) + fail_if (xxrealloc(old_buffer, echo_buffer, echo_buffer_size = n, char)); + + sprintf(echo_buffer, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Origin command: echo\n" + "%s%s" + "\n", + recv_client_id, recv_message_id, message_id, + !recv_length ? "" : recv_length, + !recv_length ? "" : "\n"); + + /* Increase message ID. */ + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - /* Validate headers. */ - if ((recv_client_id == NULL) || (strequals(recv_client_id, "0:0"))) - return eprint("received message from anonymous sender, ignoring."), 0; - else if (recv_message_id == NULL) - return eprint("received message without ID, ignoring, master server is misbehaving."), 0; - - /* Construct echo message headers. */ - - n = sizeof("To: \nIn response to: \nMessage ID: \nOrigin command: echo\n\n") / sizeof(char); - n += strlen(recv_client_id) + strlen(recv_message_id) + 3 * sizeof(uint32_t); - if (recv_length != NULL) - n += strlen(recv_length) + 1; - - if ((echo_buffer_size < n) || (echo_buffer_size * 4 > n)) - fail_if (xxrealloc(old_buffer, echo_buffer, echo_buffer_size = n, char)); - - sprintf(echo_buffer, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Origin command: echo\n" - "%s%s" - "\n", - recv_client_id, recv_message_id, message_id, - recv_length == NULL ? "" : recv_length, - recv_length == NULL ? "" : "\n"); - - /* Increase message ID. */ - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - /* Send echo. */ - fail_if (full_send(echo_buffer, strlen(echo_buffer))); - return full_send(received.payload, received.payload_size); - fail: - saved_errno = errno; - free(old_buffer); - return errno = saved_errno, -1; + /* Send echo. */ + fail_if (full_send(echo_buffer, strlen(echo_buffer))); + return full_send(received.payload, received.payload_size); +fail: + saved_errno = errno; + free(old_buffer); + return errno = saved_errno, -1; } @@ -349,13 +353,14 @@ int echo_message(void) * * @param signo The signal that has been received */ -void received_info(int signo) +void +received_info(int signo) { - SIGHANDLER_START; - (void) signo; - iprintf("next message ID: %" PRIu32, message_id); - iprintf("connected: %s", connected ? "yes" : "no"); - iprintf("echo buffer size: %zu bytes", echo_buffer_size); - SIGHANDLER_END; + SIGHANDLER_START; + (void) signo; + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + iprintf("echo buffer size: %zu bytes", echo_buffer_size); + SIGHANDLER_END; } diff --git a/src/mds-kkbd.c b/src/mds-kkbd.c index 80f67af..59214e8 100644 --- a/src/mds-kkbd.c +++ b/src/mds-kkbd.c @@ -38,49 +38,49 @@ #ifdef __sparc__ -# define GET_LED KIOCGLED -# define SET_LED KIOCSLED +# define GET_LED KIOCGLED +# define SET_LED KIOCSLED #else -# define GET_LED KDGETLED -# define SET_LED KDSETLED +# define GET_LED KDGETLED +# define SET_LED KDSETLED #endif #ifdef __sparc__ -# define LED_NUM_LOCK 1 -# define LED_CAPS_LOCK 8 -# define LED_SCRL_LOCK 4 -# define LED_COMPOSE 2 +# define LED_NUM_LOCK 1 +# define LED_CAPS_LOCK 8 +# define LED_SCRL_LOCK 4 +# define LED_COMPOSE 2 #else -# define LED_NUM_LOCK LED_NUM -# define LED_CAPS_LOCK LED_CAP -# define LED_SCRL_LOCK LED_SCR +# define LED_NUM_LOCK LED_NUM +# define LED_CAPS_LOCK LED_CAP +# define LED_SCRL_LOCK LED_SCR #endif -#define MDS_KKBD_VARS_VERSION 0 +#define MDS_KKBD_VARS_VERSION 0 /** * The name of the keyboard for which its server implements control */ -#define KEYBOARD_ID "kernel" +#define KEYBOARD_ID "kernel" /* NOTE: length hardcoded in `initialise_server` */ /** * LED:s that we believe are present on the keyboard */ #ifdef LED_COMPOSE -# define PRESENT_LEDS "num caps scrl compose" +# define PRESENT_LEDS "num caps scrl compose" #else -# define PRESENT_LEDS "num caps scrl" +# define PRESENT_LEDS "num caps scrl" #endif /** * Measure a string literal in compile time */ -#define lengthof(str) (sizeof(str) / sizeof(char) - 1) +#define lengthof(str) (sizeof(str) / sizeof(char) - 1) @@ -90,15 +90,14 @@ * * 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 = 1, - .danger_is_deadly = 0 - }; +server_characteristics_t server_characteristics = { + .require_privileges = 0, + .require_display = 1, + .require_respawn_info = 0, + .sanity_check_argc = 1, + .fork_for_safety = 1, + .danger_is_deadly = 0 +}; @@ -140,7 +139,7 @@ static int saved_kbd_mode; /** * Keycode remapping table */ -static int* restrict mapping = NULL; +static int *restrict mapping = NULL; /** * The size of `mapping` @@ -165,7 +164,7 @@ static char key_send_buffer[80 + 3 * 3 + 5 + lengthof(KEYBOARD_ID) + 10 + 1]; /** * Message buffer for the main thread */ -static char* send_buffer = NULL; +static char *send_buffer = NULL; /** * The size of `send_buffer` @@ -223,8 +222,8 @@ static int led_compose = LED_COMPOSE; * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** @@ -232,51 +231,47 @@ static int led_compose = LED_COMPOSE; * * @return Non-zero on error */ -int parse_cmdline(void) +int +parse_cmdline(void) { - int i; - - /* 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; + int i, v; + char *arg; + + /* Parse command line arguments. */ + for (i = 1; i < argc; i++) { + arg = argv[i]; + 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 (strequals(arg, "--re-exec")) { /* Re-exec state-marshal. */ + is_reexec = 1; + } else if (startswith(arg, "--alarm=")) { /* Schedule an alarm signal for forced abort. */ + alarm(min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ + } else if (strequals(arg, "--on-init-fork")) { /* Fork process when initialised. */ + on_init_fork = 1; + } else if (startswith(arg, "--on-init-sh=")) { /* Run a command when initialised. */ + on_init_sh = arg + strlen("--on-init-sh="); + } else if (strequals(arg, "--immortal")) { /* I return to serve. */ + is_immortal = 1; + } else if (startswith(arg, "--led=")) { /* Remap LED:s. */ + if (remap_led_cmdline(arg + strlen("--led=")) < 0) + return -1; + } } - else if (strequals(arg, "--re-exec")) /* Re-exec state-marshal. */ - is_reexec = 1; - else if (startswith(arg, "--alarm=")) /* Schedule an alarm signal for forced abort. */ - alarm(min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ - else if (strequals(arg, "--on-init-fork")) /* Fork process when initialised. */ - on_init_fork = 1; - else if (startswith(arg, "--on-init-sh=")) /* Run a command when initialised. */ - on_init_sh = arg + strlen("--on-init-sh="); - else if (strequals(arg, "--immortal")) /* I return to serve. */ - is_immortal = 1; - else if (startswith(arg, "--led=")) /* Remap LED:s. */ - { - if (remap_led_cmdline(arg + strlen("--led=")) < 0) - return -1; + if (is_reexec) { + is_respawn = 1; + eprint("re-exec performed."); } - } - if (is_reexec) - { - is_respawn = 1; - eprint("re-exec performed."); - } - - /* Check that mandatory arguments have been specified. */ - if (server_characteristics.require_respawn_info) - exit_if (is_respawn < 0, - eprintf("missing state argument, require either %s or %s.", - "--initial-spawn", "--respawn");); - return 0; + + /* Check that mandatory arguments have been specified. */ + if (server_characteristics.require_respawn_info) + exit_if (is_respawn < 0, + eprintf("missing state argument, require either %s or %s.", + "--initial-spawn", "--respawn");); + return 0; } @@ -286,9 +281,10 @@ int parse_cmdline(void) * * @return Non-zero on error */ -int __attribute__((const)) preinitialise_server(void) +int __attribute__((const)) +preinitialise_server(void) { - return 0; + return 0; } @@ -298,54 +294,54 @@ int __attribute__((const)) preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +int +initialise_server(void) { - int stage = 0; - const char* const message = - "Command: intercept\n" - "Message ID: 0\n" - "Length: 102\n" - "\n" - "Command: set-keyboard-leds\n" - "Command: get-keyboard-leds\n" - "Command: map-keyboard-leds\n" - "Command: keycode-map\n" - /* NEXT MESSAGE */ - "Command: intercept\n" - "Message ID: 1\n" - "Modifying: yes\n" - "Length: 59\n" - "\n" - "Command: enumerate-keyboards\n" - "Command: keyboard-enumeration\n" - /* NEXT MESSAGE */ - "Command: new-keyboard\n" - "Message ID: 2\n" - "Length: 7\n" - "\n" - KEYBOARD_ID "\n"; - - fail_if (open_leds() < 0); stage++; - fail_if (open_input() < 0); stage++; - fail_if (pthread_mutex_init(&send_mutex, NULL)); stage++; - fail_if (pthread_mutex_init(&mapping_mutex, NULL)); stage++; - fail_if (full_send(message, strlen(message))); - fail_if (server_initialised()); stage++; - fail_if (mds_message_initialise(&received)); - - return 0; - - fail: - xperror(*argv); - if (stage < 5) - { - if (stage >= 2) close_input(); - if (stage >= 1) close_leds(); - } - if (stage >= 3) pthread_mutex_destroy(&send_mutex); - if (stage >= 4) pthread_mutex_destroy(&mapping_mutex); - if (stage >= 5) mds_message_destroy(&received); - return 1; + int stage = 0; + const char *const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 102\n" + "\n" + "Command: set-keyboard-leds\n" + "Command: get-keyboard-leds\n" + "Command: map-keyboard-leds\n" + "Command: keycode-map\n" + /* NEXT MESSAGE */ + "Command: intercept\n" + "Message ID: 1\n" + "Modifying: yes\n" + "Length: 59\n" + "\n" + "Command: enumerate-keyboards\n" + "Command: keyboard-enumeration\n" + /* NEXT MESSAGE */ + "Command: new-keyboard\n" + "Message ID: 2\n" + "Length: 7\n" + "\n" + KEYBOARD_ID "\n"; + + fail_if (open_leds() < 0); stage++; + fail_if (open_input() < 0); stage++; + fail_if (pthread_mutex_init(&send_mutex, NULL)); stage++; + fail_if (pthread_mutex_init(&mapping_mutex, NULL)); stage++; + fail_if (full_send(message, strlen(message))); + fail_if (server_initialised()); stage++; + fail_if (mds_message_initialise(&received)); + + return 0; + +fail: + xperror(*argv); + if (stage < 5) { + if (stage >= 2) close_input(); + if (stage >= 1) close_leds(); + } + if (stage >= 3) pthread_mutex_destroy(&send_mutex); + if (stage >= 4) pthread_mutex_destroy(&mapping_mutex); + if (stage >= 5) mds_message_destroy(&received); + return 1; } @@ -355,17 +351,18 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - if (connected) - return 0; - - fail_if (reconnect_to_display()); - connected = 1; - return 0; - fail: - mds_message_destroy(&received); - return 1; + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; +fail: + mds_message_destroy(&received); + return 1; } @@ -376,11 +373,12 @@ int postinitialise_server(void) * * @param status The status witch which the child died */ -void fork_cleanup(int status) +void +fork_cleanup(int status) { - (void) status; - close_input(); - close_leds(); + close_input(); + close_leds(); + (void) status; } @@ -392,12 +390,13 @@ void fork_cleanup(int status) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t rc = 9 * sizeof(int) + sizeof(uint32_t) + sizeof(struct termios); - rc += sizeof(size_t) + mapping_size * sizeof(int); - rc += mds_message_marshal_size(&received); - return rc; + size_t rc = 9 * sizeof(int) + sizeof(uint32_t) + sizeof(struct termios); + rc += sizeof(size_t) + mapping_size * sizeof(int); + rc += mds_message_marshal_size(&received); + return rc; } @@ -407,30 +406,30 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - buf_set_next(state_buf, int, MDS_KKBD_VARS_VERSION); - buf_set_next(state_buf, int, connected); - buf_set_next(state_buf, uint32_t, message_id); - buf_set_next(state_buf, int, ledfd); - buf_set_next(state_buf, int, saved_leds); - buf_set_next(state_buf, struct termios, saved_stty); - buf_set_next(state_buf, int, saved_kbd_mode); - buf_set_next(state_buf, int, scancode_ptr); - buf_set_next(state_buf, int, scancode_buf[0]); - buf_set_next(state_buf, int, scancode_buf[1]); - buf_set_next(state_buf, int, scancode_buf[2]); - buf_set_next(state_buf, size_t, mapping_size); - if (mapping_size > 0) - { - memcpy(state_buf, mapping, mapping_size * sizeof(int)); - state_buf += mapping_size * sizeof(int) / sizeof(char); - } - mds_message_marshal(&received, state_buf); - - mds_message_destroy(&received); - free(mapping); - return 0; + buf_set_next(state_buf, int, MDS_KKBD_VARS_VERSION); + buf_set_next(state_buf, int, connected); + buf_set_next(state_buf, uint32_t, message_id); + buf_set_next(state_buf, int, ledfd); + buf_set_next(state_buf, int, saved_leds); + buf_set_next(state_buf, struct termios, saved_stty); + buf_set_next(state_buf, int, saved_kbd_mode); + buf_set_next(state_buf, int, scancode_ptr); + buf_set_next(state_buf, int, scancode_buf[0]); + buf_set_next(state_buf, int, scancode_buf[1]); + buf_set_next(state_buf, int, scancode_buf[2]); + buf_set_next(state_buf, size_t, mapping_size); + if (mapping_size > 0) { + memcpy(state_buf, mapping, mapping_size * sizeof(int)); + state_buf += mapping_size * sizeof(int) / sizeof(char); + } + mds_message_marshal(&received, state_buf); + + mds_message_destroy(&received); + free(mapping); + return 0; } @@ -444,37 +443,37 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - /* buf_get_next(state_buf, int, MDS_KKBD_VARS_VERSION); */ - buf_next(state_buf, int, 1); - buf_get_next(state_buf, int, connected); - buf_get_next(state_buf, uint32_t, message_id); - buf_get_next(state_buf, int, ledfd); - buf_get_next(state_buf, int, saved_leds); - buf_get_next(state_buf, struct termios, saved_stty); - buf_get_next(state_buf, int, saved_kbd_mode); - buf_get_next(state_buf, int, scancode_ptr); - buf_get_next(state_buf, int, scancode_buf[0]); - buf_get_next(state_buf, int, scancode_buf[1]); - buf_get_next(state_buf, int, scancode_buf[2]); - buf_get_next(state_buf, size_t, mapping_size); - if (mapping_size > 0) - { - fail_if (xmemdup(mapping, state_buf, mapping_size, int)); - state_buf += mapping_size * sizeof(int) / sizeof(char); - } - fail_if (mds_message_unmarshal(&received, state_buf)); - - return 0; - fail: - xperror(*argv); - mds_message_destroy(&received); - free(mapping); - abort(); /* We must abort on failure to not risk the keyboard - getting stuck and freeze up the computer until - someone ssh:es into it and kill the server. */ - return -1; + /* buf_get_next(state_buf, int, MDS_KKBD_VARS_VERSION); */ + buf_next(state_buf, int, 1); + buf_get_next(state_buf, int, connected); + buf_get_next(state_buf, uint32_t, message_id); + buf_get_next(state_buf, int, ledfd); + buf_get_next(state_buf, int, saved_leds); + buf_get_next(state_buf, struct termios, saved_stty); + buf_get_next(state_buf, int, saved_kbd_mode); + buf_get_next(state_buf, int, scancode_ptr); + buf_get_next(state_buf, int, scancode_buf[0]); + buf_get_next(state_buf, int, scancode_buf[1]); + buf_get_next(state_buf, int, scancode_buf[2]); + buf_get_next(state_buf, size_t, mapping_size); + if (mapping_size > 0) { + fail_if (xmemdup(mapping, state_buf, mapping_size, int)); + state_buf += mapping_size * sizeof(int) / sizeof(char); + } + fail_if (mds_message_unmarshal(&received, state_buf)); + + return 0; +fail: + xperror(*argv); + mds_message_destroy(&received); + free(mapping); + abort(); /* We must abort on failure to not risk the keyboard + getting stuck and freeze up the computer until + someone ssh:es into it and kill the server. */ + return -1; } @@ -484,9 +483,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } @@ -495,63 +495,62 @@ int __attribute__((const)) reexec_failure_recover(void) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - int rc = 1, joined = 0, r; - void* kbd_ret; - - /* Start thread that reads input from the keyboard. */ - fail_if ((errno = pthread_create(&kbd_thread, NULL, keyboard_loop, NULL))); - - /* Listen for messages. */ - 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; + int rc = 1, joined = 0, r; + void *kbd_ret; + + /* Start thread that reads input from the keyboard. */ + fail_if ((errno = pthread_create(&kbd_thread, NULL, keyboard_loop, NULL))); + + /* Listen for messages. */ + 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))) + if (!(r = handle_message())) + 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; } - 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; - } - - joined = 1; - fail_if ((errno = pthread_join(kbd_thread, &kbd_ret))); - rc = kbd_ret == NULL ? 0 : 1; - goto done; + + joined = 1; + fail_if ((errno = pthread_join(kbd_thread, &kbd_ret))); + rc = kbd_ret == NULL ? 0 : 1; + goto done; fail: - xperror(*argv); + xperror(*argv); done: - pthread_mutex_destroy(&send_mutex); - pthread_mutex_destroy(&mapping_mutex); - free(send_buffer); - if ((!joined) && (errno = pthread_join(kbd_thread, NULL))) - xperror(*argv); - if (!rc && reexecing) - return 0; - mds_message_destroy(&received); - free(mapping); - return rc; + pthread_mutex_destroy(&send_mutex); + pthread_mutex_destroy(&mapping_mutex); + free(send_buffer); + if (!joined && (errno = pthread_join(kbd_thread, NULL))) + xperror(*argv); + if (!rc && reexecing) + return 0; + mds_message_destroy(&received); + free(mapping); + return rc; } @@ -561,22 +560,22 @@ int master_loop(void) * @param data Input data * @return Output data */ -void* keyboard_loop(void* data) +void * +keyboard_loop(void *data) { - (void) data; - - kbd_thread_started = 1; - - while (!reexecing && !terminating) - if (fetch_keys() < 0) - fail_if (errno != EINTR); - - return NULL; - - fail: - xperror(*argv); - raise(SIGTERM); - return (void*)1024; + kbd_thread_started = 1; + + while (!reexecing && !terminating) + if (fetch_keys() < 0) + fail_if (errno != EINTR); + + return NULL; + +fail: + xperror(*argv); + raise(SIGTERM); + return (void*)1024; + (void) data; } @@ -585,63 +584,63 @@ void* keyboard_loop(void* data) * * @return Zero on success, -1 on error */ -int handle_message(void) +int +handle_message(void) { - const char* recv_command = NULL; - const char* recv_client_id = "0:0"; - const char* recv_message_id = NULL; - const char* recv_modify_id = NULL; - const char* recv_active = NULL; - const char* recv_mask = NULL; - const char* recv_keyboard = NULL; - const char* recv_action = NULL; - size_t i; - -#define __get_header(storage, header) \ - (startswith(received.headers[i], header)) \ - storage = received.headers[i] + strlen(header) - - for (i = 0; i < received.header_count; i++) - { - if __get_header(recv_command, "Command: "); - else if __get_header(recv_client_id, "Client ID: "); - else if __get_header(recv_message_id, "Message ID: "); - else if __get_header(recv_modify_id, "Modify ID: "); - else if __get_header(recv_active, "Active: "); - else if __get_header(recv_mask, "Mask: "); - else if __get_header(recv_keyboard, "Keyboard: "); - else if __get_header(recv_action, "Action: "); - } - + const char *recv_command = NULL; + const char *recv_client_id = "0:0"; + const char *recv_message_id = NULL; + const char *recv_modify_id = NULL; + const char *recv_active = NULL; + const char *recv_mask = NULL; + const char *recv_keyboard = NULL; + const char *recv_action = NULL; + size_t i; + +#define __get_header(storage, header)\ + (startswith(received.headers[i], header))\ + storage = received.headers[i] + strlen(header) + + for (i = 0; i < received.header_count; i++) { + if __get_header(recv_command, "Command: "); + else if __get_header(recv_client_id, "Client ID: "); + else if __get_header(recv_message_id, "Message ID: "); + else if __get_header(recv_modify_id, "Modify ID: "); + else if __get_header(recv_active, "Active: "); + else if __get_header(recv_mask, "Mask: "); + else if __get_header(recv_keyboard, "Keyboard: "); + else if __get_header(recv_action, "Action: "); + } + #undef __get_header - - if (recv_message_id == NULL) - return eprint("received message without ID, ignoring, master server is misbehaving."), 0; - - if (recv_command == NULL) - return 0; /* How did that get here, no matter, just ignore it? */ - -#define t(expr) do { fail_if (expr); return 0; } while (0) - if (strequals(recv_command, "enumerate-keyboards")) - t (handle_enumerate_keyboards(recv_client_id, recv_message_id, recv_modify_id)); - if (strequals(recv_command, "keyboard-enumeration")) - t (handle_keyboard_enumeration(recv_modify_id)); - if (strequals(recv_command, "keycode-map")) - t (handle_keycode_map(recv_client_id, recv_message_id, recv_action, recv_keyboard)); - /* The following do not need to be inside a mutex, because this server - only interprets on message at the time, thus there can not be any - conflicts and access to LED:s are automatically atomic. */ - if (strequals(recv_command, "set-keyboard-leds")) - t (handle_set_keyboard_leds(recv_active, recv_mask, recv_keyboard)); - if (strequals(recv_command, "get-keyboard-leds")) - t (handle_get_keyboard_leds(recv_client_id, recv_message_id, recv_keyboard)); - if (strequals(recv_command, "map-keyboard-leds")) - t (handle_map_keyboard_leds(recv_keyboard)); + + if (!recv_message_id) + return eprint("received message without ID, ignoring, master server is misbehaving."), 0; + + if (!recv_command) + return 0; /* How did that get here, no matter, just ignore it? */ + +#define t(expr) do { fail_if (expr); return 0; } while (0) + if (strequals(recv_command, "enumerate-keyboards")) + t (handle_enumerate_keyboards(recv_client_id, recv_message_id, recv_modify_id)); + if (strequals(recv_command, "keyboard-enumeration")) + t (handle_keyboard_enumeration(recv_modify_id)); + if (strequals(recv_command, "keycode-map")) + t (handle_keycode_map(recv_client_id, recv_message_id, recv_action, recv_keyboard)); + /* The following do not need to be inside a mutex, because this server + only interprets on message at the time, thus there can not be any + conflicts and access to LED:s are automatically atomic. */ + if (strequals(recv_command, "set-keyboard-leds")) + t (handle_set_keyboard_leds(recv_active, recv_mask, recv_keyboard)); + if (strequals(recv_command, "get-keyboard-leds")) + t (handle_get_keyboard_leds(recv_client_id, recv_message_id, recv_keyboard)); + if (strequals(recv_command, "map-keyboard-leds")) + t (handle_map_keyboard_leds(recv_keyboard)); #undef t - - return 0; /* How did that get here, no matter, just ignore it? */ - fail: - return -1; + + return 0; /* How did that get here, no matter, just ignore it? */ +fail: + return -1; } @@ -651,20 +650,21 @@ int handle_message(void) * @param size The size required for the buffer * @return Zero on success, -1 on error */ -static int ensure_send_buffer_size(size_t size) +static int +ensure_send_buffer_size(size_t size) { - char* old = send_buffer; - - if (send_buffer_size >= size) - return 0; - - fail_if (xrealloc(send_buffer, size, char)); - send_buffer_size = size; - - return 0; - fail: - send_buffer = old; - return -1; + char *old = send_buffer; + + if (send_buffer_size >= size) + return 0; + + fail_if (xrealloc(send_buffer, size, char)); + send_buffer_size = size; + + return 0; +fail: + send_buffer = old; + return -1; } @@ -677,75 +677,74 @@ static int ensure_send_buffer_size(size_t size) * @param recv_modify_id The value of the `Modify ID`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_enumerate_keyboards(const char* recv_client_id, const char* recv_message_id, - const char* recv_modify_id) +int +handle_enumerate_keyboards(const char *recv_client_id, const char *recv_message_id, const char *recv_modify_id) { - uint32_t msgid; - size_t n; - int r; - - if (recv_modify_id == NULL) - return eprint("did not get a modify ID, ignoring."), 0; - - - if (strequals(recv_client_id, "0:0")) - { - eprint("received information request from an anonymous client, sending non-modifying response."); - - with_mutex (send_mutex, - msgid = message_id; - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - ); - - fail_if (ensure_send_buffer_size(47 + strlen(recv_modify_id) + 1) < 0); - sprintf(send_buffer, - "Modify: no\n" - "Modify ID: %s\n" - "Message ID: %" PRIu32 "\n" - "\n", - recv_modify_id, msgid); - - with_mutex (send_mutex, - r = full_send(send_buffer, strlen(send_buffer)); - if (r) r = errno ? errno : -1; - ); - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - } - - with_mutex (send_mutex, - msgid = message_id; - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - ); - - n = 134 + 3 * sizeof(size_t) + lengthof(KEYBOARD_ID); - n += strlen(recv_client_id) + strlen(recv_modify_id) + strlen(recv_message_id); - fail_if (ensure_send_buffer_size(n + 1) < 0); - sprintf(send_buffer, - "Modify: yes\n" - "Modify ID: %s\n" - "Message ID: %" PRIu32 "\n" - "\n" - /* NEXT MESSAGE */ - "Command: keyboard-enumeration\n" - "To: %s\n" - "In response to: %s\n" - "Length: %zu\n" - "Message ID: %" PRIu32 "\n" - "\n" - KEYBOARD_ID "\n", - recv_modify_id, msgid, - recv_client_id, recv_message_id, lengthof(KEYBOARD_ID) + 1, msgid + 1); - - with_mutex (send_mutex, - r = full_send(send_buffer, strlen(send_buffer)); - if (r) r = errno ? errno : -1; - ); - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - fail: - return -1; + uint32_t msgid; + size_t n; + int r; + + if (!recv_modify_id) + return eprint("did not get a modify ID, ignoring."), 0; + + + if (strequals(recv_client_id, "0:0")) { + eprint("received information request from an anonymous client, sending non-modifying response."); + + with_mutex (send_mutex, + msgid = message_id; + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + ); + + fail_if (ensure_send_buffer_size(47 + strlen(recv_modify_id) + 1) < 0); + sprintf(send_buffer, + "Modify: no\n" + "Modify ID: %s\n" + "Message ID: %" PRIu32 "\n" + "\n", + recv_modify_id, msgid); + + with_mutex (send_mutex, + r = full_send(send_buffer, strlen(send_buffer)); + if (r) r = errno ? errno : -1; + ); + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; + } + + with_mutex (send_mutex, + msgid = message_id; + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + ); + + n = 134 + 3 * sizeof(size_t) + lengthof(KEYBOARD_ID); + n += strlen(recv_client_id) + strlen(recv_modify_id) + strlen(recv_message_id); + fail_if (ensure_send_buffer_size(n + 1) < 0); + sprintf(send_buffer, + "Modify: yes\n" + "Modify ID: %s\n" + "Message ID: %" PRIu32 "\n" + "\n" + /* NEXT MESSAGE */ + "Command: keyboard-enumeration\n" + "To: %s\n" + "In response to: %s\n" + "Length: %zu\n" + "Message ID: %" PRIu32 "\n" + "\n" + KEYBOARD_ID "\n", + recv_modify_id, msgid, + recv_client_id, recv_message_id, lengthof(KEYBOARD_ID) + 1, msgid + 1); + + with_mutex (send_mutex, + r = full_send(send_buffer, strlen(send_buffer)); + if (r) r = errno ? errno : -1; + ); + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; +fail: + return -1; } @@ -756,127 +755,126 @@ int handle_enumerate_keyboards(const char* recv_client_id, const char* recv_mess * @param recv_modify_id The value of the `Modify ID`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_keyboard_enumeration(const char* recv_modify_id) +int +handle_keyboard_enumeration(const char *recv_modify_id) { - size_t i, off, m, n = lengthof(KEYBOARD_ID "\n") + 3 * sizeof(size_t); - ssize_t top; - uint32_t msgid; - int r, have_len = 0; - - if (recv_modify_id == NULL) - return eprint("did not get a modify ID, ignoring."), 0; - - - /* Calculate length of received message. */ - - /* Measure the length of the headers. */ - for (i = 0; i < received.header_count; i++) - n += strlen(received.headers[i]); - /* Count the line feeds after the headers. */ - n += received.header_count; - /* There is an empty line between headers and payload. */ - n += 1; - /* Add the length of the payload. */ - n += received.payload_size; - - - /* Calculate upper bound for the outbound message's payload */ - n += lengthof("Length: \n") + 3 * sizeof(size_t); - n += lengthof(KEYBOARD_ID "\n"); - - - /* Calculate an upper bound for the outbound message. - `off` is an upper bound for the outbound message's - headers plus empty line and thus where we should - write the payload to the buffer. */ - off = sizeof("Modify ID: \nMessage ID: \nLength: \n\n") / sizeof(char) - 1; - n += off += strlen(recv_modify_id) + 10 + 3 * sizeof(size_t); - - - /* Make sure the buffer fits the message, add one additional - character to the allocation so sprintf does not write outside - the buffer. */ - fail_if (ensure_send_buffer_size(n + 1) < 0); - - /* Fetch and increase local message ID. */ - with_mutex (send_mutex, - msgid = message_id; - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - ); - - - /* Write outbound message payload. */ - - /* Write inbound message's headers to the outbound message, - `n` keeps track of were we are. */ - n = off; - for (i = 0; i < received.header_count; i++) - { - const char* header = received.headers[i]; - if (!have_len && startswith(header, "Length: ")) - { - have_len = 1; - sprintf(send_buffer + n, - "Length: %zu\n", - received.payload_size + lengthof(KEYBOARD_ID "\n")); - n += strlen(send_buffer + n); + size_t i, off, m, n = lengthof(KEYBOARD_ID "\n") + 3 * sizeof(size_t); + ssize_t top; + uint32_t msgid; + int r, have_len = 0; + const char *header; + + if (!recv_modify_id) + return eprint("did not get a modify ID, ignoring."), 0; + + + /* Calculate length of received message. */ + + /* Measure the length of the headers. */ + for (i = 0; i < received.header_count; i++) + n += strlen(received.headers[i]); + /* Count the line feeds after the headers. */ + n += received.header_count; + /* There is an empty line between headers and payload. */ + n += 1; + /* Add the length of the payload. */ + n += received.payload_size; + + + /* Calculate upper bound for the outbound message's payload */ + n += lengthof("Length: \n") + 3 * sizeof(size_t); + n += lengthof(KEYBOARD_ID "\n"); + + + /* Calculate an upper bound for the outbound message. + `off` is an upper bound for the outbound message's + headers plus empty line and thus where we should + write the payload to the buffer. */ + off = sizeof("Modify ID: \nMessage ID: \nLength: \n\n") / sizeof(char) - 1; + n += off += strlen(recv_modify_id) + 10 + 3 * sizeof(size_t); + + + /* Make sure the buffer fits the message, add one additional + character to the allocation so sprintf does not write outside + the buffer. */ + fail_if (ensure_send_buffer_size(n + 1) < 0); + + /* Fetch and increase local message ID. */ + with_mutex (send_mutex, + msgid = message_id; + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + ); + + + /* Write outbound message payload. */ + + /* Write inbound message's headers to the outbound message, + `n` keeps track of were we are. */ + n = off; + for (i = 0; i < received.header_count; i++) { + header = received.headers[i]; + if (!have_len && startswith(header, "Length: ")) { + have_len = 1; + sprintf(send_buffer + n, + "Length: %zu\n", + received.payload_size + lengthof(KEYBOARD_ID "\n")); + n += strlen(send_buffer + n); + } else { + m = strlen(header); + memcpy(send_buffer + n, header, m * sizeof(char)), n += m; + send_buffer[n++] = '\n'; + } } - else - { - m = strlen(header); - memcpy(send_buffer + n, header, m * sizeof(char)), n += m; - send_buffer[n++] = '\n'; + /* If we did not `Length`-header we must add it as we will extend the payload. */ + if (!have_len) { + sprintf(send_buffer + n, + "Length: %zu\n", + lengthof(KEYBOARD_ID "\n")); + n += strlen(send_buffer + n); } - } - /* If we did not `Length`-header we must add it as we will extend the payload. */ - if (!have_len) - sprintf(send_buffer + n, - "Length: %zu\n", - lengthof(KEYBOARD_ID "\n")), - n += strlen(send_buffer + n); - /* Mark end of inbound headers. */ - send_buffer[n++] = '\n'; - /* Write inbound message's payload to the outbound message. */ - memcpy(send_buffer + n, received.payload, received.payload_size * sizeof(char)); - n += received.payload_size; - /* Add our keyboard to the payload. */ - memcpy(send_buffer + n, KEYBOARD_ID "\n", lengthof(KEYBOARD_ID "\n") * sizeof(char)); - n += lengthof(KEYBOARD_ID "\n"); - /* Change `n` to tell the length of the outbound message's payload. */ - n -= off; - - - /* Complete outbound message. */ - - /* Write the outbound message's headers. */ - sprintf(send_buffer, - "Modify ID: %s\n" - "Message ID: %" PRIu32 "\n" - "Length: %zu\n%zn", - recv_modify_id, msgid, n, &top); - /* Write the empty line. */ - send_buffer[(size_t)(top++)] = '\n'; - /* Calculate what the offset in the entire buffer for the - message should be, and move the message to that offset. - Only the headers and the empty line should be moved, so - that it is juxtaposed with the payload. */ - off -= (size_t)top; - memmove(send_buffer + off, send_buffer, ((size_t)top) * sizeof(char)); - /* Calculate the final length of the message. */ - n += (size_t)top; - - - /* Send message. */ - - with_mutex (send_mutex, - r = full_send(send_buffer + off, n); - if (r) r = errno ? errno : -1; - ); - - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - fail: - return -1; + /* Mark end of inbound headers. */ + send_buffer[n++] = '\n'; + /* Write inbound message's payload to the outbound message. */ + memcpy(send_buffer + n, received.payload, received.payload_size * sizeof(char)); + n += received.payload_size; + /* Add our keyboard to the payload. */ + memcpy(send_buffer + n, KEYBOARD_ID "\n", lengthof(KEYBOARD_ID "\n") * sizeof(char)); + n += lengthof(KEYBOARD_ID "\n"); + /* Change `n` to tell the length of the outbound message's payload. */ + n -= off; + + + /* Complete outbound message. */ + + /* Write the outbound message's headers. */ + sprintf(send_buffer, + "Modify ID: %s\n" + "Message ID: %" PRIu32 "\n" + "Length: %zu\n%zn", + recv_modify_id, msgid, n, &top); + /* Write the empty line. */ + send_buffer[(size_t)(top++)] = '\n'; + /* Calculate what the offset in the entire buffer for the + message should be, and move the message to that offset. + Only the headers and the empty line should be moved, so + that it is juxtaposed with the payload. */ + off -= (size_t)top; + memmove(send_buffer + off, send_buffer, ((size_t)top) * sizeof(char)); + /* Calculate the final length of the message. */ + n += (size_t)top; + + + /* Send message. */ + + with_mutex (send_mutex, + r = full_send(send_buffer + off, n); + if (r) r = errno ? errno : -1; + ); + + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; +fail: + return -1; } @@ -889,66 +887,63 @@ int handle_keyboard_enumeration(const char* recv_modify_id) * @param recv_keyboard The value of the `Keyboard`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_set_keyboard_leds(const char* recv_active, const char* recv_mask, const char* recv_keyboard) +int +handle_set_keyboard_leds(const char *recv_active, const char *recv_mask, const char *recv_keyboard) { - int active = 0; - int mask = 0; - int current; - const char* begin; - const char* end; - - if ((recv_keyboard != NULL) && !strequals(recv_keyboard, KEYBOARD_ID)) - return 0; - - if (recv_active == NULL) - return eprint("received LED writing request without active header, ignoring."), 0; + int active = 0; + int mask = 0; + int current; + const char *begin; + const char *end; - if (recv_mask == NULL) - return eprint("received LED writing request without mask header, ignoring."), 0; - - current = get_leds(); - if (current < 0) - { - xperror(*argv); - return 0; /* Not fatal */ - } - -#define __test(have, want) (startswith(have, want " ") || strequals(have, want)) - - for (begin = end = recv_active; end != NULL;) - { - end = strchr(begin, ' '); - if (__test(begin, "num")) active |= led_num_lock; - else if (__test(begin, "caps")) active |= led_caps_lock; - else if (__test(begin, "scrl")) active |= led_scrl_lock; + if ((recv_keyboard) && !strequals(recv_keyboard, KEYBOARD_ID)) + return 0; + + if (!recv_active) + return eprint("received LED writing request without active header, ignoring."), 0; + + if (!recv_mask) + return eprint("received LED writing request without mask header, ignoring."), 0; + + current = get_leds(); + if (current < 0) { + xperror(*argv); + return 0; /* Not fatal */ + } + +#define __test(have, want) (startswith(have, want " ") || strequals(have, want)) + + for (begin = end = recv_active; end;) { + end = strchr(begin, ' '); + if (__test(begin, "num")) active |= led_num_lock; + else if (__test(begin, "caps")) active |= led_caps_lock; + else if (__test(begin, "scrl")) active |= led_scrl_lock; #ifdef LED_COMPOSE - else if (__test(begin, "compose")) active |= led_compose; + else if (__test(begin, "compose")) active |= led_compose; #endif - begin = end + 1; - } - - for (begin = end = recv_mask; end != NULL;) - { - end = strchr(begin, ' '); - if (__test(begin, "num")) mask |= led_num_lock; - else if (__test(begin, "caps")) mask |= led_caps_lock; - else if (__test(begin, "scrl")) mask |= led_scrl_lock; + begin = end + 1; + } + + for (begin = end = recv_mask; end;) { + end = strchr(begin, ' '); + if (__test(begin, "num")) mask |= led_num_lock; + else if (__test(begin, "caps")) mask |= led_caps_lock; + else if (__test(begin, "scrl")) mask |= led_scrl_lock; #ifdef LED_COMPOSE - else if (__test(begin, "compose")) mask |= led_compose; + else if (__test(begin, "compose")) mask |= led_compose; #endif - begin = end + 1; - } - + begin = end + 1; + } + #undef __test - - current = (active & mask) | ((current ^ active) & ~mask); - if (set_leds(current) < 0) - { - xperror(*argv); /* Not fatal */ - return 0; - } - - return 0; + + current = (active & mask) | ((current ^ active) & ~mask); + if (set_leds(current) < 0) { + xperror(*argv); /* Not fatal */ + return 0; + } + + return 0; } @@ -961,66 +956,65 @@ int handle_set_keyboard_leds(const char* recv_active, const char* recv_mask, con * @param recv_keyboard The value of the `Keyboard`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_get_keyboard_leds(const char* recv_client_id, const char* recv_message_id, const char* recv_keyboard) +int +handle_get_keyboard_leds(const char *recv_client_id, const char *recv_message_id, const char *recv_keyboard) { - uint32_t msgid; - size_t n; - int r, leds; - - if ((recv_keyboard != NULL) && !strequals(recv_keyboard, KEYBOARD_ID)) - return 0; - - if (recv_keyboard == NULL) - return eprint("received LED reading request but no specified keyboard, ignoring."), 0; - - if (strequals(recv_client_id, "0:0")) - return eprint("received information request from an anonymous client, ignoring."), 0; + uint32_t msgid; + size_t n; + int r, leds, error; - leds = get_leds(); - if (leds < 0) - { - int error = errno; - xperror(*argv); - send_errno(error, recv_client_id, recv_message_id); - fail_if (errno = error, 1); - } - - with_mutex (send_mutex, - msgid = message_id; - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - ); - - n = 65 + 2 * strlen(PRESENT_LEDS); - n += strlen(recv_client_id) + strlen(recv_message_id); - fail_if (ensure_send_buffer_size(n + 1) < 0); - sprintf(send_buffer, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Active:%s%s%s%s%s\n" - "Present: " PRESENT_LEDS "\n" - "\n", - recv_client_id, recv_message_id, msgid, - (leds & led_num_lock) ? " num" : "", - (leds & led_caps_lock) ? " caps" : "", - (leds & led_scrl_lock) ? " scrl" : "", + if (recv_keyboard && !strequals(recv_keyboard, KEYBOARD_ID)) + return 0; + + if (!recv_keyboard) + return eprint("received LED reading request but no specified keyboard, ignoring."), 0; + + if (strequals(recv_client_id, "0:0")) + return eprint("received information request from an anonymous client, ignoring."), 0; + + leds = get_leds(); + if (leds < 0) { + error = errno; + xperror(*argv); + send_errno(error, recv_client_id, recv_message_id); + fail_if (errno = error, 1); + } + + with_mutex (send_mutex, + msgid = message_id; + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + ); + + n = 65 + 2 * strlen(PRESENT_LEDS); + n += strlen(recv_client_id) + strlen(recv_message_id); + fail_if (ensure_send_buffer_size(n + 1) < 0); + sprintf(send_buffer, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Active:%s%s%s%s%s\n" + "Present: " PRESENT_LEDS "\n" + "\n", + recv_client_id, recv_message_id, msgid, + (leds & led_num_lock) ? " num" : "", + (leds & led_caps_lock) ? " caps" : "", + (leds & led_scrl_lock) ? " scrl" : "", #ifdef LED_COMPOSE - (leds & led_compose) ? " compose" : + (leds & led_compose) ? " compose" : #endif - "", - leds == 0 ? " none" : "" - ); - - with_mutex (send_mutex, - r = full_send(send_buffer, strlen(send_buffer)); - if (r) r = errno ? errno : -1; - ); + "", + leds == 0 ? " none" : ""); - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - fail: - xperror(*argv); - return -1; + with_mutex (send_mutex, + r = full_send(send_buffer, strlen(send_buffer)); + if (r) r = errno ? errno : -1; + ); + + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; +fail: + xperror(*argv); + return -1; } @@ -1050,46 +1044,45 @@ static int parse_led(const char* name) * @param position The new position of the LED, either zero-based index * or name of the original LED with that position */ -__attribute__((nonnull)) -static void remap_led(const char* name, const char* position) +static void __attribute__((nonnull)) +remap_led(const char *name, const char *position) { - int* leds[] = { [LED_NUM_LOCK] = &led_num_lock, - [LED_CAPS_LOCK] = &led_caps_lock, + int *leds[] = {[LED_NUM_LOCK] = &led_num_lock, + [LED_CAPS_LOCK] = &led_caps_lock, #ifdef LED_COMPOSE - [LED_COMPOSE] = &led_compose, + [LED_COMPOSE] = &led_compose, #endif - [LED_SCRL_LOCK] = &led_scrl_lock}; - - int led = parse_led(name); - int pos = parse_led(position); - size_t i, n; - char c; - - if (led < 0) - { - eprintf("received invalid LED, %s, to remap, ignoring.", name); - return; - } - - if (pos >= 0) - goto done; - - for (pos = 0, i = 0, n = strlen(position); i < n; i++) - if (c = position[i], ('0' <= c) && (c <= '9')) - pos = pos * 10 + (c & 15); - else - break; - - if (i < n) - { - eprintf("received invalid LED position, %s, ignoring.", position); - return; - } - - pos = 1 << pos; - - done: - *(leds[led]) = pos; + [LED_SCRL_LOCK] = &led_scrl_lock}; + + int led = parse_led(name); + int pos = parse_led(position); + size_t i, n; + char c; + + if (led < 0) { + eprintf("received invalid LED, %s, to remap, ignoring.", name); + return; + } + + if (pos >= 0) + goto done; + + for (pos = 0, i = 0, n = strlen(position); i < n; i++) { + if (c = position[i], ('0' <= c) && (c <= '9')) + pos = pos * 10 + (c & 15); + else + break; + } + + if (i < n) { + eprintf("received invalid LED position, %s, ignoring.", position); + return; + } + + pos = 1 << pos; + +done: + *(leds[led]) = pos; } @@ -1101,20 +1094,20 @@ static void remap_led(const char* name, const char* position) * that position; delimited by an equals-sign * @return Zero on success, -1 on error */ -int remap_led_cmdline(char* arg) +int +remap_led_cmdline(char *arg) { - char* pos = strchr(arg, '='); - - if ((pos == NULL) || (strlen(pos) == 1)) - { - eprintf("received invalid argument for --led: %s", arg); - errno = 0; - return -1; - } - - *pos++ = '\0'; - remap_led(arg, pos); - return 0; + char *pos = strchr(arg, '='); + + if (!pos || strlen(pos) == 1) { + eprintf("received invalid argument for --led: %s", arg); + errno = 0; + return -1; + } + + *pos++ = '\0'; + remap_led(arg, pos); + return 0; } @@ -1125,56 +1118,54 @@ int remap_led_cmdline(char* arg) * @param recv_keyboard The value of the `Keyboard`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_map_keyboard_leds(const char* recv_keyboard) +int +handle_map_keyboard_leds(const char *recv_keyboard) { - char* led = NULL; - char* pos = NULL; - int stage = 0; - size_t i; - - if ((recv_keyboard != NULL) && !strequals(recv_keyboard, KEYBOARD_ID)) - return 0; - - /* Parse the payload. `led` and `pos` are set just when thier first - character is iterated over, rather than at the delimiter. This way - we can easily check for message corruption at the end and give a - better error message. */ - for (i = 0; i < received.payload_size; i++) - if (stage == 0) - { - if (led == NULL) - led = received.payload + i; - if (received.payload[i] == ' ') - received.payload[i] = '\0', stage = 1; - } - else if (stage == 1) - { - if (pos == NULL) - pos = received.payload + i; - if (received.payload[i] == '\n') - { - received.payload[i] = '\0'; - remap_led(led, pos); - led = pos = NULL; - stage = 0; - } - } - if ((stage == 1) && (pos != NULL)) - { - /* Copy over the position value to a new allocation on the stack - and NUL-terminate it. We are at the of the payload and cannot - besure sure that we can put an extra NUL at the end of it - without reallocating the payload which is much ore complicated. */ - size_t len = (size_t)(pos - received.payload); - char* pos_ = alloca((len + 1) * sizeof(char)); - memcpy(pos_, pos, len * sizeof(char)); - pos_[len] = '\0'; - remap_led(led, pos_); - } - else if (led != NULL) - eprint("received incomplete LED remapping instruction, ignoring."); - - return 0; + char *led = NULL; + char *pos = NULL; + int stage = 0; + size_t i, len; + char *pos_; + + if (recv_keyboard && !strequals(recv_keyboard, KEYBOARD_ID)) + return 0; + + /* Parse the payload. `led` and `pos` are set just when thier first + character is iterated over, rather than at the delimiter. This way + we can easily check for message corruption at the end and give a + better error message. */ + for (i = 0; i < received.payload_size; i++) { + if (stage == 0) { + if (led == NULL) + led = received.payload + i; + if (received.payload[i] == ' ') + received.payload[i] = '\0', stage = 1; + } else if (stage == 1) { + if (pos == NULL) + pos = received.payload + i; + if (received.payload[i] == '\n') { + received.payload[i] = '\0'; + remap_led(led, pos); + led = pos = NULL; + stage = 0; + } + } + } + if (stage == 1 && pos) { + /* Copy over the position value to a new allocation on the stack + and NUL-terminate it. We are at the of the payload and cannot + besure sure that we can put an extra NUL at the end of it + without reallocating the payload which is much ore complicated. */ + len = (size_t)(pos - received.payload); + pos_ = alloca((len + 1) * sizeof(char)); + memcpy(pos_, pos, len * sizeof(char)); + pos_[len] = '\0'; + remap_led(led, pos_); + } else if (led) { + eprint("received incomplete LED remapping instruction, ignoring."); + } + + return 0; } @@ -1188,37 +1179,34 @@ int handle_map_keyboard_leds(const char* recv_keyboard) * @param out Output parameter for the keycode's new mapping * @return -1 on error, 1 if parsed, 0 if the line is empty */ -__attribute__((nonnull(1, 4, 5))) -static int parse_remap_line(char* begin, char* end, size_t n, int* restrict in, int* restrict out) +static int __attribute__((nonnull(1, 4, 5))) +parse_remap_line(char *begin, char *end, size_t n, int *restrict in, int *restrict out) { - static char buf[3 * sizeof(int) + 1]; - - size_t len = end == NULL ? n : (size_t)(end - begin); - char* delimiter = memchr(begin, ' ', len); - - if (len == 0) - return 0; - - if (delimiter == NULL) - fail_if (*in = -1, *out = -1); - - *delimiter++ = '\0'; - *in = atoi(begin); - if (end == NULL) - { - snprintf(buf, sizeof(buf) / sizeof(char), "%.*s", - (int)(len - (size_t)(delimiter - begin)), delimiter); - *out = atoi(buf); - } - else - { - *end = '\0'; - *out = atoi(delimiter); - } - - return 1; - fail: - return -1; + static char buf[3 * sizeof(int) + 1]; + + size_t len = !end ? n : (size_t)(end - begin); + char *delimiter = memchr(begin, ' ', len); + + if (!len) + return 0; + + if (!delimiter) + fail_if (*in = -1, *out = -1); + + *delimiter++ = '\0'; + *in = atoi(begin); + if (!end) { + snprintf(buf, sizeof(buf) / sizeof(char), "%.*s", + (int)(len - (size_t)(delimiter - begin)), delimiter); + *out = atoi(buf); + } else { + *end = '\0'; + *out = atoi(delimiter); + } + + return 1; +fail: + return -1; } @@ -1229,27 +1217,28 @@ static int parse_remap_line(char* begin, char* end, size_t n, int* restrict in, * @parma out The keycode's new mapping * @return Zero on success, -1 on error */ -static int add_mapping(int in, int out) +static int +add_mapping(int in, int out) { - size_t n = ((size_t)in) + 1; - int* old; - - if (n > mapping_size) - { - if (in == out) + size_t n = ((size_t)in) + 1; + int *old; + + if (n > mapping_size) { + if (in == out) + return 0; + + old = mapping; + if (xrealloc(mapping, n, int)) + fail_if (mapping = old, 1); + + for (; mapping_size < n; mapping_size++) + mapping[mapping_size] = (int)mapping_size; + } + + mapping[in] = out; return 0; - - if (old = mapping, xrealloc(mapping, n, int)) - fail_if (mapping = old, 1); - - for (; mapping_size < n; mapping_size++) - mapping[mapping_size] = (int)mapping_size; - } - - mapping[in] = out; - return 0; - fail: - return -1; +fail: + return -1; } @@ -1260,45 +1249,44 @@ static int add_mapping(int in, int out) * @param n The size of `table` * @return Zero on success, -1 on error */ -__attribute__((nonnull)) -static int remap(char* table, size_t n) +static int __attribute__((nonnull)) +remap(char *table, size_t n) { - char* begin = table; - int greatest_remap = -1; - int greatest_reset = -1; - - for (;;) - { - char* end = memchr(begin, '\n', n); - int in, out; - - if (!parse_remap_line(begin, end, n, &in, &out)) - goto next; - if ((in < 0) || (out < 0) || ((in | out) >= 0x4000)) - { - eprint("received malformated remapping table."); - goto next; + char *begin = table; + int greatest_remap = -1; + int greatest_reset = -1; + char *end; + int in, out; + + for (;;) { + end = memchr(begin, '\n', n); + + if (!parse_remap_line(begin, end, n, &in, &out)) + goto next; + if (in < 0 || out < 0 || (in | out) >= 0x4000) { + eprint("received malformated remapping table."); + goto next; + } + + if (in != out) greatest_remap = max(greatest_remap, in); + else greatest_reset = max(greatest_reset, in); + + fail_if (add_mapping(in, out) < 0); + + next: + if (!end) + break; + end++; + n -= (size_t)(end - begin); + begin = end; } - - if (in != out) greatest_remap = max(greatest_remap, in); - else greatest_reset = max(greatest_reset, in); - - fail_if (add_mapping(in, out) < 0); - - next: - if (end == NULL) - break; - end++; - n -= (size_t)(end - begin); - begin = end; - } - - if ((greatest_reset > greatest_remap) && (((((size_t)greatest_remap) + 1) >> 1) < mapping_size)) - shrink_map(); - - return 0; - fail: - return -1; + + if (greatest_reset > greatest_remap && ((size_t)greatest_remap + 1) >> 1 < mapping_size) + shrink_map(); + + return 0; +fail: + return -1; } @@ -1309,79 +1297,79 @@ static int remap(char* table, size_t n) * @param recv_message_id The value of the `Message ID`-header * @return Zero on success, -1 on error */ -__attribute__((nonnull)) -static int mapping_query(const char* recv_client_id, const char* recv_message_id) +static int __attribute__((nonnull)) +mapping_query(const char *recv_client_id, const char *recv_message_id) { - size_t top = 64 + 3 * sizeof(size_t), n = 0, off, i; - ssize_t len; - int greatest = 0, r; - uint32_t msgid; - - /* Count the number of non-identity mappings, and - figure out the value of non-identity mapping - with the highest value. */ - for (i = 0; i < mapping_size; i++) - if (mapping[i] != (int)i) - { - greatest = max(greatest, mapping[i]); - n++; - } - /* If the highest source is larger than the - highest targt, that source value will - be highest integer that will be included - the mapping-table. */ - greatest = max(greatest, (int)mapping_size); - /* Calculate an upper bound for the payload. */ - n *= 2 + 2 * (size_t)(greatest > 0x00FF ? 5 : 3); - - /* Ensure that the buffer is large enough for - the message and that `sprintf` will not - write outside it. */ - fail_if (ensure_send_buffer_size(top + n + 2) < 0); - - /* Fetch and increase local message ID. */ - with_mutex (send_mutex, - msgid = message_id; - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - ); - - /* The offset for the payload should fit all - headers and an empty line. */ - off = top + 1; - /* Write all non-identity mappings to the payload. */ - for (i = 0; i < mapping_size; i++) - if (mapping[i] != (int)i) - sprintf(send_buffer + off, "%i %i\n%zn", i, mapping[i], &len), - off += (size_t)len; - /* Calculate the length of the payload. */ - n = (size_t)(off - (top + 1)); - - /* Write the headers, and the empty line after them. */ - sprintf(send_buffer, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Length: %zu\n" - "\n%zn", - recv_client_id, recv_message_id, msgid, n, &len); - top = (size_t)len; - /* Move the headers and the empty line so that they are - juxtaposed with the payload. */ - off -= top; - memmove(send_buffer + off, send_buffer, top * sizeof(char)); - - - /* Send the message. */ - - with_mutex (send_mutex, - r = full_send(send_buffer + off, top + n); - if (r) r = errno ? errno : -1; - ); - - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - fail: - return -1; + size_t top = 64 + 3 * sizeof(size_t), n = 0, off, i; + ssize_t len; + int greatest = 0, r; + uint32_t msgid; + + /* Count the number of non-identity mappings, and + figure out the value of non-identity mapping + with the highest value. */ + for (i = 0; i < mapping_size; i++) { + if (mapping[i] != (int)i) { + greatest = max(greatest, mapping[i]); + n++; + } + } + /* If the highest source is larger than the + highest targt, that source value will + be highest integer that will be included + the mapping-table. */ + greatest = max(greatest, (int)mapping_size); + /* Calculate an upper bound for the payload. */ + n *= 2 + 2 * (size_t)(greatest > 0x00FF ? 5 : 3); + + /* Ensure that the buffer is large enough for + the message and that `sprintf` will not + write outside it. */ + fail_if (ensure_send_buffer_size(top + n + 2) < 0); + + /* Fetch and increase local message ID. */ + with_mutex (send_mutex, + msgid = message_id; + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + ); + + /* The offset for the payload should fit all + headers and an empty line. */ + off = top + 1; + /* Write all non-identity mappings to the payload. */ + for (i = 0; i < mapping_size; i++) + if (mapping[i] != (int)i) + sprintf(send_buffer + off, "%i %i\n%zn", i, mapping[i], &len), + off += (size_t)len; + /* Calculate the length of the payload. */ + n = (size_t)(off - (top + 1)); + + /* Write the headers, and the empty line after them. */ + sprintf(send_buffer, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Length: %zu\n" + "\n%zn", + recv_client_id, recv_message_id, msgid, n, &len); + top = (size_t)len; + /* Move the headers and the empty line so that they are + juxtaposed with the payload. */ + off -= top; + memmove(send_buffer + off, send_buffer, top * sizeof(char)); + + + /* Send the message. */ + + with_mutex (send_mutex, + r = full_send(send_buffer + off, top + n); + if (r) r = errno ? errno : -1; + ); + + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; +fail: + return -1; } @@ -1395,46 +1383,40 @@ static int mapping_query(const char* recv_client_id, const char* recv_message_id * @param recv_keyboard The value of the `Keyboard`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_keycode_map(const char* recv_client_id, const char* recv_message_id, - const char* recv_action, const char* recv_keyboard) +int +handle_keycode_map(const char *recv_client_id, const char *recv_message_id, + const char *recv_action, const char *recv_keyboard) { - int r; - if ((recv_keyboard != NULL) && !strequals(recv_keyboard, KEYBOARD_ID)) - return 0; - - if (recv_action == NULL) - eprint("received keycode map request but without any action, ignoring."); - else if (strequals(recv_action, "remap")) - { - if (received.payload_size == 0) - return eprint("received keycode remap request without a payload, ignoring."), 0; - - with_mutex (mapping_mutex, - r = remap(received.payload, received.payload_size); - if (r) r = errno ? errno : -1; - ); - fail_if (errno = (r == -1 ? 0 : r), r); - } - else if (strequals(recv_action, "reset")) - { - with_mutex (mapping_mutex, - free(mapping); - mapping_size = 0; - ); - } - else if (strequals(recv_action, "query")) - { - if (strequals(recv_client_id, "0:0")) - return eprint("received information request from an anonymous client, ignoring."), 0; - - fail_if (mapping_query(recv_client_id, recv_message_id)); - } - else - eprint("received keycode map request with invalid action, ignoring."); - - return 0; - fail: - return -1; + int r; + if (recv_keyboard && !strequals(recv_keyboard, KEYBOARD_ID)) + return 0; + + if (!recv_action) { + eprint("received keycode map request but without any action, ignoring."); + } else if (strequals(recv_action, "remap")) { + if (!received.payload_size) + return eprint("received keycode remap request without a payload, ignoring."), 0; + with_mutex (mapping_mutex, + r = remap(received.payload, received.payload_size); + if (r) r = errno ? errno : -1; + ); + fail_if (errno = (r == -1 ? 0 : r), r); + } else if (strequals(recv_action, "reset")) { + with_mutex (mapping_mutex, + free(mapping); + mapping_size = 0; + ); + } else if (strequals(recv_action, "query")) { + if (strequals(recv_client_id, "0:0")) + return eprint("received information request from an anonymous client, ignoring."), 0; + fail_if (mapping_query(recv_client_id, recv_message_id)); + } else { + eprint("received keycode map request with invalid action, ignoring."); + } + + return 0; +fail: + return -1; } @@ -1443,16 +1425,17 @@ int handle_keycode_map(const char* recv_client_id, const char* recv_message_id, * * @param signo The signal */ -void signal_all(int signo) +void +signal_all(int signo) { - pthread_t current_thread = pthread_self(); - - if (pthread_equal(current_thread, master_thread) == 0) - pthread_kill(master_thread, signo); - - if (kbd_thread_started) - if (pthread_equal(current_thread, kbd_thread) == 0) - pthread_kill(kbd_thread, signo); + pthread_t current_thread = pthread_self(); + + if (!pthread_equal(current_thread, master_thread)) + pthread_kill(master_thread, signo); + + if (kbd_thread_started) + if (!pthread_equal(current_thread, kbd_thread)) + pthread_kill(kbd_thread, signo); } @@ -1461,34 +1444,35 @@ void signal_all(int signo) * * @return Zero on success, -1 on error */ -int open_leds(void) +int +open_leds(void) { #ifdef __sparc__ - fail_if ((ledfd = open(SPARC_KBD, O_RDONLY)) < 0); - if (ioctl(ledfd, GET_LED, &saved_leds) < 0) - { - xclose(ledfd); - fail_if (1); - } - return 0; + fail_if ((ledfd = open(SPARC_KBD, O_RDONLY)) < 0); + if (ioctl(ledfd, GET_LED, &saved_leds) < 0) { + xclose(ledfd); + fail_if (1); + } + return 0; #else - fail_if (ioctl(ledfd, GET_LED, &saved_leds)); + fail_if (ioctl(ledfd, GET_LED, &saved_leds)); #endif - return 0; - fail: - return -1; + return 0; +fail: + return -1; } /** * Release access of the keyboard's LED:s */ -void close_leds(void) +void +close_leds(void) { - if (ioctl(ledfd, SET_LED, saved_leds) < 0) - xperror(*argv); + if (ioctl(ledfd, SET_LED, saved_leds) < 0) + xperror(*argv); #ifdef __sparc__ - xclose(ledfd); + xclose(ledfd); #endif } @@ -1498,16 +1482,17 @@ void close_leds(void) * * @return Active LED:s, -1 on error */ -int get_leds(void) +int +get_leds(void) { - int leds; - fail_if (ioctl(ledfd, GET_LED, &leds) < 0); + int leds; + fail_if (ioctl(ledfd, GET_LED, &leds) < 0); #ifdef __sparc__ - leds &= 15; + leds &= 15; #endif - return leds; - fail: - return -1; + return leds; +fail: + return -1; } @@ -1517,12 +1502,13 @@ int get_leds(void) * @param leds Active LED:s * @return Zero on success, -1 on error */ -int set_leds(int leds) +int +set_leds(int leds) { - fail_if (ioctl(ledfd, SET_LED, leds)); - return 0; - fail: - return -1; + fail_if (ioctl(ledfd, SET_LED, leds)); + return 0; +fail: + return -1; } @@ -1531,35 +1517,37 @@ int set_leds(int leds) * * @return Zero on success, -1 on error */ -int open_input(void) +int +open_input(void) { - struct termios stty; - if (tcgetattr(STDIN_FILENO, &saved_stty) < 0) - return -1; - stty = saved_stty; - stty.c_lflag &= (tcflag_t)~(ECHO | ICANON | ISIG); - stty.c_iflag = 0; - fail_if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty) < 0); - /* K_MEDIUMRAW: utilise keyboard drivers, but not layout */ - if ((ioctl(STDIN_FILENO, KDGKBMODE, &saved_kbd_mode) < 0) || - (ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW) < 0)) - fail_if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty)); - return 0; - fail: - xperror(*argv); - return -1; + struct termios stty; + if (tcgetattr(STDIN_FILENO, &saved_stty) < 0) + return -1; + stty = saved_stty; + stty.c_lflag &= (tcflag_t)~(ECHO | ICANON | ISIG); + stty.c_iflag = 0; + fail_if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty) < 0); + /* K_MEDIUMRAW: utilise keyboard drivers, but not layout */ + if ((ioctl(STDIN_FILENO, KDGKBMODE, &saved_kbd_mode) < 0) || + (ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW) < 0)) + fail_if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty)); + return 0; +fail: + xperror(*argv); + return -1; } /** * Release access of keyboard input */ -void close_input(void) +void +close_input(void) { - if (ioctl(STDIN_FILENO, KDSKBMODE, saved_kbd_mode) < 0) - xperror(*argv); - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty) < 0) - xperror(*argv); + if (ioctl(STDIN_FILENO, KDSKBMODE, saved_kbd_mode) < 0) + xperror(*argv); + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty) < 0) + xperror(*argv); } @@ -1570,60 +1558,61 @@ void close_input(void) * @param trio Whether the scancode has three integers rather than one * @return Zero on success, -1 on error */ -int send_key(int* restrict scancode, int trio) +int +send_key(int *restrict scancode, int trio) { - int r, keycode, released = (scancode[0] & 0x80) == 0x80; - uint32_t msgid; - scancode[0] &= 0x7F; - if (trio) - { - keycode = (scancode[1] &= 0x7F) << 7; - keycode |= (scancode[2] &= 0x7F); - } - else - keycode = scancode[0]; - - with_mutex (mapping_mutex, - if ((size_t)keycode < mapping_size) - keycode = mapping[keycode]; - ); - - with_mutex (send_mutex, - msgid = message_id; - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - ); - - if (trio) - sprintf(key_send_buffer, - "Command: key-sent\n" - "Scancode: %i %i %i\n" - "Keycode: %i\n" - "Released: %s\n" - "Keyboard: " KEYBOARD_ID "\n" - "Message ID: %" PRIu32 "\n" - "\n", - scancode[0], scancode[1], scancode[2], keycode, - released ? "yes" : "no", msgid); - else - sprintf(key_send_buffer, - "Command: key-sent\n" - "Scancode: %i\n" - "Keycode: %i\n" - "Released: %s\n" - "Keyboard: " KEYBOARD_ID "\n" - "Message ID: %" PRIu32 "\n" - "\n", - scancode[0], keycode, - released ? "yes" : "no", msgid); - - with_mutex (send_mutex, - r = full_send(key_send_buffer, strlen(key_send_buffer)); - if (r) r = errno ? errno : 0; - ); - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - fail: - return -1; + int r, keycode, released = (scancode[0] & 0x80) == 0x80; + uint32_t msgid; + scancode[0] &= 0x7F; + if (trio) { + keycode = (scancode[1] &= 0x7F) << 7; + keycode |= (scancode[2] &= 0x7F); + } else { + keycode = scancode[0]; + } + + with_mutex (mapping_mutex, + if ((size_t)keycode < mapping_size) + keycode = mapping[keycode]; + ); + + with_mutex (send_mutex, + msgid = message_id; + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + ); + + if (trio) { + sprintf(key_send_buffer, + "Command: key-sent\n" + "Scancode: %i %i %i\n" + "Keycode: %i\n" + "Released: %s\n" + "Keyboard: " KEYBOARD_ID "\n" + "Message ID: %" PRIu32 "\n" + "\n", + scancode[0], scancode[1], scancode[2], keycode, + released ? "yes" : "no", msgid); + } else { + sprintf(key_send_buffer, + "Command: key-sent\n" + "Scancode: %i\n" + "Keycode: %i\n" + "Released: %s\n" + "Keyboard: " KEYBOARD_ID "\n" + "Message ID: %" PRIu32 "\n" + "\n", + scancode[0], keycode, + released ? "yes" : "no", msgid); + } + + with_mutex (send_mutex, + r = full_send(key_send_buffer, strlen(key_send_buffer)); + if (r) r = errno ? errno : 0; + ); + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; +fail: + return -1; } @@ -1632,75 +1621,67 @@ int send_key(int* restrict scancode, int trio) * * @return Zero on success, -1 on error */ -int fetch_keys(void) +int +fetch_keys(void) { #ifdef DEBUG - int consecutive_escapes = 0; + int consecutive_escapes = 0; #endif - int c; - ssize_t r; - - for (;;) - { - r = read(STDIN_FILENO, &c, sizeof(int)); - if (r <= 0) - { - if (r == 0) - { - raise(SIGTERM); - errno = 0; - } - break; - } - + int c; + ssize_t r; + + for (;;) { + r = read(STDIN_FILENO, &c, sizeof(int)); + if (r <= 0) { + if (!r) { + raise(SIGTERM); + errno = 0; + } + break; + } + #ifdef DEBUG - if ((c & 0x7F) == 1) /* Exit with ESCAPE, ESCAPE, ESCAPE */ - { - if (++consecutive_escapes >= 2 * 3) - { - raise(SIGTERM); - errno = 0; - break; - } - } - else - consecutive_escapes = 0; + if ((c & 0x7F) == 1) { /* Exit with ESCAPE, ESCAPE, ESCAPE */ + if (++consecutive_escapes >= 2 * 3) { + raise(SIGTERM); + errno = 0; + break; + } + } else { + consecutive_escapes = 0; + } #endif - - redo: - scancode_buf[scancode_ptr] = c; - if (scancode_ptr == 0) - { - if ((c & 0x7F) == 0) - scancode_ptr++; - else - send_key(scancode_buf, 0); - } - else if (scancode_ptr == 1) - { - if ((c & 0x80) == 0) - { - scancode_ptr = 0; - goto redo; - } - scancode_ptr++; - } - else - { - scancode_ptr = 0; - if ((c & 0x80) == 0) - { - send_key(scancode_buf + 1, 0); - goto redo; - } - send_key(scancode_buf, 1); + + redo: + scancode_buf[scancode_ptr] = c; + switch (scancode_ptr) { + case 0: + if (!(c & 0x7F)) + scancode_ptr++; + else + send_key(scancode_buf, 0); + break; + case 1: + if (!(c & 0x80)) { + scancode_ptr = 0; + goto redo; + } + scancode_ptr++; + break; + default: + scancode_ptr = 0; + if (!(c & 0x80)) { + send_key(scancode_buf + 1, 0); + goto redo; + } + send_key(scancode_buf, 1); + } } - } - - fail_if (errno); - return 0; - fail: - return -1; + + fail_if (errno); + return 0; +fail: + return -1; } @@ -1712,56 +1693,54 @@ int fetch_keys(void) * @param recv_message_id The message ID of the message the client sent * @return Zero on success, -1 on error */ -int send_errno(int error, const char* recv_client_id, const char* recv_message_id) +int +send_errno(int error, const char *recv_client_id, const char *recv_message_id) { - int r; - with_mutex (send_mutex, - r = send_error(recv_client_id, recv_message_id, "get-keyboard-leds", - 0, error, NULL, &send_buffer, &send_buffer_size, - message_id, socket_fd); - message_id = message_id == INT32_MAX ? 0 : (message_id + 1); - if (r) r = errno ? errno : -1; - ); - fail_if (errno = (r == -1 ? 0 : r), r); - return 0; - fail: - return -1; + int r; + with_mutex (send_mutex, + r = send_error(recv_client_id, recv_message_id, "get-keyboard-leds", + 0, error, NULL, &send_buffer, &send_buffer_size, + message_id, socket_fd); + message_id = message_id == INT32_MAX ? 0 : (message_id + 1); + if (r) r = errno ? errno : -1; + ); + fail_if (errno = (r == -1 ? 0 : r), r); + return 0; +fail: + return -1; } /** * Attempt to shrink `mapping` */ -void shrink_map(void) +void +shrink_map(void) { - size_t i, greatest_mapping = 0; - int* old; - - for (i = mapping_size; i > 0; i--) - if (mapping[i] != (int)i) - { - greatest_mapping = i; - break; - } - - if (greatest_mapping == 0) - { - if (mapping[0] == 0) - { - free(mapping); - mapping_size = 0; + size_t i, greatest_mapping = 0; + int* old; + + for (i = mapping_size; i > 0; i--) { + if (mapping[i] != (int)i) { + greatest_mapping = i; + break; + } } - } - else if (greatest_mapping + 1 < mapping_size) - { - if (old = mapping, xrealloc(mapping, greatest_mapping + 1, int)) - { - mapping = old; - xperror(*argv); + + if (!greatest_mapping) { + if (!*mapping) { + free(mapping); + mapping_size = 0; + } + } else if (greatest_mapping + 1 < mapping_size) { + old = mapping; + if (xrealloc(mapping, greatest_mapping + 1, int)) { + mapping = old; + xperror(*argv); + } else { + mapping_size = greatest_mapping + 1; + } } - else - mapping_size = greatest_mapping + 1; - } } /** @@ -1771,25 +1750,25 @@ void shrink_map(void) * * @param signo The signal that has been received */ -void received_info(int signo) +void +received_info(int signo) { - SIGHANDLER_START; - size_t i; - (void) signo; - iprintf("next message ID: %" PRIu32, message_id); - iprintf("connected: %s", connected ? "yes" : "no"); - iprintf("LED FD: %i", ledfd); - iprintf("saved LED:s: %i", saved_leds); - iprintf("scancode buffer: %i, %i, %i", scancode_buf[0], scancode_buf[1], scancode_buf[2]); - iprintf("scancode buffer pointer: %i", scancode_ptr); - iprintf("saved keyboard mode: %i", saved_kbd_mode); - iprintf("send buffer size: %zu bytes", send_buffer_size); - iprintf("keyboard thread started: %s", kbd_thread_started ? "yes" : "no"); - iprintf("keycode remapping tabel size: %zu", mapping_size); - iprint("keycode remapping tabel:"); - for (i = 0; i < mapping_size; i++) - if ((int)i != mapping[i]) - iprintf(" %zu -> %i", i, mapping[i]); - SIGHANDLER_END; + SIGHANDLER_START; + size_t i; + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + iprintf("LED FD: %i", ledfd); + iprintf("saved LED:s: %i", saved_leds); + iprintf("scancode buffer: %i, %i, %i", scancode_buf[0], scancode_buf[1], scancode_buf[2]); + iprintf("scancode buffer pointer: %i", scancode_ptr); + iprintf("saved keyboard mode: %i", saved_kbd_mode); + iprintf("send buffer size: %zu bytes", send_buffer_size); + iprintf("keyboard thread started: %s", kbd_thread_started ? "yes" : "no"); + iprintf("keycode remapping tabel size: %zu", mapping_size); + iprint("keycode remapping tabel:"); + for (i = 0; i < mapping_size; i++) + if ((int)i != mapping[i]) + iprintf(" %zu -> %i", i, mapping[i]); + SIGHANDLER_END; + (void) signo; } - diff --git a/src/mds-kkbd.h b/src/mds-kkbd.h index 750dbfe..c5498bc 100644 --- a/src/mds-kkbd.h +++ b/src/mds-kkbd.h @@ -28,7 +28,7 @@ * @param data Input data * @return Output data */ -void* keyboard_loop(void* data); +void *keyboard_loop(void *data); /** * Handle the received message @@ -47,8 +47,8 @@ int handle_message(void); * @return Zero on success, -1 on error */ __attribute__((nonnull(1, 2))) -int handle_enumerate_keyboards(const char* recv_client_id, const char* recv_message_id, - const char* recv_modify_id); +int handle_enumerate_keyboards(const char *recv_client_id, const char *recv_message_id, + const char *recv_modify_id); /** * Handle the received message after it has been @@ -57,7 +57,7 @@ int handle_enumerate_keyboards(const char* recv_client_id, const char* recv_mess * @param recv_modify_id The value of the `Modify ID`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_keyboard_enumeration(const char* recv_modify_id); +int handle_keyboard_enumeration(const char *recv_modify_id); /** * Handle the received message after it has been @@ -68,7 +68,7 @@ int handle_keyboard_enumeration(const char* recv_modify_id); * @param recv_keyboard The value of the `Keyboard`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_set_keyboard_leds(const char* recv_active, const char* recv_mask, const char* recv_keyboard); +int handle_set_keyboard_leds(const char *recv_active, const char *recv_mask, const char *recv_keyboard); /** * Handle the received message after it has been @@ -80,7 +80,7 @@ int handle_set_keyboard_leds(const char* recv_active, const char* recv_mask, con * @return Zero on success, -1 on error */ __attribute__((nonnull(1, 2))) -int handle_get_keyboard_leds(const char* recv_client_id, const char* recv_message_id, const char* recv_keyboard); +int handle_get_keyboard_leds(const char *recv_client_id, const char *recv_message_id, const char *recv_keyboard); /** * Handle the received message after it has been @@ -89,7 +89,7 @@ int handle_get_keyboard_leds(const char* recv_client_id, const char* recv_messag * @param recv_keyboard The value of the `Keyboard`-header, `NULL` if omitted * @return Zero on success, -1 on error */ -int handle_map_keyboard_leds(const char* recv_keyboard); +int handle_map_keyboard_leds(const char *recv_keyboard); /** * Handle the received message after it has been @@ -102,8 +102,8 @@ int handle_map_keyboard_leds(const char* recv_keyboard); * @return Zero on success, -1 on error */ __attribute__((nonnull(1, 2))) -int handle_keycode_map(const char* recv_client_id, const char* recv_message_id, - const char* recv_action, const char* recv_keyboard); +int handle_keycode_map(const char *recv_client_id, const char *recv_message_id, + const char *recv_action, const char *recv_keyboard); /** * Remap a LED, from the command line @@ -114,7 +114,7 @@ int handle_keycode_map(const char* recv_client_id, const char* recv_message_id, * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int remap_led_cmdline(char* arg); +int remap_led_cmdline(char *arg); /** * Acquire access of the keyboard's LED:s @@ -163,7 +163,7 @@ void close_input(void); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int send_key(int* restrict scancode, int trio); +int send_key(int *restrict scancode, int trio); /** * Fetch and broadcast keys until interrupted @@ -181,7 +181,7 @@ int fetch_keys(void); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int send_errno(int error, const char* recv_client_id, const char* recv_message_id); +int send_errno(int error, const char *recv_client_id, const char *recv_message_id); /** * Attempt to shrink `mapping` @@ -190,4 +190,3 @@ void shrink_map(void); #endif - diff --git a/src/mds-libinput.c b/src/mds-libinput.c index cd87e72..76bfb5e 100644 --- a/src/mds-libinput.c +++ b/src/mds-libinput.c @@ -32,7 +32,7 @@ -#define MDS_LIBINPUT_VARS_VERSION 0 +#define MDS_LIBINPUT_VARS_VERSION 0 @@ -42,15 +42,14 @@ * * This tells the server-base how to behave */ -server_characteristics_t server_characteristics = - { - .require_privileges = 1, - .require_display = 1, - .require_respawn_info = 0, - .sanity_check_argc = 1, - .fork_for_safety = 0, - .danger_is_deadly = 0 - }; +server_characteristics_t server_characteristics = { + .require_privileges = 1, + .require_display = 1, + .require_respawn_info = 0, + .sanity_check_argc = 1, + .fork_for_safety = 0, + .danger_is_deadly = 0 +}; @@ -82,12 +81,12 @@ static struct libinput* li = NULL; /** * udev context */ -static struct udev* udev = NULL; +static struct udev *udev = NULL; /** * List of all opened devices */ -static struct libinput_device** devices = NULL; +static struct libinput_device **devices = NULL; /** * The number of element slots allocated for `devices` @@ -117,7 +116,7 @@ static volatile sig_atomic_t ev_thread_started = 0; /** * Message buffer for the main thread */ -static char* resp_send_buffer = NULL; +static char *resp_send_buffer = NULL; /** * The size of `resp_send_buffer` @@ -127,7 +126,7 @@ static size_t resp_send_buffer_size = 0; /** * Message buffer for the event thread */ -static char* anno_send_buffer = NULL; +static char *anno_send_buffer = NULL; /** * The size of `anno_send_buffer` @@ -176,8 +175,8 @@ static pthread_mutex_t dev_mutex; * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** @@ -185,48 +184,46 @@ static pthread_mutex_t dev_mutex; * * @return Non-zero on error */ -int parse_cmdline(void) +int +parse_cmdline(void) { - int i; - - /* 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; + int i, v; + char *arg; + + /* Parse command line arguments. */ + for (i = 1; i < argc; i++) { + arg = argv[i]; + 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 (strequals(arg, "--re-exec")) { /* Re-exec state-marshal. */ + is_reexec = 1; + } else if (startswith(arg, "--alarm=")) { /* Schedule an alarm signal for forced abort. */ + alarm(min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ + } else if (strequals(arg, "--on-init-fork")) { /* Fork process when initialised. */ + on_init_fork = 1; + } else if (startswith(arg, "--on-init-sh=")) { /* Run a command when initialised. */ + on_init_sh = arg + strlen("--on-init-sh="); + } else if (strequals(arg, "--immortal")) { /* I return to serve. */ + is_immortal = 1; + } else if (startswith(arg, "--seat=")) { /* Seat to pass to libinput. */ + seat = arg + strlen("--seat="); + } } - else if (strequals(arg, "--re-exec")) /* Re-exec state-marshal. */ - is_reexec = 1; - else if (startswith(arg, "--alarm=")) /* Schedule an alarm signal for forced abort. */ - alarm(min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ - else if (strequals(arg, "--on-init-fork")) /* Fork process when initialised. */ - on_init_fork = 1; - else if (startswith(arg, "--on-init-sh=")) /* Run a command when initialised. */ - on_init_sh = arg + strlen("--on-init-sh="); - else if (strequals(arg, "--immortal")) /* I return to serve. */ - is_immortal = 1; - else if (startswith(arg, "--seat=")) /* Seat to pass to libinput. */ - seat = arg + strlen("--seat="); - } - if (is_reexec) - { - is_respawn = 1; - eprint("re-exec performed."); - } - - /* Check that mandatory arguments have been specified. */ - if (server_characteristics.require_respawn_info) - exit_if (is_respawn < 0, - eprintf("missing state argument, require either %s or %s.", - "--initial-spawn", "--respawn");); - return 0; + if (is_reexec) { + is_respawn = 1; + eprint("re-exec performed."); + } + + /* Check that mandatory arguments have been specified. */ + if (server_characteristics.require_respawn_info) + exit_if (is_respawn < 0, + eprintf("missing state argument, require either %s or %s.", + "--initial-spawn", "--respawn");); + return 0; } @@ -236,9 +233,10 @@ int parse_cmdline(void) * * @return Non-zero on error */ -int __attribute__((const)) preinitialise_server(void) +int __attribute__((const)) +preinitialise_server(void) { - return 0; + return 0; } @@ -248,18 +246,19 @@ int __attribute__((const)) preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +int +initialise_server(void) { - int stage = 0; - fail_if (server_initialised()); - fail_if (mds_message_initialise(&received)); stage++; - - return 0; - - fail: - xperror(*argv); - if (stage >= 1) mds_message_destroy(&received); - return 1; + int stage = 0; + fail_if (server_initialised()); + fail_if (mds_message_initialise(&received)); stage++; + + return 0; + +fail: + xperror(*argv); + if (stage >= 1) mds_message_destroy(&received); + return 1; } @@ -269,23 +268,24 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - int stage = 0; - fail_if (initialise_libinput()); - fail_if (pthread_mutex_init(&dev_mutex, NULL)); stage++; - - if (connected) - return 0; - - fail_if (reconnect_to_display()); - connected = 1; - return 0; - fail: - terminate_libinput(); - mds_message_destroy(&received); - if (stage >= 1) pthread_mutex_destroy(&dev_mutex); - return 1; + int stage = 0; + fail_if (initialise_libinput()); + fail_if (pthread_mutex_init(&dev_mutex, NULL)); stage++; + + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; +fail: + terminate_libinput(); + mds_message_destroy(&received); + if (stage >= 1) pthread_mutex_destroy(&dev_mutex); + return 1; } @@ -297,11 +297,12 @@ int postinitialise_server(void) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t rc = 2 * sizeof(int) + sizeof(uint32_t); - rc += mds_message_marshal_size(&received); - return rc; + size_t rc = 2 * sizeof(int) + sizeof(uint32_t); + rc += mds_message_marshal_size(&received); + return rc; } @@ -311,15 +312,16 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - buf_set_next(state_buf, int, MDS_LIBINPUT_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; + buf_set_next(state_buf, int, MDS_LIBINPUT_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; } @@ -333,19 +335,20 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - /* buf_get_next(state_buf, int, MDS_LIBINPUT_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; + /* buf_get_next(state_buf, int, MDS_LIBINPUT_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; } @@ -355,9 +358,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } @@ -366,16 +370,17 @@ int __attribute__((const)) reexec_failure_recover(void) * * @param signo The signal */ -void signal_all(int signo) +void +signal_all(int signo) { - pthread_t current_thread = pthread_self(); - - if (pthread_equal(current_thread, master_thread) == 0) - pthread_kill(master_thread, signo); + pthread_t current_thread = pthread_self(); - if (ev_thread_started) - if (pthread_equal(current_thread, ev_thread) == 0) - pthread_kill(ev_thread, signo); + if (!pthread_equal(current_thread, master_thread)) + pthread_kill(master_thread, signo); + + if (ev_thread_started) + if (!pthread_equal(current_thread, ev_thread)) + pthread_kill(ev_thread, signo); } @@ -386,17 +391,17 @@ void signal_all(int signo) * * @param signo The signal that has been received */ -void received_danger(int signo) +void +received_danger(int signo) { - SIGHANDLER_START; - (void) signo; - if ((danger == 0) || (ev_danger == 0)) - { - danger = 1; - ev_danger = 1; - eprint("danger signal received."); - } - SIGHANDLER_END; + SIGHANDLER_START; + if (!danger || !ev_danger) { + danger = 1; + ev_danger = 1; + eprint("danger signal received."); + } + SIGHANDLER_END; + (void) signo; } @@ -405,64 +410,62 @@ void received_danger(int signo) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - int rc = 1, joined = 0, r; - void* ev_ret; - - /* Start thread that reads input events. */ - fail_if ((errno = pthread_create(&ev_thread, NULL, event_loop, NULL))); + int rc = 1, joined = 0, r; + void *ev_ret; - /* Listen for messages. */ - while (!reexecing && !terminating) - { - if (info) - dump_info(); - if (danger) - { - danger = 0; - free(resp_send_buffer), resp_send_buffer = NULL; - resp_send_buffer_size = 0; - pack_devices(); - } - - 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; + /* Start thread that reads input events. */ + fail_if ((errno = pthread_create(&ev_thread, NULL, event_loop, NULL))); + + /* Listen for messages. */ + while (!reexecing && !terminating) { + if (info) + dump_info(); + if (danger) { + danger = 0; + free(resp_send_buffer), resp_send_buffer = NULL; + resp_send_buffer_size = 0; + pack_devices(); + } + + if (!(r = mds_message_read(&received, socket_fd))) + if (!(r = handle_message())) + 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; } - 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; - } - - joined = 1; - fail_if ((errno = pthread_join(ev_thread, &ev_ret))); - rc = ev_ret == NULL ? 0 : 1; - goto done; - fail: - xperror(*argv); - done: - free(resp_send_buffer); - if (!joined && (errno = pthread_join(ev_thread, NULL))) - xperror(*argv); - if (!rc && reexecing) - return 0; - mds_message_destroy(&received); - terminate_libinput(); - return rc; + + joined = 1; + fail_if ((errno = pthread_join(ev_thread, &ev_ret))); + rc = ev_ret == NULL ? 0 : 1; + goto done; +fail: + xperror(*argv); +done: + free(resp_send_buffer); + if (!joined && (errno = pthread_join(ev_thread, NULL))) + xperror(*argv); + if (!rc && reexecing) + return 0; + mds_message_destroy(&received); + terminate_libinput(); + return rc; } @@ -472,39 +475,36 @@ int master_loop(void) * @param data Input data * @return Output data */ -void* event_loop(void* data) +void *event_loop(void *data) { - (void) data; - - ev_thread_started = 1; - - if (handle_event() < 0) - fail_if (errno != EINTR); - while (!reexecing && !terminating) - { - if (ev_danger) - { - ev_danger = 0; - free(anno_send_buffer), anno_send_buffer = NULL; - anno_send_buffer_size = 0; - } - - FD_SET(event_fd, &event_fd_set); - if (select(event_fd + 1, &event_fd_set, NULL, NULL, NULL) < 0) - { - fail_if (errno != EINTR); - continue; + ev_thread_started = 1; + + if (handle_event() < 0) + fail_if (errno != EINTR); + while (!reexecing && !terminating) { + if (ev_danger) { + ev_danger = 0; + free(anno_send_buffer); + anno_send_buffer = NULL; + anno_send_buffer_size = 0; + } + + FD_SET(event_fd, &event_fd_set); + if (select(event_fd + 1, &event_fd_set, NULL, NULL, NULL) < 0) { + fail_if (errno != EINTR); + continue; + } + if (handle_event() < 0) + fail_if (errno != EINTR); } - if (handle_event() < 0) - fail_if (errno != EINTR); - } - - return NULL; - - fail: - xperror(*argv); - raise(SIGTERM); - return (void*)1024; + + return NULL; + +fail: + xperror(*argv); + raise(SIGTERM); + return (void*)1024; + (void) data; } @@ -513,22 +513,23 @@ void* event_loop(void* data) * * @return Zero on success, -1 on error */ -int handle_event(void) +int +handle_event(void) { - struct libinput_event* ev; - if ((errno = -libinput_dispatch(li))) - return -1; - while ((ev = libinput_get_event(li))) { - switch (libinput_event_get_type(ev)) { - /* TODO */ - default: - break; - } - libinput_event_destroy(ev); - if ((errno = -libinput_dispatch(li))) - return -1; - } - return 0; + struct libinput_event* ev; + if ((errno = -libinput_dispatch(li))) + return -1; + while ((ev = libinput_get_event(li))) { + switch (libinput_event_get_type(ev)) { + /* TODO */ + default: + break; + } + libinput_event_destroy(ev); + if ((errno = -libinput_dispatch(li))) + return -1; + } + return 0; } @@ -537,10 +538,11 @@ int handle_event(void) * * @return Zero on success, -1 on error */ -int handle_message(void) +int +handle_message(void) { - /* TODO */ - return 0; + /* TODO */ + return 0; } @@ -552,13 +554,14 @@ int handle_message(void) * @param userdata Not used * @return The file descriptor, or `-errno` on error */ -int open_restricted(const char* path, int flags, void* userdata) +int +open_restricted(const char *path, int flags, void *userdata) { - int fd = open(path, flags); - if (fd < 0) - return perror(*argv), -errno; - return fd; - (void) userdata; + int fd = open(path, flags); + if (fd < 0) + return perror(*argv), -errno; + return fd; + (void) userdata; } @@ -568,10 +571,11 @@ int open_restricted(const char* path, int flags, void* userdata) * @param fd The file descriptor of the device * @param userdata Not used */ -void close_restricted(int fd, void* userdata) +void +close_restricted(int fd, void *userdata) { - close(fd); - (void) userdata; + close(fd); + (void) userdata; } @@ -580,37 +584,41 @@ void close_restricted(int fd, void* userdata) * * @return Zero on success, -1 on error */ -int initialise_libinput(void) +int +initialise_libinput(void) { - const struct libinput_interface interface = { - .open_restricted = open_restricted, - .close_restricted = close_restricted - }; - - if (!(udev = udev_new())) - return eprint("failed to initialize udev."), errno = 0, -1; - if (!(li = libinput_udev_create_context(&interface, NULL, udev))) - return eprint("failed to initialize context from udev."), errno = 0, -1; - if (libinput_udev_assign_seat(li, seat)) - return eprintf("failed to set seat: %s", seat), errno = 0, -1; - - event_fd = libinput_get_fd(li); - FD_ZERO(&event_fd_set); - - return 0; + const struct libinput_interface interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted + }; + + if (!(udev = udev_new())) + return eprint("failed to initialize udev."), errno = 0, -1; + if (!(li = libinput_udev_create_context(&interface, NULL, udev))) + return eprint("failed to initialize context from udev."), errno = 0, -1; + if (libinput_udev_assign_seat(li, seat)) + return eprintf("failed to set seat: %s", seat), errno = 0, -1; + + event_fd = libinput_get_fd(li); + FD_ZERO(&event_fd_set); + + return 0; } /** * Release access of input devices */ -void terminate_libinput(void) +void +terminate_libinput(void) { - while (devices_used--) - if (devices[devices_used]) - libinput_device_unref(devices[devices_used]); - if (li) libinput_unref(li); - if (udev) udev_unref(udev); + while (devices_used--) + if (devices[devices_used]) + libinput_device_unref(devices[devices_used]); + if (li) + libinput_unref(li); + if (udev) + udev_unref(udev); } @@ -620,21 +628,21 @@ void terminate_libinput(void) * @param dev The device * @return Zero on success, -1 on error */ -int add_device(struct libinput_device* dev) +int +add_device(struct libinput_device *dev) { - if (devices_ptr == devices_size) - { - struct libinput_device** tmp; - if (yrealloc(tmp, devices, devices_size + 10, struct libinput_device*)) - return -1; - devices_size += 10; - } - - devices[devices_ptr++] = libinput_device_ref(dev); - while ((devices_ptr < devices_used) && devices[devices_ptr]) - devices_ptr++; - - return 0; + struct libinput_device **tmp; + if (devices_ptr == devices_size) { + if (yrealloc(tmp, devices, devices_size + 10, struct libinput_device*)) + return -1; + devices_size += 10; + } + + devices[devices_ptr++] = libinput_device_ref(dev); + while (devices_ptr < devices_used && devices[devices_ptr]) + devices_ptr++; + + return 0; } @@ -643,48 +651,47 @@ int add_device(struct libinput_device* dev) * * @param dev The device */ -void remove_device(struct libinput_device* dev) +void +remove_device(struct libinput_device *dev) { - size_t i; - - for (i = 0; i < devices_used; i++) - if (devices[i] == dev) - { - libinput_device_unref(dev); - devices[i] = NULL; - if (i < devices_ptr) - devices_ptr = i; - if (i + 1 == devices_used) - devices_used -= 1; - break; - } + size_t i; + for (i = 0; i < devices_used; i++) { + if (devices[i] == dev) { + libinput_device_unref(dev); + devices[i] = NULL; + if (i < devices_ptr) + devices_ptr = i; + if (i + 1 == devices_used) + devices_used -= 1; + break; + } + } } /** * Pack the device list */ -void pack_devices(void) +void +pack_devices(void) { - size_t i; - - for (i = devices_ptr = 0; i < devices_used; i++) - if (devices[i]) - devices[devices_ptr++] = devices[i]; - devices_used = devices_ptr; + struct libinput_device **tmp; + size_t i; - if (devices_used) - { - struct libinput_device** tmp; - if (yrealloc(tmp, devices, devices_used, struct libinput_device*)) - return; - devices_size = devices_used; - } - else - { - free(devices), devices = NULL; - devices_size = 0; - } + for (i = devices_ptr = 0; i < devices_used; i++) + if (devices[i]) + devices[devices_ptr++] = devices[i]; + devices_used = devices_ptr; + + if (devices_used) { + if (yrealloc(tmp, devices, devices_used, struct libinput_device *)) + return; + devices_size = devices_used; + } else { + free(devices); + devices = NULL; + devices_size = 0; + } } @@ -695,30 +702,31 @@ void pack_devices(void) * * @param signo The signal that has been received */ -void received_info(int signo) +void +received_info(int signo) { - SIGHANDLER_START; - (void) signo; - info = 1; - SIGHANDLER_END; + SIGHANDLER_START; + info = 1; + SIGHANDLER_END; + (void) signo; } /** * The the state of the server */ -void dump_info(void) +void +dump_info(void) { - info = 1; - iprintf("next message ID: %" PRIu32, message_id); - iprintf("connected: %s", connected ? "yes" : "no"); - iprintf("libinput seat: %s", seat); - iprintf("sigdanger pending (main): %s", danger ? "yes" : "no"); - iprintf("sigdanger pending (event): %s", ev_danger ? "yes" : "no"); - iprintf("response send buffer size: %zu bytes", resp_send_buffer_size); - iprintf("announce send buffer size: %zu bytes", anno_send_buffer_size); - iprintf("event file descriptor: %i", event_fd); - iprintf("event thread started: %s", ev_thread_started ? "yes" : "no"); - /* TODO list devices -- with_mutex(dev_mutex, ); */ + info = 1; + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + iprintf("libinput seat: %s", seat); + iprintf("sigdanger pending (main): %s", danger ? "yes" : "no"); + iprintf("sigdanger pending (event): %s", ev_danger ? "yes" : "no"); + iprintf("response send buffer size: %zu bytes", resp_send_buffer_size); + iprintf("announce send buffer size: %zu bytes", anno_send_buffer_size); + iprintf("event file descriptor: %i", event_fd); + iprintf("event thread started: %s", ev_thread_started ? "yes" : "no"); + /* TODO list devices -- with_mutex(dev_mutex, ); */ } - diff --git a/src/mds-libinput.h b/src/mds-libinput.h index 64032fd..9c6dabe 100644 --- a/src/mds-libinput.h +++ b/src/mds-libinput.h @@ -32,7 +32,7 @@ * @param data Input data * @return Output data */ -void* event_loop(void* data); +void *event_loop(void *data); /** * Handle an event from libinput @@ -84,14 +84,14 @@ void terminate_libinput(void); * @param dev The device * @return Zero on success, -1 on error */ -int add_device(struct libinput_device* dev); +int add_device(struct libinput_device *dev); /** * Remove a device from the device list * * @param dev The device */ -void remove_device(struct libinput_device* dev); +void remove_device(struct libinput_device *dev); /** * Pack the device list diff --git a/src/mds-registry/globals.c b/src/mds-registry/globals.c index 6a93f3f..98d54d5 100644 --- a/src/mds-registry/globals.c +++ b/src/mds-registry/globals.c @@ -18,7 +18,6 @@ #include "globals.h" - /** * Value of the ‘Message ID’ header for the next message */ @@ -42,7 +41,7 @@ hash_table_t reg_table; /** * Reusable buffer for data to send */ -char* send_buffer = NULL; +char *send_buffer = NULL; /** * The size of `send_buffer` @@ -52,7 +51,7 @@ size_t send_buffer_size = 0; /** * Used to temporarily store the old value when reallocating heap-allocations */ -char* old; +char *old; /** * The master thread @@ -78,4 +77,3 @@ pthread_mutex_t slave_mutex; * Condition for slave data */ pthread_cond_t slave_cond; - diff --git a/src/mds-registry/globals.h b/src/mds-registry/globals.h index 68bd5c6..e1d7aab 100644 --- a/src/mds-registry/globals.h +++ b/src/mds-registry/globals.h @@ -28,8 +28,7 @@ #include <pthread.h> -#define MDS_REGISTRY_VARS_VERSION 0 - +#define MDS_REGISTRY_VARS_VERSION 0 /** @@ -55,7 +54,7 @@ extern hash_table_t reg_table; /** * Reusable buffer for data to send */ -extern char* send_buffer; +extern char *send_buffer; /** * The size of `send_buffer` @@ -65,7 +64,7 @@ extern size_t send_buffer_size; /** * Used to temporarily store the old value when reallocating heap-allocations */ -extern char* old; +extern char *old; /** * The number of running slaves @@ -89,4 +88,3 @@ extern pthread_cond_t slave_cond; #endif - diff --git a/src/mds-registry/mds-registry.c b/src/mds-registry/mds-registry.c index 6d93517..8927a62 100644 --- a/src/mds-registry/mds-registry.c +++ b/src/mds-registry/mds-registry.c @@ -38,15 +38,14 @@ * * 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 - }; +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 +}; @@ -57,8 +56,8 @@ server_characteristics_t server_characteristics = * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** @@ -69,20 +68,20 @@ server_characteristics_t server_characteristics = */ int preinitialise_server(void) { - int stage = 0; - - fail_if ((errno = pthread_mutex_init(&slave_mutex, NULL))); stage++; - fail_if ((errno = pthread_cond_init(&slave_cond, NULL))); stage++; - - linked_list_create(&slave_list, 2); - - return 0; - - fail: - xperror(*argv); - if (stage >= 1) pthread_mutex_destroy(&slave_mutex); - if (stage >= 2) pthread_cond_destroy(&slave_cond); - return 1; + int stage = 0; + + fail_if ((errno = pthread_mutex_init(&slave_mutex, NULL))); stage++; + fail_if ((errno = pthread_cond_init(&slave_cond, NULL))); stage++; + + linked_list_create(&slave_list, 2); + + return 0; + +fail: + xperror(*argv); + if (stage >= 1) pthread_mutex_destroy(&slave_mutex); + if (stage >= 2) pthread_cond_destroy(&slave_cond); + return 1; } @@ -92,43 +91,44 @@ int preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +int +initialise_server(void) { - int stage = 0; - const char* const message = - "Command: intercept\n" - "Message ID: 0\n" - "Length: 32\n" - "\n" - "Command: register\n" - "Client closed\n" - /* -- NEXT MESSAGE -- */ - "Command: reregister\n" - "Message ID: 1\n" - "\n"; - - /* We are asking all servers to reregister their - protocols for two reasons: - - 1) The server would otherwise not get registrations - from servers started before this server. - 2) If this server crashes we may miss registrations - that happen between the crash and the recovery. - */ - - fail_if (full_send(message, strlen(message))); stage++; - fail_if (hash_table_create_tuned(®_table, 32)); - reg_table.key_comparator = (compare_func*)string_comparator; - reg_table.hasher = (hash_func*)string_hash; - fail_if (server_initialised() < 0); stage++; - fail_if (mds_message_initialise(&received)); - - return 0; - fail: - xperror(*argv); - if (stage >= 1) hash_table_destroy(®_table, NULL, NULL); - if (stage >= 2) mds_message_destroy(&received); - return 1; + int stage = 0; + const char *const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 32\n" + "\n" + "Command: register\n" + "Client closed\n" + /* -- NEXT MESSAGE -- */ + "Command: reregister\n" + "Message ID: 1\n" + "\n"; + + /* We are asking all servers to reregister their + protocols for two reasons: + + 1) The server would otherwise not get registrations + from servers started before this server. + 2) If this server crashes we may miss registrations + that happen between the crash and the recovery. + */ + + fail_if (full_send(message, strlen(message))); stage++; + fail_if (hash_table_create_tuned(®_table, 32)); + reg_table.key_comparator = (compare_func*)string_comparator; + reg_table.hasher = (hash_func*)string_hash; + fail_if (server_initialised() < 0); stage++; + fail_if (mds_message_initialise(&received)); + + return 0; +fail: + xperror(*argv); + if (stage >= 1) hash_table_destroy(®_table, NULL, NULL); + if (stage >= 2) mds_message_destroy(&received); + return 1; } @@ -138,17 +138,18 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - if (connected) - return 0; - - fail_if (reconnect_to_display()); - connected = 1; - return 0; - fail: - mds_message_destroy(&received); - return 1; + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; +fail: + mds_message_destroy(&received); + return 1; } @@ -157,60 +158,57 @@ int postinitialise_server(void) * * @return Non-zero on error */ -int master_loop(void) +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; - with_mutex (slave_mutex, linked_list_pack(&slave_list);); + int rc = 1, r; + + while (!reexecing && !terminating) { + if (danger) { + danger = 0; + free(send_buffer); + send_buffer = NULL; + send_buffer_size = 0; + with_mutex (slave_mutex, linked_list_pack(&slave_list);); + } + + if (!(r = mds_message_read(&received, socket_fd))) + if (!(r = handle_message())) + 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; } - - 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); + + rc = 0; + goto done; +fail: + xperror(*argv); done: - /* Join with all slaves threads. */ - with_mutex (slave_mutex, - while (running_slaves > 0) - pthread_cond_wait(&slave_cond, &slave_mutex);); - - if (rc || !reexecing) - { - hash_table_destroy(®_table, (free_func*)reg_table_free_key, (free_func*)reg_table_free_value); - mds_message_destroy(&received); - } - pthread_mutex_destroy(&slave_mutex); - pthread_cond_destroy(&slave_cond); - free(send_buffer); - return rc; + /* Join with all slaves threads. */ + with_mutex (slave_mutex, + while (running_slaves > 0) + pthread_cond_wait(&slave_cond, &slave_mutex);); + + if (rc || !reexecing) { + hash_table_destroy(®_table, (free_func*)reg_table_free_key, (free_func*)reg_table_free_value); + mds_message_destroy(&received); + } + pthread_mutex_destroy(&slave_mutex); + pthread_cond_destroy(&slave_cond); + free(send_buffer); + return rc; } - diff --git a/src/mds-registry/mds-registry.h b/src/mds-registry/mds-registry.h index 75b5ddf..88c0734 100644 --- a/src/mds-registry/mds-registry.h +++ b/src/mds-registry/mds-registry.h @@ -23,4 +23,3 @@ #endif - diff --git a/src/mds-registry/reexec.c b/src/mds-registry/reexec.c index bd70381..e7280af 100644 --- a/src/mds-registry/reexec.c +++ b/src/mds-registry/reexec.c @@ -40,31 +40,34 @@ * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t i, rc = 2 * sizeof(int) + sizeof(uint32_t) + 4 * sizeof(size_t); - hash_entry_t* entry; - ssize_t node; - - rc += mds_message_marshal_size(&received); - rc += linked_list_marshal_size(&slave_list); - - foreach_hash_table_entry (reg_table, i, entry) - { - char* command = (char*)(void*)(entry->key); - size_t len = strlen(command) + 1; - client_list_t* list = (client_list_t*)(void*)(entry->value); - - rc += len + sizeof(size_t) + client_list_marshal_size(list); - } - - foreach_linked_list_node (slave_list, node) - { - slave_t* slave = (slave_t*)(void*)slave_list.values[node]; - rc += slave_marshal_size(slave); - } - - return rc; + size_t i, rc = 2 * sizeof(int) + sizeof(uint32_t) + 4 * sizeof(size_t); + hash_entry_t *entry; + ssize_t node; + char *command; + size_t len; + client_list_t *list; + slave_t *slave; + + rc += mds_message_marshal_size(&received); + rc += linked_list_marshal_size(&slave_list); + + foreach_hash_table_entry (reg_table, i, entry) { + command = (void *)entry->key; + len = strlen(command) + 1; + list = (void *)entry->value; + + rc += len + sizeof(size_t) + client_list_marshal_size(list); + } + + foreach_linked_list_node (slave_list, node) { + slave = (void *)slave_list.values[node]; + rc += slave_marshal_size(slave); + } + + return rc; } @@ -74,52 +77,55 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - size_t i, n = mds_message_marshal_size(&received); - hash_entry_t* entry; - ssize_t node; - - buf_set_next(state_buf, int, MDS_REGISTRY_VARS_VERSION); - buf_set_next(state_buf, int, connected); - buf_set_next(state_buf, uint32_t, message_id); - buf_set_next(state_buf, size_t, n); - mds_message_marshal(&received, state_buf); - state_buf += n / sizeof(char); - - buf_set_next(state_buf, size_t, reg_table.capacity); - buf_set_next(state_buf, size_t, reg_table.size); - foreach_hash_table_entry (reg_table, i, entry) - { - char* command = (char*)(void*)(entry->key); - size_t len = strlen(command) + 1; - client_list_t* list = (client_list_t*)(void*)(entry->value); - - memcpy(state_buf, command, len * sizeof(char)); - state_buf += len; - - n = client_list_marshal_size(list); - buf_set_next(state_buf, size_t, n); - client_list_marshal(list, state_buf); - state_buf += n / sizeof(char); - } - - n = linked_list_marshal_size(&slave_list); - buf_set_next(state_buf, size_t, n); - linked_list_marshal(&slave_list, state_buf); - state_buf += n / sizeof(char); - - foreach_linked_list_node (slave_list, node) - { - slave_t* slave = (slave_t*)(void*)(slave_list.values[node]); - state_buf += slave_marshal(slave, state_buf) / sizeof(char); - slave_destroy(slave); - } - - hash_table_destroy(®_table, (free_func*)reg_table_free_key, (free_func*)reg_table_free_value); - mds_message_destroy(&received); - linked_list_destroy(&slave_list); - return 0; + size_t i, n = mds_message_marshal_size(&received); + hash_entry_t *entry; + ssize_t node; + char *command; + size_t len; + client_list_t *list; + slave_t *slave; + + buf_set_next(state_buf, int, MDS_REGISTRY_VARS_VERSION); + buf_set_next(state_buf, int, connected); + buf_set_next(state_buf, uint32_t, message_id); + buf_set_next(state_buf, size_t, n); + mds_message_marshal(&received, state_buf); + state_buf += n / sizeof(char); + + buf_set_next(state_buf, size_t, reg_table.capacity); + buf_set_next(state_buf, size_t, reg_table.size); + foreach_hash_table_entry (reg_table, i, entry) { + command = (void *)(entry->key); + len = strlen(command) + 1; + list = (void *)(entry->value); + + memcpy(state_buf, command, len * sizeof(char)); + state_buf += len; + + n = client_list_marshal_size(list); + buf_set_next(state_buf, size_t, n); + client_list_marshal(list, state_buf); + state_buf += n / sizeof(char); + } + + n = linked_list_marshal_size(&slave_list); + buf_set_next(state_buf, size_t, n); + linked_list_marshal(&slave_list, state_buf); + state_buf += n / sizeof(char); + + foreach_linked_list_node (slave_list, node) { + slave = (void *)(slave_list.values[node]); + state_buf += slave_marshal(slave, state_buf) / sizeof(char); + slave_destroy(slave); + } + + hash_table_destroy(®_table, (free_func *)reg_table_free_key, (free_func *)reg_table_free_value); + mds_message_destroy(&received); + linked_list_destroy(&slave_list); + return 0; } @@ -133,81 +139,79 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - char* command; - client_list_t* list; - slave_t* slave; - size_t i, n, m; - ssize_t node; - int stage = 0; - - /* buf_get_next(state_buf, int, MDS_REGISTRY_VARS_VERSION); */ - buf_next(state_buf, int, 1); - buf_get_next(state_buf, int, connected); - buf_get_next(state_buf, uint32_t, message_id); - buf_get_next(state_buf, size_t, n); - fail_if (mds_message_unmarshal(&received, state_buf)); - state_buf += n / sizeof(char); - stage = 1; - - buf_get_next(state_buf, size_t, n); - fail_if (hash_table_create_tuned(®_table, n)); - buf_get_next(state_buf, size_t, n); - for (i = 0; i < n; i++) - { - stage = 1; - fail_if (xstrdup(command, state_buf)); - state_buf += strlen(command) + 1; - - stage = 2; - fail_if (xmalloc(list, 1, client_list_t)); - buf_get_next(state_buf, size_t, m); - stage = 3; - fail_if (client_list_unmarshal(list, state_buf)); - state_buf += m / sizeof(char); - - hash_table_put(®_table, (size_t)(void*)command, (size_t)(void*)list); - fail_if (errno); - } - command = NULL; - stage = 4; - - reg_table.key_comparator = (compare_func*)string_comparator; - reg_table.hasher = (hash_func*)string_hash; - - buf_get_next(state_buf, size_t, n); - fail_if (linked_list_unmarshal(&slave_list, state_buf)); - state_buf += n / sizeof(char); - - foreach_linked_list_node (slave_list, node) - { - stage = 5; - fail_if (xmalloc(slave, 1, slave_t)); - stage = 6; - fail_if ((n = slave_unmarshal(slave, state_buf)) == 0); - state_buf += n / sizeof(char); - slave_list.values[node] = (size_t)(void*)slave; - } - - foreach_linked_list_node (slave_list, node) - { - slave = (slave_t*)(void*)(slave_list.values[node]); - fail_if (start_created_slave(slave)); - } - - return 0; - fail: - xperror(*argv); - mds_message_destroy(&received); - if (stage >= 1) - hash_table_destroy(®_table, (free_func*)reg_table_free_key, (free_func*)reg_table_free_value); - if (stage >= 2) free(command); - if (stage >= 3) client_list_destroy(list), free(list); - if (stage >= 5) linked_list_destroy(&slave_list); - if (stage >= 6) slave_destroy(slave), free(slave); - abort(); - return -1; + char *command; + client_list_t *list; + slave_t *slave; + size_t i, n, m; + ssize_t node; + int stage = 0; + + /* buf_get_next(state_buf, int, MDS_REGISTRY_VARS_VERSION); */ + buf_next(state_buf, int, 1); + buf_get_next(state_buf, int, connected); + buf_get_next(state_buf, uint32_t, message_id); + buf_get_next(state_buf, size_t, n); + fail_if (mds_message_unmarshal(&received, state_buf)); + state_buf += n / sizeof(char); + stage = 1; + + buf_get_next(state_buf, size_t, n); + fail_if (hash_table_create_tuned(®_table, n)); + buf_get_next(state_buf, size_t, n); + for (i = 0; i < n; i++) { + stage = 1; + fail_if (xstrdup(command, state_buf)); + state_buf += strlen(command) + 1; + + stage = 2; + fail_if (xmalloc(list, 1, client_list_t)); + buf_get_next(state_buf, size_t, m); + stage = 3; + fail_if (client_list_unmarshal(list, state_buf)); + state_buf += m / sizeof(char); + + hash_table_put(®_table, (size_t)(void *)command, (size_t)(void *)list); + fail_if (errno); + } + command = NULL; + stage = 4; + + reg_table.key_comparator = (compare_func*)string_comparator; + reg_table.hasher = (hash_func*)string_hash; + + buf_get_next(state_buf, size_t, n); + fail_if (linked_list_unmarshal(&slave_list, state_buf)); + state_buf += n / sizeof(char); + + foreach_linked_list_node (slave_list, node) { + stage = 5; + fail_if (xmalloc(slave, 1, slave_t)); + stage = 6; + fail_if ((n = slave_unmarshal(slave, state_buf)) == 0); + state_buf += n / sizeof(char); + slave_list.values[node] = (size_t)(void *)slave; + } + + foreach_linked_list_node (slave_list, node) { + slave = (slave_t *)(void *)(slave_list.values[node]); + fail_if (start_created_slave(slave)); + } + + return 0; +fail: + xperror(*argv); + mds_message_destroy(&received); + if (stage >= 1) + hash_table_destroy(®_table, (free_func *)reg_table_free_key, (free_func *)reg_table_free_value); + if (stage >= 2) free(command); + if (stage >= 3) client_list_destroy(list), free(list); + if (stage >= 5) linked_list_destroy(&slave_list); + if (stage >= 6) slave_destroy(slave), free(slave); + abort(); + return -1; } @@ -217,8 +221,8 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } - diff --git a/src/mds-registry/reexec.h b/src/mds-registry/reexec.h index 7b95466..4238c9a 100644 --- a/src/mds-registry/reexec.h +++ b/src/mds-registry/reexec.h @@ -23,4 +23,3 @@ #endif - diff --git a/src/mds-registry/registry.c b/src/mds-registry/registry.c index 77cd463..28b38d1 100644 --- a/src/mds-registry/registry.c +++ b/src/mds-registry/registry.c @@ -44,8 +44,8 @@ * @param length:size_t The length of the message * @return :int Zero on success, -1 on error */ -#define full_send(message, length) \ - ((full_send)(socket_fd, message, length)) +#define full_send(message, length)\ + ((full_send)(socket_fd, message, length)) /** @@ -54,74 +54,69 @@ * @return Zero on success -1 on error or interruption, * `errno` will be set accordingly */ -static int handle_close_message(void) +static int +handle_close_message(void) { - /* Servers do not close too often, there is no need to - optimise this with another hash table. Doing so would - also require some caution because the keys are 32-bit - on 32-bit computers, and the client ID:s are 64-bit. */ - - size_t i, j, ptr = 0, size = 1; - size_t* keys = NULL; - size_t* old_keys; - - - /* Remove server for all protocols. */ - - for (i = 0; i < received.header_count; i++) - if (startswith(received.headers[i], "Client closed: ")) - { - uint64_t client = parse_client_id(received.headers[i] + strlen("Client closed: ")); - hash_entry_t* entry; - - foreach_hash_table_entry (reg_table, j, entry) - { - /* Remove server from list of servers that support the protocol, - once, if it is in the list. */ - client_list_t* list = (client_list_t*)(void*)(entry->value); - client_list_remove(list, client); - if (list->size) - continue; - - /* If no servers support the protocol, list the protocol for removal. */ - fail_if ((keys == NULL) && xmalloc(keys, size, size_t)); - fail_if (ptr == size ? growalloc(old_keys, keys, size, size_t) : 0); - keys[ptr++] = entry->key; - } - - - /* Mark client as closed. */ + /* Servers do not close too often, there is no need to + optimise this with another hash table. Doing so would + also require some caution because the keys are 32-bit + on 32-bit computers, and the client ID:s are 64-bit. */ + + size_t i, j, ptr = 0, size = 1; + size_t *keys = NULL; + size_t *old_keys; + uint64_t client; + hash_entry_t *entry; + client_list_t *list; + char *command; + + /* Remove server for all protocols. */ + for (i = 0; i < received.header_count; i++) { + if (startswith(received.headers[i], "Client closed: ")) { + client = parse_client_id(received.headers[i] + strlen("Client closed: ")); + + foreach_hash_table_entry (reg_table, j, entry) { + /* Remove server from list of servers that support the protocol, + once, if it is in the list. */ + list = (void *)(entry->value); + client_list_remove(list, client); + if (list->size) + continue; + + /* If no servers support the protocol, list the protocol for removal. */ + fail_if (!keys && xmalloc(keys, size, size_t)); + fail_if (ptr == size ? growalloc(old_keys, keys, size, size_t) : 0); + keys[ptr++] = entry->key; + } + - close_slaves(client); - } - - - /* Close slaves those clients have closed. */ - - with_mutex (slave_mutex, pthread_cond_broadcast(&slave_cond);); - - - /* Remove protocol that no longer have any supporting servers. */ - - for (i = 0; i < ptr; i++) - { - hash_entry_t* entry = hash_table_get_entry(®_table, keys[i]); - client_list_t* list = (client_list_t*)(void*)(entry->value); - char* command = (char*)(void*)(entry->key); - - hash_table_remove(®_table, entry->key); - - client_list_destroy(list); - free(list); - free(command); - } - - free(keys); - return 0; - fail: - xperror(*argv); - free(keys); - return -1; + /* Mark client as closed. */ + close_slaves(client); + } + } + + /* Close slaves those clients have closed. */ + with_mutex (slave_mutex, pthread_cond_broadcast(&slave_cond);); + + /* Remove protocol that no longer have any supporting servers. */ + for (i = 0; i < ptr; i++) { + entry = hash_table_get_entry(®_table, keys[i]); + list = (void *)(entry->value); + command = (void *)(entry->key); + + hash_table_remove(®_table, entry->key); + + client_list_destroy(list); + free(list); + free(command); + } + + free(keys); + return 0; +fail: + xperror(*argv); + free(keys); + return -1; } @@ -134,54 +129,50 @@ static int handle_close_message(void) * @param client The ID of the client that implements the server-side of the protocol * @return Non-zero on error */ -__attribute__((nonnull)) -static int registry_action_add(int has_key, char* command, size_t command_key, uint64_t client) +static int __attribute__((nonnull)) +registry_action_add(int has_key, char *command, size_t command_key, uint64_t client) { - int saved_errno; - - if (has_key) - { - /* Add server to protocol if the protocol is already in the table. */ - size_t address = hash_table_get(®_table, command_key); - client_list_t* list = (client_list_t*)(void*)address; - fail_if (client_list_add(list, client) < 0); - } - else - { - /* If the protocol is not already in the table. */ - - /* Allocate list of servers for the protocol. */ - client_list_t* list; - void* address; - fail_if (xmalloc(address = list, 1, client_list_t)); - /* Duplicate the protocol name so it can be accessed later. */ - if (xstrdup_nn(command, command)) - { - saved_errno = errno, free(list), errno = saved_errno; - fail_if (1); - } - /* Create list of servers, add server to list and add the protocol to the table. */ - command_key = (size_t)(void*)command; - if (client_list_create(list, 1) || - client_list_add(list, client) || - (hash_table_put(®_table, command_key, (size_t)address) == 0)) - { - saved_errno = errno; - client_list_destroy(list); - free(list); - free(command); - errno = saved_errno; - fail_if (1); + int saved_errno; + client_list_t *list; + size_t address; + void *paddress; + + if (has_key) { + /* Add server to protocol if the protocol is already in the table. */ + address = hash_table_get(®_table, command_key); + list = (void *)address; + fail_if (client_list_add(list, client) < 0); + } else { + /* If the protocol is not already in the table. */ + + /* Allocate list of servers for the protocol. */ + fail_if (xmalloc(paddress = list, 1, client_list_t)); + /* Duplicate the protocol name so it can be accessed later. */ + if (xstrdup_nn(command, command)) { + saved_errno = errno, free(list), errno = saved_errno; + fail_if (1); + } + /* Create list of servers, add server to list and add the protocol to the table. */ + command_key = (size_t)(void*)command; + if (client_list_create(list, 1) || + client_list_add(list, client) || + !hash_table_put(®_table, command_key, (size_t)paddress)) { + saved_errno = errno; + client_list_destroy(list); + free(list); + free(command); + errno = saved_errno; + fail_if (1); + } } - } - - /* Notify slaves. */ - fail_if (advance_slaves(command)); - - return 0; - fail: - xperror(*argv); - return -1; + + /* Notify slaves. */ + fail_if (advance_slaves(command)); + + return 0; +fail: + xperror(*argv); + return -1; } @@ -192,23 +183,23 @@ static int registry_action_add(int has_key, char* command, size_t command_key, u * @param client The ID of the client that implements the server-side of the protocol * @return Non-zero on error */ -static void registry_action_remove(size_t command_key, uint64_t client) +static void +registry_action_remove(size_t command_key, uint64_t client) { - hash_entry_t* entry = hash_table_get_entry(®_table, command_key); - size_t address = entry->value; - client_list_t* list = (client_list_t*)(void*)address; - - /* Remove server from protocol. */ - client_list_remove(list, client); - - /* Remove protocol if no servers support it anymore. */ - if (list->size == 0) - { - client_list_destroy(list); - free(list); - hash_table_remove(®_table, command_key); - reg_table_free_key(entry->key); - } + hash_entry_t *entry = hash_table_get_entry(®_table, command_key); + size_t address = entry->value; + client_list_t *list = (void *)address; + + /* Remove server from protocol. */ + client_list_remove(list, client); + + /* Remove protocol if no servers support it anymore. */ + if (!list->size) { + client_list_destroy(list); + free(list); + hash_table_remove(®_table, command_key); + reg_table_free_key(entry->key); + } } @@ -222,40 +213,46 @@ static void registry_action_remove(size_t command_key, uint64_t client) * @param wait_set Table to fill with missing protocols if `action == 0` * @return Non-zero on error */ -__attribute__((nonnull)) -static int registry_action_act(char* command, int action, uint64_t client, hash_table_t* wait_set) +static int __attribute__((nonnull)) +registry_action_act(char *command, int action, uint64_t client, hash_table_t *wait_set) { - size_t command_key = (size_t)(void*)command; - int has_key = hash_table_contains_key(®_table, command_key); - int saved_errno; - - if (action == 1) - { - /* Register server to protocol. */ - fail_if (registry_action_add(has_key, command, command_key, client)); - } - else if ((action == -1) && has_key) - /* Unregister server from protocol. */ - registry_action_remove(command_key, client); - else if ((action == 0) && !has_key) - { - /* Add protocol to wait set of not present in the protocol table. */ - fail_if (xstrdup_nn(command, command)); - command_key = (size_t)(void*)command; - if (hash_table_put(wait_set, command_key, 1) == 0) - if (errno) - { - saved_errno = errno, free(command), errno = saved_errno; - fail_if (1); - } - } - - return 0; - fail: - xperror(*argv); - if (action != 1) - hash_table_destroy(wait_set, (free_func*)reg_table_free_key, NULL), free(wait_set); - return -1; + size_t command_key = (size_t)(void *)command; + int has_key = hash_table_contains_key(®_table, command_key); + int saved_errno; + + switch (action) { + case 1: + /* Register server to protocol. */ + fail_if (registry_action_add(has_key, command, command_key, client)); + break; + case -1: + if (has_key) + /* Unregister server from protocol. */ + registry_action_remove(command_key, client); + break; + case 0: + if (has_key) + break; + /* Add protocol to wait set of not present in the protocol table. */ + fail_if (xstrdup_nn(command, command)); + command_key = (size_t)(void*)command; + if (!hash_table_put(wait_set, command_key, 1) && errno) { + saved_errno = errno, free(command), errno = saved_errno; + fail_if (1); + } + break; + default: + break; + } + + return 0; +fail: + xperror(*argv); + if (action != 1) { + hash_table_destroy(wait_set, (free_func *)reg_table_free_key, NULL); + free(wait_set); + } + return -1; } @@ -270,71 +267,57 @@ static int registry_action_act(char* command, int action, uint64_t client, hash_ * @return Zero on success -1 on error or interruption, * `errno` will be set accordingly */ -__attribute__((nonnull)) -static int registry_action(size_t length, int action, const char* recv_client_id, const char* recv_message_id) +static int __attribute__((nonnull)) +registry_action(size_t length, int action, const char *recv_client_id, const char *recv_message_id) { - char* payload = received.payload; - uint64_t client = action ? parse_client_id(recv_client_id) : 0; - hash_table_t* wait_set = NULL; - size_t begin; - int saved_errno; - - - /* If ‘Action: wait’, create a set for the protocols that are not already available. */ - - if (action == 0) - { - fail_if (xmalloc(wait_set, 1, hash_table_t)); - fail_if (hash_table_create(wait_set)); - wait_set->key_comparator = (compare_func*)string_comparator; - wait_set->hasher = (hash_func*)string_hash; - } - - - /* If the payload buffer is full, increase it so we can fit another character. */ - - if (received.payload_size == length) - { - fail_if (growalloc(old, received.payload, received.payload_size, char)); - payload = received.payload; - } - - - /* LF-terminate the payload, perhaps it did not have a terminal LF. */ - - payload[length] = '\n'; - - - /* For all protocols in the payload, either add or remove - them from or to the protocl table or the wait set. */ - - for (begin = 0; begin < length;) - { - char* end = rawmemchr(payload + begin, '\n'); - size_t len = (size_t)(end - payload) - begin - 1; - char* command = payload + begin; - - command[len] = '\0'; - begin += len + 1; - - if (len > 0) - if (registry_action_act(command, action, client, wait_set)) - fail_if (wait_set = NULL, 1); - } - - - /* If ‘Action: wait’, start a new thread that waits for the protocols and the responds. */ - - if (action == 0) - if (start_slave(wait_set, recv_client_id, recv_message_id)) - fail_if (wait_set = NULL, 1); - - return 0; - fail: - saved_errno = errno; - if (wait_set != NULL) - hash_table_destroy(wait_set, NULL, NULL), free(wait_set); - return errno = saved_errno, -1; + char *payload = received.payload; + uint64_t client = action ? parse_client_id(recv_client_id) : 0; + hash_table_t *wait_set = NULL; + size_t begin, len; + int saved_errno; + char *end, *command; + + /* If ‘Action: wait’, create a set for the protocols that are not already available. */ + if (!action) { + fail_if (xmalloc(wait_set, 1, hash_table_t)); + fail_if (hash_table_create(wait_set)); + wait_set->key_comparator = (compare_func*)string_comparator; + wait_set->hasher = (hash_func*)string_hash; + } + + /* If the payload buffer is full, increase it so we can fit another character. */ + if (received.payload_size == length) { + fail_if (growalloc(old, received.payload, received.payload_size, char)); + payload = received.payload; + } + + /* LF-terminate the payload, perhaps it did not have a terminal LF. */ + payload[length] = '\n'; + + /* For all protocols in the payload, either add or remove + them from or to the protocl table or the wait set. */ + for (begin = 0; begin < length;) { + end = rawmemchr(payload + begin, '\n'); + len = (size_t)(end - payload) - begin - 1; + command = payload + begin; + + command[len] = '\0'; + begin += len + 1; + + if (len > 0 && registry_action_act(command, action, client, wait_set)) + fail_if (wait_set = NULL, 1); + } + + /* If ‘Action: wait’, start a new thread that waits for the protocols and the responds. */ + if (!action && start_slave(wait_set, recv_client_id, recv_message_id)) + fail_if (wait_set = NULL, 1); + + return 0; +fail: + saved_errno = errno; + if (wait_set) + hash_table_destroy(wait_set, NULL, NULL), free(wait_set); + return errno = saved_errno, -1; } @@ -346,73 +329,66 @@ static int registry_action(size_t length, int action, const char* recv_client_id * @return Zero on success, -1 on error or interruption, * `errno` will be set accordingly */ -__attribute__((nonnull)) -static int list_registry(const char* recv_client_id, const char* recv_message_id) +static int __attribute__((nonnull)) +list_registry(const char *recv_client_id, const char *recv_message_id) { - size_t ptr = 0, i; - hash_entry_t* entry; - - - /* Allocate the send buffer for the first time, it cannot be doubled if it is zero. */ - - if (send_buffer_size == 0) - { - fail_if (xmalloc(send_buffer, 256, char)); - send_buffer_size = 256; - } - - - /* Add all protocols to the send buffer. */ - - foreach_hash_table_entry (reg_table, i, entry) - { - size_t key = entry->key; - char* command = (char*)(void*)key; - size_t len = strlen(command); - - /* Make sure the send buffer can fit all protocols. */ - while (ptr + len + 1 >= send_buffer_size) - fail_if (growalloc(old, send_buffer, send_buffer_size, char)); - - memcpy(send_buffer + ptr, command, len * sizeof(char)); - ptr += len; - send_buffer[ptr++] = '\n'; - } - - - /* Make sure the message headers can fit the send buffer. */ - - i = sizeof("To: \n" - "In response to: \n" - "Message ID: \n" - "Origin command: register\n" - "Length: \n" - "\n") / sizeof(char) - 1; - i += strlen(recv_message_id) + strlen(recv_client_id) + 10 + 19; - - while (ptr + i >= send_buffer_size) - fail_if (growalloc(old, send_buffer, send_buffer_size, char)); - - - /* Construct message headers. */ - sprintf(send_buffer + ptr, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Origin command: register\n" - "Length: %" PRIu64 "\n" - "\n", - recv_client_id, recv_message_id, message_id, ptr); - - /* Increase message ID. */ - with_mutex (slave_mutex, message_id = message_id == UINT32_MAX ? 0 : (message_id + 1);); - - /* Send message. */ - fail_if (full_send(send_buffer + ptr, strlen(send_buffer + ptr))); - fail_if (full_send(send_buffer, ptr)); - return 0; - fail: - return -1; + size_t ptr = 0, i, key, len; + hash_entry_t *entry; + char *command; + + /* Allocate the send buffer for the first time, it cannot be doubled if it is zero. */ + if (!send_buffer_size) { + fail_if (xmalloc(send_buffer, 256, char)); + send_buffer_size = 256; + } + + /* Add all protocols to the send buffer. */ + + foreach_hash_table_entry (reg_table, i, entry) { + key = entry->key; + command = (char*)(void*)key; + len = strlen(command); + + /* Make sure the send buffer can fit all protocols. */ + while (ptr + len + 1 >= send_buffer_size) + fail_if (growalloc(old, send_buffer, send_buffer_size, char)); + + memcpy(send_buffer + ptr, command, len * sizeof(char)); + ptr += len; + send_buffer[ptr++] = '\n'; + } + + /* Make sure the message headers can fit the send buffer. */ + i = sizeof("To: \n" + "In response to: \n" + "Message ID: \n" + "Origin command: register\n" + "Length: \n" + "\n") / sizeof(char) - 1; + i += strlen(recv_message_id) + strlen(recv_client_id) + 10 + 19; + + while (ptr + i >= send_buffer_size) + fail_if (growalloc(old, send_buffer, send_buffer_size, char)); + + /* Construct message headers. */ + sprintf(send_buffer + ptr, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Origin command: register\n" + "Length: %" PRIu64 "\n" + "\n", + recv_client_id, recv_message_id, message_id, ptr); + + /* Increase message ID. */ + with_mutex (slave_mutex, message_id = message_id == UINT32_MAX ? 0 : (message_id + 1);); + + /* Send message. */ + fail_if (full_send(send_buffer + ptr, strlen(send_buffer + ptr))); + fail_if (full_send(send_buffer, ptr)); + return 0; +fail: + return -1; } @@ -422,71 +398,63 @@ static int list_registry(const char* recv_client_id, const char* recv_message_id * @return Zero on success -1 on error or interruption, * `errno` will be set accordingly */ -static int handle_register_message(void) +static int +handle_register_message(void) { - /* Fetch message headers. */ - - const char* recv_client_id = NULL; - const char* recv_message_id = NULL; - const char* recv_length = NULL; - const char* recv_action = NULL; - size_t i, length = 0; - -#define __get_header(storage, header) \ - (startswith(received.headers[i], header)) \ - storage = received.headers[i] + strlen(header) - - for (i = 0; i < received.header_count; i++) - { - if __get_header(recv_client_id, "Client ID: "); - else if __get_header(recv_message_id, "Message ID: "); - else if __get_header(recv_length, "Length: "); - else if __get_header(recv_action, "Action: "); - else - continue; - - /* Stop if we got all headers we recognised, except ‘Time to live’. */ - if (recv_client_id && recv_message_id && recv_length && recv_action) - break; - } - + /* Fetch message headers. */ + const char *recv_client_id = NULL; + const char *recv_message_id = NULL; + const char *recv_length = NULL; + const char *recv_action = NULL; + size_t i, length = 0; + +#define __get_header(storage, header)\ + (startswith(received.headers[i], header))\ + storage = received.headers[i] + strlen(header) + + for (i = 0; i < received.header_count; i++) { + if __get_header(recv_client_id, "Client ID: "); + else if __get_header(recv_message_id, "Message ID: "); + else if __get_header(recv_length, "Length: "); + else if __get_header(recv_action, "Action: "); + else + continue; + + /* Stop if we got all headers we recognised, except ‘Time to live’. */ + if (recv_client_id && recv_message_id && recv_length && recv_action) + break; + } + #undef __get_header - - - /* Validate headers. */ - - if ((recv_client_id == NULL) || (strequals(recv_client_id, "0:0"))) - return eprint("received message from anonymous sender, ignoring."), 0; - else if (strchr(recv_client_id, ':') == NULL) - return eprint("received message from sender without a colon it its ID, ignoring, invalid ID."), 0; - else if ((recv_length == NULL) && ((recv_action == NULL) || !strequals(recv_action, "list"))) - return eprint("received empty message without `Action: list`, ignoring, has no effect."), 0; - else if (recv_message_id == NULL) - return eprint("received message without ID, ignoring, master server is misbehaving."), 0; - - - /* Get message length, and make sure the action is defined. */ - - if (recv_length != NULL) - length = atoz(recv_length); - if (recv_action != NULL) - recv_action = "add"; - - - /* Perform action. */ - -#define __registry_action(action) registry_action(length, action, recv_client_id, recv_message_id) - - if (strequals(recv_action, "add")) return __registry_action(1); - else if (strequals(recv_action, "remove")) return __registry_action(-1); - else if (strequals(recv_action, "wait")) return __registry_action(0); - else if (strequals(recv_action, "list")) return list_registry(recv_client_id, recv_message_id); - else - { - eprint("received invalid action, ignoring."); - return 0; - } - + + /* Validate headers. */ + if (!recv_client_id || strequals(recv_client_id, "0:0")) + return eprint("received message from anonymous sender, ignoring."), 0; + else if (!strchr(recv_client_id, ':')) + return eprint("received message from sender without a colon it its ID, ignoring, invalid ID."), 0; + else if (!recv_length && (!recv_action || !strequals(recv_action, "list"))) + return eprint("received empty message without `Action: list`, ignoring, has no effect."), 0; + else if (!recv_message_id) + return eprint("received message without ID, ignoring, master server is misbehaving."), 0; + + /* Get message length, and make sure the action is defined. */ + if (recv_length) + length = atoz(recv_length); + if (recv_action) + recv_action = "add"; + + /* Perform action. */ +#define __registry_action(action) registry_action(length, action, recv_client_id, recv_message_id) + + if (strequals(recv_action, "add")) return __registry_action(1); + else if (strequals(recv_action, "remove")) return __registry_action(-1); + else if (strequals(recv_action, "wait")) return __registry_action(0); + else if (strequals(recv_action, "list")) return list_registry(recv_client_id, recv_message_id); + else { + eprint("received invalid action, ignoring."); + return 0; + } + #undef __registry_action } @@ -499,16 +467,15 @@ static int handle_register_message(void) */ int handle_message(void) { - size_t i; - for (i = 0; i < received.header_count; i++) - if (strequals(received.headers[i], "Command: register")) - { - fail_if (handle_register_message()); + size_t i; + for (i = 0; i < received.header_count; i++) { + if (strequals(received.headers[i], "Command: register")) { + fail_if (handle_register_message()); + return 0; + } + } + fail_if (handle_close_message()); return 0; - } - fail_if (handle_close_message()); - return 0; fail: - return -1; + return -1; } - diff --git a/src/mds-registry/registry.h b/src/mds-registry/registry.h index 319d615..e35b14f 100644 --- a/src/mds-registry/registry.h +++ b/src/mds-registry/registry.h @@ -29,4 +29,3 @@ int handle_message(void); #endif - diff --git a/src/mds-registry/signals.c b/src/mds-registry/signals.c index 024e2f7..22be1aa 100644 --- a/src/mds-registry/signals.c +++ b/src/mds-registry/signals.c @@ -36,21 +36,20 @@ */ void signal_all(int signo) { - pthread_t current_thread; - ssize_t node; - - current_thread = pthread_self(); - - if (pthread_equal(current_thread, master_thread) == 0) - pthread_kill(master_thread, signo); - - with_mutex (slave_mutex, - foreach_linked_list_node (slave_list, node) - { - slave_t* value = (slave_t*)(void*)(slave_list.values[node]); - if (pthread_equal(current_thread, value->thread) == 0) - pthread_kill(value->thread, signo); - } - ); + pthread_t current_thread; + ssize_t node; + slave_t *value; + + current_thread = pthread_self(); + + if (!pthread_equal(current_thread, master_thread)) + pthread_kill(master_thread, signo); + + with_mutex (slave_mutex, + foreach_linked_list_node (slave_list, node) { + value = (slave_t*)(void*)(slave_list.values[node]); + if (pthread_equal(current_thread, value->thread) == 0) + pthread_kill(value->thread, signo); + } + ); } - diff --git a/src/mds-registry/signals.h b/src/mds-registry/signals.h index 38d3121..f2b5ccd 100644 --- a/src/mds-registry/signals.h +++ b/src/mds-registry/signals.h @@ -23,4 +23,3 @@ #endif - diff --git a/src/mds-registry/slave.c b/src/mds-registry/slave.c index b936c29..be77c5b 100644 --- a/src/mds-registry/slave.c +++ b/src/mds-registry/slave.c @@ -31,40 +31,38 @@ #include <inttypes.h> - /** * Notify the waiting client that it may resume * * @param slave The slave * @return Non-zero, `errno` will be set accordingly */ -__attribute__((nonnull)) -static int slave_notify_client(slave_t* slave) +static int __attribute__((nonnull)) +slave_notify_client(slave_t *slave) { - char buf[sizeof("To: %s\nIn response to: %s\nMessage ID: %" PRIu32 "\nOrigin command: register\n\n") - / sizeof(char) + 41]; - size_t ptr = 0, sent, left; - - /* Construct message headers. */ - sprintf(buf, "To: %s\nIn response to: %s\nMessage ID: %" PRIu32 "\nOrigin command: register\n\n", - slave->client_id, slave->message_id, message_id); - - /* Increase message ID. */ - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - /* Send message to client. */ - left = strlen(buf); - while (left > 0) - { - sent = send_message(socket_fd, buf + ptr, left); - fail_if ((sent < left) && errno && (errno != EINTR)); - left -= sent; - ptr += sent; - } - - return 0; - fail: - return -1; + char buf[sizeof("To: %s\nIn response to: %s\nMessage ID: %" PRIu32 "\nOrigin command: register\n\n") + / sizeof(char) + 41]; + size_t ptr = 0, sent, left; + + /* Construct message headers. */ + sprintf(buf, "To: %s\nIn response to: %s\nMessage ID: %" PRIu32 "\nOrigin command: register\n\n", + slave->client_id, slave->message_id, message_id); + + /* Increase message ID. */ + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + + /* Send message to client. */ + left = strlen(buf); + while (left > 0) { + sent = send_message(socket_fd, buf + ptr, left); + fail_if ((sent < left) && errno && (errno != EINTR)); + left -= sent; + ptr += sent; + } + + return 0; +fail: + return -1; } @@ -74,60 +72,58 @@ static int slave_notify_client(slave_t* slave) * @param data Input data * @return Output data */ -static void* slave_loop(void* data) +static void * +slave_loop(void *data) { - /* pthread_cond_timedwait is required to handle re-exec and termination because - pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */ - struct timespec timeout = - { - .tv_sec = 1, - .tv_nsec = 0 - }; - slave_t* slave = data; - struct timespec now; - - if (slave->closed) - goto done; - - /* Set up traps for especially handled signals. */ - fail_if (trap_signals() < 0); - - fail_if ((errno = pthread_mutex_lock(&slave_mutex))); - - while (!reexecing && !terminating) - { - if ((slave->wait_set->size == 0) || slave->closed) - break; - if (slave->timed) - { - fail_if (monotone(&now)); - if (now.tv_sec > slave->dethklok.tv_sec) - break; - if (now.tv_sec == slave->dethklok.tv_sec) - if (now.tv_nsec >= slave->dethklok.tv_nsec) - break; + /* pthread_cond_timedwait is required to handle re-exec and termination because + pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */ + struct timespec timeout = { + .tv_sec = 1, + .tv_nsec = 0 + }; + slave_t* slave = data; + struct timespec now; + + if (slave->closed) + goto done; + + /* Set up traps for especially handled signals. */ + fail_if (trap_signals() < 0); + + fail_if ((errno = pthread_mutex_lock(&slave_mutex))); + + while (!reexecing && !terminating) { + if (!slave->wait_set->size || slave->closed) + break; + if (slave->timed) { + fail_if (monotone(&now)); + if (now.tv_sec > slave->dethklok.tv_sec) + break; + if (now.tv_sec == slave->dethklok.tv_sec) + if (now.tv_nsec >= slave->dethklok.tv_nsec) + break; + } + pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); } - pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); - } - - if (!(slave->closed) && (slave->wait_set->size == 0)) - slave_notify_client(slave); - - pthread_mutex_unlock(&slave_mutex); - - goto done; - - fail: - xperror(*argv); - done: - with_mutex (slave_mutex, - if (!reexecing) - linked_list_remove(&slave_list, slave->node); - running_slaves--; - if (running_slaves == 0) - pthread_cond_signal(&slave_cond); - ); - return NULL; + + if (!slave->closed && !slave->wait_set->size) + slave_notify_client(slave); + + pthread_mutex_unlock(&slave_mutex); + + goto done; + +fail: + xperror(*argv); +done: + with_mutex (slave_mutex, + if (!reexecing) + linked_list_remove(&slave_list, slave->node); + running_slaves--; + if (!running_slaves) + pthread_cond_signal(&slave_cond); + ); + return NULL; } @@ -137,26 +133,27 @@ static void* slave_loop(void* data) * @param slave The slave * @return Non-zero on error, `errno` will be set accordingly */ -int start_created_slave(slave_t* restrict slave) +int +start_created_slave(slave_t *restrict slave) { - int locked = 0; - - fail_if ((errno = pthread_mutex_lock(&slave_mutex))); - locked = 1; - - fail_if ((errno = pthread_create(&(slave->thread), NULL, slave_loop, (void*)(intptr_t)slave))); - - if ((errno = pthread_detach(slave->thread))) - xperror(*argv); - - running_slaves++; - pthread_mutex_unlock(&slave_mutex); - - return 0; - fail: - if (locked) - pthread_mutex_unlock(&slave_mutex); - return -1; + int locked = 0; + + fail_if ((errno = pthread_mutex_lock(&slave_mutex))); + locked = 1; + + fail_if ((errno = pthread_create(&(slave->thread), NULL, slave_loop, (void*)(intptr_t)slave))); + + if ((errno = pthread_detach(slave->thread))) + xperror(*argv); + + running_slaves++; + pthread_mutex_unlock(&slave_mutex); + + return 0; +fail: + if (locked) + pthread_mutex_unlock(&slave_mutex); + return -1; } @@ -168,49 +165,50 @@ int start_created_slave(slave_t* restrict slave) * @param recv_message_id The ID of the message that triggered the waiting * @return Non-zero on error */ -int start_slave(hash_table_t* restrict wait_set, const char* restrict recv_client_id, - const char* restrict recv_message_id) +int +start_slave(hash_table_t *restrict wait_set, const char *restrict recv_client_id, const char *restrict recv_message_id) { - slave_t* slave = slave_create(wait_set, recv_client_id, recv_message_id); - size_t slave_address, i; - ssize_t node = LINKED_LIST_UNUSED; - int locked = 0; - - fail_if (slave == NULL); - fail_if ((errno = pthread_mutex_lock(&slave_mutex))); - locked = 1; - - slave_address = (size_t)(void*)slave; - slave->node = node = linked_list_insert_end(&slave_list, slave_address); - fail_if (slave->node == LINKED_LIST_UNUSED); - - for (i = 0; i < received.header_count; i++) - if (startswith(received.headers[i], "Time to live: ")) - { - const char* ttl = received.headers[i] + strlen("Time to live: "); - slave->timed = 1; - fail_if (monotone(&(slave->dethklok))); - slave->dethklok.tv_sec += (time_t)atoll(ttl); - /* It should really be `atol`, but we want to be future-proof. */ - break; - } - - fail_if ((errno = pthread_create(&(slave->thread), NULL, slave_loop, (void*)(intptr_t)slave))); - - if ((errno = pthread_detach(slave->thread))) - xperror(*argv); - - running_slaves++; - pthread_mutex_unlock(&slave_mutex); - - return 0; - fail: - xperror(*argv); - if (locked) - pthread_mutex_unlock(&slave_mutex); - if (node != LINKED_LIST_UNUSED) - linked_list_remove(&slave_list, node); - return -1; + slave_t *slave = slave_create(wait_set, recv_client_id, recv_message_id); + size_t slave_address, i; + ssize_t node = LINKED_LIST_UNUSED; + int locked = 0; + const char* ttl; + + fail_if (!slave); + fail_if ((errno = pthread_mutex_lock(&slave_mutex))); + locked = 1; + + slave_address = (size_t)(void*)slave; + slave->node = node = linked_list_insert_end(&slave_list, slave_address); + fail_if (slave->node == LINKED_LIST_UNUSED); + + for (i = 0; i < received.header_count; i++) { + if (startswith(received.headers[i], "Time to live: ")) { + ttl = received.headers[i] + strlen("Time to live: "); + slave->timed = 1; + fail_if (monotone(&(slave->dethklok))); + slave->dethklok.tv_sec += (time_t)atoll(ttl); + /* It should really be `atol`, but we want to be future-proof. */ + break; + } + } + + fail_if ((errno = pthread_create(&(slave->thread), NULL, slave_loop, (void*)(intptr_t)slave))); + + if ((errno = pthread_detach(slave->thread))) + xperror(*argv); + + running_slaves++; + pthread_mutex_unlock(&slave_mutex); + + return 0; +fail: + xperror(*argv); + if (locked) + pthread_mutex_unlock(&slave_mutex); + if (node != LINKED_LIST_UNUSED) + linked_list_remove(&slave_list, node); + return -1; } @@ -219,17 +217,18 @@ int start_slave(hash_table_t* restrict wait_set, const char* restrict recv_clien * * @param client The client's ID */ -void close_slaves(uint64_t client) +void +close_slaves(uint64_t client) { - ssize_t node; - with_mutex (slave_mutex, - foreach_linked_list_node (slave_list, node) - { - slave_t* slave = (slave_t*)(void*)(slave_list.values[node]); - if (slave->client == client) - slave->closed = 1; - } - ); + ssize_t node; + slave_t *slave; + with_mutex (slave_mutex, + foreach_linked_list_node (slave_list, node) { + slave = (slave_t *)(void *)(slave_list.values[node]); + if (slave->client == client) + slave->closed = 1; + } + ); } @@ -239,31 +238,31 @@ void close_slaves(uint64_t client) * @param command The protocol * @return Non-zero on error, `ernno`will be set accordingly */ -int advance_slaves(char* command) +int +advance_slaves(char *command) { - size_t key = (size_t)(void*)command; - int signal_slaves = 0; - ssize_t node; - - fail_if ((errno = pthread_mutex_lock(&slave_mutex))); - - foreach_linked_list_node (slave_list, node) - { - slave_t* slave = (slave_t*)(void*)(slave_list.values[node]); - if (hash_table_contains_key(slave->wait_set, key)) - { - hash_table_remove(slave->wait_set, key); - signal_slaves |= slave->wait_set == 0; + size_t key = (size_t)(void *)command; + int signal_slaves = 0; + ssize_t node; + slave_t *slave; + + fail_if ((errno = pthread_mutex_lock(&slave_mutex))); + + foreach_linked_list_node (slave_list, node) { + slave = (void *)(slave_list.values[node]); + if (hash_table_contains_key(slave->wait_set, key)) { + hash_table_remove(slave->wait_set, key); + signal_slaves |= slave->wait_set == 0; + } } - } - - if (signal_slaves) - pthread_cond_broadcast(&slave_cond); - pthread_mutex_unlock(&slave_mutex); - return 0; - fail: - return -1; + if (signal_slaves) + pthread_cond_broadcast(&slave_cond); + + pthread_mutex_unlock(&slave_mutex); + return 0; +fail: + return -1; } @@ -275,27 +274,27 @@ int advance_slaves(char* command) * @param recv_message_id The ID of the message that triggered the waiting * @return The slave, `NULL` on error, `errno` will be set accordingly */ -slave_t* slave_create(hash_table_t* restrict wait_set, const char* restrict recv_client_id, - const char* restrict recv_message_id) +slave_t * +slave_create(hash_table_t *restrict wait_set, const char *restrict recv_client_id, const char *restrict recv_message_id) { - slave_t* restrict rc = NULL; - int saved_errno; - - fail_if (xmalloc(rc, 1, slave_t)); - - slave_initialise(rc); - rc->wait_set = wait_set; - rc->client = parse_client_id(recv_client_id); - - fail_if (xstrdup_nn(rc->client_id, recv_client_id)); - fail_if (xstrdup_nn(rc->message_id, recv_message_id)); - - return rc; - - fail: - saved_errno = errno; - slave_destroy(rc), free(rc); - return errno = saved_errno, NULL; + slave_t *restrict rc = NULL; + int saved_errno; + + fail_if (xmalloc(rc, 1, slave_t)); + + slave_initialise(rc); + rc->wait_set = wait_set; + rc->client = parse_client_id(recv_client_id); + + fail_if (xstrdup_nn(rc->client_id, recv_client_id)); + fail_if (xstrdup_nn(rc->message_id, recv_message_id)); + + return rc; + +fail: + saved_errno = errno; + slave_destroy(rc), free(rc); + return errno = saved_errno, NULL; } @@ -304,15 +303,16 @@ slave_t* slave_create(hash_table_t* restrict wait_set, const char* restrict recv * * @param this Memory slot in which to store the new slave information */ -void slave_initialise(slave_t* restrict this) +void +slave_initialise(slave_t *restrict this) { - this->wait_set = NULL; - this->client_id = NULL; - this->message_id = NULL; - this->closed = 0; - this->dethklok.tv_sec = 0; - this->dethklok.tv_nsec = 0; - this->timed = 0; + this->wait_set = NULL; + this->client_id = NULL; + this->message_id = NULL; + this->closed = 0; + this->dethklok.tv_sec = 0; + this->dethklok.tv_nsec = 0; + this->timed = 0; } @@ -321,23 +321,23 @@ void slave_initialise(slave_t* restrict this) * * @param this The slave information */ -void slave_destroy(slave_t* restrict this) +void +slave_destroy(slave_t *restrict this) { - if (this == NULL) - return; - - if (this->wait_set != NULL) - { - hash_table_destroy(this->wait_set, (free_func*)reg_table_free_key, NULL); - free(this->wait_set); - this->wait_set = NULL; - } - - free(this->client_id); - this->client_id = NULL; - - free(this->message_id); - this->message_id = NULL; + if (!this) + return; + + if (this->wait_set) { + hash_table_destroy(this->wait_set, (free_func*)reg_table_free_key, NULL); + free(this->wait_set); + this->wait_set = NULL; + } + + free(this->client_id); + this->client_id = NULL; + + free(this->message_id); + this->message_id = NULL; } @@ -347,23 +347,24 @@ void slave_destroy(slave_t* restrict this) * @param this The slave information * @return The number of bytes to allocate to the output buffer */ -size_t slave_marshal_size(const slave_t* restrict this) +size_t +slave_marshal_size(const slave_t *restrict this) { - size_t rc; - hash_entry_t* restrict entry; - size_t n; - - rc = sizeof(int) + sizeof(sig_atomic_t) + sizeof(ssize_t) + sizeof(size_t) + sizeof(uint64_t); - rc += sizeof(int) + sizeof(time_t) + sizeof(long); - rc += (strlen(this->client_id) + strlen(this->message_id) + 2) * sizeof(char); - - foreach_hash_table_entry (*(this->wait_set), n, entry) - { - char* protocol = (char*)(void*)(entry->key); - rc += strlen(protocol) + 1; - } - - return rc; + size_t rc; + hash_entry_t *restrict entry; + size_t n; + char *protocol; + + rc = sizeof(int) + sizeof(sig_atomic_t) + sizeof(ssize_t) + sizeof(size_t) + sizeof(uint64_t); + rc += sizeof(int) + sizeof(time_t) + sizeof(long); + rc += (strlen(this->client_id) + strlen(this->message_id) + 2) * sizeof(char); + + foreach_hash_table_entry (*(this->wait_set), n, entry) { + protocol = (void *)(entry->key); + rc += strlen(protocol) + 1; + } + + return rc; } @@ -374,36 +375,37 @@ size_t slave_marshal_size(const slave_t* restrict this) * @param data Output buffer for the marshalled data * @return The number of bytes that have been written (everything will be written) */ -size_t slave_marshal(const slave_t* restrict this, char* restrict data) +size_t +slave_marshal(const slave_t *restrict this, char *restrict data) { - hash_entry_t* restrict entry; - size_t n; - - buf_set_next(data, int, SLAVE_T_VERSION); - buf_set_next(data, sig_atomic_t, this->closed); - buf_set_next(data, ssize_t, this->node); - buf_set_next(data, uint64_t, this->client); - buf_set_next(data, int, this->timed); - buf_set_next(data, time_t, this->dethklok.tv_sec); - buf_set_next(data, long, this->dethklok.tv_nsec); - - memcpy(data, this->client_id, (strlen(this->client_id) + 1) * sizeof(char)); - data += strlen(this->client_id) + 1; - - memcpy(data, this->message_id, (strlen(this->message_id) + 1) * sizeof(char)); - data += strlen(this->message_id) + 1; - - n = this->wait_set->size; - buf_set_next(data, size_t, n); - - foreach_hash_table_entry (*(this->wait_set), n, entry) - { - char* restrict protocol = (char*)(void*)(entry->key); - memcpy(data, protocol, (strlen(protocol) + 1) * sizeof(char)); - data += strlen(protocol) + 1; - } - - return slave_marshal_size(this); + hash_entry_t *restrict entry; + size_t n; + char *restrict protocol; + + buf_set_next(data, int, SLAVE_T_VERSION); + buf_set_next(data, sig_atomic_t, this->closed); + buf_set_next(data, ssize_t, this->node); + buf_set_next(data, uint64_t, this->client); + buf_set_next(data, int, this->timed); + buf_set_next(data, time_t, this->dethklok.tv_sec); + buf_set_next(data, long, this->dethklok.tv_nsec); + + memcpy(data, this->client_id, (strlen(this->client_id) + 1) * sizeof(char)); + data += strlen(this->client_id) + 1; + + memcpy(data, this->message_id, (strlen(this->message_id) + 1) * sizeof(char)); + data += strlen(this->message_id) + 1; + + n = this->wait_set->size; + buf_set_next(data, size_t, n); + + foreach_hash_table_entry (*(this->wait_set), n, entry) { + protocol = (void *)(entry->key); + memcpy(data, protocol, (strlen(protocol) + 1) * sizeof(char)); + data += strlen(protocol) + 1; + } + + return slave_marshal_size(this); } @@ -415,55 +417,55 @@ size_t slave_marshal(const slave_t* restrict this, char* restrict data) * @return Zero on error, `errno` will be set accordingly, otherwise the * number of read bytes. Destroy the slave information on error. */ -size_t slave_unmarshal(slave_t* restrict this, char* restrict data) +size_t +slave_unmarshal(slave_t *restrict this, char *restrict data) { - size_t key, n, m, rc = 2 * sizeof(int) + sizeof(ssize_t) + sizeof(size_t) + sizeof(uint64_t); - char* protocol = NULL; - int saved_errno; - - this->wait_set = NULL; - this->client_id = NULL; - this->message_id = NULL; - - /* buf_get_next(data, int, SLAVE_T_VERSION); */ - buf_next(data, int, 1); - - buf_get_next(data, sig_atomic_t, this->closed); - buf_get_next(data, ssize_t, this->node); - buf_get_next(data, uint64_t, this->client); - buf_get_next(data, int, this->timed); - buf_get_next(data, time_t, this->dethklok.tv_sec); - buf_get_next(data, long, this->dethklok.tv_nsec); - - n = strlen((char*)data) + 1; - fail_if (xmemdup(this->client_id, data, n, char)); - data += n, rc += n * sizeof(char); - - n = strlen((char*)data) + 1; - fail_if (xmemdup(this->message_id, data, n, char)); - data += n, rc += n * sizeof(char); - - fail_if (xmalloc(this->wait_set, 1, hash_table_t)); - fail_if (hash_table_create(this->wait_set)); - - buf_get_next(data, size_t, m); - - while (m--) - { - n = strlen((char*)data) + 1; - fail_if (xmemdup(protocol, data, n, char)); - data += n, rc += n * sizeof(char); - - key = (size_t)(void*)protocol; - if (hash_table_put(this->wait_set, key, 1) == 0) - fail_if (errno); - } - - return rc; - fail: - saved_errno = errno; - free(protocol); - return errno = saved_errno, (size_t)0; + size_t key, n, m, rc = 2 * sizeof(int) + sizeof(ssize_t) + sizeof(size_t) + sizeof(uint64_t); + char *protocol = NULL; + int saved_errno; + + this->wait_set = NULL; + this->client_id = NULL; + this->message_id = NULL; + + /* buf_get_next(data, int, SLAVE_T_VERSION); */ + buf_next(data, int, 1); + + buf_get_next(data, sig_atomic_t, this->closed); + buf_get_next(data, ssize_t, this->node); + buf_get_next(data, uint64_t, this->client); + buf_get_next(data, int, this->timed); + buf_get_next(data, time_t, this->dethklok.tv_sec); + buf_get_next(data, long, this->dethklok.tv_nsec); + + n = strlen((char *)data) + 1; + fail_if (xmemdup(this->client_id, data, n, char)); + data += n, rc += n * sizeof(char); + + n = strlen((char *)data) + 1; + fail_if (xmemdup(this->message_id, data, n, char)); + data += n, rc += n * sizeof(char); + + fail_if (xmalloc(this->wait_set, 1, hash_table_t)); + fail_if (hash_table_create(this->wait_set)); + + buf_get_next(data, size_t, m); + + while (m--) { + n = strlen((char *)data) + 1; + fail_if (xmemdup(protocol, data, n, char)); + data += n, rc += n * sizeof(char); + + key = (size_t)(void*)protocol; + if (!hash_table_put(this->wait_set, key, 1)) + fail_if (errno); + } + + return rc; +fail: + saved_errno = errno; + free(protocol); + return errno = saved_errno, (size_t)0; } @@ -473,35 +475,34 @@ size_t slave_unmarshal(slave_t* restrict this, char* restrict data) * @param data In buffer with the marshalled data * @return The number of read bytes */ -size_t slave_unmarshal_skip(char* restrict data) +size_t +slave_unmarshal_skip(char *restrict data) { - size_t n, m, rc = 2 * sizeof(int) + sizeof(ssize_t) + sizeof(size_t) + sizeof(uint64_t); - rc += sizeof(int) + sizeof(time_t) + sizeof(long); - - /* buf_get_next(data, int, SLAVE_T_VERSION); */ - buf_next(data, int, 1); - - buf_next(data, sig_atomic_t, 1); - buf_next(data, ssize_t, 1); - buf_next(data, uint64_t, 1); - buf_next(data, int, 1); - buf_next(data, time_t, 1); - buf_next(data, long, 1); - - n = (strlen((char*)data) + 1) * sizeof(char); - data += n, rc += n; - - n = (strlen((char*)data) + 1) * sizeof(char); - data += n, rc += n; - - buf_get_next(data, size_t, m); - - while (m--) - { - n = (strlen((char*)data) + 1) * sizeof(char); - data += n, rc += n; - } + size_t n, m, rc = 2 * sizeof(int) + sizeof(ssize_t) + sizeof(size_t) + sizeof(uint64_t); + rc += sizeof(int) + sizeof(time_t) + sizeof(long); + + /* buf_get_next(data, int, SLAVE_T_VERSION); */ + buf_next(data, int, 1); + + buf_next(data, sig_atomic_t, 1); + buf_next(data, ssize_t, 1); + buf_next(data, uint64_t, 1); + buf_next(data, int, 1); + buf_next(data, time_t, 1); + buf_next(data, long, 1); - return rc; -} + n = (strlen((char *)data) + 1) * sizeof(char); + data += n, rc += n; + + n = (strlen((char *)data) + 1) * sizeof(char); + data += n, rc += n; + + buf_get_next(data, size_t, m); + while (m--) { + n = (strlen((char*)data) + 1) * sizeof(char); + data += n, rc += n; + } + + return rc; +} diff --git a/src/mds-registry/slave.h b/src/mds-registry/slave.h index 14ff04b..616575d 100644 --- a/src/mds-registry/slave.h +++ b/src/mds-registry/slave.h @@ -30,59 +30,59 @@ -#define SLAVE_T_VERSION 0 +#define SLAVE_T_VERSION 0 /** * Slave information, a thread waiting for protocols to become available */ typedef struct slave { - /** - * Set of protocols for which to wait that they become available - */ - hash_table_t* wait_set; - - /** - * The ID of the waiting client - */ - uint64_t client; - - /** - * The ID of the waiting client - */ - char* client_id; - - /** - * The ID of the message that triggered the waiting - */ - char* message_id; - - /** - * The slave's node in the linked list of slaves - */ - ssize_t node; - - /** - * Whether the client has been closed - */ - volatile sig_atomic_t closed; - - /** - * The slave thread - */ - pthread_t thread; - - /** - * The time slave should die if its condition - * has not be meet at that time - */ - struct timespec dethklok; - - /** - * Whether `dethklok` should apply - */ - int timed; - + /** + * Set of protocols for which to wait that they become available + */ + hash_table_t *wait_set; + + /** + * The ID of the waiting client + */ + uint64_t client; + + /** + * The ID of the waiting client + */ + char *client_id; + + /** + * The ID of the message that triggered the waiting + */ + char *message_id; + + /** + * The slave's node in the linked list of slaves + */ + ssize_t node; + + /** + * Whether the client has been closed + */ + volatile sig_atomic_t closed; + + /** + * The slave thread + */ + pthread_t thread; + + /** + * The time slave should die if its condition + * has not be meet at that time + */ + struct timespec dethklok; + + /** + * Whether `dethklok` should apply + */ + int timed; + } slave_t; @@ -94,7 +94,7 @@ typedef struct slave * @return Non-zero on error, `errno` will be set accordingly */ __attribute__((nonnull)) -int start_created_slave(slave_t* restrict slave); +int start_created_slave(slave_t *restrict slave); /** * Start a slave thread @@ -105,8 +105,8 @@ int start_created_slave(slave_t* restrict slave); * @return Non-zero on error */ __attribute__((nonnull)) -int start_slave(hash_table_t* restrict wait_set, const char* restrict recv_client_id, - const char* restrict recv_message_id); +int start_slave(hash_table_t *restrict wait_set, const char *restrict recv_client_id, + const char *restrict recv_message_id); /** * Close all slaves associated with a client @@ -122,7 +122,7 @@ void close_slaves(uint64_t client); * @return Non-zero on error, `ernno`will be set accordingly */ __attribute__((nonnull)) -int advance_slaves(char* command); +int advance_slaves(char *command); /** * Create a slave @@ -133,8 +133,8 @@ int advance_slaves(char* command); * @return The slave, `NULL` on error, `errno` will be set accordingly */ __attribute__((nonnull)) -slave_t* slave_create(hash_table_t* restrict wait_set, const char* restrict recv_client_id, - const char* restrict recv_message_id); +slave_t *slave_create(hash_table_t *restrict wait_set, const char *restrict recv_client_id, + const char *restrict recv_message_id); /** @@ -143,14 +143,14 @@ slave_t* slave_create(hash_table_t* restrict wait_set, const char* restrict recv * @param this Memory slot in which to store the new slave information */ __attribute__((nonnull)) -void slave_initialise(slave_t* restrict this); +void slave_initialise(slave_t *restrict this); /** * Release all resources assoicated with a slave * * @param this The slave information */ -void slave_destroy(slave_t* restrict this); +void slave_destroy(slave_t *restrict this); /** * Calculate the buffer size need to marshal slave information @@ -159,7 +159,7 @@ void slave_destroy(slave_t* restrict this); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t slave_marshal_size(const slave_t* restrict this); +size_t slave_marshal_size(const slave_t *restrict this); /** * Marshals slave information @@ -169,7 +169,7 @@ size_t slave_marshal_size(const slave_t* restrict this); * @return The number of bytes that have been written (everything will be written) */ __attribute__((nonnull)) -size_t slave_marshal(const slave_t* restrict this, char* restrict data); +size_t slave_marshal(const slave_t *restrict this, char *restrict data); /** * Unmarshals slave information @@ -180,7 +180,7 @@ size_t slave_marshal(const slave_t* restrict this, char* restrict data); * number of read bytes. Destroy the slave information on error. */ __attribute__((nonnull)) -size_t slave_unmarshal(slave_t* restrict this, char* restrict data); +size_t slave_unmarshal(slave_t *restrict this, char *restrict data); /** * Pretend to unmarshal slave information @@ -189,8 +189,7 @@ size_t slave_unmarshal(slave_t* restrict this, char* restrict data); * @return The number of read bytes */ __attribute__((pure, nonnull)) -size_t slave_unmarshal_skip(char* restrict data); +size_t slave_unmarshal_skip(char *restrict data); #endif - diff --git a/src/mds-registry/util.c b/src/mds-registry/util.c index e49867f..4889a09 100644 --- a/src/mds-registry/util.c +++ b/src/mds-registry/util.c @@ -39,8 +39,8 @@ */ void reg_table_free_key(size_t obj) { - char* command = (char*)(void*)obj; - free(command); + char *command = (void *)obj; + free(command); } @@ -51,8 +51,7 @@ void reg_table_free_key(size_t obj) */ void reg_table_free_value(size_t obj) { - client_list_t* list = (client_list_t*)(void*)obj; - client_list_destroy(list); - free(list); + client_list_t *list = (void *)obj; + client_list_destroy(list); + free(list); } - diff --git a/src/mds-registry/util.h b/src/mds-registry/util.h index c4be42a..222b887 100644 --- a/src/mds-registry/util.h +++ b/src/mds-registry/util.h @@ -38,5 +38,3 @@ void reg_table_free_value(size_t obj); #endif - - diff --git a/src/mds-respawn.c b/src/mds-respawn.c index 3d62c8f..8b136be 100644 --- a/src/mds-respawn.c +++ b/src/mds-respawn.c @@ -31,7 +31,7 @@ -#define MDS_RESPAWN_VARS_VERSION 0 +#define MDS_RESPAWN_VARS_VERSION 0 @@ -41,15 +41,14 @@ * * This tells the server-base how to behave */ -server_characteristics_t server_characteristics = - { - .require_privileges = 0, - .require_display = 0, - .require_respawn_info = 1, - .sanity_check_argc = 0, - .fork_for_safety = 0, - .danger_is_deadly = 0 - }; +server_characteristics_t server_characteristics = { + .require_privileges = 0, + .require_display = 0, + .require_respawn_info = 1, + .sanity_check_argc = 0, + .fork_for_safety = 0, + .danger_is_deadly = 0 +}; @@ -66,18 +65,18 @@ static size_t servers = 0; /** * Command line arguments, for each server — concatenated, with NULL-termination */ -static char** commands_args = NULL; +static char **commands_args = NULL; /** * Mapping elements in `commands_args` that are the first * argument for each server to run */ -static char*** commands = NULL; +static char ***commands = NULL; /** * States of managed servers */ -static server_state_t* states = NULL; +static server_state_t *states = NULL; /** * Whether a revive request has been received but not processed @@ -98,68 +97,60 @@ static size_t live_count = 0; */ int parse_cmdline(void) { - /* Parse command line arguments. */ - - int i; - size_t j, args = 0, stack = 0; - for (i = 1; i < argc; i++) - { - char* arg = argv[i]; - if (startswith(arg, "--alarm=")) /* Schedule an alarm signal for forced abort. */ - alarm((unsigned)min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ - else if (startswith(arg, "--interval=")) - interval = min(atoi(arg + strlen("--interval=")), 60); /* At most 1 minute. */ - else if (strequals(arg, "--re-exec")) /* Re-exec state-marshal. */ - is_reexec = 1; - else if (strequals(arg, "{")) - servers += stack++ == 0 ? 1 : 0; - else if (strequals(arg, "}")) - { - exit_if (stack-- == 0, eprint("Terminating non-started command, aborting.");); - exit_if (stack == 0 && strequals(argv[i - 1], "{"), - eprint("Zero argument command specified, aborting.");); + /* Parse command line arguments. */ + int i; + size_t j, args = 0, stack = 0; + char* arg; + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (startswith(arg, "--alarm=")) { /* Schedule an alarm signal for forced abort. */ + alarm((unsigned)min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ + } else if (startswith(arg, "--interval=")) { + interval = min(atoi(arg + strlen("--interval=")), 60); /* At most 1 minute. */ + } else if (strequals(arg, "--re-exec")) { /* Re-exec state-marshal. */ + is_reexec = 1; + } else if (strequals(arg, "{")) { + servers += stack++ == 0 ? 1 : 0; + } else if (strequals(arg, "}")) { + exit_if (!stack--, eprint("Terminating non-started command, aborting.");); + exit_if (!stack && strequals(argv[i - 1], "{"), + eprint("Zero argument command specified, aborting.");); + } else if (!stack) { + eprintf("Unrecognised option: %s, did you forget `='?", arg); + } else { + args++; + } } - else if (stack == 0) - eprintf("Unrecognised option: %s, did you forget `='?", arg); - else - args++; - } - if (is_reexec) - { - is_respawn = 1; - eprint("re-exec performed."); - } - - - /* Validate command line arguments. */ - - exit_if (stack > 0, eprint("Non-terminated command specified, aborting.");); - exit_if (servers == 0, eprint("No programs to spawn, aborting.");); - - - /* Allocate arrays. */ - - fail_if (xmalloc(commands_args, args + servers, char*)); - fail_if (xmalloc(commands, servers, char**)); - fail_if (xmalloc(states, servers, server_state_t)); - - - /* Fill command arrays. */ - - for (i = 1, args = j = 0; i < argc; i++) - { - char* arg = argv[i]; - if (strequals(arg, "}")) commands_args[args++] = --stack == 0 ? NULL : arg; - else if (stack > 0) commands_args[args++] = arg; - else if (strequals(arg, "{") && (stack++ == 0)) - commands[j++] = commands_args + args; - } - - return 0; - - fail: - xperror(*argv); - return 1; + if (is_reexec) { + is_respawn = 1; + eprint("re-exec performed."); + } + + /* Validate command line arguments. */ + exit_if (stack > 0, eprint("Non-terminated command specified, aborting.");); + exit_if (servers == 0, eprint("No programs to spawn, aborting.");); + + /* Allocate arrays. */ + fail_if (xmalloc(commands_args, args + servers, char*)); + fail_if (xmalloc(commands, servers, char**)); + fail_if (xmalloc(states, servers, server_state_t)); + + /* Fill command arrays. */ + for (i = 1, args = j = 0; i < argc; i++) { + arg = argv[i]; + if (strequals(arg, "}")) + commands_args[args++] = --stack == 0 ? NULL : arg; + else if (stack > 0) + commands_args[args++] = arg; + else if (strequals(arg, "{") && !stack++) + commands[j++] = commands_args + args; + } + + return 0; +fail: + xperror(*argv); + return 1; } @@ -168,51 +159,43 @@ int parse_cmdline(void) * * @param index The index of the server */ -static void spawn_server(size_t index) +static void +spawn_server(size_t index) { - struct timespec started; - pid_t pid; - - /* When did the spawned server start? */ - - if (monotone(&started) < 0) - { - xperror(*argv); - eprintf("cannot read clock when starting %s, burying.", commands[index][0]); - states[index].state = DEAD_AND_BURIED; - return; - } - states[index].started = started; - - - /* Fork process to spawn the server. */ - - pid = fork(); - if (pid == (pid_t)-1) - { - xperror(*argv); - eprintf("cannot fork in order to start %s, burying.", commands[index][0]); - states[index].state = DEAD_AND_BURIED; - return; - } - - - /* In the parent process (respawner): store spawned server information. */ - - if (pid) - { - states[index].pid = pid; - states[index].state = ALIVE; - live_count++; - return; - } - - /* In the child process (server): remove the alarm and change execution image to the server.. */ - - alarm(0); - execvp(commands[index][0], commands[index]); - xperror(commands[index][0]); - _exit(1); + struct timespec started; + pid_t pid; + + /* When did the spawned server start? */ + if (monotone(&started) < 0) { + xperror(*argv); + eprintf("cannot read clock when starting %s, burying.", commands[index][0]); + states[index].state = DEAD_AND_BURIED; + return; + } + states[index].started = started; + + /* Fork process to spawn the server. */ + pid = fork(); + if (pid == (pid_t)-1) { + xperror(*argv); + eprintf("cannot fork in order to start %s, burying.", commands[index][0]); + states[index].state = DEAD_AND_BURIED; + return; + } + + /* In the parent process (respawner): store spawned server information. */ + if (pid) { + states[index].pid = pid; + states[index].state = ALIVE; + live_count++; + return; + } + + /* In the child process (server): remove the alarm and change execution image to the server.. */ + alarm(0); + execvp(commands[index][0], commands[index]); + xperror(commands[index][0]); + _exit(1); } @@ -223,13 +206,14 @@ static void spawn_server(size_t index) * * @param signo The signal that has been received */ -static void received_revive(int signo) +static void +received_revive(int signo) { - SIGHANDLER_START; - (void) signo; - reviving = 1; - eprint("revive signal received."); - SIGHANDLER_END; + SIGHANDLER_START; + (void) signo; + reviving = 1; + eprint("revive signal received."); + SIGHANDLER_END; } @@ -239,15 +223,16 @@ static void received_revive(int signo) * * @return Non-zero on error */ -int preinitialise_server(void) +int +preinitialise_server(void) { - /* Make the server revive all `DEAD_AND_BURIED` servers on SIGUSR2. */ - fail_if (xsigaction(SIGUSR2, received_revive) < 0); - - return 0; - fail: - xperror(*argv); - return 1; + /* Make the server revive all `DEAD_AND_BURIED` servers on SIGUSR2. */ + fail_if (xsigaction(SIGUSR2, received_revive) < 0); + + return 0; +fail: + xperror(*argv); + return 1; } @@ -257,17 +242,18 @@ int preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +int +initialise_server(void) { #if UNBORN != 0 - size_t i; + size_t i; #endif - memset(states, 0, servers * sizeof(server_state_t)); + memset(states, 0, servers * sizeof(server_state_t)); #if UNBORN != 0 - for (i = 0; i < servers; i++) - states[i].state = UNBORN; + for (i = 0; i < servers; i++) + states[i].state = UNBORN; #endif - return 0; + return 0; } @@ -277,36 +263,33 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - size_t i, j; - - /* Spawn servers that has not been spawned yet. */ - - for (i = 0; i < servers; i++) - if (states[i].state == UNBORN) - spawn_server(i); - - /* Forever mark newly spawned services (after this point in time) - as respawned. */ - - for (i = j = 0; j < servers; i++) - if (commands_args[i] == NULL) - j++; - else if (strequals(commands_args[i], "--initial-spawn")) - fail_if (xstrdup(commands_args[i], "--respawn")); - - /* Respawn dead and dead and buried servers. */ - - for (i = 0; i < servers; i++) - if ((states[i].state == DEAD) || - (states[i].state == DEAD_AND_BURIED)) - spawn_server(i); - - return 0; - fail: - xperror(*argv); - return 1; + size_t i, j; + + /* Spawn servers that has not been spawned yet. */ + for (i = 0; i < servers; i++) + if (states[i].state == UNBORN) + spawn_server(i); + + /* Forever mark newly spawned services (after this point in time) as respawned. */ + for (i = j = 0; j < servers; i++) { + if (!commands_args[i]) + j++; + else if (strequals(commands_args[i], "--initial-spawn")) + fail_if (xstrdup(commands_args[i], "--respawn")); + } + + /* Respawn dead and dead and buried servers. */ + for (i = 0; i < servers; i++) + if (states[i].state == DEAD || states[i].state == DEAD_AND_BURIED) + spawn_server(i); + + return 0; +fail: + xperror(*argv); + return 1; } @@ -318,12 +301,13 @@ int postinitialise_server(void) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t rc = sizeof(int) + sizeof(sig_atomic_t); - rc += sizeof(time_t) + sizeof(long); - rc += servers * sizeof(server_state_t); - return rc; + size_t rc = sizeof(int) + sizeof(sig_atomic_t); + rc += sizeof(time_t) + sizeof(long); + rc += servers * sizeof(server_state_t); + return rc; } @@ -333,26 +317,26 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - size_t i; - struct timespec antiepoch; - antiepoch.tv_sec = 0; - antiepoch.tv_nsec = 0; - (void) monotone(&antiepoch); - buf_set_next(state_buf, int, MDS_RESPAWN_VARS_VERSION); - buf_set_next(state_buf, sig_atomic_t, reviving); - buf_set_next(state_buf, time_t, antiepoch.tv_sec); - buf_set_next(state_buf, long, antiepoch.tv_nsec); - for (i = 0; i < servers; i++) - { - buf_set_next(state_buf, pid_t, states[i].pid); - buf_set_next(state_buf, int, states[i].state); - buf_set_next(state_buf, time_t, states[i].started.tv_sec); - buf_set_next(state_buf, long, states[i].started.tv_nsec); - } - free(states); - return 0; + size_t i; + struct timespec antiepoch; + antiepoch.tv_sec = 0; + antiepoch.tv_nsec = 0; + (void) monotone(&antiepoch); + buf_set_next(state_buf, int, MDS_RESPAWN_VARS_VERSION); + buf_set_next(state_buf, sig_atomic_t, reviving); + buf_set_next(state_buf, time_t, antiepoch.tv_sec); + buf_set_next(state_buf, long, antiepoch.tv_nsec); + for (i = 0; i < servers; i++) { + buf_set_next(state_buf, pid_t, states[i].pid); + buf_set_next(state_buf, int, states[i].state); + buf_set_next(state_buf, time_t, states[i].started.tv_sec); + buf_set_next(state_buf, long, states[i].started.tv_nsec); + } + free(states); + return 0; } @@ -366,53 +350,47 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - size_t i; - struct timespec antiepoch; - struct timespec epoch; - epoch.tv_sec = 0; - epoch.tv_nsec = 0; - (void) monotone(&epoch); - /* buf_get_next(state_buf, int, MDS_RESPAWN_VARS_VERSION); */ - buf_next(state_buf, int, 1); - buf_get_next(state_buf, sig_atomic_t, reviving); - buf_get_next(state_buf, time_t, antiepoch.tv_sec); - buf_get_next(state_buf, long, antiepoch.tv_nsec); - epoch.tv_sec -= antiepoch.tv_sec; - epoch.tv_nsec -= antiepoch.tv_nsec; - for (i = 0; i < servers; i++) - { - buf_get_next(state_buf, pid_t, states[i].pid); - buf_get_next(state_buf, int, states[i].state); - buf_get_next(state_buf, time_t, states[i].started.tv_sec); - buf_get_next(state_buf, long, states[i].started.tv_nsec); - if (validate_state(states[i].state) == 0) - { - states[i].state = CREMATED; - eprintf("invalid state unmarshallaed for `%s', cremating.", commands[i][0]); - } - else if (states[i].state == ALIVE) - { - live_count++; - /* Monotonic time epoch adjusment, the epoch of the monotonic - clock is unspecified, so we cannot know whether an exec - with cause a time jump. */ - states[i].started.tv_sec -= epoch.tv_sec; - states[i].started.tv_nsec -= epoch.tv_nsec; - if (states[i].started.tv_nsec < 0) - { - states[i].started.tv_sec -= 1; - states[i].started.tv_nsec += 1000000000; - } - else if (states[i].started.tv_nsec > 0) - { - states[i].started.tv_sec += 1; - states[i].started.tv_nsec -= 1000000000; - } + size_t i; + struct timespec antiepoch; + struct timespec epoch; + epoch.tv_sec = 0; + epoch.tv_nsec = 0; + (void) monotone(&epoch); + /* buf_get_next(state_buf, int, MDS_RESPAWN_VARS_VERSION); */ + buf_next(state_buf, int, 1); + buf_get_next(state_buf, sig_atomic_t, reviving); + buf_get_next(state_buf, time_t, antiepoch.tv_sec); + buf_get_next(state_buf, long, antiepoch.tv_nsec); + epoch.tv_sec -= antiepoch.tv_sec; + epoch.tv_nsec -= antiepoch.tv_nsec; + for (i = 0; i < servers; i++) { + buf_get_next(state_buf, pid_t, states[i].pid); + buf_get_next(state_buf, int, states[i].state); + buf_get_next(state_buf, time_t, states[i].started.tv_sec); + buf_get_next(state_buf, long, states[i].started.tv_nsec); + if (validate_state(states[i].state) == 0) { + states[i].state = CREMATED; + eprintf("invalid state unmarshallaed for `%s', cremating.", commands[i][0]); + } else if (states[i].state == ALIVE) { + live_count++; + /* Monotonic time epoch adjusment, the epoch of the monotonic + clock is unspecified, so we cannot know whether an exec + with cause a time jump. */ + states[i].started.tv_sec -= epoch.tv_sec; + states[i].started.tv_nsec -= epoch.tv_nsec; + if (states[i].started.tv_nsec < 0) { + states[i].started.tv_sec -= 1; + states[i].started.tv_nsec += 1000000000; + } else if (states[i].started.tv_nsec > 0) { + states[i].started.tv_sec += 1; + states[i].started.tv_nsec -= 1000000000; + } + } } - } - return 0; + return 0; } @@ -422,10 +400,11 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((cold, const)) reexec_failure_recover(void) +int __attribute__((cold, const)) +reexec_failure_recover(void) { - /* Re-exec cannot fail. */ - return 0; + /* Re-exec cannot fail. */ + return 0; } @@ -435,68 +414,64 @@ int __attribute__((cold, const)) reexec_failure_recover(void) * @param pid The process ID of the server that has exited * @param status The server's death status */ -static void joined_with_server(pid_t pid, int status) +static void +joined_with_server(pid_t pid, int status) { - struct timespec ended; - size_t i; - - /* Find index of reaped server. */ - for (i = 0; i < servers; i++) - if (states[i].pid == pid) - break; - if (i == servers) - { - eprintf("joined with unknown child process: %i", pid); - return; - } - - /* Do nothing if the server is cremated. */ - if (states[i].state == CREMATED) - { - eprintf("cremated child process `%s' exited, ignoring.", commands[i][0]); - return; - } - - /* Mark server as dead if it was alive. */ - if (states[i].state == ALIVE) - live_count--; - states[i].state = DEAD; - - /* Cremate server if it exited normally or was killed nicely. */ - if (WIFEXITED(status) ? (WEXITSTATUS(status) == 0) : - ((WTERMSIG(status) == SIGTERM) || (WTERMSIG(status) == SIGINT))) - { - eprintf("child process `%s' exited normally, cremating.", commands[i][0]); - states[i].state = CREMATED; - return; - } - - /* Print exit status of the reaped server. */ - if (WIFEXITED(status)) - eprintf("`%s' exited with code %i.", commands[i][0], WEXITSTATUS(status)); - else - eprintf("`%s' died by signal %i.", commands[i][0], WTERMSIG(status)); - - /* When did the server exit. */ - if (monotone(&ended) < 0) - { - xperror(*argv); - eprintf("`%s' died abnormally, burying because we could not read the time.", commands[i][0]); - states[i].state = DEAD_AND_BURIED; - return; - } - - /* Bury the server if it died abnormally too fast. */ - if (ended.tv_sec - states[i].started.tv_sec < interval) - { - eprintf("`%s' died abnormally, burying because it died too fast.", commands[i][0]); - states[i].state = DEAD_AND_BURIED; - return; - } - - /* Respawn server if it died abnormally in a responable time. */ - eprintf("`%s' died abnormally, respawning.", commands[i][0]); - spawn_server(i); + struct timespec ended; + size_t i; + + /* Find index of reaped server. */ + for (i = 0; i < servers; i++) + if (states[i].pid == pid) + break; + if (i == servers) { + eprintf("joined with unknown child process: %i", pid); + return; + } + + /* Do nothing if the server is cremated. */ + if (states[i].state == CREMATED) { + eprintf("cremated child process `%s' exited, ignoring.", commands[i][0]); + return; + } + + /* Mark server as dead if it was alive. */ + if (states[i].state == ALIVE) + live_count--; + states[i].state = DEAD; + + /* Cremate server if it exited normally or was killed nicely. */ + if (WIFEXITED(status) ? !WEXITSTATUS(status) : + (WTERMSIG(status) == SIGTERM || WTERMSIG(status) == SIGINT)) { + eprintf("child process `%s' exited normally, cremating.", commands[i][0]); + states[i].state = CREMATED; + return; + } + + /* Print exit status of the reaped server. */ + if (WIFEXITED(status)) + eprintf("`%s' exited with code %i.", commands[i][0], WEXITSTATUS(status)); + else + eprintf("`%s' died by signal %i.", commands[i][0], WTERMSIG(status)); + + /* When did the server exit. */ + if (monotone(&ended) < 0) { + xperror(*argv); + eprintf("`%s' died abnormally, burying because we could not read the time.", commands[i][0]); + states[i].state = DEAD_AND_BURIED; + return; + } + + /* Bury the server if it died abnormally too fast. */ + if (ended.tv_sec - states[i].started.tv_sec < interval) { + eprintf("`%s' died abnormally, burying because it died too fast.", commands[i][0]); + states[i].state = DEAD_AND_BURIED; + return; + } + + /* Respawn server if it died abnormally in a responable time. */ + eprintf("`%s' died abnormally, respawning.", commands[i][0]); + spawn_server(i); } @@ -505,36 +480,36 @@ static void joined_with_server(pid_t pid, int status) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - int status, rc = 0; - size_t i; - - while (!reexecing && !terminating && live_count) - { - pid_t pid = uninterruptable_waitpid(-1, &status, 0); - - if (reviving) - for (reviving = 0, i = 0; i < servers; i++) - if (states[i].state == DEAD_AND_BURIED) - spawn_server(i); - - if (pid == (pid_t)-1) - { - xperror(*argv); - rc = 1; - break; + int status, rc = 0; + size_t i; + pid_t pid; + + while (!reexecing && !terminating && live_count) { + pid = uninterruptable_waitpid(-1, &status, 0); + + if (reviving) + for (reviving = 0, i = 0; i < servers; i++) + if (states[i].state == DEAD_AND_BURIED) + spawn_server(i); + + if (pid == (pid_t)-1) { + xperror(*argv); + rc = 1; + break; + } + + joined_with_server(pid, status); } - - joined_with_server(pid, status); - } - - free(commands_args); - free(commands); - if (reexecing == 0) - free(states); - - return rc; + + free(commands_args); + free(commands); + if (!reexecing) + free(states); + + return rc; } @@ -545,41 +520,40 @@ int master_loop(void) * * @param signo The signal that has been received */ -void received_info(int signo) +void +received_info(int signo) { - SIGHANDLER_START; - server_state_t state; - size_t i, n = servers; - char** cmdline; - struct timespec now; - (void) signo; - if (monotone(&now) < 0) - iprint("(unable to get current time)"); - else - iprintf("current time: %ji.%09li", (intmax_t)(now.tv_sec), (long)(now.tv_nsec)); - iprintf("do-not-resuscitate period: %i seconds", interval); - iprintf("managed servers: %zu", n); - iprintf("alive servers: %zu", live_count); - iprintf("reviving: %s", reviving ? "yes" : "no"); - for (i = 0; i < n; i++) - { - state = states[i]; - cmdline = commands[i]; - iprintf("managed server %zu: pid: %li", i, (long)(state.pid)); - iprintf("managed server %zu: state: %s", i, - state.state == UNBORN ? "not started yet" : - state.state == ALIVE ? "up and running" : - state.state == DEAD ? "about to be respawn" : - state.state == DEAD_AND_BURIED ? "requires SIGUSR2 to respawn" : - state.state == CREMATED ? "will never respawn" : - "unrecognised state, something is wrong here!"); - iprintf("managed server %zu: started: %ji.%09li", i, - (intmax_t)(state.started.tv_sec), - (long)(state.started.tv_nsec)); - iprintf("managed server %zu: cmdline:", i); - while (*cmdline) - iprintf(" %z", *cmdline++); - } - SIGHANDLER_END; + SIGHANDLER_START; + server_state_t state; + size_t i, n = servers; + char **cmdline; + struct timespec now; + if (monotone(&now) < 0) + iprint("(unable to get current time)"); + else + iprintf("current time: %ji.%09li", (intmax_t)(now.tv_sec), (long)(now.tv_nsec)); + iprintf("do-not-resuscitate period: %i seconds", interval); + iprintf("managed servers: %zu", n); + iprintf("alive servers: %zu", live_count); + iprintf("reviving: %s", reviving ? "yes" : "no"); + for (i = 0; i < n; i++) { + state = states[i]; + cmdline = commands[i]; + iprintf("managed server %zu: pid: %li", i, (long)(state.pid)); + iprintf("managed server %zu: state: %s", i, + state.state == UNBORN ? "not started yet" : + state.state == ALIVE ? "up and running" : + state.state == DEAD ? "about to be respawn" : + state.state == DEAD_AND_BURIED ? "requires SIGUSR2 to respawn" : + state.state == CREMATED ? "will never respawn" : + "unrecognised state, something is wrong here!"); + iprintf("managed server %zu: started: %ji.%09li", i, + (intmax_t)(state.started.tv_sec), + (long)(state.started.tv_nsec)); + iprintf("managed server %zu: cmdline:", i); + while (*cmdline) + iprintf(" %z", *cmdline++); + } + SIGHANDLER_END; + (void) signo; } - diff --git a/src/mds-respawn.h b/src/mds-respawn.h index fb0e4fd..d1acd67 100644 --- a/src/mds-respawn.h +++ b/src/mds-respawn.h @@ -29,27 +29,27 @@ /** * The server has not started yet */ -#define UNBORN 0 +#define UNBORN 0 /** * The server is up and running */ -#define ALIVE 1 +#define ALIVE 1 /** * The server has crashed and will be respawn momentarily */ -#define DEAD 2 +#define DEAD 2 /** * The server crashed too fast, it will only respawn if SIGUSR2 is received */ -#define DEAD_AND_BURIED 3 +#define DEAD_AND_BURIED 3 /** * The server has exited successfully, it will never be respawn again */ -#define CREMATED 4 +#define CREMATED 4 @@ -59,7 +59,7 @@ * @param VALUE:int The state * @return :int Whether the state is value */ -#define validate_state(VALUE) ((UNBORN <= VALUE) && (VALUE <= CREMATED)) +#define validate_state(VALUE) (UNBORN <= (VALUE) && (VALUE) <= CREMATED) @@ -68,21 +68,21 @@ */ typedef struct server_state { - /** - * The server's process ID - */ - pid_t pid; - - /** - * The server's state - */ - int state; - - /** - * The time (monotonic) the server started - */ - struct timespec started; - + /** + * The server's process ID + */ + pid_t pid; + + /** + * The server's state + */ + int state; + + /** + * The time (monotonic) the server started + */ + struct timespec started; + } server_state_t; diff --git a/src/mds-server/client.c b/src/mds-server/client.c index 749a6ca..ad7104b 100644 --- a/src/mds-server/client.c +++ b/src/mds-server/client.c @@ -44,22 +44,23 @@ * * @param this Memory slot in which to store the new client information */ -void client_initialise(client_t* restrict this) +void +client_initialise(client_t *restrict this) { - this->list_entry = -1; - this->socket_fd = -1; - this->open = 0; - this->id = 0; - this->mutex_created = 0; - this->interception_conditions = NULL; - this->interception_conditions_count = 0; - this->multicasts = NULL; - this->multicasts_count = 0; - this->send_pending = NULL; - this->send_pending_size = 0; - this->modify_message = NULL; - this->modify_mutex_created = 0; - this->modify_cond_created = 0; + this->list_entry = -1; + this->socket_fd = -1; + this->open = 0; + this->id = 0; + this->mutex_created = 0; + this->interception_conditions = NULL; + this->interception_conditions_count = 0; + this->multicasts = NULL; + this->multicasts_count = 0; + this->send_pending = NULL; + this->send_pending_size = 0; + this->modify_message = NULL; + this->modify_mutex_created = 0; + this->modify_cond_created = 0; } @@ -75,25 +76,26 @@ void client_initialise(client_t* restrict this) * @param this The client information * @return Zero on success, -1 on error */ -int client_initialise_threading(client_t* restrict this) +int +client_initialise_threading(client_t *restrict this) { - /* Store the thread so that other threads can kill it. */ - this->thread = pthread_self(); - - /* Create mutex to make sure two thread to not try to send - messages concurrently, and other client local actions. */ - fail_if ((errno = pthread_mutex_init(&(this->mutex), NULL))); - this->mutex_created = 1; - - /* Create mutex and codition for multicast interception replies. */ - fail_if ((errno = pthread_mutex_init(&(this->modify_mutex), NULL))); - this->modify_mutex_created = 1; - fail_if ((errno = pthread_cond_init(&(this->modify_cond), NULL))); - this->modify_cond_created = 1; - - return 0; + /* Store the thread so that other threads can kill it. */ + this->thread = pthread_self(); + + /* Create mutex to make sure two thread to not try to send + messages concurrently, and other client local actions. */ + fail_if ((errno = pthread_mutex_init(&(this->mutex), NULL))); + this->mutex_created = 1; + + /* Create mutex and codition for multicast interception replies. */ + fail_if ((errno = pthread_mutex_init(&(this->modify_mutex), NULL))); + this->modify_mutex_created = 1; + fail_if ((errno = pthread_cond_init(&(this->modify_cond), NULL))); + this->modify_cond_created = 1; + + return 0; fail: - return -1; + return -1; } @@ -102,36 +104,33 @@ int client_initialise_threading(client_t* restrict this) * * @param this The client information */ -void client_destroy(client_t* restrict this) +void +client_destroy(client_t *restrict this) { - if (this->interception_conditions != NULL) - { - size_t i; - for (i = 0; i < this->interception_conditions_count; i++) - free(this->interception_conditions[i].condition); - free(this->interception_conditions); - } - if (this->mutex_created) - pthread_mutex_destroy(&(this->mutex)); - mds_message_destroy(&(this->message)); - if (this->multicasts != NULL) - { - size_t i; - for (i = 0; i < this->multicasts_count; i++) - multicast_destroy(this->multicasts + i); - free(this->multicasts); - } - free(this->send_pending); - if (this->modify_message != NULL) - { - mds_message_destroy(this->modify_message); - free(this->modify_message); - } - if (this->modify_mutex_created) - pthread_mutex_destroy(&(this->modify_mutex)); - if (this->modify_cond_created) - pthread_cond_destroy(&(this->modify_cond)); - free(this); + size_t i; + if (this->interception_conditions) { + for (i = 0; i < this->interception_conditions_count; i++) + free(this->interception_conditions[i].condition); + free(this->interception_conditions); + } + if (this->mutex_created) + pthread_mutex_destroy(&(this->mutex)); + mds_message_destroy(&(this->message)); + if (this->multicasts) { + for (i = 0; i < this->multicasts_count; i++) + multicast_destroy(this->multicasts + i); + free(this->multicasts); + } + free(this->send_pending); + if (this->modify_message) { + mds_message_destroy(this->modify_message); + free(this->modify_message); + } + if (this->modify_mutex_created) + pthread_mutex_destroy(&(this->modify_mutex)); + if (this->modify_cond_created) + pthread_cond_destroy(&(this->modify_cond)); + free(this); } @@ -141,19 +140,20 @@ void client_destroy(client_t* restrict this) * @param this The client information * @return The number of bytes to allocate to the output buffer */ -size_t client_marshal_size(const client_t* restrict this) +size_t +client_marshal_size(const client_t *restrict this) { - size_t i, n = sizeof(ssize_t) + 3 * sizeof(int) + sizeof(uint64_t) + 5 * sizeof(size_t); - - n += mds_message_marshal_size(&(this->message)); - for (i = 0; i < this->interception_conditions_count; i++) - n += interception_condition_marshal_size(this->interception_conditions + i); - for (i = 0; i < this->multicasts_count; i++) - n += multicast_marshal_size(this->multicasts + i); - n += this->send_pending_size * sizeof(char); - n += this->modify_message == NULL ? 0 : mds_message_marshal_size(this->modify_message); - - return n; + size_t i, n = sizeof(ssize_t) + 3 * sizeof(int) + sizeof(uint64_t) + 5 * sizeof(size_t); + + n += mds_message_marshal_size(&(this->message)); + for (i = 0; i < this->interception_conditions_count; i++) + n += interception_condition_marshal_size(this->interception_conditions + i); + for (i = 0; i < this->multicasts_count; i++) + n += multicast_marshal_size(this->multicasts + i); + n += this->send_pending_size * sizeof(char); + n += !this->modify_message ? 0 : mds_message_marshal_size(this->modify_message); + + return n; } @@ -164,34 +164,35 @@ size_t client_marshal_size(const client_t* restrict this) * @param data Output buffer for the marshalled data * @return The number of bytes that have been written (everything will be written) */ -size_t client_marshal(const client_t* restrict this, char* restrict data) +size_t +client_marshal(const client_t *restrict this, char *restrict data) { - size_t i, n; - buf_set_next(data, int, CLIENT_T_VERSION); - buf_set_next(data, ssize_t, this->list_entry); - buf_set_next(data, int, this->socket_fd); - buf_set_next(data, int, this->open); - buf_set_next(data, uint64_t, this->id); - n = mds_message_marshal_size(&(this->message)); - buf_set_next(data, size_t, n); - if (n > 0) - mds_message_marshal(&(this->message), data); - data += n / sizeof(char); - buf_set_next(data, size_t, this->interception_conditions_count); - for (i = 0; i < this->interception_conditions_count; i++) - data += n = interception_condition_marshal(this->interception_conditions + i, data) / sizeof(char); - buf_set_next(data, size_t, this->multicasts_count); - for (i = 0; i < this->multicasts_count; i++) - data += multicast_marshal(this->multicasts + i, data) / sizeof(char); - buf_set_next(data, size_t, this->send_pending_size); - if (this->send_pending_size > 0) - memcpy(data, this->send_pending, this->send_pending_size * sizeof(char)); - data += this->send_pending_size; - n = this->modify_message == NULL ? 0 : mds_message_marshal_size(this->modify_message); - buf_set_next(data, size_t, n); - if (this->modify_message != NULL) - mds_message_marshal(this->modify_message, data); - return client_marshal_size(this); + size_t i, n; + buf_set_next(data, int, CLIENT_T_VERSION); + buf_set_next(data, ssize_t, this->list_entry); + buf_set_next(data, int, this->socket_fd); + buf_set_next(data, int, this->open); + buf_set_next(data, uint64_t, this->id); + n = mds_message_marshal_size(&(this->message)); + buf_set_next(data, size_t, n); + if (n > 0) + mds_message_marshal(&(this->message), data); + data += n / sizeof(char); + buf_set_next(data, size_t, this->interception_conditions_count); + for (i = 0; i < this->interception_conditions_count; i++) + data += n = interception_condition_marshal(this->interception_conditions + i, data) / sizeof(char); + buf_set_next(data, size_t, this->multicasts_count); + for (i = 0; i < this->multicasts_count; i++) + data += multicast_marshal(this->multicasts + i, data) / sizeof(char); + buf_set_next(data, size_t, this->send_pending_size); + if (this->send_pending_size > 0) + memcpy(data, this->send_pending, this->send_pending_size * sizeof(char)); + data += this->send_pending_size; + n = !this->modify_message ? 0 : mds_message_marshal_size(this->modify_message); + buf_set_next(data, size_t, n); + if (this->modify_message) + mds_message_marshal(this->modify_message, data); + return client_marshal_size(this); } @@ -202,122 +203,116 @@ size_t client_marshal(const client_t* restrict this, char* restrict data) * @param data In buffer with the marshalled data * @return Zero on error, `errno` will be set accordingly, otherwise the number of read bytes */ -size_t client_unmarshal(client_t* restrict this, char* restrict data) +size_t +client_unmarshal(client_t *restrict this, char *restrict data) { - size_t i, n, rc = sizeof(ssize_t) + 3 * sizeof(int) + sizeof(uint64_t) + 5 * sizeof(size_t); - int saved_errno, stage = 0; - this->interception_conditions = NULL; - this->multicasts = NULL; - this->send_pending = NULL; - this->mutex_created = 0; - this->modify_mutex_created = 0; - this->modify_cond_created = 0; - this->multicasts_count = 0; - /* buf_get_next(data, int, CLIENT_T_VERSION); */ - buf_next(data, int, 1); - buf_get_next(data, ssize_t, this->list_entry); - buf_get_next(data, int, this->socket_fd); - buf_get_next(data, int, this->open); - buf_get_next(data, uint64_t, this->id); - buf_get_next(data, size_t, n); - if (n > 0) - fail_if (mds_message_unmarshal(&(this->message), data)); - stage++; - data += n / sizeof(char); - rc += n; - buf_get_next(data, size_t, this->interception_conditions_count); - fail_if (xmalloc(this->interception_conditions, - this->interception_conditions_count, interception_condition_t)); - for (i = 0; i < this->interception_conditions_count; i++) - { - n = interception_condition_unmarshal(this->interception_conditions + i, data); - if (n == 0) - { - this->interception_conditions_count = i - 1; - fail_if (1); + size_t i, n, m, rc = sizeof(ssize_t) + 3 * sizeof(int) + sizeof(uint64_t) + 5 * sizeof(size_t); + int saved_errno, stage = 0; + this->interception_conditions = NULL; + this->multicasts = NULL; + this->send_pending = NULL; + this->mutex_created = 0; + this->modify_mutex_created = 0; + this->modify_cond_created = 0; + this->multicasts_count = 0; + /* buf_get_next(data, int, CLIENT_T_VERSION); */ + buf_next(data, int, 1); + buf_get_next(data, ssize_t, this->list_entry); + buf_get_next(data, int, this->socket_fd); + buf_get_next(data, int, this->open); + buf_get_next(data, uint64_t, this->id); + buf_get_next(data, size_t, n); + if (n > 0) + fail_if (mds_message_unmarshal(&(this->message), data)); + stage++; + data += n / sizeof(char); + rc += n; + buf_get_next(data, size_t, this->interception_conditions_count); + fail_if (xmalloc(this->interception_conditions, this->interception_conditions_count, interception_condition_t)); + for (i = 0; i < this->interception_conditions_count; i++) { + n = interception_condition_unmarshal(this->interception_conditions + i, data); + if (!n) { + this->interception_conditions_count = i - 1; + fail_if (1); + } + data += n / sizeof(char); + rc += n; } - data += n / sizeof(char); - rc += n; - } - buf_get_next(data, size_t, n); - fail_if (xmalloc(this->multicasts, n, multicast_t)); - for (i = 0; i < n; i++, this->multicasts_count++) - { - size_t m = multicast_unmarshal(this->multicasts + i, data); - fail_if (m == 0); - data += m / sizeof(char); - rc += m; - } - buf_get_next(data, size_t, this->send_pending_size); - if (this->send_pending_size > 0) - { - fail_if (xmemdup(this->send_pending, data, this->send_pending_size, char)); - data += this->send_pending_size, rc += this->send_pending_size * sizeof(char); - } - buf_get_next(data, size_t, n); - if (n > 0) - mds_message_unmarshal(this->modify_message, data); - else - this->modify_message = NULL; - rc += n * sizeof(char); - return rc; - - fail: - saved_errno = errno; - if (stage == 0) - goto done_failing; - mds_message_destroy(&(this->message)); - for (i = 0; i < this->interception_conditions_count; i++) - free(this->interception_conditions[i].condition); - free(this->interception_conditions); - for (i = 0; i < this->multicasts_count; i++) - multicast_destroy(this->multicasts + i); - free(this->multicasts); - free(this->send_pending); - if (this->modify_message != NULL) - { - mds_message_destroy(this->modify_message); - free(this->modify_message); - } - done_failing: - return errno = saved_errno, (size_t)0; + buf_get_next(data, size_t, n); + fail_if (xmalloc(this->multicasts, n, multicast_t)); + for (i = 0; i < n; i++, this->multicasts_count++) { + m = multicast_unmarshal(this->multicasts + i, data); + fail_if (!m); + data += m / sizeof(char); + rc += m; + } + buf_get_next(data, size_t, this->send_pending_size); + if (this->send_pending_size > 0) { + fail_if (xmemdup(this->send_pending, data, this->send_pending_size, char)); + data += this->send_pending_size, rc += this->send_pending_size * sizeof(char); + } + buf_get_next(data, size_t, n); + if (n > 0) + mds_message_unmarshal(this->modify_message, data); + else + this->modify_message = NULL; + rc += n * sizeof(char); + return rc; + +fail: + saved_errno = errno; + if (!stage) + goto done_failing; + mds_message_destroy(&(this->message)); + for (i = 0; i < this->interception_conditions_count; i++) + free(this->interception_conditions[i].condition); + free(this->interception_conditions); + for (i = 0; i < this->multicasts_count; i++) + multicast_destroy(this->multicasts + i); + free(this->multicasts); + free(this->send_pending); + if (this->modify_message) { + mds_message_destroy(this->modify_message); + free(this->modify_message); + } +done_failing: + return errno = saved_errno, (size_t)0; } + /** * Pretend to unmarshal client information * * @param data In buffer with the marshalled data * @return The number of read bytes */ -size_t client_unmarshal_skip(char* restrict data) +size_t +client_unmarshal_skip(char *restrict data) { - size_t n, c, rc = sizeof(ssize_t) + 3 * sizeof(int) + sizeof(uint64_t) + 5 * sizeof(size_t); - buf_next(data, int, 1); - buf_next(data, ssize_t, 1); - buf_next(data, int, 2); - buf_next(data, uint64_t, 1); - buf_get_next(data, size_t, n); - data += n / sizeof(char); - rc += n; - buf_get_next(data, size_t, c); - while (c--) - { - n = interception_condition_unmarshal_skip(data); - data += n / sizeof(char); - rc += n; - } - buf_get_next(data, size_t, c); - while (c--) - { - n = multicast_unmarshal_skip(data); - data += n / sizeof(char); - rc += n; - } - buf_get_next(data, size_t, n); - data += n; - rc += n * sizeof(char); - buf_get_next(data, size_t, n); - rc += n * sizeof(char); - return rc; + size_t n, c, rc = sizeof(ssize_t) + 3 * sizeof(int) + sizeof(uint64_t) + 5 * sizeof(size_t); + buf_next(data, int, 1); + buf_next(data, ssize_t, 1); + buf_next(data, int, 2); + buf_next(data, uint64_t, 1); + buf_get_next(data, size_t, n); + data += n / sizeof(char); + rc += n; + buf_get_next(data, size_t, c); + while (c--) { + n = interception_condition_unmarshal_skip(data); + data += n / sizeof(char); + rc += n; + } + buf_get_next(data, size_t, c); + while (c--) { + n = multicast_unmarshal_skip(data); + data += n / sizeof(char); + rc += n; + } + buf_get_next(data, size_t, n); + data += n; + rc += n * sizeof(char); + buf_get_next(data, size_t, n); + rc += n * sizeof(char); + return rc; } - diff --git a/src/mds-server/client.h b/src/mds-server/client.h index cf0aec6..b8c5533 100644 --- a/src/mds-server/client.h +++ b/src/mds-server/client.h @@ -31,110 +31,110 @@ -#define CLIENT_T_VERSION 0 +#define CLIENT_T_VERSION 0 /** * Client information structure */ typedef struct client { - /** - * The client's entry in the list of clients - */ - ssize_t list_entry; - - /** - * The socket file descriptor for the socket connected to the client - */ - int socket_fd; - - /** - * Whether the socket is open - */ - int open; - - /** - * Message read buffer for the client - */ - struct mds_message message; - - /** - * The read thread for the client - */ - pthread_t thread; - - /** - * The client's ID - */ - uint64_t id; - - /** - * Mutex for sending data and other - * actions that only affacts this client - */ - pthread_mutex_t mutex; - - /** - * Whether `mutex` has been initialised - */ - int mutex_created; - - /** - * The messages interception conditions conditions - * for the client - */ - struct interception_condition* interception_conditions; - - /** - * The number of interception conditions - */ - size_t interception_conditions_count; - - /** - * Pending multicast messages - */ - struct multicast* multicasts; - - /** - * The number of pending multicast messages - */ - size_t multicasts_count; - - /** - * Messages pending to be sent (concatenated) - */ - char* send_pending; - - /** - * The character length of the messages pending to be sent - */ - size_t send_pending_size; - - /** - * Pending reply to the multicast interception - */ - struct mds_message* modify_message; - - /** - * Mutex for `modify_message` - */ - pthread_mutex_t modify_mutex; - - /** - * Condidition for `modify_message` - */ - pthread_cond_t modify_cond; - - /** - * Whether `modify_mutex` has been initialised - */ - int modify_mutex_created; - - /** - * Whether `modify_cond` has been initialised - */ - int modify_cond_created; - + /** + * The client's entry in the list of clients + */ + ssize_t list_entry; + + /** + * The socket file descriptor for the socket connected to the client + */ + int socket_fd; + + /** + * Whether the socket is open + */ + int open; + + /** + * Message read buffer for the client + */ + struct mds_message message; + + /** + * The read thread for the client + */ + pthread_t thread; + + /** + * The client's ID + */ + uint64_t id; + + /** + * Mutex for sending data and other + * actions that only affacts this client + */ + pthread_mutex_t mutex; + + /** + * Whether `mutex` has been initialised + */ + int mutex_created; + + /** + * The messages interception conditions conditions + * for the client + */ + struct interception_condition *interception_conditions; + + /** + * The number of interception conditions + */ + size_t interception_conditions_count; + + /** + * Pending multicast messages + */ + struct multicast *multicasts; + + /** + * The number of pending multicast messages + */ + size_t multicasts_count; + + /** + * Messages pending to be sent (concatenated) + */ + char *send_pending; + + /** + * The character length of the messages pending to be sent + */ + size_t send_pending_size; + + /** + * Pending reply to the multicast interception + */ + struct mds_message *modify_message; + + /** + * Mutex for `modify_message` + */ + pthread_mutex_t modify_mutex; + + /** + * Condidition for `modify_message` + */ + pthread_cond_t modify_cond; + + /** + * Whether `modify_mutex` has been initialised + */ + int modify_mutex_created; + + /** + * Whether `modify_cond` has been initialised + */ + int modify_cond_created; + } client_t; @@ -156,7 +156,7 @@ typedef struct client * @param this Memory slot in which to store the new client information */ __attribute__((nonnull)) -void client_initialise(client_t* restrict this); +void client_initialise(client_t *restrict this); /** * Initialise fields that have to do with threading @@ -171,7 +171,7 @@ void client_initialise(client_t* restrict this); * @return Zero on success, -1 on error */ __attribute__((nonnull)) -int client_initialise_threading(client_t* restrict this); +int client_initialise_threading(client_t *restrict this); /** * Release all resources assoicated with a client @@ -179,7 +179,7 @@ int client_initialise_threading(client_t* restrict this); * @param this The client information */ __attribute__((nonnull)) -void client_destroy(client_t* restrict this); +void client_destroy(client_t *restrict this); /** * Calculate the buffer size need to marshal client information @@ -188,7 +188,7 @@ void client_destroy(client_t* restrict this); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t client_marshal_size(const client_t* restrict this); +size_t client_marshal_size(const client_t *restrict this); /** * Marshals client information @@ -198,7 +198,7 @@ size_t client_marshal_size(const client_t* restrict this); * @return The number of bytes that have been written (everything will be written) */ __attribute__((nonnull)) -size_t client_marshal(const client_t* restrict this, char* restrict data); +size_t client_marshal(const client_t *restrict this, char *restrict data); /** * Unmarshals client information @@ -209,7 +209,7 @@ size_t client_marshal(const client_t* restrict this, char* restrict data); * number of read bytes. Destroy the client information on error. */ __attribute__((nonnull)) -size_t client_unmarshal(client_t* restrict this, char* restrict data); +size_t client_unmarshal(client_t *restrict this, char *restrict data); /** * Pretend to unmarshal client information @@ -218,8 +218,7 @@ size_t client_unmarshal(client_t* restrict this, char* restrict data); * @return The number of read bytes */ __attribute__((pure, nonnull)) -size_t client_unmarshal_skip(char* restrict data); +size_t client_unmarshal_skip(char *restrict data); #endif - diff --git a/src/mds-server/globals.c b/src/mds-server/globals.c index 077c222..548befa 100644 --- a/src/mds-server/globals.c +++ b/src/mds-server/globals.c @@ -73,4 +73,3 @@ pthread_cond_t modify_cond; * Map from modification ID to waiting client */ hash_table_t modify_map; - diff --git a/src/mds-server/globals.h b/src/mds-server/globals.h index e836ffe..4ca7376 100644 --- a/src/mds-server/globals.h +++ b/src/mds-server/globals.h @@ -31,7 +31,7 @@ -#define MDS_SERVER_VARS_VERSION 0 +#define MDS_SERVER_VARS_VERSION 0 diff --git a/src/mds-server/interception-condition.c b/src/mds-server/interception-condition.c index 3ef66b0..4b35796 100644 --- a/src/mds-server/interception-condition.c +++ b/src/mds-server/interception-condition.c @@ -30,9 +30,10 @@ * @param this The interception condition * @return The number of bytes to allocate to the output buffer */ -size_t interception_condition_marshal_size(const interception_condition_t* restrict this) +size_t +interception_condition_marshal_size(const interception_condition_t *restrict this) { - return sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int) + (strlen(this->condition) + 1) * sizeof(char); + return sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int) + (strlen(this->condition) + 1) * sizeof(char); } /** @@ -42,15 +43,16 @@ size_t interception_condition_marshal_size(const interception_condition_t* restr * @param data Output buffer for the marshalled data * @return The number of bytes that have been written (everything will be written) */ -size_t interception_condition_marshal(const interception_condition_t* restrict this, char* restrict data) +size_t +interception_condition_marshal(const interception_condition_t *restrict this, char *restrict data) { - size_t n = (strlen(this->condition) + 1) * sizeof(char); - buf_set_next(data, int, INTERCEPTION_CONDITION_T_VERSION); - buf_set_next(data, size_t, this->header_hash); - buf_set_next(data, int64_t, this->priority); - buf_set_next(data, int, this->modifying); - memcpy(data, this->condition, n); - return sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int) + n; + size_t n = (strlen(this->condition) + 1) * sizeof(char); + buf_set_next(data, int, INTERCEPTION_CONDITION_T_VERSION); + buf_set_next(data, size_t, this->header_hash); + buf_set_next(data, int64_t, this->priority); + buf_set_next(data, int, this->modifying); + memcpy(data, this->condition, n); + return sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int) + n; } @@ -61,20 +63,21 @@ size_t interception_condition_marshal(const interception_condition_t* restrict t * @param data In buffer with the marshalled data * @return Zero on error, `errno` will be set accordingly, otherwise the number of read bytes */ -size_t interception_condition_unmarshal(interception_condition_t* restrict this, char* restrict data) +size_t +interception_condition_unmarshal(interception_condition_t *restrict this, char *restrict data) { - size_t n; - this->condition = NULL; - /* buf_get_next(data, int, INTERCEPTION_CONDITION_T_VERSION); */ - buf_next(data, int, 1); - buf_get_next(data, size_t, this->header_hash); - buf_get_next(data, int64_t, this->priority); - buf_get_next(data, int, this->modifying); - n = strlen(data) + 1; - fail_if (xmemdup(this->condition, data, n, char)); - return sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int) + n * sizeof(char); - fail: - return 0; + size_t n; + this->condition = NULL; + /* buf_get_next(data, int, INTERCEPTION_CONDITION_T_VERSION); */ + buf_next(data, int, 1); + buf_get_next(data, size_t, this->header_hash); + buf_get_next(data, int64_t, this->priority); + buf_get_next(data, int, this->modifying); + n = strlen(data) + 1; + fail_if (xmemdup(this->condition, data, n, char)); + return sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int) + n * sizeof(char); +fail: + return 0; } @@ -84,14 +87,14 @@ size_t interception_condition_unmarshal(interception_condition_t* restrict this, * @param data In buffer with the marshalled data * @return The number of read bytes */ -size_t interception_condition_unmarshal_skip(char* restrict data) +size_t +interception_condition_unmarshal_skip(char *restrict data) { - size_t n = sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int); - buf_next(data, int, 1); - buf_next(data, size_t, 1); - buf_next(data, int64_t, 1); - buf_next(data, int, 1); - n += (strlen(data) + 1) * sizeof(char); - return n; + size_t n = sizeof(size_t) + sizeof(int64_t) + 2 * sizeof(int); + buf_next(data, int, 1); + buf_next(data, size_t, 1); + buf_next(data, int64_t, 1); + buf_next(data, int, 1); + n += (strlen(data) + 1) * sizeof(char); + return n; } - diff --git a/src/mds-server/interception-condition.h b/src/mds-server/interception-condition.h index 73919cc..e562f22 100644 --- a/src/mds-server/interception-condition.h +++ b/src/mds-server/interception-condition.h @@ -23,36 +23,36 @@ #include <stdint.h> -#define INTERCEPTION_CONDITION_T_VERSION 0 +#define INTERCEPTION_CONDITION_T_VERSION 0 /** * A condition for a message being intercepted by a client */ typedef struct interception_condition { - /** - * The header of messages to intercept, optionally with a value, - * empty (most not be NULL) for all messages. - */ - char* condition; - - /** - * The hash of the header of messages to intercept - */ - size_t header_hash; - - /** - * The interception priority. The client should be - * consistent with the priority for conditions that - * are not mutually exclusive. - */ - int64_t priority; - - /** - * Whether the messages may get modified by the client - */ - int modifying; - + /** + * The header of messages to intercept, optionally with a value, + * empty (most not be NULL) for all messages. + */ + char *condition; + + /** + * The hash of the header of messages to intercept + */ + size_t header_hash; + + /** + * The interception priority. The client should be + * consistent with the priority for conditions that + * are not mutually exclusive. + */ + int64_t priority; + + /** + * Whether the messages may get modified by the client + */ + int modifying; + } interception_condition_t; @@ -63,7 +63,7 @@ typedef struct interception_condition * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t interception_condition_marshal_size(const interception_condition_t* restrict this); +size_t interception_condition_marshal_size(const interception_condition_t *restrict this); /** * Marshals an interception condition @@ -73,7 +73,7 @@ size_t interception_condition_marshal_size(const interception_condition_t* restr * @return The number of bytes that have been written (everything will be written) */ __attribute__((nonnull)) -size_t interception_condition_marshal(const interception_condition_t* restrict this, char* restrict data); +size_t interception_condition_marshal(const interception_condition_t *restrict this, char *restrict data); /** * Unmarshals an interception condition @@ -84,7 +84,7 @@ size_t interception_condition_marshal(const interception_condition_t* restrict t * number of read bytes. Destroy the interception condition on error. */ __attribute__((nonnull)) -size_t interception_condition_unmarshal(interception_condition_t* restrict this, char* restrict data); +size_t interception_condition_unmarshal(interception_condition_t *restrict this, char *restrict data); /** * Pretend to an interception condition @@ -93,8 +93,7 @@ size_t interception_condition_unmarshal(interception_condition_t* restrict this, * @return The number of read bytes */ __attribute__((pure, nonnull)) -size_t interception_condition_unmarshal_skip(char* restrict data); +size_t interception_condition_unmarshal_skip(char *restrict data); #endif - diff --git a/src/mds-server/interceptors.c b/src/mds-server/interceptors.c index fccb0fa..a39e0d6 100644 --- a/src/mds-server/interceptors.c +++ b/src/mds-server/interceptors.c @@ -38,28 +38,26 @@ * @param client The intercepting client * @param index The index of the condition */ -__attribute__((nonnull)) -static void remove_intercept_condition(client_t* client, size_t index) +static void __attribute__((nonnull)) +remove_intercept_condition(client_t *client, size_t index) { - interception_condition_t* conds = client->interception_conditions; - size_t n = client->interception_conditions_count; - - /* Remove the condition from the list. */ - free(conds[index].condition); - memmove(conds + index, conds + index + 1, --n - index); - client->interception_conditions_count--; - - /* Shrink the list. */ - if (client->interception_conditions_count == 0) - { - free(conds); - client->interception_conditions = NULL; - } - else - if (xrealloc(conds, n, interception_condition_t)) - xperror(*argv); - else - client->interception_conditions = conds; + interception_condition_t *conds = client->interception_conditions; + size_t n = client->interception_conditions_count; + + /* Remove the condition from the list. */ + free(conds[index].condition); + memmove(conds + index, conds + index + 1, --n - index); + client->interception_conditions_count--; + + /* Shrink the list. */ + if (!client->interception_conditions_count) { + free(conds); + client->interception_conditions = NULL; + } else if (xrealloc(conds, n, interception_condition_t)) { + xperror(*argv); + } else { + client->interception_conditions = conds; + } } @@ -72,106 +70,100 @@ static void remove_intercept_condition(client_t* client, size_t index) * @param modifying Whether the client may modify the messages * @param stop Whether the condition should be removed rather than added */ -void add_intercept_condition(client_t* client, char* condition, int64_t priority, int modifying, int stop) +void +add_intercept_condition(client_t *client, char *condition, int64_t priority, int modifying, int stop) { - size_t n = client->interception_conditions_count; - interception_condition_t* conds = client->interception_conditions; - ssize_t nonmodifying = -1; - char* header = condition; - char* colon = NULL; - char* value; - size_t hash; - size_t i; - - /* Split header and value apart. */ - if ((value = strchr(header, ':')) != NULL) - { - *value = '\0'; /* NUL-terminate header. */ - colon = value; /* End of header. */ - value += 2; /* Skip over delimiter. */ - } - - /* Calcuate header hash (comparison optimisation) */ - hash = string_hash(header); - /* Undo header–value splitting. */ - if (colon != NULL) - *colon = ':'; - - /* Remove of update condition of already registered, - also look for non-modifying condition to swap position - with for optimisation. */ - for (i = 0; i < n; i++) - { - if ((conds[i].header_hash != hash) || !strequals(conds[i].condition, condition)) - { - /* Look for the first non-modifying, this is a part of the - optimisation where we put all modifying conditions at the - beginning. */ - if ((nonmodifying < 0) && conds[i].modifying) - nonmodifying = (ssize_t)i; - continue; + size_t n = client->interception_conditions_count; + interception_condition_t *conds = client->interception_conditions; + ssize_t nonmodifying = -1; + char *header = condition; + char *colon = NULL; + char *value; + size_t hash, i; + interception_condition_t temp; + + /* Split header and value apart. */ + if ((value = strchr(header, ':'))) { + *value = '\0'; /* NUL-terminate header. */ + colon = value; /* End of header. */ + value += 2; /* Skip over delimiter. */ } - - if (stop) - remove_intercept_condition(client, i); - else - { - /* Update parameters. */ - conds[i].priority = priority; - conds[i].modifying = modifying; - - if (modifying && (nonmodifying >= 0)) - { - /* Optimisation: put conditions that are modifying - at the beginning. When a client is intercepting - we most know if any satisfying condition is - modifying. With this optimisation the first - satisfying condition will tell us if there is - any satisfying condition that is modifying. */ - interception_condition_t temp = conds[nonmodifying]; - conds[nonmodifying] = conds[i]; - conds[i] = temp; - } + + /* Calcuate header hash (comparison optimisation) */ + hash = string_hash(header); + /* Undo header–value splitting. */ + if (colon) + *colon = ':'; + + /* Remove of update condition of already registered, + also look for non-modifying condition to swap position + with for optimisation. */ + for (i = 0; i < n; i++) { + if ((conds[i].header_hash != hash) || !strequals(conds[i].condition, condition)) { + /* Look for the first non-modifying, this is a part of the + optimisation where we put all modifying conditions at the + beginning. */ + if (nonmodifying < 0 && conds[i].modifying) + nonmodifying = (ssize_t)i; + continue; + } + + if (stop) { + remove_intercept_condition(client, i); + } else { + /* Update parameters. */ + conds[i].priority = priority; + conds[i].modifying = modifying; + + if (modifying && nonmodifying >= 0) { + /* Optimisation: put conditions that are modifying + at the beginning. When a client is intercepting + we most know if any satisfying condition is + modifying. With this optimisation the first + satisfying condition will tell us if there is + any satisfying condition that is modifying. */ + temp = conds[nonmodifying]; + conds[nonmodifying] = conds[i]; + conds[i] = temp; + } + } + return; } - return; - } - - if (stop) - eprint("client tried to stop intercepting messages that it does not intercept."); - else - { - /* Duplicate condition string. */ - fail_if (xstrdup_nn(condition, condition)); - - /* Grow the interception condition list. */ - fail_if (xrealloc(conds, n + 1, interception_condition_t)); - client->interception_conditions = conds; - /* Store condition. */ - client->interception_conditions_count++; - conds[n].condition = condition; - conds[n].header_hash = hash; - conds[n].priority = priority; - conds[n].modifying = modifying; - - if (modifying && (nonmodifying >= 0)) - { - /* Optimisation: put conditions that are modifying - at the beginning. When a client is intercepting - we most know if any satisfying condition is - modifying. With this optimisation the first - satisfying condition will tell us if there is - any satisfying condition that is modifying. */ - interception_condition_t temp = conds[nonmodifying]; - conds[nonmodifying] = conds[n]; - conds[n] = temp; + + if (stop) { + eprint("client tried to stop intercepting messages that it does not intercept."); + } else { + /* Duplicate condition string. */ + fail_if (xstrdup_nn(condition, condition)); + + /* Grow the interception condition list. */ + fail_if (xrealloc(conds, n + 1, interception_condition_t)); + client->interception_conditions = conds; + /* Store condition. */ + client->interception_conditions_count++; + conds[n].condition = condition; + conds[n].header_hash = hash; + conds[n].priority = priority; + conds[n].modifying = modifying; + + if (modifying && nonmodifying >= 0) { + /* Optimisation: put conditions that are modifying + at the beginning. When a client is intercepting + we most know if any satisfying condition is + modifying. With this optimisation the first + satisfying condition will tell us if there is + any satisfying condition that is modifying. */ + temp = conds[nonmodifying]; + conds[nonmodifying] = conds[n]; + conds[n] = temp; + } } - } - return; - fail: - xperror(*argv); - free(condition); - return; + return; +fail: + xperror(*argv); + free(condition); + return; } @@ -185,18 +177,20 @@ void add_intercept_condition(client_t* client, char* condition, int64_t priority * @param count The number of accepted patterns * @return Evaluates to true if and only if a matching pattern was found */ -int is_condition_matching(interception_condition_t* cond, size_t* hashes, - char** keys, char** headers, size_t count) +int +is_condition_matching(interception_condition_t *cond, size_t *hashes, + char **keys, char **headers, size_t count) { - size_t i; - for (i = 0; i < count; i++) - if (*(cond->condition) == '\0') - return 1; - else if ((cond->header_hash == hashes[i]) && - (strequals(cond->condition, keys[i]) || - strequals(cond->condition, headers[i]))) - return 1; - return 0; + size_t i; + for (i = 0; i < count; i++) { + if (*cond->condition == '\0') + return 1; + else if ((cond->header_hash == hashes[i]) && + (strequals(cond->condition, keys[i]) || + strequals(cond->condition, headers[i]))) + return 1; + } + return 0; } @@ -211,33 +205,34 @@ int is_condition_matching(interception_condition_t* cond, size_t* hashes, * @param interception_out Storage slot for found interception * @return -1 on error, otherwise: evalutes to true iff a matching condition was found */ -int find_matching_condition(client_t* client, size_t* hashes, char** keys, char** headers, - size_t count, queued_interception_t* interception_out) +int +find_matching_condition(client_t *client, size_t *hashes, char **keys, char **headers, + size_t count, queued_interception_t *interception_out) { - pthread_mutex_t mutex = client->mutex; - interception_condition_t* conds = client->interception_conditions; - size_t n = 0, i; - - fail_if ((errno = pthread_mutex_lock(&(mutex)))); - - /* Look for a matching condition. */ - if (client->open) - n = client->interception_conditions_count; - for (i = 0; i < n; i++) - if (is_condition_matching(conds + i, hashes, keys, headers, count)) - { - /* Report matching condition. */ - interception_out->client = client; - interception_out->priority = conds[i].priority; - interception_out->modifying = conds[i].modifying; - break; - } - - pthread_mutex_unlock(&(mutex)); - - return i < n; - fail: - return -1; + pthread_mutex_t mutex = client->mutex; + interception_condition_t *conds = client->interception_conditions; + size_t n = 0, i; + + fail_if ((errno = pthread_mutex_lock(&(mutex)))); + + /* Look for a matching condition. */ + if (client->open) + n = client->interception_conditions_count; + for (i = 0; i < n; i++) { + if (is_condition_matching(conds + i, hashes, keys, headers, count)) { + /* Report matching condition. */ + interception_out->client = client; + interception_out->priority = conds[i].priority; + interception_out->modifying = conds[i].modifying; + break; + } + } + + pthread_mutex_unlock(&mutex); + + return i < n; +fail: + return -1; } @@ -252,44 +247,43 @@ int find_matching_condition(client_t* client, size_t* hashes, char** keys, char* * @param interceptions_count_out Slot at where to store the number of found interceptors * @return The found interceptors, `NULL` on error */ -queued_interception_t* get_interceptors(client_t* sender, size_t* hashes, char** keys, char** headers, - size_t count, size_t* interceptions_count_out) +queued_interception_t * +get_interceptors(client_t *sender, size_t *hashes, char **keys, char **headers, + size_t count, size_t *interceptions_count_out) { - queued_interception_t* interceptions = NULL; - size_t interceptions_count = 0, n = 0; - ssize_t node; - int saved_errno; - - /* Count clients. */ - foreach_linked_list_node (client_list, node) - n++; - - /* Allocate interceptor list. */ - fail_if (xmalloc(interceptions, n, queued_interception_t)); - - /* Search clients. */ - foreach_linked_list_node (client_list, node) - { - client_t* client = (client_t*)(void*)(client_list.values[node]); - - /* Look for and list a matching condition. */ - if (client->open && (client != sender)) - { - int r = find_matching_condition(client, hashes, keys, headers, count, - interceptions + interceptions_count); - fail_if (r == -1); - if (r) - /* List client of there was a matching condition. */ - interceptions_count++; + queued_interception_t *interceptions = NULL; + size_t interceptions_count = 0, n = 0; + ssize_t node; + int saved_errno, r; + client_t *client; + + /* Count clients. */ + foreach_linked_list_node (client_list, node) + n++; + + /* Allocate interceptor list. */ + fail_if (xmalloc(interceptions, n, queued_interception_t)); + + /* Search clients. */ + foreach_linked_list_node (client_list, node) { + client = (void *)(client_list.values[node]); + + /* Look for and list a matching condition. */ + if (client->open && (client != sender)) { + r = find_matching_condition(client, hashes, keys, headers, count, + interceptions + interceptions_count); + fail_if (r == -1); + if (r) + /* List client of there was a matching condition. */ + interceptions_count++; + } } - } - - *interceptions_count_out = interceptions_count; - return interceptions; - - fail: - saved_errno = errno; - free(interceptions); - return errno = saved_errno, NULL; -} + *interceptions_count_out = interceptions_count; + return interceptions; + +fail: + saved_errno = errno; + free(interceptions); + return errno = saved_errno, NULL; +} diff --git a/src/mds-server/interceptors.h b/src/mds-server/interceptors.h index d5cfc6f..e51d240 100644 --- a/src/mds-server/interceptors.h +++ b/src/mds-server/interceptors.h @@ -37,7 +37,7 @@ * @param stop Whether the condition should be removed rather than added */ __attribute__((nonnull)) -void add_intercept_condition(client_t* client, char* condition, int64_t priority, int modifying, int stop); +void add_intercept_condition(client_t *client, char *condition, int64_t priority, int modifying, int stop); /** @@ -51,8 +51,8 @@ void add_intercept_condition(client_t* client, char* condition, int64_t priority * @return Evaluates to true if and only if a matching pattern was found */ __attribute__((pure, nonnull(1))) -int is_condition_matching(interception_condition_t* cond, size_t* hashes, - char** keys, char** headers, size_t count); +int is_condition_matching(interception_condition_t *cond, size_t *hashes, + char **keys, char **headers, size_t count); /** @@ -67,8 +67,8 @@ int is_condition_matching(interception_condition_t* cond, size_t* hashes, * @return -1 on error, otherwise: evalutes to true iff a matching condition was found */ __attribute__((pure, nonnull(1, 6))) -int find_matching_condition(client_t* client, size_t* hashes, char** keys, char** headers, - size_t count, queued_interception_t* interception_out); +int find_matching_condition(client_t *client, size_t *hashes, char **keys, char **headers, + size_t count, queued_interception_t *interception_out); /** @@ -83,8 +83,7 @@ int find_matching_condition(client_t* client, size_t* hashes, char** keys, char* * @return The found interceptors, `NULL` on error */ __attribute__((pure, nonnull(1, 6))) -queued_interception_t* get_interceptors(client_t* sender, size_t* hashes, char** keys, char** headers, - size_t count, size_t* interceptions_count_out); +queued_interception_t *get_interceptors(client_t *sender, size_t *hashes, char **keys, char **headers, + size_t count, size_t *interceptions_count_out); #endif - diff --git a/src/mds-server/mds-server.c b/src/mds-server/mds-server.c index cfedf82..bb0e26c 100644 --- a/src/mds-server/mds-server.c +++ b/src/mds-server/mds-server.c @@ -51,29 +51,28 @@ * * This tells the server-base how to behave */ -server_characteristics_t server_characteristics = - { - .require_privileges = 0, - .require_display = 0, /* We will service one ourself. */ - .require_respawn_info = 1, - .sanity_check_argc = 1, - .fork_for_safety = 0, - .danger_is_deadly = 0 - }; - - - -#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) { xperror(*argv); __free(I); return 1; } +server_characteristics_t server_characteristics = { + .require_privileges = 0, + .require_display = 0, /* We will service one ourself. */ + .require_respawn_info = 1, + .sanity_check_argc = 1, + .fork_for_safety = 0, + .danger_is_deadly = 0 +}; + + + +#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) { xperror(*argv); __free(I); return 1; } /** @@ -82,74 +81,71 @@ server_characteristics_t server_characteristics = * * @return Non-zero on error */ -int preinitialise_server(void) +int +preinitialise_server(void) { - int unparsed_args_ptr = 1; - char* unparsed_args[ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT + 1]; - int i; - + int unparsed_args_ptr = 1; + char *unparsed_args[ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT + 1]; + char *arg; + int i; + pid_t pid; + #if (LIBEXEC_ARGC_EXTRA_LIMIT < 3) # error LIBEXEC_ARGC_EXTRA_LIMIT is too small, need at least 3. #endif - - - /* Parse command line arguments. */ - for (i = 1; i < argc; i++) - { - char* arg = argv[i]; - 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);); + + + /* Parse command line arguments. */ + for (i = 1; i < argc; i++) { + arg = argv[i]; + 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 (startswith(arg, "--alarm=")) { /* Schedule an alarm signal for forced abort. */ + alarm((unsigned)min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ + } else if (!strequals(arg, "--initial-spawn") && !strequals(arg, "--respawn")) { + /* Not recognised, it is probably for another server. */ + unparsed_args[unparsed_args_ptr++] = arg; + } } - else if (startswith(arg, "--alarm=")) /* Schedule an alarm signal for forced abort. */ - alarm((unsigned)min(atou(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */ - else - 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; - - /* Check that mandatory arguments have been specified. */ - exit_if (socket_fd < 0, - eprint("missing socket file descriptor argument.");); - - - /* Run mdsinitrc. */ - if (is_respawn == 0) - { - pid_t pid = fork(); - fail_if (pid == (pid_t)-1); - - if (pid == 0) /* Child process exec:s, the parent continues without waiting for it. */ - { - /* Close all files except stdin, stdout and stderr. */ - close_files((fd > 2) || (fd == socket_fd)); - - /* Run mdsinitrc. */ - run_initrc(unparsed_args); /* Does not return. */ + unparsed_args[unparsed_args_ptr] = NULL; + + /* Check that mandatory arguments have been specified. */ + exit_if (socket_fd < 0, eprint("missing socket file descriptor argument.");); + + + /* Run mdsinitrc. */ + if (!is_respawn) { + pid = fork(); + fail_if (pid == (pid_t)-1); + + if (!pid) { /* Child process exec:s, the parent continues without waiting for it. */ + /* Close all files except stdin, stdout and stderr. */ + close_files(fd > 2 || fd == socket_fd); + + /* Run mdsinitrc. */ + run_initrc(unparsed_args); /* Does not return. */ + } } - } - - - /* Create mutex and condition for slave counter. */ - 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 (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)); - - - return 0; - - fail: - xperror(*argv); - return 1; + + + /* Create mutex and condition for slave counter. */ + 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 (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)); + + + return 0; + +fail: + xperror(*argv); + return 1; } @@ -159,13 +155,14 @@ int preinitialise_server(void) * * @return Non-zero on error */ -int initialise_server(void) +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; + /* 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; } @@ -175,10 +172,11 @@ int initialise_server(void) * * @return Non-zero on error */ -int __attribute__((const)) postinitialise_server(void) +int __attribute__((const)) +postinitialise_server(void) { - /* We do not need to initialise anything else. */ - return 0; + /* We do not need to initialise anything else. */ + return 0; } @@ -187,33 +185,31 @@ int __attribute__((const)) postinitialise_server(void) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - /* Accepting incoming connections and take care of dangers. */ - while (running && (terminating == 0)) - { - if (danger) - { - danger = 0; - with_mutex (slave_mutex, linked_list_pack(&client_list);); + /* Accepting incoming connections and take care of dangers. */ + while (running && !terminating) { + if (danger) { + danger = 0; + with_mutex (slave_mutex, linked_list_pack(&client_list);); + } + + if (accept_connection() == 1) + break; } - - if (accept_connection() == 1) - break; - } - - /* Join with all slaves threads. */ - with_mutex (slave_mutex, - while (running_slaves > 0) - pthread_cond_wait(&slave_cond, &slave_mutex);); - - if (reexecing == 0) - { - /* Release resources. */ - __free(9999); - } - - return 0; + + /* Join with all slaves threads. */ + with_mutex (slave_mutex, + while (running_slaves > 0) + pthread_cond_wait(&slave_cond, &slave_mutex);); + + if (!reexecing) { + /* Release resources. */ + __free(9999); + } + + return 0; } @@ -226,29 +222,29 @@ int master_loop(void) * * @return Zero normally, 1 if terminating */ -int accept_connection(void) +int +accept_connection(void) { - pthread_t slave_thread; - int client_fd; - - /* Accept connection. */ - client_fd = accept(socket_fd, NULL, NULL); - if (client_fd >= 0) - { - /* Increase number of running slaves. */ - with_mutex (slave_mutex, running_slaves++;); - - /* Start slave thread. */ - create_slave(&slave_thread, client_fd); - } - else - /* Handle errors and shutdown. */ - if ((errno == EINTR) && terminating) /* Interrupted for termination. */ - return 1; - else if ((errno == ECONNABORTED) || (errno == EINVAL)) /* Closing. */ - running = 0; - else if (errno != EINTR) /* Error. */ - xperror(*argv); + pthread_t slave_thread; + int client_fd; + + /* Accept connection. */ + client_fd = accept(socket_fd, NULL, NULL); + if (client_fd >= 0) { + /* Increase number of running slaves. */ + with_mutex (slave_mutex, running_slaves++;); + + /* Start slave thread. */ + create_slave(&slave_thread, client_fd); + } else { + /* Handle errors and shutdown. */ + if (errno == EINTR && terminating) /* Interrupted for termination. */ + return 1; + else if (errno == ECONNABORTED || errno == EINVAL) /* Closing. */ + running = 0; + else if (errno != EINTR) /* Error. */ + xperror(*argv); + } return 0; } @@ -259,108 +255,105 @@ int accept_connection(void) * @param data Input data * @return Output data */ -void* slave_loop(void* data) +void * +slave_loop(void *data) { - 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"; - size_t n; - int r; - - - if (information == NULL) /* Did not re-exec. */ - { - /* Initialise the client. */ - fail_if ((information = initialise_client(slave_fd)) == NULL); - - /* Register client to receive broadcasts. */ - add_intercept_condition(information, buf, 0, 0, 0); - } - - /* Store slave thread and create mutexes and conditions. */ - fail_if (client_initialise_threading(information)); - - /* Set up traps for especially handled signals. */ - fail_if (trap_signals() < 0); - - - /* Fetch messages from the slave. */ - while ((terminating == 0) && information->open) - { - /* Send queued multicast messages. */ - send_multicast_queue(information); - - /* Send queued messages. */ - send_reply_queue(information); - - - /* Fetch message. */ - r = fetch_message(information); - if ((r == 0) && message_received(information)) - goto terminate; - else if (r == -2) + int slave_fd = (int)(intptr_t)data; + size_t information_address = fd_table_get(&client_map, (size_t)slave_fd); + client_t *information = (void *)information_address; + char *msgbuf = NULL; + char buf[] = "To: all"; + size_t n; + int r; + + + if (!information) { /* Did not re-exec. */ + /* Initialise the client. */ + fail_if (!(information = initialise_client(slave_fd))); + + /* Register client to receive broadcasts. */ + add_intercept_condition(information, buf, 0, 0, 0); + } + + /* Store slave thread and create mutexes and conditions. */ + fail_if (client_initialise_threading(information)); + + /* Set up traps for especially handled signals. */ + fail_if (trap_signals() < 0); + + + /* Fetch messages from the slave. */ + while (!terminating && information->open) { + /* Send queued multicast messages. */ + send_multicast_queue(information); + + /* Send queued messages. */ + send_reply_queue(information); + + /* Fetch message. */ + r = fetch_message(information); + if (!r && message_received(information)) + goto terminate; + else if (r == -2) + goto done; + else if (r && errno == EINTR && terminating) + goto terminate; /* Stop the thread if we are re-exec:ing or terminating the server. */ + } + /* Stop the thread if we are re-exec:ing or terminating the server. */ + if (terminating) + goto terminate; + + + /* Multicast information about the client closing. */ + n = 2 * 10 + 1 + strlen("Client closed: :\n\n"); + fail_if (xmalloc(msgbuf, n, char)); + snprintf(msgbuf, n, + "Client closed: %" PRIu32 ":%" PRIu32 "\n" + "\n", + (uint32_t)(information->id >> 32), + (uint32_t)(information->id >> 0)); + n = strlen(msgbuf); + queue_message_multicast(msgbuf, n, information); + msgbuf = NULL; + send_multicast_queue(information); + + +terminate: /* This done on success as well. */ + if (reexecing) + goto reexec; + +done: + /* Close socket and free resources. */ + xclose(slave_fd); + free(msgbuf); + if (information) { + /* Unlist and free client. */ + with_mutex (slave_mutex, linked_list_remove(&client_list, information->list_entry);); + client_destroy(information); + } + + /* Unmap client and decrease the slave count. */ + with_mutex (slave_mutex, + fd_table_remove(&client_map, slave_fd); + running_slaves--; + pthread_cond_signal(&slave_cond);); + return NULL; + + +fail: + xperror(*argv); goto done; - else if (r && (errno == EINTR) && terminating) - goto terminate; /* Stop the thread if we are re-exec:ing or terminating the server. */ - } - /* Stop the thread if we are re-exec:ing or terminating the server. */ - if (terminating) - goto terminate; - - - /* Multicast information about the client closing. */ - n = 2 * 10 + 1 + strlen("Client closed: :\n\n"); - fail_if (xmalloc(msgbuf, n, char)); - snprintf(msgbuf, n, - "Client closed: %" PRIu32 ":%" PRIu32 "\n" - "\n", - (uint32_t)(information->id >> 32), - (uint32_t)(information->id >> 0)); - n = strlen(msgbuf); - queue_message_multicast(msgbuf, n, information); - msgbuf = NULL; - send_multicast_queue(information); - - - terminate: /* This done on success as well. */ - if (reexecing) - goto reexec; - - done: - /* Close socket and free resources. */ - xclose(slave_fd); - free(msgbuf); - if (information != NULL) - { - /* Unlist and free client. */ - with_mutex (slave_mutex, linked_list_remove(&client_list, information->list_entry);); - client_destroy(information); - } - - /* Unmap client and decrease the slave count. */ - with_mutex (slave_mutex, - fd_table_remove(&client_map, slave_fd); - running_slaves--; - pthread_cond_signal(&slave_cond);); - return NULL; - - - fail: - xperror(*argv); - goto done; - - - reexec: - /* Tell the master thread that the slave has closed, - this is done because re-exec causes a race-condition - between the acception of a slave and the execution - of the the slave thread. */ - with_mutex (slave_mutex, - running_slaves--; - pthread_cond_signal(&slave_cond);); - return NULL; + + +reexec: + /* Tell the master thread that the slave has closed, + this is done because re-exec causes a race-condition + between the acception of a slave and the execution + of the the slave thread. */ + with_mutex (slave_mutex, + running_slaves--; + pthread_cond_signal(&slave_cond);); + return NULL; } @@ -371,13 +364,12 @@ void* slave_loop(void* data) * @param b:const queued_interception_t* The other of the two interceptors * @return Negative if a before b, positive if a after b, otherwise zero */ -__attribute__((nonnull)) -static int cmp_queued_interception(const void* a, const void* b) +static int __attribute__((nonnull)) +cmp_queued_interception(const void *a, const void *b) { - const queued_interception_t* p = b; /* Highest first, so swap them. */ - const queued_interception_t* q = a; - return p->priority < q->priority ? -1 : - p->priority > q->priority ? 1 : 0; + const queued_interception_t *p = b; /* Highest first, so swap them. */ + const queued_interception_t *q = a; + return p->priority < q->priority ? -1 : p->priority > q->priority; } @@ -388,127 +380,127 @@ static int cmp_queued_interception(const void* a, const void* b) * @param length The length of the message * @param sender The original sender of the message */ -void queue_message_multicast(char* message, size_t length, client_t* sender) +void +queue_message_multicast(char *message, size_t length, client_t *sender) { - char* msg = message; - size_t header_count = 0; - size_t n = length - 1; - size_t* hashes = NULL; - char** headers = NULL; - char** header_values = NULL; - queued_interception_t* interceptions = NULL; - size_t interceptions_count = 0; - multicast_t* multicast = NULL; - size_t i; - uint64_t modify_id; - char modify_id_header[13 + 3 * sizeof(uint64_t)]; - void* new_buf; - int saved_errno; - - /* Count the number of headers. */ - for (i = 0; i < n; i++) - if (message[i] == '\n') - if (header_count++, message[i + 1] == '\n') - break; - - if (header_count == 0) - return; /* Invalid message. */ - - /* Allocate multicast message. */ - fail_if (xmalloc(multicast, 1, multicast_t)); - multicast_initialise(multicast); - - /* Allocate header lists. */ - fail_if (xmalloc(hashes, header_count, size_t)); - fail_if (xmalloc(headers, header_count, char*)); - fail_if (xmalloc(header_values, header_count, char*)); - - /* Populate header lists. */ - for (i = 0; i < header_count; i++) - { - char* end = strchr(msg, '\n'); - char* colon = strchr(msg, ':'); - - *end = '\0'; - if (xstrdup(header_values[i], msg)) - { - header_count = i; - fail_if (1); - } - *colon = '\0'; - if (xstrdup(headers[i], msg)) - { - saved_errno = errno, free(headers[i]), errno = saved_errno; - header_count = i; - fail_if (1); - } - *colon = ':'; - *end = '\n'; - hashes[i] = string_hash(headers[i]); - - msg = end + 1; - } - - /* Get intercepting clients. */ - pthread_mutex_lock(&(slave_mutex)); - interceptions = get_interceptors(sender, hashes, headers, header_values, header_count, &interceptions_count); - pthread_mutex_unlock(&(slave_mutex)); - fail_if (interceptions == NULL); - - /* Sort interceptors. */ - qsort(interceptions, interceptions_count, sizeof(queued_interception_t), cmp_queued_interception); - - /* Add prefix to message with ‘Modify ID’ header. */ - with_mutex (slave_mutex, - modify_id = next_modify_id++; - if (next_modify_id == 0) - next_modify_id = 1; - ); - xsnprintf(modify_id_header, "Modify ID: %" PRIu64 "\n", modify_id); - n = strlen(modify_id_header); - new_buf = message; - fail_if (xrealloc(new_buf, n + length, char)); - message = new_buf; - memmove(message + n, message, length * sizeof(char)); - memcpy(message, modify_id_header, n * sizeof(char)); - - /* Store information. */ - multicast->interceptions = interceptions; - multicast->interceptions_count = interceptions_count; - multicast->message = message; - multicast->message_length = length + n; - multicast->message_prefix = n; - message = NULL; - -#define fail fail_in_mutex - /* Queue message multicasting. */ - with_mutex (sender->mutex, - new_buf = sender->multicasts; - fail_if (xrealloc(new_buf, sender->multicasts_count + 1, multicast_t)); - sender->multicasts = new_buf; - sender->multicasts[sender->multicasts_count++] = *multicast; - free(multicast); - multicast = NULL; - errno = 0; - fail_in_mutex: - xperror(*argv); - ); + char *msg = message; + size_t header_count = 0; + size_t n = length - 1; + size_t *hashes = NULL; + char **headers = NULL; + char **header_values = NULL; + queued_interception_t *interceptions = NULL; + size_t interceptions_count = 0; + multicast_t *multicast = NULL; + size_t i; + uint64_t modify_id; + char modify_id_header[13 + 3 * sizeof(uint64_t)]; + void *new_buf; + int saved_errno; + char *end, *colon; + + /* Count the number of headers. */ + for (i = 0; i < n; i++) + if (message[i] == '\n') + if (header_count++, message[i + 1] == '\n') + break; + + if (!header_count) + return; /* Invalid message. */ + + /* Allocate multicast message. */ + fail_if (xmalloc(multicast, 1, multicast_t)); + multicast_initialise(multicast); + + /* Allocate header lists. */ + fail_if (xmalloc(hashes, header_count, size_t)); + fail_if (xmalloc(headers, header_count, char *)); + fail_if (xmalloc(header_values, header_count, char *)); + + /* Populate header lists. */ + for (i = 0; i < header_count; i++) + { + end = strchr(msg, '\n'); + colon = strchr(msg, ':'); + + *end = '\0'; + if (xstrdup(header_values[i], msg)) { + header_count = i; + fail_if (1); + } + *colon = '\0'; + if (xstrdup(headers[i], msg)) { + saved_errno = errno, free(headers[i]), errno = saved_errno; + header_count = i; + fail_if (1); + } + *colon = ':'; + *end = '\n'; + hashes[i] = string_hash(headers[i]); + + msg = end + 1; + } + + /* Get intercepting clients. */ + pthread_mutex_lock(&(slave_mutex)); + interceptions = get_interceptors(sender, hashes, headers, header_values, header_count, &interceptions_count); + pthread_mutex_unlock(&(slave_mutex)); + fail_if (!interceptions); + + /* Sort interceptors. */ + qsort(interceptions, interceptions_count, sizeof(queued_interception_t), cmp_queued_interception); + + /* Add prefix to message with ‘Modify ID’ header. */ + with_mutex (slave_mutex, + modify_id = next_modify_id++; + if (!next_modify_id) + next_modify_id = 1; + ); + xsnprintf(modify_id_header, "Modify ID: %" PRIu64 "\n", modify_id); + n = strlen(modify_id_header); + new_buf = message; + fail_if (xrealloc(new_buf, n + length, char)); + message = new_buf; + memmove(message + n, message, length * sizeof(char)); + memcpy(message, modify_id_header, n * sizeof(char)); + + /* Store information. */ + multicast->interceptions = interceptions; + multicast->interceptions_count = interceptions_count; + multicast->message = message; + multicast->message_length = length + n; + multicast->message_prefix = n; + message = NULL; + +#define fail fail_in_mutex + /* Queue message multicasting. */ + with_mutex (sender->mutex, + new_buf = sender->multicasts; + fail_if (xrealloc(new_buf, sender->multicasts_count + 1, multicast_t)); + sender->multicasts = new_buf; + sender->multicasts[sender->multicasts_count++] = *multicast; + free(multicast); + multicast = NULL; + errno = 0; + fail_in_mutex: + xperror(*argv); + ); #undef fail - - done: - /* Release resources. */ - xfree(headers, header_count); - xfree(header_values, header_count); - free(hashes); - free(message); - if (multicast != NULL) - multicast_destroy(multicast); - free(multicast); - return; - - fail: - xperror(*argv); - goto done; + +done: + /* Release resources. */ + xfree(headers, header_count); + xfree(header_values, header_count); + free(hashes); + free(message); + if (multicast) + multicast_destroy(multicast); + free(multicast); + return; + +fail: + xperror(*argv); + goto done; } @@ -517,70 +509,59 @@ void queue_message_multicast(char* message, size_t length, client_t* sender) * * @param args The arguments to the child process */ -void run_initrc(char** args) +void +run_initrc(char **args) { - char pathname[PATH_MAX]; - struct passwd* pwd; - char* env; - char* home; - args[0] = pathname; - -#define __exec(FORMAT, ...) \ - xsnprintf(pathname, FORMAT, __VA_ARGS__); execv(args[0], args) - - /* Test $XDG_CONFIG_HOME. */ - if ((env = getenv_nonempty("XDG_CONFIG_HOME")) != NULL) - { - __exec("%s/%s", env, INITRC_FILE); - } - - /* Test $HOME. */ - if ((env = getenv_nonempty("HOME")) != NULL) - { - __exec("%s/.config/%s", env, INITRC_FILE); - __exec("%s/.%s", env, INITRC_FILE); - } - - /* Test ~. */ - pwd = getpwuid(getuid()); /* Ignore error. */ - if (pwd != NULL) - { - home = pwd->pw_dir; - if ((home != NULL) && (*home != '\0')) - { - __exec("%s/.config/%s", home, INITRC_FILE); - __exec("%s/.%s", home, INITRC_FILE); + char pathname[PATH_MAX]; + struct passwd *pwd; + char *env, *home, *begin, *end; + int len; + + args[0] = pathname; + +#define __exec(FORMAT, ...)\ + (xsnprintf(pathname, FORMAT, __VA_ARGS__), execv(args[0], args)) + + /* Test $XDG_CONFIG_HOME. */ + if ((env = getenv_nonempty("XDG_CONFIG_HOME"))) + __exec("%s/%s", env, INITRC_FILE); + + /* Test $HOME. */ + if ((env = getenv_nonempty("HOME"))) { + __exec("%s/.config/%s", env, INITRC_FILE); + __exec("%s/.%s", env, INITRC_FILE); } - } - - /* Test $XDG_CONFIG_DIRS. */ - if ((env = getenv_nonempty("XDG_CONFIG_DIRS")) != NULL) - { - char* begin = env; - char* end; - int len; - for (;;) - { - end = strchrnul(begin, ':'); - len = (int)(end - begin); - if (len > 0) - { - __exec("%.*s/%s", len, begin, INITRC_FILE); - } - if (*end == '\0') - break; - begin = end + 1; + + /* Test ~. */ + pwd = getpwuid(getuid()); /* Ignore error. */ + if (pwd) { + home = pwd->pw_dir; + if (home && *home) { + __exec("%s/.config/%s", home, INITRC_FILE); + __exec("%s/.%s", home, INITRC_FILE); + } + } + + /* Test $XDG_CONFIG_DIRS. */ + if ((env = getenv_nonempty("XDG_CONFIG_DIRS"))) { + for (begin = env;;) { + end = strchrnul(begin, ':'); + len = (int)(end - begin); + if (len > 0) + __exec("%.*s/%s", len, begin, INITRC_FILE); + if (!*end) + break; + begin = end + 1; + } } - } - - /* Test /etc. */ - __exec("%s/%s", SYSCONFDIR, INITRC_FILE); + + /* Test /etc. */ + __exec("%s/%s", SYSCONFDIR, INITRC_FILE); #undef __exec - - /* Everything failed. */ - eprintf("unable to run %s file, you might as well kill me.", INITRC_FILE); - /* (‘me’ actually refers to the parant, whence it will to be coming.) */ - exit(0); -} + /* Everything failed. */ + eprintf("unable to run %s file, you might as well kill me.", INITRC_FILE); + /* (‘me’ actually refers to the parant, whence it will to be coming.) */ + exit(0); +} diff --git a/src/mds-server/mds-server.h b/src/mds-server/mds-server.h index 44c9acc..50c18ac 100644 --- a/src/mds-server/mds-server.h +++ b/src/mds-server/mds-server.h @@ -37,7 +37,7 @@ int accept_connection(void); * @param data Input data * @return Output data */ -void* slave_loop(void* data); +void *slave_loop(void *data); /** * Queue a message for multicasting @@ -47,7 +47,7 @@ void* slave_loop(void* data); * @param sender The original sender of the message */ __attribute__((nonnull)) -void queue_message_multicast(char* message, size_t length, client_t* sender); +void queue_message_multicast(char *message, size_t length, client_t *sender); /** * Exec into the mdsinitrc script @@ -55,8 +55,7 @@ void queue_message_multicast(char* message, size_t length, client_t* sender); * @param args The arguments to the child process */ __attribute__((noreturn, nonnull)) -void run_initrc(char** args); +void run_initrc(char **args); #endif - diff --git a/src/mds-server/multicast.c b/src/mds-server/multicast.c index d30530f..a71ddf4 100644 --- a/src/mds-server/multicast.c +++ b/src/mds-server/multicast.c @@ -30,15 +30,16 @@ * * @param this The message multicast state */ -void multicast_initialise(multicast_t* restrict this) +void +multicast_initialise(multicast_t *restrict this) { - this->interceptions = NULL; - this->interceptions_count = 0; - this->interceptions_ptr = 0; - this->message = NULL; - this->message_length = 0; - this->message_ptr = 0; - this->message_prefix = 0; + this->interceptions = NULL; + this->interceptions_count = 0; + this->interceptions_ptr = 0; + this->message = NULL; + this->message_length = 0; + this->message_ptr = 0; + this->message_prefix = 0; } @@ -47,10 +48,11 @@ void multicast_initialise(multicast_t* restrict this) * * @param this The message multicast state */ -void multicast_destroy(multicast_t* restrict this) +void +multicast_destroy(multicast_t *restrict this) { - free(this->interceptions); - free(this->message); + free(this->interceptions); + free(this->message); } @@ -60,13 +62,13 @@ void multicast_destroy(multicast_t* restrict this) * @param this The client information * @return The number of bytes to allocate to the output buffer */ -size_t multicast_marshal_size(const multicast_t* restrict this) +size_t +multicast_marshal_size(const multicast_t *restrict this) { - size_t rc = sizeof(int) + 5 * sizeof(size_t) + this->message_length * sizeof(char); - size_t i; - for (i = 0; i < this->interceptions_count; i++) - rc += queued_interception_marshal_size(); - return rc; + size_t i, rc = sizeof(int) + 5 * sizeof(size_t) + this->message_length * sizeof(char); + for (i = 0; i < this->interceptions_count; i++) + rc += queued_interception_marshal_size(); + return rc; } @@ -77,28 +79,26 @@ size_t multicast_marshal_size(const multicast_t* restrict this) * @param data Output buffer for the marshalled data * @return The number of bytes that have been written (everything will be written) */ -size_t multicast_marshal(const multicast_t* restrict this, char* restrict data) +size_t +multicast_marshal(const multicast_t *restrict this, char *restrict data) { - size_t rc = sizeof(int) + 5 * sizeof(size_t); - size_t i, n; - buf_set_next(data, int, MULTICAST_T_VERSION); - buf_set_next(data, size_t, this->interceptions_count); - buf_set_next(data, size_t, this->interceptions_ptr); - buf_set_next(data, size_t, this->message_length); - buf_set_next(data, size_t, this->message_ptr); - buf_set_next(data, size_t, this->message_prefix); - for (i = 0; i < this->interceptions_count; i++) - { - n = queued_interception_marshal(this->interceptions + i, data); - data += n / sizeof(char); - rc += n; - } - if (this->message_length > 0) - { - memcpy(data, this->message, this->message_length * sizeof(char)); - rc += this->message_length * sizeof(char); - } - return rc; + size_t i, n, rc = sizeof(int) + 5 * sizeof(size_t); + buf_set_next(data, int, MULTICAST_T_VERSION); + buf_set_next(data, size_t, this->interceptions_count); + buf_set_next(data, size_t, this->interceptions_ptr); + buf_set_next(data, size_t, this->message_length); + buf_set_next(data, size_t, this->message_ptr); + buf_set_next(data, size_t, this->message_prefix); + for (i = 0; i < this->interceptions_count; i++) { + n = queued_interception_marshal(this->interceptions + i, data); + data += n / sizeof(char); + rc += n; + } + if (this->message_length > 0) { + memcpy(data, this->message, this->message_length * sizeof(char)); + rc += this->message_length * sizeof(char); + } + return rc; } @@ -110,35 +110,33 @@ size_t multicast_marshal(const multicast_t* restrict this, char* restrict data) * @return Zero on error, `errno` will be set accordingly, otherwise the * number of read bytes. Destroy the client information on error. */ -size_t multicast_unmarshal(multicast_t* restrict this, char* restrict data) +size_t +multicast_unmarshal(multicast_t *restrict this, char *restrict data) { - size_t rc = sizeof(int) + 5 * sizeof(size_t); - size_t i, n; - this->interceptions = NULL; - this->message = NULL; - /* buf_get_next(data, int, MULTICAST_T_VERSION); */ - buf_next(data, int, 1); - buf_get_next(data, size_t, this->interceptions_count); - buf_get_next(data, size_t, this->interceptions_ptr); - buf_get_next(data, size_t, this->message_length); - buf_get_next(data, size_t, this->message_ptr); - buf_get_next(data, size_t, this->message_prefix); - if (this->interceptions_count > 0) - fail_if (xmalloc(this->interceptions, this->interceptions_count, queued_interception_t)); - for (i = 0; i < this->interceptions_count; i++) - { - n = queued_interception_unmarshal(this->interceptions + i, data); - data += n / sizeof(char); - rc += n; - } - if (this->message_length > 0) - { - fail_if (xmemdup(this->message, data, this->message_length, char)); - rc += this->message_length * sizeof(char); - } - return rc; - fail: - return 0; + size_t i, n, rc = sizeof(int) + 5 * sizeof(size_t); + this->interceptions = NULL; + this->message = NULL; + /* buf_get_next(data, int, MULTICAST_T_VERSION); */ + buf_next(data, int, 1); + buf_get_next(data, size_t, this->interceptions_count); + buf_get_next(data, size_t, this->interceptions_ptr); + buf_get_next(data, size_t, this->message_length); + buf_get_next(data, size_t, this->message_ptr); + buf_get_next(data, size_t, this->message_prefix); + if (this->interceptions_count > 0) + fail_if (xmalloc(this->interceptions, this->interceptions_count, queued_interception_t)); + for (i = 0; i < this->interceptions_count; i++) { + n = queued_interception_unmarshal(this->interceptions + i, data); + data += n / sizeof(char); + rc += n; + } + if (this->message_length > 0) { + fail_if (xmemdup(this->message, data, this->message_length, char)); + rc += this->message_length * sizeof(char); + } + return rc; +fail: + return 0; } @@ -148,18 +146,16 @@ size_t multicast_unmarshal(multicast_t* restrict this, char* restrict data) * @param data In buffer with the marshalled data * @return The number of read bytes */ -size_t multicast_unmarshal_skip(char* restrict data) +size_t +multicast_unmarshal_skip(char *restrict data) { - size_t interceptions_count = buf_cast(data, size_t, 0); - size_t message_length = buf_cast(data, size_t, 2); - size_t rc = sizeof(int) + 5 * sizeof(size_t) + message_length * sizeof(char); - size_t n; - while (interceptions_count--) - { - n = queued_interception_unmarshal_skip(); - data += n / sizeof(char); - rc += n; - } - return rc; + size_t interceptions_count = buf_cast(data, size_t, 0); + size_t message_length = buf_cast(data, size_t, 2); + size_t n, rc = sizeof(int) + 5 * sizeof(size_t) + message_length * sizeof(char); + while (interceptions_count--) { + n = queued_interception_unmarshal_skip(); + data += n / sizeof(char); + rc += n; + } + return rc; } - diff --git a/src/mds-server/multicast.h b/src/mds-server/multicast.h index 0cd20e1..24dc704 100644 --- a/src/mds-server/multicast.h +++ b/src/mds-server/multicast.h @@ -22,48 +22,48 @@ #include "queued-interception.h" -#define MULTICAST_T_VERSION 0 +#define MULTICAST_T_VERSION 0 /** * Message multicast state */ typedef struct multicast { - /** - * Queue of clients that is listening this message - */ - struct queued_interception* interceptions; - - /** - * The number of clients in `interceptions` - */ - size_t interceptions_count; - - /** - * The index of the current/next client in `interceptions` to whom to send the message - */ - size_t interceptions_ptr; - - /** - * The message to send - */ - char* message; - - /** - * The length of `message` - */ - size_t message_length; - - /** - * How much of the message that has already been sent to the current recipient - */ - size_t message_ptr; - - /** - * How much of the message to skip if the recipient is not a modifier - */ - size_t message_prefix; - + /** + * Queue of clients that is listening this message + */ + struct queued_interception *interceptions; + + /** + * The number of clients in `interceptions` + */ + size_t interceptions_count; + + /** + * The index of the current/next client in `interceptions` to whom to send the message + */ + size_t interceptions_ptr; + + /** + * The message to send + */ + char *message; + + /** + * The length of `message` + */ + size_t message_length; + + /** + * How much of the message that has already been sent to the current recipient + */ + size_t message_ptr; + + /** + * How much of the message to skip if the recipient is not a modifier + */ + size_t message_prefix; + } multicast_t; @@ -73,7 +73,7 @@ typedef struct multicast * @param this The message multicast state */ __attribute__((nonnull)) -void multicast_initialise(multicast_t* restrict this); +void multicast_initialise(multicast_t *restrict this); /** * Destroy a message multicast state @@ -81,7 +81,7 @@ void multicast_initialise(multicast_t* restrict this); * @param this The message multicast state */ __attribute__((nonnull)) -void multicast_destroy(multicast_t* restrict this); +void multicast_destroy(multicast_t *restrict this); /** * Calculate the buffer size need to marshal a message multicast state @@ -90,7 +90,7 @@ void multicast_destroy(multicast_t* restrict this); * @return The number of bytes to allocate to the output buffer */ __attribute__((pure, nonnull)) -size_t multicast_marshal_size(const multicast_t* restrict this); +size_t multicast_marshal_size(const multicast_t *restrict this); /** * Marshals a message multicast state @@ -100,7 +100,7 @@ size_t multicast_marshal_size(const multicast_t* restrict this); * @return The number of bytes that have been written (everything will be written) */ __attribute__((nonnull)) -size_t multicast_marshal(const multicast_t* restrict this, char* restrict data); +size_t multicast_marshal(const multicast_t *restrict this, char *restrict data); /** * Unmarshals a message multicast state @@ -111,7 +111,7 @@ size_t multicast_marshal(const multicast_t* restrict this, char* restrict data); * number of read bytes. Destroy the message multicast state on error. */ __attribute__((nonnull)) -size_t multicast_unmarshal(multicast_t* restrict this, char* restrict data); +size_t multicast_unmarshal(multicast_t *restrict this, char *restrict data); /** * Pretend to unmarshal a message multicast state @@ -120,9 +120,8 @@ size_t multicast_unmarshal(multicast_t* restrict this, char* restrict data); * @return The number of read bytes */ __attribute__((pure, nonnull)) -size_t multicast_unmarshal_skip(char* restrict data); +size_t multicast_unmarshal_skip(char *restrict data); #endif - diff --git a/src/mds-server/queued-interception.c b/src/mds-server/queued-interception.c index ff00339..b74eb11 100644 --- a/src/mds-server/queued-interception.c +++ b/src/mds-server/queued-interception.c @@ -26,9 +26,10 @@ * @param this The client information * @return The number of bytes to allocate to the output buffer */ -size_t queued_interception_marshal_size(void) +size_t +queued_interception_marshal_size(void) { - return sizeof(int64_t) + 3 * sizeof(int); + return sizeof(int64_t) + 3 * sizeof(int); } @@ -39,13 +40,14 @@ size_t queued_interception_marshal_size(void) * @param data Output buffer for the marshalled data * @return The number of bytes that have been written (everything will be written) */ -size_t queued_interception_marshal(const queued_interception_t* restrict this, char* restrict data) +size_t +queued_interception_marshal(const queued_interception_t *restrict this, char *restrict data) { - buf_set_next(data, int, QUEUED_INTERCEPTION_T_VERSION); - buf_set_next(data, int64_t, this->priority); - buf_set_next(data, int, this->modifying); - buf_set_next(data, int, this->client->socket_fd); - return queued_interception_marshal_size(); + buf_set_next(data, int, QUEUED_INTERCEPTION_T_VERSION); + buf_set_next(data, int64_t, this->priority); + buf_set_next(data, int, this->modifying); + buf_set_next(data, int, this->client->socket_fd); + return queued_interception_marshal_size(); } @@ -56,15 +58,16 @@ size_t queued_interception_marshal(const queued_interception_t* restrict this, c * @param data In buffer with the marshalled data * @return Zero on error, `errno` will be set accordingly, otherwise the number of read bytes. */ -size_t queued_interception_unmarshal(queued_interception_t* restrict this, char* restrict data) +size_t +queued_interception_unmarshal(queued_interception_t *restrict this, char *restrict data) { - this->client = NULL; - /* buf_get_next(data, int, QUEUED_INTERCEPTION_T_VERSION); */ - buf_next(data, int, 1); - buf_get_next(data, int64_t, this->priority); - buf_get_next(data, int, this->modifying); - buf_get_next(data, int, this->socket_fd); - return queued_interception_marshal_size(); + this->client = NULL; + /* buf_get_next(data, int, QUEUED_INTERCEPTION_T_VERSION); */ + buf_next(data, int, 1); + buf_get_next(data, int64_t, this->priority); + buf_get_next(data, int, this->modifying); + buf_get_next(data, int, this->socket_fd); + return queued_interception_marshal_size(); } @@ -74,8 +77,8 @@ size_t queued_interception_unmarshal(queued_interception_t* restrict this, char* * @param data In buffer with the marshalled data * @return The number of read bytes */ -size_t queued_interception_unmarshal_skip(void) +size_t +queued_interception_unmarshal_skip(void) { - return queued_interception_marshal_size(); + return queued_interception_marshal_size(); } - diff --git a/src/mds-server/queued-interception.h b/src/mds-server/queued-interception.h index 5a17579..56f9d62 100644 --- a/src/mds-server/queued-interception.h +++ b/src/mds-server/queued-interception.h @@ -24,33 +24,33 @@ #include <stdint.h> -#define QUEUED_INTERCEPTION_T_VERSION 0 +#define QUEUED_INTERCEPTION_T_VERSION 0 /** * A queued interception */ typedef struct queued_interception { - /** - * The intercepting client - */ - struct client* client; - - /** - * The interception priority - */ - int64_t priority; - - /** - * Whether the messages may get modified by the client - */ - int modifying; - - /** - * The file descriptor of the intercepting client's socket (used for unmarshalling) - */ - int socket_fd; - + /** + * The intercepting client + */ + struct client *client; + + /** + * The interception priority + */ + int64_t priority; + + /** + * Whether the messages may get modified by the client + */ + int modifying; + + /** + * The file descriptor of the intercepting client's socket (used for unmarshalling) + */ + int socket_fd; + } queued_interception_t; @@ -71,7 +71,7 @@ size_t queued_interception_marshal_size(void); * @return The number of bytes that have been written (everything will be written) */ __attribute__((nonnull)) -size_t queued_interception_marshal(const queued_interception_t* restrict this, char* restrict data); +size_t queued_interception_marshal(const queued_interception_t *restrict this, char *restrict data); /** * Unmarshals a queued interception @@ -81,7 +81,7 @@ size_t queued_interception_marshal(const queued_interception_t* restrict this, c * @return Zero on error, `errno` will be set accordingly, otherwise the number of read bytes. */ __attribute__((nonnull)) -size_t queued_interception_unmarshal(queued_interception_t* restrict this, char* restrict data); +size_t queued_interception_unmarshal(queued_interception_t *restrict this, char *restrict data); /** * Pretend to unmarshal a queued interception @@ -94,4 +94,3 @@ size_t queued_interception_unmarshal_skip(void); #endif - diff --git a/src/mds-server/receiving.c b/src/mds-server/receiving.c index b93f638..09684ae 100644 --- a/src/mds-server/receiving.c +++ b/src/mds-server/receiving.c @@ -40,7 +40,7 @@ * @param sender The original sender of the message */ __attribute__((nonnull)) -void queue_message_multicast(char* message, size_t length, client_t* sender); +void queue_message_multicast(char *message, size_t length, client_t *sender); /** @@ -51,55 +51,50 @@ void queue_message_multicast(char* message, size_t length, client_t* sender); * @param modify_id The modify ID of the message * @return Normally zero, but 1 if exited because of re-exec or termination */ -__attribute__((nonnull)) -static int modifying_notify(client_t* client, mds_message_t message, uint64_t modify_id) +static int __attribute__((nonnull)) +modifying_notify(client_t *client, mds_message_t message, uint64_t modify_id) { - /* pthread_cond_timedwait is required to handle re-exec and termination because - pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */ - struct timespec timeout = - { - .tv_sec = 1, - .tv_nsec = 0 - }; - size_t address; - client_t* recipient; - mds_message_t* multicast; - size_t i; - - pthread_mutex_lock(&(modify_mutex)); - while (hash_table_contains_key(&modify_map, (size_t)modify_id) == 0) - { - if (terminating) - { - pthread_mutex_unlock(&(modify_mutex)); - return 1; + /* pthread_cond_timedwait is required to handle re-exec and termination because + pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */ + struct timespec timeout = { + .tv_sec = 1, + .tv_nsec = 0 + }; + size_t address; + client_t *recipient; + mds_message_t *multicast; + size_t i; + + pthread_mutex_lock(&(modify_mutex)); + while (!hash_table_contains_key(&modify_map, (size_t)modify_id)) { + if (terminating) { + pthread_mutex_unlock(&(modify_mutex)); + return 1; + } + pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); } - pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); - } - address = hash_table_get(&modify_map, (size_t)modify_id); - recipient = (client_t*)(void*)address; - fail_if (xmalloc(multicast = recipient->modify_message, 1, mds_message_t)); - mds_message_zero_initialise(multicast); - fail_if (xmemdup(multicast->payload, message.payload, message.payload_size, char)); - fail_if (xmalloc(multicast->headers, message.header_count, char*)); - for (i = 0; i < message.header_count; i++, multicast->header_count++) - fail_if (xstrdup(multicast->headers[i], message.headers[i])); - done: - pthread_mutex_unlock(&(modify_mutex)); - with_mutex (client->modify_mutex, pthread_cond_signal(&(client->modify_cond));); - - return 0; - - - fail: - xperror(*argv); - if (multicast != NULL) - { - mds_message_destroy(multicast); - free(multicast); - recipient->modify_message = NULL; - } - goto done; + address = hash_table_get(&modify_map, (size_t)modify_id); + recipient = (void *)address; + fail_if (xmalloc(multicast = recipient->modify_message, 1, mds_message_t)); + mds_message_zero_initialise(multicast); + fail_if (xmemdup(multicast->payload, message.payload, message.payload_size, char)); + fail_if (xmalloc(multicast->headers, message.header_count, char*)); + for (i = 0; i < message.header_count; i++, multicast->header_count++) + fail_if (xstrdup(multicast->headers[i], message.headers[i])); +done: + pthread_mutex_unlock(&(modify_mutex)); + with_mutex (client->modify_mutex, pthread_cond_signal(&(client->modify_cond));); + + return 0; + +fail: + xperror(*argv); + if (multicast) { + mds_message_destroy(multicast); + free(multicast); + recipient->modify_message = NULL; + } + goto done; } @@ -112,61 +107,56 @@ static int modifying_notify(client_t* client, mds_message_t message, uint64_t mo * @param stop Whether to stop listening rather than start or reconfigure * @return Zero on success, -1 on error */ -__attribute__((nonnull)) -static int add_intercept_conditions_from_message(client_t* client, int modifying, int64_t priority, int stop) +static int __attribute__((nonnull)) +add_intercept_conditions_from_message(client_t *client, int modifying, int64_t priority, int stop) { - int saved_errno; - char* payload = client->message.payload; - size_t payload_size = client->message.payload_size; - size_t size = 64; - char* buf; - - fail_if (xmalloc(buf, size + 1, char)); - - /* All messages. */ - if (client->message.payload_size == 0) - { - *buf = '\0'; - add_intercept_condition(client, buf, priority, modifying, stop); - goto done; - } - - /* Filtered messages. */ - for (;;) - { - char* end = memchr(payload, '\n', payload_size); - size_t len = end == NULL ? payload_size : (size_t)(end - payload); - if (len == 0) - { - payload++; - payload_size--; - break; + int saved_errno; + char *payload = client->message.payload; + size_t payload_size = client->message.payload_size; + size_t size = 64, len; + char *buf, *end, *old_buf; + + fail_if (xmalloc(buf, size + 1, char)); + + /* All messages. */ + if (!client->message.payload_size) { + *buf = '\0'; + add_intercept_condition(client, buf, priority, modifying, stop); + goto done; } - if (len > size) - { - char* old_buf = buf; - if (xrealloc(buf, (size <<= 1) + 1, char)) - { - saved_errno = errno; - free(old_buf); - pthread_mutex_unlock(&(client->mutex)); - fail_if (errno = saved_errno, 1); - } + + /* Filtered messages. */ + for (;;) { + end = memchr(payload, '\n', payload_size); + len = !end ? payload_size : (size_t)(end - payload); + if (len == 0) { + payload++; + payload_size--; + break; + } + if (len > size) { + old_buf = buf; + if (xrealloc(buf, (size <<= 1) + 1, char)) { + saved_errno = errno; + free(old_buf); + pthread_mutex_unlock(&(client->mutex)); + fail_if (errno = saved_errno, 1); + } + } + memcpy(buf, payload, len); + buf[len] = '\0'; + add_intercept_condition(client, buf, priority, modifying, stop); + if (!end) + break; + payload = end + 1; + payload_size -= len + 1; } - memcpy(buf, payload, len); - buf[len] = '\0'; - add_intercept_condition(client, buf, priority, modifying, stop); - if (end == NULL) - break; - payload = end + 1; - payload_size -= len + 1; - } - - done: - free(buf); - return 0; - fail: - return -1; + +done: + free(buf); + return 0; +fail: + return -1; } @@ -177,60 +167,58 @@ static int add_intercept_conditions_from_message(client_t* client, int modifying * @param message_id The message ID of the ID request * @return Zero on success, -1 on error */ -__attribute__((nonnull(1))) -static int assign_and_send_id(client_t* client, const char* message_id) +static int __attribute__((nonnull(1))) +assign_and_send_id(client_t *client, const char *message_id) { - char* msgbuf = NULL; - char* msgbuf_; - size_t n; - int rc = -1; - - /* Construct response. */ - n = 2 * 10 + strlen(message_id); - n += sizeof("ID assignment: :\nIn response to: \n\n") / sizeof(char); - fail_if (xmalloc(msgbuf, n, char)); - snprintf(msgbuf, n, - "ID assignment: %" PRIu32 ":%" PRIu32 "\n" - "In response to: %s\n" - "\n", - (uint32_t)(client->id >> 32), - (uint32_t)(client->id >> 0), - message_id == NULL ? "" : message_id); - n = strlen(msgbuf); - - /* Multicast the reply. */ - fail_if (xstrdup(msgbuf_, msgbuf)); - queue_message_multicast(msgbuf_, n, client); - - /* Queue message to be sent when this function returns. - This done to simplify `multicast_message` for re-exec and termination. */ -#define fail fail_in_mutex - with_mutex (client->mutex, - if (client->send_pending_size == 0) - { - /* Set the pending message. */ - client->send_pending = msgbuf; - client->send_pending_size = n; - } - else - { - /* Concatenate message to already pending messages. */ - size_t new_len = client->send_pending_size + n; - char* msg_new = client->send_pending; - fail_if (xrealloc(msg_new, new_len, char)); - memcpy(msg_new + client->send_pending_size, msgbuf, n * sizeof(char)); - client->send_pending = msg_new; - client->send_pending_size = new_len; - } - (msgbuf = NULL, rc = 0, errno = 0); - fail_in_mutex: - ); + char *msgbuf = NULL; + char *msgbuf_; + char *msg_new; + size_t n, new_len; + int rc = -1; + + /* Construct response. */ + n = 2 * 10 + strlen(message_id); + n += sizeof("ID assignment: :\nIn response to: \n\n") / sizeof(char); + fail_if (xmalloc(msgbuf, n, char)); + snprintf(msgbuf, n, + "ID assignment: %" PRIu32 ":%" PRIu32 "\n" + "In response to: %s\n" + "\n", + (uint32_t)(client->id >> 32), + (uint32_t)(client->id >> 0), + !message_id ? "" : message_id); + n = strlen(msgbuf); + + /* Multicast the reply. */ + fail_if (xstrdup(msgbuf_, msgbuf)); + queue_message_multicast(msgbuf_, n, client); + + /* Queue message to be sent when this function returns. + This done to simplify `multicast_message` for re-exec and termination. */ +#define fail fail_in_mutex + with_mutex (client->mutex, + if (!client->send_pending_size) { + /* Set the pending message. */ + client->send_pending = msgbuf; + client->send_pending_size = n; + } else { + /* Concatenate message to already pending messages. */ + new_len = client->send_pending_size + n; + msg_new = client->send_pending; + fail_if (xrealloc(msg_new, new_len, char)); + memcpy(msg_new + client->send_pending_size, msgbuf, n * sizeof(char)); + client->send_pending = msg_new; + client->send_pending_size = new_len; + } + (msgbuf = NULL, rc = 0, errno = 0); + fail_in_mutex: + ); #undef fail - fail: /* Also success. */ - xperror(*argv); - free(msgbuf); - return rc; +fail: /* Also success. */ + xperror(*argv); + free(msgbuf); + return rc; } @@ -241,95 +229,92 @@ static int assign_and_send_id(client_t* client, const char* message_id) * @param client The client whom sent the message * @return Normally zero, but 1 if exited because of re-exec or termination */ -int message_received(client_t* client) +int +message_received(client_t *client) { - mds_message_t message = client->message; - int assign_id = 0; - int modifying = 0; - int intercept = 0; - int64_t priority = 0; - int stop = 0; - const char* message_id = NULL; - uint64_t modify_id = 0; - char* msgbuf = NULL; - size_t i, n; - - - /* Parser headers. */ - for (i = 0; i < message.header_count; i++) - { - const char* h = message.headers[i]; - if (strequals(h, "Command: assign-id")) assign_id = 1; - else if (strequals(h, "Command: intercept")) intercept = 1; - else if (strequals(h, "Modifying: yes")) modifying = 1; - else if (strequals(h, "Stop: yes")) stop = 1; - else if (startswith(h, "Message ID: ")) message_id = strstr(h, ": ") + 2; - else if (startswith(h, "Priority: ")) priority = ato64(strstr(h, ": ") + 2); - else if (startswith(h, "Modify ID: ")) modify_id = atou64(strstr(h, ": ") + 2); - } - - - /* Notify waiting client about a received message modification. */ - if (modifying) - return modifying_notify(client, message, modify_id); - /* Do nothing more, not not even multicast this message. */ - - - if (message_id == NULL) - { - eprint("received message without a message ID, ignoring."); - return 0; - } - - /* Assign ID if not already assigned. */ - if (assign_id && (client->id == 0)) - { - intercept |= 2; - with_mutex_if (slave_mutex, (client->id = next_client_id++) == 0, - eprint("this is impossible, ID counter has overflowed."); - /* If the program ran for a millennium it would - take c:a 585 assignments per nanosecond. This - cannot possibly happen. (It would require serious - dedication by generations of ponies (or just an alicorn) - to maintain the process and transfer it new hardware.) */ - abort(); - ); - } - - /* Make the client listen for messages addressed to it. */ - if (intercept) - { - pthread_mutex_lock(&(client->mutex)); - if ((intercept & 1)) /* from payload */ - fail_if (add_intercept_conditions_from_message(client, modifying, priority, stop) < 0); - if ((intercept & 2)) /* "To: $(client->id)" */ - { - char buf[26]; - xsnprintf(buf, "To: %" PRIu32 ":%" PRIu32, - (uint32_t)(client->id >> 32), - (uint32_t)(client->id >> 0)); - add_intercept_condition(client, buf, priority, modifying, 0); + mds_message_t message = client->message; + int assign_id = 0; + int modifying = 0; + int intercept = 0; + int64_t priority = 0; + int stop = 0; + const char *message_id = NULL; + uint64_t modify_id = 0; + char *msgbuf = NULL; + size_t i, n; + const char *h; + char buf[26]; + + + /* Parser headers. */ + for (i = 0; i < message.header_count; i++) { + h = message.headers[i]; + if (strequals(h, "Command: assign-id")) assign_id = 1; + else if (strequals(h, "Command: intercept")) intercept = 1; + else if (strequals(h, "Modifying: yes")) modifying = 1; + else if (strequals(h, "Stop: yes")) stop = 1; + else if (startswith(h, "Message ID: ")) message_id = strstr(h, ": ") + 2; + else if (startswith(h, "Priority: ")) priority = ato64(strstr(h, ": ") + 2); + else if (startswith(h, "Modify ID: ")) modify_id = atou64(strstr(h, ": ") + 2); } - pthread_mutex_unlock(&(client->mutex)); - } - - - /* Multicast the message. */ - n = mds_message_compose_size(&message); - fail_if (xbmalloc(msgbuf, n)); - mds_message_compose(&message, msgbuf); - queue_message_multicast(msgbuf, n / sizeof(char), client); - msgbuf = NULL; - - - /* Send asigned ID. */ - if (assign_id) - fail_if (assign_and_send_id(client, message_id) < 0); - - return 0; - - fail: - xperror(*argv); - free(msgbuf); - return 0; + + + /* Notify waiting client about a received message modification. */ + if (modifying) + return modifying_notify(client, message, modify_id); + /* Do nothing more, not not even multicast this message. */ + + + if (!message_id) { + eprint("received message without a message ID, ignoring."); + return 0; + } + + /* Assign ID if not already assigned. */ + if (assign_id && !client->id) { + intercept |= 2; + with_mutex_if (slave_mutex, !(client->id = next_client_id++), + eprint("this is impossible, ID counter has overflowed."); + /* If the program ran for a millennium it would + take c:a 585 assignments per nanosecond. This + cannot possibly happen. (It would require serious + dedication by generations of ponies (or just an alicorn) + to maintain the process and transfer it new hardware.) */ + abort(); + ); + } + + /* Make the client listen for messages addressed to it. */ + if (intercept) { + pthread_mutex_lock(&(client->mutex)); + if ((intercept & 1)) /* from payload */ + fail_if (add_intercept_conditions_from_message(client, modifying, priority, stop) < 0); + if ((intercept & 2)) { /* "To: $(client->id)" */ + xsnprintf(buf, "To: %" PRIu32 ":%" PRIu32, + (uint32_t)(client->id >> 32), + (uint32_t)(client->id >> 0)); + add_intercept_condition(client, buf, priority, modifying, 0); + } + pthread_mutex_unlock(&(client->mutex)); + } + + + /* Multicast the message. */ + n = mds_message_compose_size(&message); + fail_if (xbmalloc(msgbuf, n)); + mds_message_compose(&message, msgbuf); + queue_message_multicast(msgbuf, n / sizeof(char), client); + msgbuf = NULL; + + + /* Send asigned ID. */ + if (assign_id) + fail_if (assign_and_send_id(client, message_id) < 0); + + return 0; + +fail: + xperror(*argv); + free(msgbuf); + return 0; } diff --git a/src/mds-server/receiving.h b/src/mds-server/receiving.h index 612c94b..cc684b0 100644 --- a/src/mds-server/receiving.h +++ b/src/mds-server/receiving.h @@ -30,8 +30,7 @@ * @return Normally zero, but 1 if exited because of re-exec or termination */ __attribute__((nonnull)) -int message_received(client_t* client); +int message_received(client_t *client); #endif - diff --git a/src/mds-server/reexec.c b/src/mds-server/reexec.c index bac066a..a2e0620 100644 --- a/src/mds-server/reexec.c +++ b/src/mds-server/reexec.c @@ -49,26 +49,26 @@ * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +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; - ssize_t node; - - /* Calculate the grand size of all client information. */ - foreach_linked_list_node (client_list, node) - { - 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; - - return state_n; + 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; + ssize_t node; + + /* Calculate the grand size of all client information. */ + foreach_linked_list_node (client_list, node) { + state_n += client_marshal_size((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; + + return state_n; } @@ -78,68 +78,69 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +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); - - /* 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); - - /* 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); - - /* Marshal the clients. */ - foreach_linked_list_node (client_list, node) - { - /* Get the memory address of the client. */ - size_t value_address = client_list.values[node]; - /* Get the client's information. */ - 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); - /* Marshal the client informationation. */ - 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); - /* Marshal the client map. */ - fd_table_marshal(&client_map, state_buf); - - - /* 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); - - return 0; + size_t list_size = linked_list_marshal_size(&client_list); + size_t list_elements = 0; + ssize_t node; + size_t value_address; + client_t *value, *client; + + + /* 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); + + /* 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); + + /* 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); + + /* Marshal the clients. */ + foreach_linked_list_node (client_list, node) { + /* Get the memory address of the client. */ + value_address = client_list.values[node]; + /* Get the client's information. */ + value = (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); + /* Marshal the client informationation. */ + 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); + /* Marshal the client map. */ + fd_table_marshal(&client_map, state_buf); + + + /* Release resources. */ + foreach_linked_list_node (client_list, node) { + client = (void *)(client_list.values[node]); + client_destroy(client); + } + fd_table_destroy(&client_map, NULL, NULL); + linked_list_destroy(&client_list); + + return 0; } @@ -154,9 +155,10 @@ static hash_table_t unmarshal_remap_map; * @param old The old address * @return The new address */ -static size_t unmarshal_remapper(size_t old) +static size_t +unmarshal_remapper(size_t old) { - return hash_table_get(&unmarshal_remap_map, old); + return hash_table_get(&unmarshal_remap_map, old); } @@ -170,131 +172,126 @@ static size_t unmarshal_remapper(size_t old) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - int with_error = 0; - size_t list_size; - size_t list_elements; - size_t i; - ssize_t node; - pthread_t slave_thread; - -#define fail soft_fail + int with_error = 0; + size_t list_size; + size_t list_elements; + size_t i; + ssize_t node; + pthread_t slave_thread; + size_t n, value_address, new_address; + client_t *value, *client; + int slave_fd; - /* Create memory address remapping table. */ - fail_if (hash_table_create(&unmarshal_remap_map)); +#define fail soft_fail + + /* Create memory address remapping table. */ + fail_if (hash_table_create(&unmarshal_remap_map)); #undef fail -#define fail clients_fail - - /* 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); +#define fail clients_fail - /* 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); - - /* 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); - - /* Unmarshal the clients. */ - for (i = 0; i < list_elements; i++) - { - size_t n; - size_t value_address; - client_t* value; - - /* Allocate the client's information. */ - fail_if (xmalloc(value, 1, client_t)); - - /* 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); - /* Unmarshal the client information. */ - fail_if (n = client_unmarshal(value, state_buf), n == 0); - - /* Populate the remapping table. */ - if (hash_table_put(&unmarshal_remap_map, value_address, (size_t)(void*)value) == 0) - fail_if (errno); - - /* Delayed seeking. */ - state_buf += n / sizeof(char); - - - /* On error, seek past all clients. */ - continue; - clients_fail: - xperror(*argv); - with_error = 1; - if (value != NULL) - { - buf_prev(state_buf, size_t, 1); - free(value); + /* 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); + + /* 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); + + /* 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); + + /* Unmarshal the clients. */ + for (i = 0; i < list_elements; i++) { + /* Allocate the client's information. */ + fail_if (xmalloc(value, 1, client_t)); + + /* 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); + /* Unmarshal the client information. */ + fail_if (n = client_unmarshal(value, state_buf), n == 0); + + /* Populate the remapping table. */ + if (!hash_table_put(&unmarshal_remap_map, value_address, (size_t)(void *)value)) + fail_if (errno); + + /* Delayed seeking. */ + state_buf += n / sizeof(char); + + /* On error, seek past all clients. */ + continue; + clients_fail: + xperror(*argv); + with_error = 1; + if (value) { + 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); + break; } - 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); - break; - } - + #undef fail #define fail critical_fail - - /* Unmarshal the client list. */ - fail_if (linked_list_unmarshal(&client_list, state_buf)); - state_buf += list_size / sizeof(char); - - /* Unmarshal the client map. */ - fail_if (fd_table_unmarshal(&client_map, state_buf, unmarshal_remapper)); - - /* 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) - for (i = 0; i < client_map.capacity; i++) - if ((__bit(i, &)) && (client_map.values[i] == 0)) - /* Lets not presume that fd-table actually initialise its allocations. */ - __bit(i, &= ~); + + /* Unmarshal the client list. */ + fail_if (linked_list_unmarshal(&client_list, state_buf)); + state_buf += list_size / sizeof(char); + + /* Unmarshal the client map. */ + fail_if (fd_table_unmarshal(&client_map, state_buf, unmarshal_remapper)); + + /* 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) + for (i = 0; i < client_map.capacity; i++) + if (__bit(i, &) && !client_map.values[i]) + /* Lets not presume that fd-table actually initialise its allocations. */ + __bit(i, &= ~); #undef __bit - - /* Remap the linked list and remove non-found elements, and start the clients. */ - foreach_linked_list_node (client_list, node) - { - /* Remap the linked list and remove non-found elements. */ - size_t new_address = unmarshal_remapper(client_list.values[node]); - client_list.values[node] = new_address; - if (new_address == 0) /* Returned if missing (or if the address is the invalid NULL.) */ - linked_list_remove(&client_list, node); - else - { - /* Start the clients. (Errors do not need to be reported.) */ - client_t* client = (client_t*)(void*)new_address; - int slave_fd = client->socket_fd; - - /* Increase number of running slaves. */ - with_mutex (slave_mutex, running_slaves++;); - - /* Start slave thread. */ - create_slave(&slave_thread, slave_fd); + + /* Remap the linked list and remove non-found elements, and start the clients. */ + foreach_linked_list_node (client_list, node) { + /* Remap the linked list and remove non-found elements. */ + new_address = unmarshal_remapper(client_list.values[node]); + client_list.values[node] = new_address; + if (new_address == 0) { /* Returned if missing (or if the address is the invalid NULL.) */ + linked_list_remove(&client_list, node); + } else { + /* Start the clients. (Errors do not need to be reported.) */ + client = (client_t*)(void*)new_address; + slave_fd = client->socket_fd; + + /* Increase number of running slaves. */ + with_mutex (slave_mutex, running_slaves++;); + + /* Start slave thread. */ + create_slave(&slave_thread, slave_fd); + } } - } - - /* Release the remapping table's resources. */ - hash_table_destroy(&unmarshal_remap_map, NULL, NULL); - - return with_error; + + /* Release the remapping table's resources. */ + hash_table_destroy(&unmarshal_remap_map, NULL, NULL); + + return with_error; #undef fail - - soft_fail: - xperror(*argv); - hash_table_destroy(&unmarshal_remap_map, NULL, NULL); - return -1; - critical_fail: - xperror(*argv); - abort(); + +soft_fail: + xperror(*argv); + hash_table_destroy(&unmarshal_remap_map, NULL, NULL); + return -1; +critical_fail: + xperror(*argv); + abort(); } @@ -304,10 +301,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int reexec_failure_recover(void) +int +reexec_failure_recover(void) { - /* 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; + /* 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)); + return 0; } - diff --git a/src/mds-server/sending.c b/src/mds-server/sending.c index 05e5cc0..e6a8094 100644 --- a/src/mds-server/sending.c +++ b/src/mds-server/sending.c @@ -41,11 +41,12 @@ * @param client_fd The file descriptor of the client's socket * @return The client */ -static client_t* client_by_socket(int client_fd) +static client_t * +client_by_socket(int client_fd) { - size_t address; - with_mutex (slave_mutex, address = fd_table_get(&client_map, client_fd);); - return (client_t*)(void*)address; + size_t address; + with_mutex (slave_mutex, address = fd_table_get(&client_map, client_fd);); + return (client_t*)(void*)address; } @@ -57,34 +58,32 @@ static client_t* client_by_socket(int client_fd) * @param modifying Whether the recipient may modify the message * @return Evaluates to true if and only if the entire message was sent */ -__attribute__((nonnull)) -static int send_multicast_to_recipient(multicast_t* multicast, client_t* recipient, int modifying) +static int __attribute__((nonnull)) +send_multicast_to_recipient(multicast_t *multicast, client_t *recipient, int modifying) { - char* msg = multicast->message + multicast->message_ptr; - size_t n = multicast->message_length - multicast->message_ptr; - size_t sent; - - /* Skip Modify ID header if the interceptors will not perform a modification. */ - if ((modifying == 0) && (multicast->message_ptr == 0)) - { - n -= multicast->message_prefix; - multicast->message_ptr += multicast->message_prefix; - } - - /* Send the message. */ - n *= sizeof(char); - with_mutex (recipient->mutex, - if (recipient->open) - { - sent = send_message(recipient->socket_fd, msg + multicast->message_ptr, n); - n -= sent; - multicast->message_ptr += sent / sizeof(char); - if ((n > 0) && (errno != EINTR)) - xperror(*argv); - } - ); - - return n == 0; + char *msg = multicast->message + multicast->message_ptr; + size_t n = multicast->message_length - multicast->message_ptr; + size_t sent; + + /* Skip Modify ID header if the interceptors will not perform a modification. */ + if (!modifying && !multicast->message_ptr) { + n -= multicast->message_prefix; + multicast->message_ptr += multicast->message_prefix; + } + + /* Send the message. */ + n *= sizeof(char); + with_mutex (recipient->mutex, + if (recipient->open) { + sent = send_message(recipient->socket_fd, msg + multicast->message_ptr, n); + n -= sent; + multicast->message_ptr += sent / sizeof(char); + if (n > 0 && errno != EINTR) + xperror(*argv); + } + ); + + return !n; } @@ -94,31 +93,29 @@ static int send_multicast_to_recipient(multicast_t* multicast, client_t* recipie * @param recipient The recipient * @param modify_id The modify ID of the multicast */ -__attribute__((nonnull)) -static void wait_for_reply(client_t* recipient, uint64_t modify_id) +static void __attribute__((nonnull)) +wait_for_reply(client_t *recipient, uint64_t modify_id) { - /* pthread_cond_timedwait is required to handle re-exec and termination because - pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */ - struct timespec timeout = - { - .tv_sec = 1, - .tv_nsec = 0 - }; - - with_mutex_if (modify_mutex, recipient->modify_message == NULL, - if (hash_table_contains_key(&modify_map, (size_t)modify_id) == 0) - { - hash_table_put(&modify_map, (size_t)modify_id, (size_t)(void*)recipient); - pthread_cond_signal(&slave_cond); - } - ); - - with_mutex_if (recipient->modify_mutex, recipient->modify_message == NULL, - while ((recipient->modify_message == NULL) && (terminating == 0)) - pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); - if (terminating == 0) - hash_table_remove(&modify_map, (size_t)modify_id); - ); + /* pthread_cond_timedwait is required to handle re-exec and termination because + pthread_cond_timedwait and pthread_cond_wait ignore interruptions via signals. */ + struct timespec timeout = { + .tv_sec = 1, + .tv_nsec = 0 + }; + + with_mutex_if (modify_mutex, !recipient->modify_message, + if (!hash_table_contains_key(&modify_map, (size_t)modify_id)) { + hash_table_put(&modify_map, (size_t)modify_id, (size_t)(void*)recipient); + pthread_cond_signal(&slave_cond); + } + ); + + with_mutex_if (recipient->modify_mutex, !recipient->modify_message, + while (!recipient->modify_message && !terminating) + pthread_cond_timedwait(&slave_cond, &slave_mutex, &timeout); + if (!terminating) + hash_table_remove(&modify_map, (size_t)modify_id); + ); } @@ -127,88 +124,83 @@ static void wait_for_reply(client_t* recipient, uint64_t modify_id) * * @param multicast The multicast message */ -void multicast_message(multicast_t* multicast) +void multicast_message(multicast_t *multicast) { - int consumed = 0; - uint64_t modify_id = 0; - size_t n = strlen("Modify ID: "); - - if (startswith_n(multicast->message, "Modify ID: ", multicast->message_length, n)) - { - char* value = multicast->message + n; - char* lf = strchr(value, '\n'); - *lf = '\0'; - modify_id = atou64(value); - *lf = '\n'; - } - - for (; multicast->interceptions_ptr < multicast->interceptions_count; multicast->interceptions_ptr++) - { - queued_interception_t client_ = multicast->interceptions[multicast->interceptions_ptr]; - client_t* client = client_.client; - int modifying = 0; - char* old_buf; - size_t i; - mds_message_t* mod; - - /* After unmarshalling at re-exec, client will be NULL and must be mapped from its socket. */ - if (client == NULL) - client_.client = client = client_by_socket(client_.socket_fd); - - /* Send the message to the recipient. */ - if (send_multicast_to_recipient(multicast, client, client_.modifying) == 0) - { - /* Stop if we are re-exec:ing or terminating, or continue to next recipient on error. */ - if (terminating) - return; - else - continue; - } - - /* Do not wait for a reply if it is non-modifying. */ - if (client_.modifying == 0) - { - /* Reset how much of the message has been sent before we continue with next recipient. */ - multicast->message_ptr = 0; - continue; + int consumed = 0, modifying = 0; + uint64_t modify_id = 0; + size_t i, n = strlen("Modify ID: "); + char *value, *lf, *old_buf; + mds_message_t* mod; + client_t* client; + queued_interception_t client_; + + if (startswith_n(multicast->message, "Modify ID: ", multicast->message_length, n)) { + value = multicast->message + n; + lf = strchr(value, '\n'); + *lf = '\0'; + modify_id = atou64(value); + *lf = '\n'; } - - /* Wait for a reply. */ - wait_for_reply(client, modify_id); - if (terminating) - return; - - /* Act upon the reply. */ - mod = client->modify_message; - for (i = 0; i < mod->header_count; i++) - if (strequals(mod->headers[i], "Modify: yes")) - { - modifying = 1; - consumed = mod->payload_size == 0; - break; - } - if (modifying && !consumed) - { - n = mod->payload_size; - old_buf = multicast->message; - if (xrealloc(multicast->message, multicast->message_prefix + n, char)) - { - xperror(*argv); - multicast->message = old_buf; - } - else - memcpy(multicast->message + multicast->message_prefix, mod->payload, n); + + for (; multicast->interceptions_ptr < multicast->interceptions_count; multicast->interceptions_ptr++) { + client_ = multicast->interceptions[multicast->interceptions_ptr]; + client = client_.client; + modifying = 0; + + /* After unmarshalling at re-exec, client will be NULL and must be mapped from its socket. */ + if (!client) + client_.client = client = client_by_socket(client_.socket_fd); + + /* Send the message to the recipient. */ + if (!send_multicast_to_recipient(multicast, client, client_.modifying)) { + /* Stop if we are re-exec:ing or terminating, or continue to next recipient on error. */ + if (terminating) + return; + else + continue; + } + + /* Do not wait for a reply if it is non-modifying. */ + if (!client_.modifying) { + /* Reset how much of the message has been sent before we continue with next recipient. */ + multicast->message_ptr = 0; + continue; + } + + /* Wait for a reply. */ + wait_for_reply(client, modify_id); + if (terminating) + return; + + /* Act upon the reply. */ + mod = client->modify_message; + for (i = 0; i < mod->header_count; i++) { + if (strequals(mod->headers[i], "Modify: yes")) { + modifying = 1; + consumed = mod->payload_size == 0; + break; + } + } + if (modifying && !consumed) { + n = mod->payload_size; + old_buf = multicast->message; + if (xrealloc(multicast->message, multicast->message_prefix + n, char)) { + xperror(*argv); + multicast->message = old_buf; + } else { + memcpy(multicast->message + multicast->message_prefix, mod->payload, n); + } + } + + /* Free the reply. */ + mds_message_destroy(client->modify_message); + + /* Reset how much of the message has been sent before we continue with next recipient. */ + multicast->message_ptr = 0; + + if (consumed) + break; } - - /* Free the reply. */ - mds_message_destroy(client->modify_message); - - /* Reset how much of the message has been sent before we continue with next recipient. */ - multicast->message_ptr = 0; - - if (consumed) - break; - } } @@ -217,24 +209,24 @@ void multicast_message(multicast_t* multicast) * * @param client The client */ -void send_multicast_queue(client_t* client) +void +send_multicast_queue(client_t *client) { - while (client->multicasts_count > 0) - { - multicast_t multicast; - with_mutex_if (client->mutex, client->multicasts_count > 0, - size_t c = (client->multicasts_count -= 1) * sizeof(multicast_t); - multicast = client->multicasts[0]; - memmove(client->multicasts, client->multicasts + 1, c); - if (c == 0) - { - free(client->multicasts); - client->multicasts = NULL; - } - ); - multicast_message(&multicast); - multicast_destroy(&multicast); - } + multicast_t multicast; + size_t c; + while (client->multicasts_count > 0) { + with_mutex_if (client->mutex, client->multicasts_count > 0, + c = (client->multicasts_count -= 1) * sizeof(multicast_t); + multicast = client->multicasts[0]; + memmove(client->multicasts, client->multicasts + 1, c); + if (c == 0) { + free(client->multicasts); + client->multicasts = NULL; + } + ); + multicast_message(&multicast); + multicast_destroy(&multicast); + } } @@ -243,32 +235,29 @@ void send_multicast_queue(client_t* client) * * @param client The client */ -void send_reply_queue(client_t* client) +void +send_reply_queue(client_t *client) { - char* sendbuf = client->send_pending; - char* sendbuf_ = sendbuf; - size_t sent; - size_t n; - - if (client->send_pending_size == 0) - return; - - n = client->send_pending_size; - client->send_pending_size = 0; - client->send_pending = NULL; - with_mutex (client->mutex, - while (n > 0) - { - sent = send_message(client->socket_fd, sendbuf_, n); - n -= sent; - sendbuf_ += sent / sizeof(char); - if ((n > 0) && (errno != EINTR)) /* Ignore EINTR */ - { - xperror(*argv); - break; - } - } - free(sendbuf); - ); -} + char *sendbuf = client->send_pending; + char *sendbuf_ = sendbuf; + size_t sent, n; + + if (!client->send_pending_size) + return; + n = client->send_pending_size; + client->send_pending_size = 0; + client->send_pending = NULL; + with_mutex (client->mutex, + while (n > 0) { + sent = send_message(client->socket_fd, sendbuf_, n); + n -= sent; + sendbuf_ += sent / sizeof(char); + if (n > 0 && errno != EINTR) { /* Ignore EINTR */ + xperror(*argv); + break; + } + } + free(sendbuf); + ); +} diff --git a/src/mds-server/sending.h b/src/mds-server/sending.h index 487b711..7a4fdd8 100644 --- a/src/mds-server/sending.h +++ b/src/mds-server/sending.h @@ -29,7 +29,7 @@ * @param multicast The multicast message */ __attribute__((nonnull)) -void multicast_message(multicast_t* multicast); +void multicast_message(multicast_t *multicast); /** * Send the next message in a clients multicast queue @@ -37,7 +37,7 @@ void multicast_message(multicast_t* multicast); * @param client The client */ __attribute__((nonnull)) -void send_multicast_queue(client_t* client); +void send_multicast_queue(client_t *client); /** * Send the messages that are in a clients reply queue @@ -45,8 +45,7 @@ void send_multicast_queue(client_t* client); * @param client The client */ __attribute__((nonnull)) -void send_reply_queue(client_t* client); +void send_reply_queue(client_t *client); #endif - diff --git a/src/mds-server/signals.c b/src/mds-server/signals.c index 8e4dc0e..8e1ce1d 100644 --- a/src/mds-server/signals.c +++ b/src/mds-server/signals.c @@ -32,21 +32,20 @@ */ void signal_all(int signo) { - pthread_t current_thread; - ssize_t node; - - current_thread = pthread_self(); - - if (pthread_equal(current_thread, master_thread) == 0) - pthread_kill(master_thread, signo); - - with_mutex (slave_mutex, - foreach_linked_list_node (client_list, node) - { - client_t* value = (client_t*)(void*)(client_list.values[node]); - if (pthread_equal(current_thread, value->thread) == 0) - pthread_kill(value->thread, signo); - } - ); -} + pthread_t current_thread; + ssize_t node; + client_t *value; + + current_thread = pthread_self(); + if (pthread_equal(current_thread, master_thread) == 0) + pthread_kill(master_thread, signo); + + with_mutex (slave_mutex, + foreach_linked_list_node (client_list, node) { + value = (client_t*)(void*)(client_list.values[node]); + if (!pthread_equal(current_thread, value->thread)) + pthread_kill(value->thread, signo); + } + ); +} diff --git a/src/mds-server/slavery.c b/src/mds-server/slavery.c index de0336b..6669da6 100644 --- a/src/mds-server/slavery.c +++ b/src/mds-server/slavery.c @@ -35,7 +35,7 @@ * @param data Input data * @return Outout data */ -void* slave_loop(void*); +void *slave_loop(void *); /** @@ -44,34 +44,29 @@ void* slave_loop(void*); * @param client The client * @return Zero on success, -2 on failure, otherwise -1 */ -int fetch_message(client_t* client) +int +fetch_message(client_t *client) { - int r = mds_message_read(&(client->message), client->socket_fd); - - if (r == 0) - return 0; - - if (r == -2) - { - eprint("corrupt message received."); - fail_if (1); - } - else if (errno == ECONNRESET) - { - r = mds_message_read(&(client->message), client->socket_fd); - client->open = 0; - /* Connection closed. */ - } - else if (errno != EINTR) - { - xperror(*argv); - fail_if (1); - } - - fail_if (r == -2); - return r; - fail: - return -2; + int r = mds_message_read(&(client->message), client->socket_fd); + + if (!r) { + return 0; + } else if (r == -2) { + eprint("corrupt message received."); + fail_if (1); + } else if (errno == ECONNRESET) { + r = mds_message_read(&(client->message), client->socket_fd); + client->open = 0; + /* Connection closed. */ + } else if (errno != EINTR) { + xperror(*argv); + fail_if (1); + } + + fail_if (r == -2); + return r; +fail: + return -2; } @@ -82,22 +77,21 @@ int fetch_message(client_t* client) * @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 slave_fd) +int +create_slave(pthread_t *thread_slot, int slave_fd) { - if ((errno = pthread_create(thread_slot, NULL, slave_loop, (void*)(intptr_t)slave_fd))) - { - xperror(*argv); - with_mutex (slave_mutex, running_slaves--;); - fail_if (1); - } - if ((errno = pthread_detach(*thread_slot))) - { - xperror(*argv); - fail_if (1); - } - return 0; - fail: - return -1; + if ((errno = pthread_create(thread_slot, NULL, slave_loop, (void *)(intptr_t)slave_fd))) { + xperror(*argv); + with_mutex (slave_mutex, running_slaves--;); + fail_if (1); + } + if ((errno = pthread_detach(*thread_slot))) { + xperror(*argv); + fail_if (1); + } + return 0; +fail: + return -1; } @@ -107,45 +101,44 @@ int create_slave(pthread_t* thread_slot, int slave_fd) * @param client_fd The file descriptor of the client's socket * @return The client information, `NULL` on error */ -client_t* initialise_client(int client_fd) +client_t * +initialise_client(int client_fd) { - ssize_t entry = LINKED_LIST_UNUSED; - client_t* information; - int locked = 0, saved_errno; - size_t tmp; - - /* Create information table. */ - fail_if (xmalloc(information, 1, client_t)); - client_initialise(information); - - /* Add to list of clients. */ - fail_if ((errno = pthread_mutex_lock(&slave_mutex))); - locked = 1; - entry = linked_list_insert_end(&client_list, (size_t)(void*)information); - fail_if (entry == LINKED_LIST_UNUSED); - - /* Add client to table. */ - 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 = client_fd; - information->open = 1; - fail_if (mds_message_initialise(&(information->message))); - - return information; - - - fail: - saved_errno = errno; - if (locked) - pthread_mutex_unlock(&slave_mutex); - free(information); - if (entry != LINKED_LIST_UNUSED) - with_mutex (slave_mutex, linked_list_remove(&client_list, entry);); - return errno = saved_errno, NULL; -} + ssize_t entry = LINKED_LIST_UNUSED; + client_t *information; + int locked = 0, saved_errno; + size_t tmp; + + /* Create information table. */ + fail_if (xmalloc(information, 1, client_t)); + client_initialise(information); + + /* Add to list of clients. */ + fail_if ((errno = pthread_mutex_lock(&slave_mutex))); + locked = 1; + entry = linked_list_insert_end(&client_list, (size_t)(void *)information); + fail_if (entry == LINKED_LIST_UNUSED); + /* Add client to table. */ + tmp = fd_table_put(&client_map, client_fd, (size_t)(void *)information); + fail_if (!tmp && errno); + pthread_mutex_unlock(&slave_mutex); + locked = 0; + + /* Fill information table. */ + information->list_entry = entry; + information->socket_fd = client_fd; + information->open = 1; + fail_if (mds_message_initialise(&(information->message))); + + return information; + +fail: + saved_errno = errno; + if (locked) + pthread_mutex_unlock(&slave_mutex); + free(information); + if (entry != LINKED_LIST_UNUSED) + with_mutex (slave_mutex, linked_list_remove(&client_list, entry);); + return errno = saved_errno, NULL; +} diff --git a/src/mds-server/slavery.h b/src/mds-server/slavery.h index 72e745d..89f2b83 100644 --- a/src/mds-server/slavery.h +++ b/src/mds-server/slavery.h @@ -31,7 +31,7 @@ * @return Zero on success, -2 on failure, otherwise -1 */ __attribute__((nonnull)) -int fetch_message(client_t* client); +int fetch_message(client_t *client); /** * Create, start and detache a slave thread @@ -41,7 +41,7 @@ int fetch_message(client_t* client); * @return Zero on success, -1 on error, error message will have been printed */ __attribute__((nonnull)) -int create_slave(pthread_t* thread_slot, int slave_fd); +int create_slave(pthread_t *thread_slot, int slave_fd); /** * Initialise a client, except for threading @@ -49,8 +49,7 @@ int create_slave(pthread_t* thread_slot, int slave_fd); * @param client_fd The file descriptor of the client's socket * @return The client information, `NULL` on error */ -client_t* initialise_client(int client_fd); +client_t *initialise_client(int client_fd); #endif - diff --git a/src/mds-vt.c b/src/mds-vt.c index 24d8baf..6784e7d 100644 --- a/src/mds-vt.c +++ b/src/mds-vt.c @@ -48,17 +48,16 @@ * * This tells the server-base how to behave */ -server_characteristics_t server_characteristics = - { - .require_privileges = 1, - /* Required for acquiring a TTY and requesting a VT switch. */ - - .require_display = 1, - .require_respawn_info = 1, - .sanity_check_argc = 1, - .fork_for_safety = 0, - .danger_is_deadly = 0 - }; +server_characteristics_t server_characteristics = { + .require_privileges = 1, + /* Required for acquiring a TTY and requesting a VT switch. */ + + .require_display = 1, + .require_respawn_info = 1, + .sanity_check_argc = 1, + .fork_for_safety = 0, + .danger_is_deadly = 0 +}; @@ -140,9 +139,10 @@ static ssize_t nonexclusive_counter = 0; * * @return Non-zero on error */ -int __attribute__((const)) preinitialise_server(void) +int __attribute__((const)) +preinitialise_server(void) { - return 0; + return 0; } @@ -151,23 +151,25 @@ int __attribute__((const)) preinitialise_server(void) * * @return Zero on success, -1 on error */ -static int write_vt_file(void) +static int +write_vt_file(void) { - char buf[(sizeof(int) + sizeof(struct stat)) / sizeof(char)]; - int* intbuf = (int*)buf; - int fd = -1, saved_errno; - - *intbuf = display_vt; - *(struct stat*)(buf + sizeof(int) / sizeof(char)) = old_vt_stat; - - fail_if (open(vtfile_path, O_WRONLY | O_CREAT, 0644), fd < 0); - fail_if (full_write(fd, buf, sizeof(buf))); - return 0; - fail: - saved_errno = errno; - if (fd >= 0) - xclose(fd); - return errno = saved_errno, -1; + char buf[(sizeof(int) + sizeof(struct stat)) / sizeof(char)]; + int *intbuf = (int *)buf; + int fd = -1, saved_errno; + + *intbuf = display_vt; + *(struct stat *)(buf + sizeof(int) / sizeof(char)) = old_vt_stat; + + fail_if (open(vtfile_path, O_WRONLY | O_CREAT, 0644), fd < 0); + fail_if (full_write(fd, buf, sizeof(buf))); + return 0; + +fail: + saved_errno = errno; + if (fd >= 0) + xclose(fd); + return errno = saved_errno, -1; } @@ -176,26 +178,26 @@ static int write_vt_file(void) * * @return Zero on success, -1 on error */ -static int read_vt_file(void) +static int +read_vt_file(void) { - char* buf; - size_t len; - int fd; - - fail_if (fd = open(vtfile_path, O_RDONLY), fd < 0); - fail_if (buf = full_read(fd, &len), buf == NULL); - - if (len != sizeof(int) + sizeof(struct stat)) - { - eprint("VT file is of wrong size."); - return errno = 0, -1; - } - - display_vt = *(int*)buf; - old_vt_stat = *(struct stat*)(buf + sizeof(int) / sizeof(char)); - return 0; - fail: - return -1; + char *buf; + size_t len; + int fd; + + fail_if (fd = open(vtfile_path, O_RDONLY), fd < 0); + fail_if (buf = full_read(fd, &len), buf == NULL); + + if (len != sizeof(int) + sizeof(struct stat)) { + eprint("VT file is of wrong size."); + return errno = 0, -1; + } + + display_vt = *(int *)buf; + old_vt_stat = *(struct stat *)(buf + sizeof(int) / sizeof(char)); + return 0; +fail: + return -1; } @@ -205,81 +207,79 @@ static int read_vt_file(void) * * @return Non-zero on error */ -int initialise_server(void) +int +initialise_server(void) { - struct vt_mode mode; - char* display_env; - int primary_socket_fd; - int stage = 0; - const char* const message = - "Command: intercept\n" - "Message ID: 0\n" - "Length: 38\n" - "\n" - "Command: get-vt\n" - "Command: configure-vt\n"; - const char* const secondary_message = - "Command: intercept\n" - "Message ID: 0\n" - "Priority: -4611686018427387904\n" /* −2⁶² */ - "Length: 22\n" - "\n" - "Command: switching-vt\n"; - - primary_socket_fd = socket_fd; - fail_if (connect_to_display()); - secondary_socket_fd = socket_fd; - socket_fd = primary_socket_fd; - - display_env = getenv("MDS_DISPLAY"); - display_env = display_env ? strchr(display_env, ':') : NULL; - if ((display_env == NULL) || (strlen(display_env) < 2)) - goto no_display; - - memset(vtfile_path, 0, sizeof(vtfile_path)); - xsnprintf(vtfile_path, "%s/%s.vt", MDS_RUNTIME_ROOT_DIRECTORY, display_env + 1); - stage = 1; - - if (is_respawn == 0) - { - display_vt = select_vt(); - fail_if (display_vt < 0); - display_tty_fd = vt_open(display_vt, &old_vt_stat); - fail_if (write_vt_file() < 0); - fail_if (vt_set_active(display_vt) < 0); - } - else - { - fail_if (read_vt_file() < 0); - vt_is_active = (display_vt == vt_get_active()); - fail_if (vt_is_active < 0); - } - - fail_if (full_send(secondary_socket_fd, secondary_message, strlen(secondary_message))); - fail_if (full_send(socket_fd, message, strlen(message))); - fail_if (server_initialised() < 0); - fail_if (mds_message_initialise(&received)); stage = 2; - - fail_if (xsigaction(SIGRTMIN + 2, received_switch_vt) < 0); - fail_if (xsigaction(SIGRTMIN + 3, received_switch_vt) < 0); - vt_construct_mode(1, SIGRTMIN + 2, SIGRTMIN + 3, &mode); - fail_if (vt_get_set_mode(display_tty_fd, 1, &mode) < 0); - if (vt_set_exclusive(display_tty_fd, 1) < 0) - xperror(*argv); - - return 0; - no_display: - eprint("no display has been set, how did this happen."); - return 1; - fail: - xperror(*argv); - if (stage >= 1) - unlink(vtfile_path); - if (display_tty_fd >= 0) - vt_close(display_tty_fd, &old_vt_stat); - if (stage >= 2) - mds_message_destroy(&received); - return 1; + struct vt_mode mode; + char *display_env; + int primary_socket_fd; + int stage = 0; + const char *const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 38\n" + "\n" + "Command: get-vt\n" + "Command: configure-vt\n"; + const char *const secondary_message = + "Command: intercept\n" + "Message ID: 0\n" + "Priority: -4611686018427387904\n" /* −2⁶² */ + "Length: 22\n" + "\n" + "Command: switching-vt\n"; + + primary_socket_fd = socket_fd; + fail_if (connect_to_display()); + secondary_socket_fd = socket_fd; + socket_fd = primary_socket_fd; + + display_env = getenv("MDS_DISPLAY"); + display_env = display_env ? strchr(display_env, ':') : NULL; + if ((display_env == NULL) || (strlen(display_env) < 2)) + goto no_display; + + memset(vtfile_path, 0, sizeof(vtfile_path)); + xsnprintf(vtfile_path, "%s/%s.vt", MDS_RUNTIME_ROOT_DIRECTORY, display_env + 1); + stage = 1; + + if (is_respawn == 0) { + display_vt = select_vt(); + fail_if (display_vt < 0); + display_tty_fd = vt_open(display_vt, &old_vt_stat); + fail_if (write_vt_file() < 0); + fail_if (vt_set_active(display_vt) < 0); + } else { + fail_if (read_vt_file() < 0); + vt_is_active = (display_vt == vt_get_active()); + fail_if (vt_is_active < 0); + } + + fail_if (full_send(secondary_socket_fd, secondary_message, strlen(secondary_message))); + fail_if (full_send(socket_fd, message, strlen(message))); + fail_if (server_initialised() < 0); + fail_if (mds_message_initialise(&received)); stage = 2; + + fail_if (xsigaction(SIGRTMIN + 2, received_switch_vt) < 0); + fail_if (xsigaction(SIGRTMIN + 3, received_switch_vt) < 0); + vt_construct_mode(1, SIGRTMIN + 2, SIGRTMIN + 3, &mode); + fail_if (vt_get_set_mode(display_tty_fd, 1, &mode) < 0); + if (vt_set_exclusive(display_tty_fd, 1) < 0) + xperror(*argv); + + return 0; +no_display: + eprint("no display has been set, how did this happen."); + return 1; +fail: + xperror(*argv); + if (stage >= 1) + unlink(vtfile_path); + if (display_tty_fd >= 0) + vt_close(display_tty_fd, &old_vt_stat); + if (stage >= 2) + mds_message_destroy(&received); + return 1; } @@ -289,23 +289,23 @@ int initialise_server(void) * * @return Non-zero on error */ -int postinitialise_server(void) +int +postinitialise_server(void) { - if (connected) - return 0; - - if (reconnect_to_display()) - { - mds_message_destroy(&received); - fail_if (1); - } - connected = 1; - - fail_if ((errno = pthread_create(&secondary_thread, NULL, secondary_loop, NULL))); - - return 0; - fail: - return 1; + if (connected) + return 0; + + if (reconnect_to_display()) { + mds_message_destroy(&received); + fail_if (1); + } + connected = 1; + + fail_if ((errno = pthread_create(&secondary_thread, NULL, secondary_loop, NULL))); + + return 0; +fail: + return 1; } @@ -317,13 +317,14 @@ int postinitialise_server(void) * * @return The number of bytes that will be stored by `marshal_server` */ -size_t marshal_server_size(void) +size_t +marshal_server_size(void) { - size_t rc = 6 * sizeof(int) + sizeof(uint32_t) + sizeof(ssize_t); - rc += sizeof(struct stat); - rc += PATH_MAX * sizeof(char); - rc += mds_message_marshal_size(&received); - return rc; + size_t rc = 6 * sizeof(int) + sizeof(uint32_t) + sizeof(ssize_t); + rc += sizeof(struct stat); + rc += PATH_MAX * sizeof(char); + rc += mds_message_marshal_size(&received); + return rc; } @@ -333,23 +334,24 @@ size_t marshal_server_size(void) * @param state_buf The buffer for the marshalled data * @return Non-zero on error */ -int marshal_server(char* state_buf) +int +marshal_server(char *state_buf) { - buf_set_next(state_buf, int, MDS_VT_VARS_VERSION); - buf_set_next(state_buf, int, connected); - buf_set_next(state_buf, uint32_t, message_id); - buf_set_next(state_buf, int, display_vt); - buf_set_next(state_buf, int, display_tty_fd); - buf_set_next(state_buf, int, vt_is_active); - buf_set_next(state_buf, struct stat, old_vt_stat); - buf_set_next(state_buf, int, secondary_socket_fd); - buf_set_next(state_buf, ssize_t, nonexclusive_counter); - memcpy(state_buf, vtfile_path, PATH_MAX * sizeof(char)); - state_buf += PATH_MAX; - mds_message_marshal(&received, state_buf); - - mds_message_destroy(&received); - return 0; + buf_set_next(state_buf, int, MDS_VT_VARS_VERSION); + buf_set_next(state_buf, int, connected); + buf_set_next(state_buf, uint32_t, message_id); + buf_set_next(state_buf, int, display_vt); + buf_set_next(state_buf, int, display_tty_fd); + buf_set_next(state_buf, int, vt_is_active); + buf_set_next(state_buf, struct stat, old_vt_stat); + buf_set_next(state_buf, int, secondary_socket_fd); + buf_set_next(state_buf, ssize_t, nonexclusive_counter); + memcpy(state_buf, vtfile_path, PATH_MAX * sizeof(char)); + state_buf += PATH_MAX; + mds_message_marshal(&received, state_buf); + + mds_message_destroy(&received); + return 0; } @@ -363,28 +365,27 @@ int marshal_server(char* state_buf) * @param state_buf The marshalled data that as not been read already * @return Non-zero on error */ -int unmarshal_server(char* state_buf) +int +unmarshal_server(char *state_buf) { - int r; - /* buf_get_next(state_buf, int, MDS_VT_VARS_VERSION); */ - buf_next(state_buf, int, 1); - buf_get_next(state_buf, int, connected); - buf_get_next(state_buf, uint32_t, message_id); - buf_get_next(state_buf, int, display_vt); - buf_get_next(state_buf, int, display_tty_fd); - buf_get_next(state_buf, int, vt_is_active); - buf_get_next(state_buf, struct stat, old_vt_stat); - buf_get_next(state_buf, int, secondary_socket_fd); - buf_get_next(state_buf, ssize_t, nonexclusive_counter); - memcpy(vtfile_path, state_buf, PATH_MAX * sizeof(char)); - state_buf += PATH_MAX; - r = mds_message_unmarshal(&received, state_buf); - if (r) - { - xperror(*argv); - mds_message_destroy(&received); - } - return r; + int r; + /* buf_get_next(state_buf, int, MDS_VT_VARS_VERSION); */ + buf_next(state_buf, int, 1); + buf_get_next(state_buf, int, connected); + buf_get_next(state_buf, uint32_t, message_id); + buf_get_next(state_buf, int, display_vt); + buf_get_next(state_buf, int, display_tty_fd); + buf_get_next(state_buf, int, vt_is_active); + buf_get_next(state_buf, struct stat, old_vt_stat); + buf_get_next(state_buf, int, secondary_socket_fd); + buf_get_next(state_buf, ssize_t, nonexclusive_counter); + memcpy(vtfile_path, state_buf, PATH_MAX * sizeof(char)); + state_buf += PATH_MAX; + if ((r = mds_message_unmarshal(&received, state_buf))) { + xperror(*argv); + mds_message_destroy(&received); + } + return r; } @@ -394,9 +395,10 @@ int unmarshal_server(char* state_buf) * * @return Non-zero on error */ -int __attribute__((const)) reexec_failure_recover(void) +int __attribute__((const)) +reexec_failure_recover(void) { - return -1; + return -1; } @@ -405,58 +407,58 @@ int __attribute__((const)) reexec_failure_recover(void) * * @return Non-zero on error */ -int master_loop(void) +int +master_loop(void) { - int rc = 1, r; - - while (!reexecing && !terminating) - { - if (switching_vt) - { - int leaving = switching_vt == 1; - switching_vt = 0; - r = switch_vt(leaving); - } - else - if (r = mds_message_read(&received, socket_fd), r == 0) - r = handle_message(); - if (r == 0) - continue; - - if (r == -2) - { - eprint("corrupt message received, aborting."); - goto done; + int rc = 1, r, leaving; + + while (!reexecing && !terminating) { + if (switching_vt) { + leaving = switching_vt == 1; + switching_vt = 0; + r = switch_vt(leaving); + } else if (!(r = mds_message_read(&received, socket_fd))) { + r = handle_message(); + } + + if (!r) { + continue; + } else if (r == -2) { + eprint("corrupt message received, aborting."); + goto done; + } else if (errno == EINTR) { + continue; + } else { + fail_if (errno != ECONNRESET); + } + + eprint("lost primary connection to server."); + mds_message_destroy(&received); + mds_message_initialise(&received); + connected = 0; + fail_if (reconnect_to_display()); + connected = 1; } - else if (errno == EINTR) - continue; - else - fail_if (errno != ECONNRESET); - - eprint("lost primary connection to server."); - mds_message_destroy(&received); - mds_message_initialise(&received); - connected = 0; - fail_if (reconnect_to_display()); - connected = 1; - } - rc = 0; - if (vt_set_exclusive(display_tty_fd, 0) < 0) xperror(*argv); - if (vt_set_graphical(display_tty_fd, 0) < 0) xperror(*argv); - if (unlink(vtfile_path) < 0) - xperror(*argv); - vt_close(display_tty_fd, &old_vt_stat); - goto done; - fail: - xperror(*argv); - done: - rc |= secondary_thread_failed; - if (rc || !reexecing) - mds_message_destroy(&received); - if ((errno = pthread_join(secondary_thread, NULL))) - xperror(*argv); - return rc; + rc = 0; + if (vt_set_exclusive(display_tty_fd, 0) < 0) + xperror(*argv); + if (vt_set_graphical(display_tty_fd, 0) < 0) + xperror(*argv); + if (unlink(vtfile_path) < 0) + xperror(*argv); + vt_close(display_tty_fd, &old_vt_stat); + goto done; + +fail: + xperror(*argv); +done: + rc |= secondary_thread_failed; + if (rc || !reexecing) + mds_message_destroy(&received); + if ((errno = pthread_join(secondary_thread, NULL))) + xperror(*argv); + return rc; } @@ -466,49 +468,47 @@ int master_loop(void) * @param data Thread input parameter, will always be `NULL` * @return Thread return value, will always be `NULL` */ -void* secondary_loop(void* data) +void *secondary_loop(void *data) { - mds_message_t secondary_received; - int r; - (void) data; - - secondary_thread_started = 1; - fail_if (mds_message_initialise(&secondary_received) < 0); - - while (!reexecing && !terminating) - { - if (r = mds_message_read(&secondary_received, secondary_socket_fd), r == 0) - r = vt_accept_switch(display_tty_fd); - if (r == 0) - continue; - - if (r == -2) - { - eprint("corrupt message received, aborting."); - secondary_thread_failed = 1; - goto done; + mds_message_t secondary_received; + int r; + + secondary_thread_started = 1; + fail_if (mds_message_initialise(&secondary_received) < 0); + + while (!reexecing && !terminating) { + if (!(r = mds_message_read(&secondary_received, secondary_socket_fd))) + r = vt_accept_switch(display_tty_fd); + if (!r) { + continue; + } else if (r == -2) { + eprint("corrupt message received, aborting."); + secondary_thread_failed = 1; + goto done; + } else if (errno == EINTR) { + continue; + } else { + fail_if (errno != ECONNRESET); + } + + eprint("lost secondary connection to server."); + mds_message_destroy(&secondary_received); + mds_message_initialise(&secondary_received); + fail_if (reconnect_fd_to_display(&secondary_socket_fd) < 0); } - else if (errno == EINTR) - continue; - else - fail_if (errno != ECONNRESET); - - eprint("lost secondary connection to server."); - mds_message_destroy(&secondary_received); - mds_message_initialise(&secondary_received); - fail_if (reconnect_fd_to_display(&secondary_socket_fd) < 0); - } - - goto done; - fail: - xperror(*argv); - secondary_thread_failed = 1; - done: - secondary_thread_started = 0; - mds_message_destroy(&secondary_received); - if (!reexecing && !terminating) - pthread_kill(master_thread, SIGTERM); - return NULL; + + goto done; + +fail: + xperror(*argv); + secondary_thread_failed = 1; +done: + secondary_thread_started = 0; + mds_message_destroy(&secondary_received); + if (!reexecing && !terminating) + pthread_kill(master_thread, SIGTERM); + return NULL; + (void) data; } @@ -518,24 +518,25 @@ void* secondary_loop(void* data) * @param leave_foreground Whether the display is leaving the foreground * @return Zero on success, -1 on error */ -int switch_vt(int leave_foreground) +int +switch_vt(int leave_foreground) { - char buf[46 + 22]; - - sprintf(buf, - "Command: switching-vt\n" - "Message ID: %" PRIu32 "\n" - "Status: %s\n" - "\n", - message_id, - leave_foreground ? "deactivating" : "activating"); - - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - fail_if (full_send(socket_fd, buf, strlen(buf))); - return 0; - fail: - return -1; + char buf[46 + 22]; + + sprintf(buf, + "Command: switching-vt\n" + "Message ID: %" PRIu32 "\n" + "Status: %s\n" + "\n", + message_id, + leave_foreground ? "deactivating" : "activating"); + + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + + fail_if (full_send(socket_fd, buf, strlen(buf))); + return 0; +fail: + return -1; } @@ -544,61 +545,59 @@ int switch_vt(int leave_foreground) * * @return Zero on success, -1 on error */ -int handle_message(void) +int +handle_message(void) { - /* Fetch message headers. */ - - const char* recv_client_id = "0:0"; - const char* recv_message_id = NULL; - const char* recv_graphical = "neither"; - const char* recv_exclusive = "neither"; - const char* recv_command = NULL; - size_t i; - -#define __get_header(storage, header) \ - (startswith(received.headers[i], header)) \ - storage = received.headers[i] + strlen(header) - - for (i = 0; i < received.header_count; i++) - { - if __get_header(recv_client_id, "Client ID: "); - else if __get_header(recv_message_id, "Message ID: "); - else if __get_header(recv_graphical, "Graphical: "); - else if __get_header(recv_exclusive, "Exclusive: "); - else if __get_header(recv_command, "Command: "); - } - + /* Fetch message headers. */ + + const char* recv_client_id = "0:0"; + const char* recv_message_id = NULL; + const char* recv_graphical = "neither"; + const char* recv_exclusive = "neither"; + const char* recv_command = NULL; + size_t i; + +#define __get_header(storage, header)\ + (startswith(received.headers[i], header))\ + storage = received.headers[i] + strlen(header) + + for (i = 0; i < received.header_count; i++) { + if __get_header(recv_client_id, "Client ID: "); + else if __get_header(recv_message_id, "Message ID: "); + else if __get_header(recv_graphical, "Graphical: "); + else if __get_header(recv_exclusive, "Exclusive: "); + else if __get_header(recv_command, "Command: "); + } + #undef __get_header - - - /* Validate headers. */ - - if (recv_message_id == NULL) - return eprint("received message without ID, ignoring, master server is misbehaving."), 0; - - if (strequals(recv_client_id, "0:0")) - return eprint("received information request from an anonymous client, ignoring."), 0; - - if (strlen(recv_client_id) > 21) - return eprint("received invalid client ID, ignoring."), 0; - if (strlen(recv_message_id) > 10) - return eprint("received invalid message ID, ignoring."), 0; - - - /* Take appropriate action. */ - - if (recv_command == NULL) - return 0; /* How did that get here, no matter, just ignore it? */ - - if (strequals(recv_command, "get-vt")) - fail_if (handle_get_vt(recv_client_id, recv_message_id)); - - if (strequals(recv_command, "configure-vt")) - fail_if (handle_configure_vt(recv_client_id, recv_message_id, recv_graphical, recv_exclusive)); - - return 0; /* How did that get here, no matter, just ignore it? */ - fail: - return -1; + + /* Validate headers. */ + + if (!recv_message_id) + return eprint("received message without ID, ignoring, master server is misbehaving."), 0; + + if (strequals(recv_client_id, "0:0")) + return eprint("received information request from an anonymous client, ignoring."), 0; + + if (strlen(recv_client_id) > 21) + return eprint("received invalid client ID, ignoring."), 0; + if (strlen(recv_message_id) > 10) + return eprint("received invalid message ID, ignoring."), 0; + + /* Take appropriate action. */ + + if (!recv_command) + return 0; /* How did that get here, no matter, just ignore it? */ + + if (strequals(recv_command, "get-vt")) + fail_if (handle_get_vt(recv_client_id, recv_message_id)); + + if (strequals(recv_command, "configure-vt")) + fail_if (handle_configure_vt(recv_client_id, recv_message_id, recv_graphical, recv_exclusive)); + + return 0; /* How did that get here, no matter, just ignore it? */ +fail: + return -1; } @@ -609,30 +608,31 @@ int handle_message(void) * @param message The value of the header `Message ID` in the received message * @return Zero on success, -1 on error */ -int handle_get_vt(const char* client, const char* message) +int +handle_get_vt(const char *client, const char *message) { - char buf[81 + 44 + 3 * sizeof(int)]; - int active = vt_get_active(); - int r; - - sprintf(buf, - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Origin command: get-vt\n" - "VT index: %i\n" - "Active: %s\n" - "\n", - client, message, message_id, display_vt, - active == display_vt ? "yes" : "no"); - - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - r = full_send(socket_fd, buf, strlen(buf)); - fail_if ((active < 0) || r); - return 0; - fail: - return -1; + char buf[81 + 44 + 3 * sizeof(int)]; + int active = vt_get_active(); + int r; + + sprintf(buf, + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Origin command: get-vt\n" + "VT index: %i\n" + "Active: %s\n" + "\n", + client, message, message_id, display_vt, + active == display_vt ? "yes" : "no"); + + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + + r = full_send(socket_fd, buf, strlen(buf)); + fail_if ((active < 0) || r); + return 0; +fail: + return -1; } @@ -645,41 +645,41 @@ int handle_get_vt(const char* client, const char* message) * @param exclusive The value of the header `Exclusive` in the received message * @return Zero on success, -1 on error */ -int handle_configure_vt(const char* client, const char* message, const char* graphical, const char* exclusive) +int +handle_configure_vt(const char *client, const char *message, const char *graphical, const char *exclusive) { - char buf[60 + 41 + 3 * sizeof(int)]; - int r = 0, set_nonexclusive; - - if (strequals(exclusive, "yes") || strequals(exclusive, "no")) - { - /* Switch to exclusive mode when no server has request - non-exclusive mode anymore, and switch to non-exclusive - mode when the number of server that server that has - request non-exclusive switches from zero to one. */ - set_nonexclusive = strequals(exclusive, "no"); - if (nonexclusive_counter == (ssize_t)!set_nonexclusive) - r |= vt_set_exclusive(display_tty_fd, !set_nonexclusive); - nonexclusive_counter += set_nonexclusive ? 1 : -1; - } - - if (strequals(graphical, "yes") || strequals(graphical, "no")) - r |= vt_set_graphical(display_tty_fd, strequals(graphical, "yes")); - - sprintf(buf, - "Command: error\n" - "To: %s\n" - "In response to: %s\n" - "Message ID: %" PRIu32 "\n" - "Error: %i\n" - "\n", - client, message, message_id, r); - - message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); - - fail_if (full_send(socket_fd, buf, strlen(buf))); - return 0; - fail: - return -1; + char buf[60 + 41 + 3 * sizeof(int)]; + int r = 0, set_nonexclusive; + + if (strequals(exclusive, "yes") || strequals(exclusive, "no")) { + /* Switch to exclusive mode when no server has request + non-exclusive mode anymore, and switch to non-exclusive + mode when the number of server that server that has + request non-exclusive switches from zero to one. */ + set_nonexclusive = strequals(exclusive, "no"); + if (nonexclusive_counter == (ssize_t)!set_nonexclusive) + r |= vt_set_exclusive(display_tty_fd, !set_nonexclusive); + nonexclusive_counter += set_nonexclusive ? 1 : -1; + } + + if (strequals(graphical, "yes") || strequals(graphical, "no")) + r |= vt_set_graphical(display_tty_fd, strequals(graphical, "yes")); + + sprintf(buf, + "Command: error\n" + "To: %s\n" + "In response to: %s\n" + "Message ID: %" PRIu32 "\n" + "Error: %i\n" + "\n", + client, message, message_id, r); + + message_id = message_id == UINT32_MAX ? 0 : (message_id + 1); + + fail_if (full_send(socket_fd, buf, strlen(buf))); + return 0; +fail: + return -1; } @@ -688,14 +688,15 @@ int handle_configure_vt(const char* client, const char* message, const char* gra * * @param signo The signal */ -void signal_all(int signo) +void +signal_all(int signo) { - pthread_t current_thread = pthread_self(); - - if (pthread_equal(current_thread, master_thread) == 0) - pthread_kill(master_thread, signo); - else if (secondary_thread_started) - pthread_kill(secondary_thread, signo); + pthread_t current_thread = pthread_self(); + + if (pthread_equal(current_thread, master_thread) == 0) + pthread_kill(master_thread, signo); + else if (secondary_thread_started) + pthread_kill(secondary_thread, signo); } @@ -705,12 +706,13 @@ void signal_all(int signo) * * @param signo The received signal number */ -void received_switch_vt(int signo) +void +received_switch_vt(int signo) { - SIGHANDLER_START; - int leaving = signo == (SIGRTMIN + 2); - switching_vt = leaving ? 1 : -1; - SIGHANDLER_END; + SIGHANDLER_START; + int leaving = signo == (SIGRTMIN + 2); + switching_vt = leaving ? 1 : -1; + SIGHANDLER_END; } @@ -719,39 +721,35 @@ void received_switch_vt(int signo) * * @return The index of the virtual terminal on which the display should be opened, -1 on error */ -int select_vt(void) +int +select_vt(void) { - int rc, r; - const char* xdg_vtnr; - - xdg_vtnr = getenv("XDG_VTNR"); - if (xdg_vtnr == NULL) - xdg_vtnr = ""; - - if (*xdg_vtnr) - { - /* $XDG_VTNR has been specified, use it to select VT. */ - r = strict_atoi(xdg_vtnr, &rc, MIN_NR_CONSOLES, MAX_NR_CONSOLES); - if (r < 0) - { - eprint("the environment variable XDG_VTNR contains an invalid value."); - fail_if (errno = 0, 1); + int rc, r; + const char *xdg_vtnr; + + xdg_vtnr = getenv("XDG_VTNR"); + if (xdg_vtnr == NULL) + xdg_vtnr = ""; + + if (*xdg_vtnr) { + /* $XDG_VTNR has been specified, use it to select VT. */ + r = strict_atoi(xdg_vtnr, &rc, MIN_NR_CONSOLES, MAX_NR_CONSOLES); + if (r < 0) { + eprint("the environment variable XDG_VTNR contains an invalid value."); + fail_if (errno = 0, 1); + } + } else { + /* $XDG_VTNR has not been specified, select next available VT. */ + rc = vt_get_next_available(); + if (rc == 0) { + eprint("out of available virtual terminals, I am stymied."); + fail_if (errno = 0, 1); + } } - } - else - { - /* $XDG_VTNR has not been specified, select next available VT. */ - rc = vt_get_next_available(); - if (rc == 0) - { - eprint("out of available virtual terminals, I am stymied."); - fail_if (errno = 0, 1); - } - } - - return rc; - fail: - return -1; + + return rc; +fail: + return -1; } @@ -760,13 +758,14 @@ int select_vt(void) * * @return -1 on error, 0 if the terminals are exhausted, otherwise the next terminal */ -int vt_get_next_available(void) +int +vt_get_next_available(void) { - int next_vt = -1; - fail_if (ioctl(STDIN_FILENO, VT_OPENQRY, &next_vt) < 0); - return ((next_vt < 0) || (MAX_NR_CONSOLES < next_vt)) ? 0 : next_vt; - fail: - return -1; + int next_vt = -1; + fail_if (ioctl(STDIN_FILENO, VT_OPENQRY, &next_vt) < 0); + return ((next_vt < 0) || (MAX_NR_CONSOLES < next_vt)) ? 0 : next_vt; +fail: + return -1; } @@ -775,13 +774,14 @@ int vt_get_next_available(void) * * @return -1 on error, otherwise the current terminal */ -int vt_get_active(void) +int +vt_get_active(void) { - struct vt_stat state; - fail_if (ioctl(STDIN_FILENO, VT_GETSTATE, &state) < 0); - return state.v_active; - fail: - return -1; + struct vt_stat state; + fail_if (ioctl(STDIN_FILENO, VT_GETSTATE, &state) < 0); + return state.v_active; +fail: + return -1; } @@ -791,15 +791,16 @@ int vt_get_active(void) * @param vt The index of the terminal * @return Zero on success, -1 on error */ -int vt_set_active(int vt) +int +vt_set_active(int vt) { - fail_if (ioctl(STDIN_FILENO, VT_ACTIVATE, vt) < 0); - if (ioctl(STDIN_FILENO, VT_WAITACTIVE, vt) < 0) - xperror(*argv); - - return 0; - fail: - return -1; + fail_if (ioctl(STDIN_FILENO, VT_ACTIVATE, vt) < 0); + if (ioctl(STDIN_FILENO, VT_WAITACTIVE, vt) < 0) + xperror(*argv); + + return 0; +fail: + return -1; } @@ -810,21 +811,22 @@ int vt_set_active(int vt) * @param old_stat Output parameter for the old file stat for the terminal * @return The file descriptor for the terminal, -1 on error */ -int vt_open(int vt, struct stat* restrict old_stat) +int +vt_open(int vt, struct stat *restrict old_stat) { - char vtpath[64]; /* Should be small enough and large enough for any - lunatic alternative to /dev/ttyNNN, if not you - will need to apply a patch (or fix your system.) */ - int fd = -1, saved_errno; - sprintf(vtpath, VT_PATH_PATTERN, vt); - fail_if (fd = open(vtpath, O_RDWR), fd < 0); - fail_if ((fstat(fd, old_stat) < 0) || (fchown(fd, getuid(), getgid()) < 0)); - return fd; - fail: - saved_errno = errno; - if (fd >= 0) - xclose(fd); - return errno = saved_errno, -1; + char vtpath[64]; /* Should be small enough and large enough for any + lunatic alternative to /dev/ttyNNN, if not you + will need to apply a patch (or fix your system.) */ + int fd = -1, saved_errno; + sprintf(vtpath, VT_PATH_PATTERN, vt); + fail_if (fd = open(vtpath, O_RDWR), fd < 0); + fail_if ((fstat(fd, old_stat) < 0) || (fchown(fd, getuid(), getgid()) < 0)); + return fd; +fail: + saved_errno = errno; + if (fd >= 0) + xclose(fd); + return errno = saved_errno, -1; } @@ -834,14 +836,14 @@ int vt_open(int vt, struct stat* restrict old_stat) * @param vt The index of the terminal * @param old_stat The old file stat for the terminal */ -void vt_close(int fd, struct stat* restrict old_stat) +void +vt_close(int fd, struct stat *restrict old_stat) { - if (fchown(fd, old_stat->st_uid, old_stat->st_gid) < 0) - { - xperror(*argv); - eprint("while resetting TTY ownership."); - } - xclose(fd); + if (fchown(fd, old_stat->st_uid, old_stat->st_gid) < 0) { + xperror(*argv); + eprint("while resetting TTY ownership."); + } + xclose(fd); } @@ -855,13 +857,14 @@ void vt_close(int fd, struct stat* restrict old_stat) * to switch terminal to our terminal * @param mode Output parameter */ -void vt_construct_mode(int vt_switch_control, int vt_leave_signal, - int vt_enter_signal, struct vt_mode* restrict mode) +void +vt_construct_mode(int vt_switch_control, int vt_leave_signal, + int vt_enter_signal, struct vt_mode *restrict mode) { - mode->mode = vt_switch_control ? VT_PROCESS : VT_AUTO; - mode->waitv = 0; - mode->relsig = (short int)vt_leave_signal; - mode->acqsig = (short int)vt_enter_signal; + mode->mode = vt_switch_control ? VT_PROCESS : VT_AUTO; + mode->waitv = 0; + mode->relsig = (short int)vt_leave_signal; + mode->acqsig = (short int)vt_enter_signal; } @@ -872,24 +875,24 @@ void vt_construct_mode(int vt_switch_control, int vt_leave_signal, * * @param signo The signal that has been received */ -void received_info(int signo) +void +received_info(int signo) { - SIGHANDLER_START; - (void) signo; - iprintf("next message ID: %" PRIu32, message_id); - iprintf("connected: %s", connected ? "yes" : "no"); - iprintf("VT of the display: %i", display_vt); - iprintf("TTY FD of the display: %i", display_tty_fd); - iprintf("TTY in foreground: %s", vt_is_active ? "yes" : "no"); - iprintf("old VT stat: mode: %lo", (long)(old_vt_stat.st_mode)); - iprintf("old VT stat: uid: %li", (long)(old_vt_stat.st_uid)); - iprintf("old VT stat: gid: %li", (long)(old_vt_stat.st_gid)); - iprintf("switching VT: %s", switching_vt ? "yes" : "no"); - iprintf("VT-file pathname: %s", vtfile_path); - iprintf("secondary socket FD: %i", secondary_socket_fd); - iprintf("secondary thread started: %s", secondary_thread_started ? "yes" : "no"); - iprintf("secondary thread failed: %s", secondary_thread_failed ? "yes" : "no"); - iprintf("non-exclusive counter: %zi", nonexclusive_counter); - SIGHANDLER_END; + SIGHANDLER_START; + (void) signo; + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + iprintf("VT of the display: %i", display_vt); + iprintf("TTY FD of the display: %i", display_tty_fd); + iprintf("TTY in foreground: %s", vt_is_active ? "yes" : "no"); + iprintf("old VT stat: mode: %lo", (long)(old_vt_stat.st_mode)); + iprintf("old VT stat: uid: %li", (long)(old_vt_stat.st_uid)); + iprintf("old VT stat: gid: %li", (long)(old_vt_stat.st_gid)); + iprintf("switching VT: %s", switching_vt ? "yes" : "no"); + iprintf("VT-file pathname: %s", vtfile_path); + iprintf("secondary socket FD: %i", secondary_socket_fd); + iprintf("secondary thread started: %s", secondary_thread_started ? "yes" : "no"); + iprintf("secondary thread failed: %s", secondary_thread_failed ? "yes" : "no"); + iprintf("non-exclusive counter: %zi", nonexclusive_counter); + SIGHANDLER_END; } - diff --git a/src/mds-vt.h b/src/mds-vt.h index 76b990a..35ea860 100644 --- a/src/mds-vt.h +++ b/src/mds-vt.h @@ -32,7 +32,7 @@ * @param data Thread input parameter, will always be `NULL` * @return Thread return value, will always be `NULL` */ -void* secondary_loop(void* data); +void *secondary_loop(void *data); /** @@ -58,7 +58,7 @@ int handle_message(void); * @param message The value of the header `Message ID` in the received message * @return Zero on success, -1 on error */ -int handle_get_vt(const char* client, const char* message); +int handle_get_vt(const char *client, const char *message); /** * Handle a received `Command: configure-vt` message @@ -69,7 +69,7 @@ int handle_get_vt(const char* client, const char* message); * @param exclusive The value of the header `Exclusive` in the received message * @return Zero on success, -1 on error */ -int handle_configure_vt(const char* client, const char* message, const char* graphical, const char* exclusive); +int handle_configure_vt(const char *client, const char *message, const char *graphical, const char *exclusive); /** @@ -121,7 +121,7 @@ int vt_set_active(int vt); * @param old_stat Output parameter for the old file stat for the terminal * @return The file descriptor for the terminal, -1 on error */ -int vt_open(int vt, struct stat* restrict old_stat); +int vt_open(int vt, struct stat *restrict old_stat); /** @@ -130,7 +130,7 @@ int vt_open(int vt, struct stat* restrict old_stat); * @param vt The index of the terminal * @param old_stat The old file stat for the terminal */ -void vt_close(int fd, struct stat* restrict old_stat); +void vt_close(int fd, struct stat *restrict old_stat); @@ -141,8 +141,8 @@ void vt_close(int fd, struct stat* restrict old_stat); * @param exclusive:int Whether to block other programs for using the terminal * @return :int Zero on success, -1 on error */ -#define vt_set_exclusive(fd, exclusive) \ - (ioctl(fd, (exclusive) ? TIOCEXCL : TIOCNXCL)) +#define vt_set_exclusive(fd, exclusive)\ + (ioctl(fd, (exclusive) ? TIOCEXCL : TIOCNXCL)) /** @@ -152,8 +152,8 @@ void vt_close(int fd, struct stat* restrict old_stat); * @param graphical:int Whether to use graphical mode * @return :int Zero on success, -1 on error */ -#define vt_set_graphical(fd, graphical) \ - (ioctl(fd, KDSETMODE, (graphical) ? KD_GRAPHICS : KD_TEXT)) +#define vt_set_graphical(fd, graphical)\ + (ioctl(fd, KDSETMODE, (graphical) ? KD_GRAPHICS : KD_TEXT)) /** @@ -167,7 +167,7 @@ void vt_close(int fd, struct stat* restrict old_stat); * @param mode Output parameter */ void vt_construct_mode(int vt_switch_control, int vt_leave_signal, - int vt_enter_signal, struct vt_mode* restrict mode); + int vt_enter_signal, struct vt_mode *restrict mode); /** @@ -178,8 +178,8 @@ void vt_construct_mode(int vt_switch_control, int vt_leave_signal, * @param mode:struct vt_mode* Input or outpur parameter for the mode * @return :int Zero on success, -1 on error */ -#define vt_get_set_mode(fd, set, mode) \ - (ioctl(fd, set ? VT_SETMODE : VT_GETMODE, mode)) +#define vt_get_set_mode(fd, set, mode)\ + (ioctl(fd, set ? VT_SETMODE : VT_GETMODE, mode)) /** @@ -188,8 +188,8 @@ void vt_construct_mode(int vt_switch_control, int vt_leave_signal, * @param fd:int File descriptor for our terminal * @return :int Zero on success, -1 on error */ -#define vt_stop_switch(fd) \ - (ioctl(fd, VT_RELDISP, 0)) +#define vt_stop_switch(fd)\ + (ioctl(fd, VT_RELDISP, 0)) /** @@ -198,8 +198,8 @@ void vt_construct_mode(int vt_switch_control, int vt_leave_signal, * @param fd:int File descriptor for our terminal * @return :int Zero on success, -1 on error */ -#define vt_continue_switch(fd) \ - (ioctl(fd, VT_RELDISP, 1)) +#define vt_continue_switch(fd)\ + (ioctl(fd, VT_RELDISP, 1)) /** @@ -208,8 +208,8 @@ void vt_construct_mode(int vt_switch_control, int vt_leave_signal, * @param fd:int File descriptor for our terminal * @return :int Zero on success, -1 on error */ -#define vt_accept_switch(fd) \ - (ioctl(fd, VT_RELDISP, VT_ACKACQ)) +#define vt_accept_switch(fd)\ + (ioctl(fd, VT_RELDISP, VT_ACKACQ)) #endif @@ -46,12 +46,12 @@ static int argc; /** * Command line arguments */ -static char** argv; +static char **argv; /** * The master server */ -static const char* master_server = LIBEXECDIR "/mds-server"; +static const char *master_server = LIBEXECDIR "/mds-server"; /** * The umask the server start with @@ -66,167 +66,157 @@ static mode_t saved_umask; * @param argv_ Command line arguments * @return Non-zero on error */ -int main(int argc_, char** argv_) +int main(int argc_, char **argv_) { - int fd = -1; - int got_master_server = 0; - struct sockaddr_un address; - char pathname[PATH_MAX]; - char piddata[64]; - unsigned int display = DISPLAY_MAX; - FILE* f; - int rc; - int j, r; - - - argc = argc_; - argv = argv_; - - - /* Sanity check the number of command line arguments. */ - exit_if (argc > ARGC_LIMIT, - eprint("that number of arguments is ridiculous, I will not allow it.");); - - /* Parse command line arguments. */ - for (j = 1; j < argc; j++) - { - char* arg = argv[j]; - if (startswith(arg, "--master-server=")) /* Master server. */ - { - exit_if (got_master_server, - eprintf("duplicate declaration of %s.", "--master-server");); - got_master_server = 1; - master_server = arg + strlen("--master-server="); + int fd = -1; + int got_master_server = 0; + struct sockaddr_un address; + char pathname[PATH_MAX]; + char piddata[64]; + unsigned int display = DISPLAY_MAX; + FILE *f; + int rc; + int j, r; + char *arg; + + argc = argc_; + argv = argv_; + + /* Sanity check the number of command line arguments. */ + exit_if (argc > ARGC_LIMIT, + eprint("that number of arguments is ridiculous, I will not allow it.");); + + /* Parse command line arguments. */ + for (j = 1; j < argc; j++) { + arg = argv[j]; + if (startswith(arg, "--master-server=")) { /* Master server. */ + exit_if (got_master_server, + eprintf("duplicate declaration of %s.", "--master-server");); + got_master_server = 1; + master_server = arg + strlen("--master-server="); + } } - } - - /* Stymied if the effective user is not root. */ - exit_if (geteuid() != ROOT_USER_UID, - eprint("the effective user is not root, cannot continue.");); - - /* Set up to ignore SIGUPDATE, used in mds for re-exec, but we cannot re-exec. */ - if (xsigaction(SIGUPDATE, SIG_IGN) < 0) - xperror(*argv); - - /* Set up to ignore SIGDANGER. */ - if (xsigaction(SIGDANGER, SIG_IGN) < 0) - xperror(*argv); - - /* Set up to ignore SIGINFO. */ - if (xsigaction(SIGINFO, SIG_IGN) < 0) - xperror(*argv); - - /* Remove umask. */ - saved_umask = umask(0); - - /* Create directory for socket files, PID files and such. */ - fail_if (create_directory_root(MDS_RUNTIME_ROOT_DIRECTORY)); - - - /* Determine display index. */ - for (display = 0; display < DISPLAY_MAX; display++) - { - xsnprintf(pathname, "%s/%u.pid", MDS_RUNTIME_ROOT_DIRECTORY, display); - - fd = open(pathname, O_CREAT | O_EXCL, 0644); - if (fd == -1) - { - /* Reuse display index if no longer used. */ - f = fopen(pathname, "r"); - if (f == NULL) /* Race, or error? */ - { - xperror(*argv); - continue; - } - r = is_pid_file_reusable(f); - xfclose(f); - if (r == 0) - continue; + + /* Stymied if the effective user is not root. */ + exit_if (geteuid() != ROOT_USER_UID, + eprint("the effective user is not root, cannot continue.");); + + /* Set up to ignore SIGUPDATE, used in mds for re-exec, but we cannot re-exec. */ + if (xsigaction(SIGUPDATE, SIG_IGN) < 0) + xperror(*argv); + + /* Set up to ignore SIGDANGER. */ + if (xsigaction(SIGDANGER, SIG_IGN) < 0) + xperror(*argv); + + /* Set up to ignore SIGINFO. */ + if (xsigaction(SIGINFO, SIG_IGN) < 0) + xperror(*argv); + + /* Remove umask. */ + saved_umask = umask(0); + + /* Create directory for socket files, PID files and such. */ + fail_if (create_directory_root(MDS_RUNTIME_ROOT_DIRECTORY)); + + /* Determine display index. */ + for (display = 0; display < DISPLAY_MAX; display++) { + xsnprintf(pathname, "%s/%u.pid", MDS_RUNTIME_ROOT_DIRECTORY, display); + + fd = open(pathname, O_CREAT | O_EXCL, 0644); + if (fd < 0) { + /* Reuse display index if no longer used. */ + f = fopen(pathname, "r"); + if (!f) { /* Race, or error? */ + xperror(*argv); + continue; + } + r = is_pid_file_reusable(f); + xfclose(f); + if (!r) + continue; + } + xclose(fd); + break; + } + exit_if (display == DISPLAY_MAX, + eprint("sorry, too many displays on the system.");); + /* Yes, the directory could have been removed, but it probably was not. */ + + /* Create PID file. */ + fail_if (!(f = fopen(pathname, "w"))); + xsnprintf(piddata, "%u\n", getpid()); + if (fwrite(piddata, 1, strlen(piddata), f) < strlen(piddata)) { + xfclose(f); + fail_if (1); + } + fflush(f); + xfclose(f); + if (chmod(pathname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) + xperror(*argv); + + /* Create data storage directory. */ + xsnprintf(pathname, "%s/%u.data", MDS_STORAGE_ROOT_DIRECTORY, display); + fail_if (create_directory_root(MDS_STORAGE_ROOT_DIRECTORY)); + fail_if (unlink_recursive(pathname)); + fail_if (create_directory_user(pathname)); + + /* Save MDS_DISPLAY environment variable. */ + xsnprintf(pathname, /* Excuse the reuse without renaming. */ + ":%u", display); + fail_if (setenv(DISPLAY_ENV, pathname, 1) < 0); + + /* Create a new process group and export MDS_PGROUP */ + fail_if (setpgid(0, 0) < 0); + xsnprintf(pathname, /* Excuse the reuse without renaming. */ + "%ji", (intmax_t)getpgrp()); + fail_if (setenv(PGROUP_ENV, pathname, 1) < 0); + + /* Create display socket. */ + xsnprintf(pathname, "%s/%u.socket", MDS_RUNTIME_ROOT_DIRECTORY, display); + address.sun_family = AF_UNIX; + if (strlen(pathname) >= sizeof(address.sun_path)) + fail_if ((errno = ENAMETOOLONG)); + strcpy(address.sun_path, pathname); + unlink(pathname); + fail_if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0); + fail_if (fchmod(fd, S_IRWXU) < 0); + fail_if (fchown(fd, getuid(), NOBODY_GROUP_GID) < 0); + fail_if (bind(fd, (struct sockaddr*)(&address), sizeof(address)) < 0); + + /* Start listening on socket. */ + fail_if (listen(fd, SOMAXCONN) < 0); + + /* Start master server and respawn it if it crashes. */ + rc = spawn_and_respawn_server(fd); + +done: + /* Shutdown, close and remove the socket. */ + if (fd >= 0) { + shutdown(fd, SHUT_RDWR); + xclose(fd); + unlink(pathname); } - xclose(fd); - break; - } - exit_if (display == DISPLAY_MAX, - eprint("sorry, too many displays on the system.");); - /* Yes, the directory could have been removed, but it probably was not. */ - - /* Create PID file. */ - fail_if (f = fopen(pathname, "w"), f == NULL); - xsnprintf(piddata, "%u\n", getpid()); - if (fwrite(piddata, 1, strlen(piddata), f) < strlen(piddata)) - { - xfclose(f); - fail_if (1); - } - fflush(f); - xfclose(f); - if (chmod(pathname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) - xperror(*argv); - - /* Create data storage directory. */ - xsnprintf(pathname, "%s/%u.data", MDS_STORAGE_ROOT_DIRECTORY, display); - fail_if (create_directory_root(MDS_STORAGE_ROOT_DIRECTORY)); - fail_if (unlink_recursive(pathname)); - fail_if (create_directory_user(pathname)); - - - /* Save MDS_DISPLAY environment variable. */ - xsnprintf(pathname, /* Excuse the reuse without renaming. */ - ":%u", display); - fail_if (setenv(DISPLAY_ENV, pathname, 1) < 0); - - /* Create a new process group and export MDS_PGROUP */ - fail_if (setpgid(0, 0) < 0); - xsnprintf(pathname, /* Excuse the reuse without renaming. */ - "%ji", (intmax_t)getpgrp()); - fail_if (setenv(PGROUP_ENV, pathname, 1) < 0); - - /* Create display socket. */ - xsnprintf(pathname, "%s/%u.socket", MDS_RUNTIME_ROOT_DIRECTORY, display); - address.sun_family = AF_UNIX; - if (strlen(pathname) >= sizeof(address.sun_path)) - fail_if ((errno = ENAMETOOLONG)); - strcpy(address.sun_path, pathname); - unlink(pathname); - fail_if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0); - fail_if (fchmod(fd, S_IRWXU) < 0); - fail_if (fchown(fd, getuid(), NOBODY_GROUP_GID) < 0); - fail_if (bind(fd, (struct sockaddr*)(&address), sizeof(address)) < 0); - - /* Start listening on socket. */ - fail_if (listen(fd, SOMAXCONN) < 0); - - /* Start master server and respawn it if it crashes. */ - rc = spawn_and_respawn_server(fd); - - done: - /* Shutdown, close and remove the socket. */ - if (fd != -1) - { - shutdown(fd, SHUT_RDWR); - xclose(fd); - unlink(pathname); - } - - if (display == DISPLAY_MAX) - return rc; - - /* Remove PID file. */ - xsnprintf(pathname, "%s/%u.pid", MDS_RUNTIME_ROOT_DIRECTORY, display); - unlink(pathname); - - /* Remove directories. */ - rmdir(MDS_RUNTIME_ROOT_DIRECTORY); /* Do not care if it fails, it is probably used by another display. */ - rmdir(MDS_STORAGE_ROOT_DIRECTORY); /* Do not care if it fails, it is probably used by another display. */ - xsnprintf(pathname, "%s/%u.data", MDS_STORAGE_ROOT_DIRECTORY, display); - unlink_recursive(pathname); /* An error will be printed on error, do nothing more. */ - - return rc; - - fail: - xperror(*argv); - rc = 1; - goto done; + + if (display == DISPLAY_MAX) + return rc; + + /* Remove PID file. */ + xsnprintf(pathname, "%s/%u.pid", MDS_RUNTIME_ROOT_DIRECTORY, display); + unlink(pathname); + + /* Remove directories. */ + rmdir(MDS_RUNTIME_ROOT_DIRECTORY); /* Do not care if it fails, it is probably used by another display. */ + rmdir(MDS_STORAGE_ROOT_DIRECTORY); /* Do not care if it fails, it is probably used by another display. */ + xsnprintf(pathname, "%s/%u.data", MDS_STORAGE_ROOT_DIRECTORY, display); + unlink_recursive(pathname); /* An error will be printed on error, do nothing more. */ + + return rc; + +fail: + xperror(*argv); + rc = 1; + goto done; } @@ -236,29 +226,29 @@ int main(int argc_, char** argv_) * @param f The PID-file * @return Whether the PID-file is not longer used */ -int is_pid_file_reusable(FILE* f) +int +is_pid_file_reusable(FILE *f) { - char piddata[64]; - size_t read_len; - - read_len = fread(piddata, 1, sizeof(piddata) / sizeof(char), f); - fail_if (ferror(f)); /* Failed to read. */ - if (feof(f) == 0) /* Did not read everything. */ - eprint("the content of a PID file is larger than expected."); - else - { - pid_t pid = parse_pid_t(piddata, read_len - 1); - if (pid == (pid_t)-1) - eprint("the content of a PID file is invalid."); - else - if (kill(pid, 0) < 0) /* Check if the PID is still allocated to any process. */ - return errno == ESRCH; /* PID is not used. */ - } - - return 0; - fail: - xperror(*argv); - return 0; + char piddata[64]; + size_t read_len; + pid_t pid; + + read_len = fread(piddata, 1, sizeof(piddata) / sizeof(char), f); + fail_if (ferror(f)); /* Failed to read. */ + if (!feof(f)) { /* Did not read everything. */ + eprint("the content of a PID file is larger than expected."); + } else { + pid = parse_pid_t(piddata, read_len - 1); + if (pid == (pid_t)-1) + eprint("the content of a PID file is invalid."); + else if (kill(pid, 0) < 0) /* Check if the PID is still allocated to any process. */ + return errno == ESRCH; /* PID is not used. */ + } + + return 0; +fail: + xperror(*argv); + return 0; } @@ -269,24 +259,25 @@ int is_pid_file_reusable(FILE* f) * @param n The length of the string, excluding LF-termination * @return The pid, `(pid_t)-1` if malformated */ -pid_t parse_pid_t(const char* str, size_t n) +pid_t +parse_pid_t(const char *str, size_t n) { - pid_t pid = 0; - size_t i; - - for (i = 0; i < n; i++) - { - char c = str[i]; - if (('0' <= c) && (c <= '9')) - pid = pid * 10 + (c & 15); - else - return (pid_t)-1; - } - - if (str[n] != '\n') - return (pid_t)-1; - - return pid; + pid_t pid = 0; + size_t i; + char c; + + for (i = 0; i < n; i++) { + c = str[i]; + if ('0' <= c && c <= '9') + pid = pid * 10 + (c & 15); + else + return (pid_t)-1; + } + + if (str[n] != '\n') + return (pid_t)-1; + + return pid; } @@ -297,18 +288,18 @@ pid_t parse_pid_t(const char* str, size_t n) * * @param child_args Command line arguments for the new image */ -__attribute__((nonnull)) -static void exec_master_server(char** child_args) +static void __attribute__((nonnull)) +exec_master_server(char **child_args) { - /* Drop privileges. They most not be propagated non-authorised components. */ - /* setgid should not be set, but just to be safe we are restoring both user and group. */ - fail_if (drop_privileges()); - - /* Start master server. */ - execv(master_server, child_args); - fail_if (1); - fail: - return; + /* Drop privileges. They most not be propagated non-authorised components. */ + /* setgid should not be set, but just to be safe we are restoring both user and group. */ + fail_if (drop_privileges()); + + /* Start master server. */ + execv(master_server, child_args); + fail_if (1); +fail: + return; } @@ -318,113 +309,105 @@ static void exec_master_server(char** child_args) * @param fd The file descriptor of the socket * @return Non-zero on error */ -int spawn_and_respawn_server(int fd) +int +spawn_and_respawn_server(int fd) { - int time_error = 0; - int first_spawn = 1; - int rc = 0; - struct timespec time_start; - struct timespec time_end; - char* child_args[ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT + 1]; - char fdstr[(sizeof("--socket-fd=") / sizeof(char) - 1) + 64]; - int i; - pid_t pid; - int status; - - fail_if (xstrdup(child_args[0], master_server)); - for (i = 1; i < argc; i++) - child_args[i] = argv[i]; - fail_if (xstrdup(child_args[argc + 0], "--initial-spawn")); - xsnprintf(fdstr, "--socket-fd=%i", fd); - child_args[argc + 1] = fdstr; - child_args[argc + 2] = NULL; - + int time_error = 0; + int first_spawn = 1; + int rc = 0; + struct timespec time_start; + struct timespec time_end; + char *child_args[ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT + 1]; + char fdstr[(sizeof("--socket-fd=") / sizeof(char) - 1) + 64]; + int i; + pid_t pid; + int status; + + fail_if (xstrdup(child_args[0], master_server)); + for (i = 1; i < argc; i++) + child_args[i] = argv[i]; + fail_if (xstrdup(child_args[argc + 0], "--initial-spawn")); + xsnprintf(fdstr, "--socket-fd=%i", fd); + child_args[argc + 1] = fdstr; + child_args[argc + 2] = NULL; + #if (LIBEXEC_ARGC_EXTRA_LIMIT < 2) # error LIBEXEC_ARGC_EXTRA_LIMIT is too small, need at least 2. #endif - - - respawn: - - pid = fork(); - fail_if (pid == (pid_t)-1); - - if (pid == 0) /* Child. */ - { - /* If this image exits, it should do so with failure status. */ - rc++; - /* Reinstate original umask. */ - umask(saved_umask); - /* Change image into the master server. */ - exec_master_server(child_args); - fail_if (1); - } - - - /* Parent. */ - - /* Get the current time. (Start of child process.) */ - if ((time_error = (monotone(&time_start) < 0))) - xperror(*argv); - - /* Wait for master server to die. */ - fail_if (uninterruptable_waitpid(pid, &status, 0) == (pid_t)-1); - - /* If the server exited normally or SIGTERM, do not respawn. */ - if (WIFEXITED(status) ? (WEXITSTATUS(status) == 0) : - ((WTERMSIG(status) == SIGTERM) || (WTERMSIG(status) == SIGINT))) - { - /* Child exited normally, stop. */ - rc--; - goto done; - } - - /* Get the current time. (End of child process.) */ - time_error |= (monotone(&time_end) < 0); - - if (WIFEXITED(status)) - eprintf("`%s' exited with code %i.", master_server, WEXITSTATUS(status)); - else - eprintf("`%s' died by signal %i.", master_server, WTERMSIG(status)); - - /* Do not respawn if we could not read the time. */ - if (time_error) - { - xperror(*argv); - eprintf("`%s' died abnormally, not respawning because we could not read the time.", master_server); - goto done; - } - - /* Respawn if the server did not die too fast. */ - if (time_end.tv_sec - time_start.tv_sec >= RESPAWN_TIME_LIMIT_SECONDS) - eprintf("`%s' died abnormally, respawning.", master_server); - else - { - eprintf("`%s' died abnormally, died too fast, not respawning.", master_server); - goto done; - } - - if (first_spawn) - { - first_spawn = 0; - free(child_args[argc + 0]); - fail_if (xstrdup(child_args[argc + 0], "--respawn")); - } - - goto respawn; - - - done: - rc++; - free(child_args[0]); - free(child_args[argc + 0]); - if (rc == 2) - _exit(1); - return rc; - - fail: - xperror(*argv); - goto done; + +respawn: + pid = fork(); + fail_if (pid == (pid_t)-1); + + if (!pid) { /* Child. */ + /* If this image exits, it should do so with failure status. */ + rc++; + /* Reinstate original umask. */ + umask(saved_umask); + /* Change image into the master server. */ + exec_master_server(child_args); + fail_if (1); + } + + /* Parent. */ + + /* Get the current time. (Start of child process.) */ + if ((time_error = (monotone(&time_start) < 0))) + xperror(*argv); + + /* Wait for master server to die. */ + fail_if (uninterruptable_waitpid(pid, &status, 0) == (pid_t)-1); + + /* If the server exited normally or SIGTERM, do not respawn. */ + if (WIFEXITED(status) ? !WEXITSTATUS(status) : + (WTERMSIG(status) == SIGTERM || WTERMSIG(status) == SIGINT)) { + /* Child exited normally, stop. */ + rc--; + goto done; + } + + /* Get the current time. (End of child process.) */ + time_error |= (monotone(&time_end) < 0); + + if (WIFEXITED(status)) + eprintf("`%s' exited with code %i.", master_server, WEXITSTATUS(status)); + else + eprintf("`%s' died by signal %i.", master_server, WTERMSIG(status)); + + /* Do not respawn if we could not read the time. */ + if (time_error) { + xperror(*argv); + eprintf("`%s' died abnormally, not respawning because we could not read the time.", master_server); + goto done; + } + + /* Respawn if the server did not die too fast. */ + if (time_end.tv_sec - time_start.tv_sec >= RESPAWN_TIME_LIMIT_SECONDS) { + eprintf("`%s' died abnormally, respawning.", master_server); + } else { + eprintf("`%s' died abnormally, died too fast, not respawning.", master_server); + goto done; + } + + if (first_spawn) { + first_spawn = 0; + free(child_args[argc + 0]); + fail_if (xstrdup(child_args[argc + 0], "--respawn")); + } + + goto respawn; + +done: + rc++; + free(child_args[0]); + free(child_args[argc + 0]); + if (rc == 2) + _exit(1); + return rc; + +fail: + xperror(*argv); + goto done; } @@ -434,33 +417,32 @@ int spawn_and_respawn_server(int fd) * @param pathname The pathname of the directory to create * @return Non-zero on error */ -int create_directory_root(const char* pathname) +int +create_directory_root(const char *pathname) { - struct stat attr; - - if (stat(pathname, &attr) == 0) - { - /* Cannot create the directory, its pathname refers to an existing. */ - if (S_ISDIR(attr.st_mode) == 0) - { - /* But it is not a directory so we cannot continue. */ - eprintf("%s already exists but is not a directory.", pathname); - return 1; + struct stat attr; + + if (!stat(pathname, &attr)) { + /* Cannot create the directory, its pathname refers to an existing. */ + if (!S_ISDIR(attr.st_mode)) { + /* But it is not a directory so we cannot continue. */ + eprintf("%s already exists but is not a directory.", pathname); + return 1; + } + } else { + /* Directory is missing, create it. */ + if (mkdir(pathname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + /* Unlikely race condition. */ + fail_if (errno != EEXIST); + else + /* Set ownership. */ + fail_if (chown(pathname, ROOT_USER_UID, ROOT_GROUP_GID) < 0); } - } - else - /* Directory is missing, create it. */ - if (mkdir(pathname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) - /* Unlikely race condition. */ - fail_if (errno != EEXIST); - else - /* Set ownership. */ - fail_if (chown(pathname, ROOT_USER_UID, ROOT_GROUP_GID) < 0); - - return 0; - fail: - xperror(*argv); - return 1; + + return 0; +fail: + xperror(*argv); + return 1; } @@ -470,33 +452,32 @@ int create_directory_root(const char* pathname) * @param pathname The pathname of the directory to create * @return Non-zero on error */ -int create_directory_user(const char* pathname) +int +create_directory_user(const char *pathname) { - struct stat attr; - - if (stat(pathname, &attr) == 0) - { - /* Cannot create the directory, its pathname refers to an existing. */ - if (S_ISDIR(attr.st_mode) == 0) - { - /* But it is not a directory so we cannot continue. */ - eprintf("%s already exists but is not a directory.", pathname); - return 1; + struct stat attr; + + if (!stat(pathname, &attr)) { + /* Cannot create the directory, its pathname refers to an existing. */ + if (!S_ISDIR(attr.st_mode)) { + /* But it is not a directory so we cannot continue. */ + eprintf("%s already exists but is not a directory.", pathname); + return 1; + } + } else { + /* Directory is missing, create it. */ + if (mkdir(pathname, S_IRWXU) < 0) + /* Unlikely race condition. */ + fail_if (errno != EEXIST); + else + /* Set ownership. */ + fail_if (chown(pathname, getuid(), NOBODY_GROUP_GID) < 0); } - } - else - /* Directory is missing, create it. */ - if (mkdir(pathname, S_IRWXU) < 0) - /* Unlikely race condition. */ - fail_if (errno != EEXIST); - else - /* Set ownership. */ - fail_if (chown(pathname, getuid(), NOBODY_GROUP_GID) < 0); - - return 0; - fail: - xperror(*argv); - return 1; + + return 0; +fail: + xperror(*argv); + return 1; } @@ -506,45 +487,44 @@ int create_directory_user(const char* pathname) * @param pathname The pathname of the directory to remove * @return Non-zero on error, but zero if the directory does not exist */ -int unlink_recursive(const char* pathname) +int +unlink_recursive(const char *pathname) { - DIR* dir = opendir(pathname); - int rc = 0; - struct dirent* file; - - /* Check that we could examine the directory. */ - if (dir == NULL) - { - int saved_errno = errno; - struct stat _attr; - if (stat(pathname, &_attr) < 0) - return 0; /* Directory does not exist. */ - errno = saved_errno; - fail_if (1); - } - - /* Remove the content of the directory. */ - while ((file = readdir(dir)) != NULL) - if (strcmp(file->d_name, ".") && - strcmp(file->d_name, "..") && - (unlink(file->d_name) < 0)) - { - fail_if (errno != EISDIR); - unlink_recursive(file->d_name); - } - - /* Remove the drectory. */ - fail_if (rmdir(pathname) < 0); - - done: - if (dir != NULL) - closedir(dir); - return rc; - - - fail: - xperror(*argv); - rc = -1; - goto done; -} + DIR *dir = opendir(pathname); + int rc = 0; + struct dirent *file; + int saved_errno; + struct stat _attr; + + /* Check that we could examine the directory. */ + if (!dir) { + saved_errno = errno; + if (stat(pathname, &_attr) < 0) + return 0; /* Directory does not exist. */ + errno = saved_errno; + fail_if (1); + } + + /* Remove the content of the directory. */ + while ((file = readdir(dir))) { + if (strcmp(file->d_name, ".") && + strcmp(file->d_name, "..") && + (unlink(file->d_name) < 0)) { + fail_if (errno != EISDIR); + unlink_recursive(file->d_name); + } + } + + /* Remove the drectory. */ + fail_if (rmdir(pathname) < 0); +done: + if (dir) + closedir(dir); + return rc; + +fail: + xperror(*argv); + rc = -1; + goto done; +} @@ -30,7 +30,7 @@ * @return Whether the PID-file is not longer used */ __attribute__((nonnull)) -int is_pid_file_reusable(FILE* f); +int is_pid_file_reusable(FILE *f); /** * Parse an LF-terminated string as a non-negative `pid_t` @@ -40,7 +40,7 @@ int is_pid_file_reusable(FILE* f); * @return The pid, `(pid_t)-1` if malformated */ __attribute__((pure, nonnull)) -pid_t parse_pid_t(const char* str, size_t n); +pid_t parse_pid_t(const char *str, size_t n); /** * Start master server and respawn it if it crashes |