From 92a6194673aa19fe9db5f6f32ce95972700daf11 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Wed, 26 Aug 2015 02:17:12 +0200 Subject: libmdsclient: implement support for domain sockets 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 | 94 ++++++++++++++++++++++++++++++++++++++++++++-- src/libmdsclient/address.h | 5 ++- src/libmdsclient/comm.c | 15 ++++---- src/libmdsclient/comm.h | 16 ++++---- 4 files changed, 110 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/libmdsclient/address.c b/src/libmdsclient/address.c index 3a7aba3..0bb347a 100644 --- a/src/libmdsclient/address.c +++ b/src/libmdsclient/address.c @@ -17,9 +17,76 @@ */ #include "address.h" +#include +#include #include #include +#include +#include +#include +#include +#include + + + +/** + * Check whether a string is a radix-10 non-negative integer + * + * @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) +{ + for (; *str; str++) + if (('0' > *str) || (*str > '9')) + return 0; + return 1; +} + + +/** + * Set the socket adress, with the address family `AF_UNIX` + * + * @param out_address Output paramter for the socket address + * @param pathlen Pointer to a variable where the length of the pathname will be stored + * @param format Formatting string for the pathname (should end with "%zn") + * @param ... Formatting arguments for the pathname (should end with `pathlen`) + * @return Zero on success, -1 on error, `errno` + * will have been set accordinly on error + * + * @throws ENOMEM Out of memory. Possibly, the application hit the + * 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)) +{ + 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; +} /** @@ -30,17 +97,38 @@ * @return Zero on success, even if parsing failed, -1 on error, * `errno` will have been set accordinly on error * - * @throws ENOMEM Out of memory. Possibly, the application hit the - * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2). + * @throws ENOMEM Out of memory. Possibly, the application hit the + * 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_adress(const char* restrict display, libmds_display_address_t* restrict address) { + ssize_t pathlen; + address->domain = -1; address->type = -1; address->protocol = -1; address->address = NULL; address->address_len = 0; - return (void) display, 0; /* TODO */ + 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; + } + + return 0; } diff --git a/src/libmdsclient/address.h b/src/libmdsclient/address.h index b094772..88ad4d3 100644 --- a/src/libmdsclient/address.h +++ b/src/libmdsclient/address.h @@ -74,8 +74,9 @@ typedef struct libmds_display_address * @return Zero on success, even if parsing failed, -1 on error, * `errno` will have been set accordinly on error * - * @throws ENOMEM Out of memory. Possibly, the application hit the - * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2). + * @throws ENOMEM Out of memory. Possibly, the application hit the + * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2). + * @throws ENAMETOOLONG The filename of the target socket is too long */ __attribute__((nonnull)) int libmds_parse_display_adress(const char* restrict display, libmds_display_address_t* restrict address); diff --git a/src/libmdsclient/comm.c b/src/libmdsclient/comm.c index 11d03d4..a4c5fff 100644 --- a/src/libmdsclient/comm.c +++ b/src/libmdsclient/comm.c @@ -24,8 +24,6 @@ #include #include -#include - #define min(a, b) ((a) < (b) ? (a) : (b)) @@ -137,12 +135,13 @@ void libmds_connection_free(libmds_connection_t* restrict this) * otherwise, `errno` will have been set to describe * the error. * - * @throws EFAULT If the display server's address is not properly - * formatted, or specifies an unsupported protocol, - * `libmds_parse_display_adress` can be used to - * figure out what is wrong. - * @throws Any error specified for socket(2) - * @throws Any error specified for connect(2), except EINTR + * @throws EFAULT If the display server's address is not properly + * formatted, or specifies an unsupported protocol, + * `libmds_parse_display_adress` can be used to + * figure out what is wrong. + * @throws ENAMETOOLONG The filename of the target socket is too long + * @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) { diff --git a/src/libmdsclient/comm.h b/src/libmdsclient/comm.h index b868e77..94dcc7a 100644 --- a/src/libmdsclient/comm.h +++ b/src/libmdsclient/comm.h @@ -124,13 +124,15 @@ void libmds_connection_free(libmds_connection_t* restrict this); * otherwise, `errno` will have been set to describe * the error. * - * @throws EFAULT If the display server's address is not properly - * formatted, or specifies an unsupported protocol, - * `libmds_parse_display_adress` can be used to - * figure out what is wrong. - * @throws Any error specified for socket(2) - * @throws Any error specified for connect(2), except EINTR - */__attribute__((nonnull)) + * @throws EFAULT If the display server's address is not properly + * formatted, or specifies an unsupported protocol, + * `libmds_parse_display_adress` can be used to + * figure out what is wrong. + * @throws ENAMETOOLONG The filename of the target socket is too long + * @throws Any error specified for socket(2) + * @throws Any error specified for connect(2), except EINTR + */ +__attribute__((nonnull)) int libmds_connection_establish(libmds_connection_t* restrict this, const char** restrict display); /** -- cgit v1.2.3-70-g09d2