From 9e8dec188d55ca1f0a3b33acab702ced8ed07a18 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 5 Nov 2017 00:09:50 +0100 Subject: Work on changing style, and an important typo fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/libmdsclient/address.c | 297 +++++----- src/libmdsclient/address.h | 91 ++- src/libmdsclient/comm.c | 261 ++++----- src/libmdsclient/comm.h | 112 ++-- src/libmdsclient/inbound.c | 1041 +++++++++++++++++------------------ src/libmdsclient/inbound.h | 335 ++++++----- src/libmdsclient/libmdsclient.pc.in | 1 - src/libmdsclient/proto-util.c | 713 ++++++++++++------------ src/libmdsclient/proto-util.h | 157 +++--- 9 files changed, 1504 insertions(+), 1504 deletions(-) (limited to 'src/libmdsclient') 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 -#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 . */ -static int verify_utf8(const char* string, int allow_modified_nul) +static int __attribute__((nonnull, warn_unused_result)) /* Cannibalised from . */ +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 - -- cgit v1.2.3-70-g09d2