diff options
Diffstat (limited to 'src/libmdsclient/address.c')
-rw-r--r-- | src/libmdsclient/address.c | 297 |
1 files changed, 153 insertions, 144 deletions
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); +} |