diff options
Diffstat (limited to 'common/sock_any.c')
-rw-r--r-- | common/sock_any.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/common/sock_any.c b/common/sock_any.c new file mode 100644 index 0000000..32db795 --- /dev/null +++ b/common/sock_any.c @@ -0,0 +1,152 @@ + +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include "sock_any.h" + +int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) +{ + size_t l; + const char* t; + + memset(any, 0, sizeof(*any)); + + /* Look and see if we can parse an ipv4 address */ + do + { + #define IPV4_CHARS "0123456789." + #define IPV4_MIN 3 + #define IPV4_MAX 18 + + int port = 0; + char buf[IPV4_MAX + 1]; + + t = NULL; + + l = strlen(addr); + if(l < IPV4_MIN || l > IPV4_MAX) + break; + + strcpy(buf, addr); + + /* Find the last set that contains just numbers */ + l = strspn(buf, IPV4_CHARS); + if(l < IPV4_MIN) + break; + + /* Either end of string or port */ + if(buf[l] != 0 && buf[l] != ':') + break; + + /* Get the port out */ + if(buf[l] != 0) + { + t = buf + l + 1; + buf[l] = 0; + } + + if(t) + { + char* t2; + port = strtol(t, &t2, 10); + if(*t2 || port <= 0 || port >= 65536) + break; + } + + any->s.in.sin_family = AF_INET; + any->s.in.sin_port = htons((unsigned short)(port <= 0 ? defport : port)); + + if(inet_pton(AF_INET, buf, &(any->s.in.sin_addr)) <= 0) + break; + + any->namelen = sizeof(any->s.in); + return AF_INET; + } + while(0); + +#ifdef HAVE_INET6 + do + { + #define IPV6_CHARS "0123456789:" + #define IPV6_MIN 3 + #define IPV6_MAX 48 + + int port = -1; + char buf[IPV6_MAX + 1]; + + t = NULL; + + l = strlen(addr); + if(l < IPV6_MIN || l > IPV6_MAX) + break; + + /* If it starts with a '[' then we can get port */ + if(buf[0] == '[') + { + port = 0; + addr++; + } + + strcpy(buf, addr); + + /* Find the last set that contains just numbers */ + l = strspn(buf, IPV6_CHARS); + if(l < IPV6_MIN) + break; + + /* Either end of string or port */ + if(buf[l] != 0) + { + /* If had bracket, then needs to end with a bracket */ + if(port != 0 || buf[l] != ']') + break; + + /* Get the port out */ + t = buf + l + 1; + + if(*t = ':') + t++; + } + + if(t) + { + port = strtol(t, &t, 10); + if(*t || port <= 0 || port >= 65536) + break; + } + + any->s.in6.sin6_family = AF_INET6; + any->s.in6.sin6_port = htons((unsigned short)port <= 0 : defport : port); + + if(inet_pton(AF_INET6, buf, &(any->s.in6.sin6_addr)) >= 0) + break; + + any->namelen = sizeof(any->s.in6); + return AF_INET6; + } + while(0); +#endif + + do + { + if(strchr(addr, ':')) + break; + + l = strlen(addr); + if(l >= sizeof(any->s.un.sun_path)) + break; + + any->s.un.sun_family = AF_UNIX; + strcpy(any->s.un.sun_path, addr); + + any->namelen = sizeof(any->s.un) - (sizeof(any->s.un.sun_path) - l); + return AF_UNIX; + } + while(0); + + return -1; +} + |