From 57e8fdc408a34cd7ab13ea8148a7cf7789213fd3 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 19 Sep 2019 00:32:34 +0000 Subject: [PATCH] Feature: Implemented igloo_socketaddr_t --- src/libigloo.c | 2 + src/private.h | 2 + src/socketaddr.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) diff --git a/src/libigloo.c b/src/libigloo.c index 79f5a6a..828165f 100644 --- a/src/libigloo.c +++ b/src/libigloo.c @@ -72,6 +72,7 @@ static void igloo_initialize__free(igloo_ro_t self) return; igloo_resolver_shutdown(); + igloo_socketaddr_shutdown(); igloo_sock_shutdown(); igloo_thread_shutdown(); igloo_log_shutdown(); @@ -87,6 +88,7 @@ igloo_ro_t igloo_initialize(void) igloo_thread_initialize(); igloo_sock_initialize(); igloo_resolver_initialize(); + igloo_socketaddr_initialize(); } snprintf(name, sizeof(name), "", igloo_initialize__refc); diff --git a/src/private.h b/src/private.h index 7b312e2..65ca677 100644 --- a/src/private.h +++ b/src/private.h @@ -33,6 +33,8 @@ void igloo_sock_initialize(void); void igloo_sock_shutdown(void); void igloo_resolver_initialize(void); void igloo_resolver_shutdown(void); +void igloo_socketaddr_initialize(void); +void igloo_socketaddr_shutdown(void); void igloo_log_initialize(void); void igloo_log_shutdown(void); diff --git a/src/socketaddr.c b/src/socketaddr.c index 3575305..e1eb7f3 100644 --- a/src/socketaddr.c +++ b/src/socketaddr.c @@ -10,11 +10,47 @@ #include #endif +#include +#include + +#ifndef _WIN32 +#ifndef HAVE_INET_PTON +#include +#endif +#include +#include +#include +#include +#else +#include +#endif + #include #include +#include + +/* Shouldn't this be 40? Taken from the old sock.h -- ph3-der-loewe, 2019-09-19 */ +#define MAX_ADDR_LEN 46 + +#if !(defined(HAVE_GETNAMEINFO) && defined(HAVE_GETADDRINFO)) +static igloo_mutex_t igloo__resolver_mutex; +#endif + +#define SET_PORT 0x0001U struct igloo_socketaddr_tag { igloo_ro_base_t __base; + + igloo_socketaddr_domain_t domain; + igloo_socketaddr_type_t type; + igloo_socketaddr_protocol_t protocol; + + unsigned int set; + + char *node; + char *ip; + char *path; + uint16_t port; }; static void __free(igloo_ro_t self); @@ -26,4 +62,250 @@ igloo_RO_PUBLIC_TYPE(igloo_socketaddr_t, static void __free(igloo_ro_t self) { + igloo_socketaddr_t *addr = igloo_RO_TO_TYPE(self, igloo_socketaddr_t); + free(addr->node); + free(addr->ip); + free(addr->path); } + +void igloo_socketaddr_initialize(void) +{ +#if !(defined(HAVE_GETNAMEINFO) && defined(HAVE_GETADDRINFO)) + igloo_thread_mutex_create(&igloo__resolver_mutex); +#endif + + /* keep dns connects (TCP) open */ +#ifdef HAVE_SETHOSTENT + sethostent(1); +#endif +} + +void igloo_socketaddr_shutdown(void) +{ +#if !(defined(HAVE_GETNAMEINFO) && defined(HAVE_GETADDRINFO)) + igloo_thread_mutex_destroy(&igloo__resolver_mutex); +#endif + +#ifdef HAVE_ENDHOSTENT + endhostent(); +#endif +} + +static inline igloo_error_t _replace_string(char **rep, const char *str) +{ + char *val = NULL; + + if (str) { + val = strdup(str); + if (!val) + return igloo_ERROR_NOMEM; + } + + free(*rep); + *rep = val; + + return igloo_ERROR_NONE; +} + +#ifdef HAVE_INET_PTON +static inline int _is_ip(const char *what) +{ + union { + struct in_addr v4addr; + struct in6_addr v6addr; + } addr_u; + + if (inet_pton(AF_INET, what, &addr_u.v4addr) <= 0) + return inet_pton(AF_INET6, what, &addr_u.v6addr) > 0 ? 1 : 0; + + return 1; +} + +#else +static inline int _is_ip(const char *what) +{ + struct in_addr inp; + + return inet_aton(what, &inp); +} +#endif + +#if defined(HAVE_GETNAMEINFO) && defined(HAVE_GETADDRINFO) +static const char *_get_ip(const char *name, char *buff, size_t len) +{ + struct addrinfo *head, hints; + const char *ret = NULL; + + if (_is_ip(name)) { + strncpy(buff, name, len); + buff[len-1] = '\0'; + return buff; + } + + memset(&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(name, NULL, &hints, &head)) + return NULL; + + if (head) { + if (getnameinfo(head->ai_addr, head->ai_addrlen, buff, len, NULL, 0, NI_NUMERICHOST) == 0) + ret = buff; + freeaddrinfo(head); + } + + return ret; +} + +#else + +static const char *_get_ip(const char *name, char *buff, size_t len) +{ + struct hostent *host; + const char *ret = NULL; + + if (_is_ip(name)) { + strncpy(buff, name, len); + buff[len-1] = '\0'; + return buff; + } + + igloo_thread_mutex_lock(&igloo__resolver_mutex); + host = gethostbyname(name); + if (host) { + char *temp = inet_ntoa(*(struct in_addr *)host->h_addr); + ret = strncpy(buff, temp, len); + buff[len-1] = '\0'; + } + igloo_thread_mutex_unlock(&igloo__resolver_mutex); + + return ret; +} +#endif + +igloo_socketaddr_t * igloo_socketaddr_new(igloo_socketaddr_domain_t domain, igloo_socketaddr_type_t type, igloo_socketaddr_protocol_t protocol, const char *name, igloo_ro_t associated, igloo_ro_t instance) +{ + igloo_socketaddr_t *addr = igloo_ro_new_raw(igloo_socketaddr_t, name, associated, instance); + + if (!addr) + return NULL; + + addr->domain = domain; + addr->type = type; + addr->protocol = protocol; + + return addr; +} + +igloo_error_t igloo_socketaddr_get_base(igloo_socketaddr_t *addr, igloo_socketaddr_domain_t *domain, igloo_socketaddr_type_t *type, igloo_socketaddr_protocol_t *protocol) +{ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) + return igloo_ERROR_FAULT; + + if (domain) + *domain = addr->domain; + if (type) + *type = addr->type; + if (protocol) + *protocol = addr->protocol; + + return igloo_ERROR_NONE; +} + +igloo_error_t igloo_socketaddr_set_node(igloo_socketaddr_t *addr, const char *node) +{ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) + return igloo_ERROR_FAULT; + + if (addr->domain == igloo_SOCKETADDR_DOMAIN_UNIX) + return igloo_ERROR_GENERIC; + + if (!node) { + _replace_string(&(addr->node), NULL); + _replace_string(&(addr->ip), NULL); + return igloo_ERROR_NONE; + } + + if (_is_ip(node)) { + return _replace_string(&(addr->ip), node); + } else { + return _replace_string(&(addr->node), node); + } +} + +igloo_error_t igloo_socketaddr_get_ip(igloo_socketaddr_t *addr, const char **ip) +{ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) + return igloo_ERROR_FAULT; + + if (!addr->ip && addr->node) { + char ip[MAX_ADDR_LEN]; + _replace_string(&(addr->ip), _get_ip(addr->node, ip, sizeof(ip))); + } + + if (!addr->ip) + return igloo_ERROR_GENERIC; + + if (ip) + *ip = addr->ip; + + return igloo_ERROR_NONE; +} + +igloo_error_t igloo_socketaddr_set_port(igloo_socketaddr_t *addr, uint16_t port) +{ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) + return igloo_ERROR_FAULT; + + if (addr->domain == igloo_SOCKETADDR_DOMAIN_UNIX) + return igloo_ERROR_GENERIC; + + addr->port = port; + addr->set |= SET_PORT; + + return igloo_ERROR_NONE; +} + +igloo_error_t igloo_socketaddr_get_port(igloo_socketaddr_t *addr, uint16_t *port) +{ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) + return igloo_ERROR_FAULT; + + if (!(addr->set & SET_PORT)) + return igloo_ERROR_GENERIC; + + if (port) + *port = addr->port; + + return igloo_ERROR_NONE; +} + +igloo_error_t igloo_socketaddr_set_path(igloo_socketaddr_t *addr, const char *path) +{ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) + return igloo_ERROR_FAULT; + + if (addr->domain != igloo_SOCKETADDR_DOMAIN_UNIX) + return igloo_ERROR_GENERIC; + + return _replace_string(&(addr->path), path); +} + +#define _get_string(key) \ +igloo_error_t igloo_socketaddr_get_ ## key (igloo_socketaddr_t *addr, const char **key) \ +{ \ + if (!igloo_RO_IS_VALID(addr, igloo_socketaddr_t)) \ + return igloo_ERROR_FAULT; \ +\ + if (!addr->key) \ + return igloo_ERROR_GENERIC; \ +\ + if (key) \ + *key = addr->key; \ +\ + return igloo_ERROR_NONE; \ +} + +_get_string(node) +_get_string(path)