diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/buffer.c | 6 | ||||
-rw-r--r-- | common/sock_any.c | 152 | ||||
-rw-r--r-- | common/sock_any.h | 32 |
3 files changed, 188 insertions, 2 deletions
diff --git a/common/buffer.c b/common/buffer.c index 57d20e2..72f0b6c 100644 --- a/common/buffer.c +++ b/common/buffer.c @@ -214,13 +214,15 @@ int ha_bufreadline(int fd, ha_buffer_t* buf) return 0; /* Transient errors */ - else if(l == -1 && (errno == EINTR || errno == EAGAIN)) + else if(l == -1 && errno == EAGAIN) continue; /* Fatal errors */ else if(l == -1) { - ha_message(LOG_ERR, "couldn't read data"); + if(errno != EINTR) + ha_message(LOG_ERR, "couldn't read data"); + return 0; } } 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; +} + diff --git a/common/sock_any.h b/common/sock_any.h new file mode 100644 index 0000000..f281020 --- /dev/null +++ b/common/sock_any.h @@ -0,0 +1,32 @@ + +#ifndef __SOCK_ANY_H__ +#define __SOCK_ANY_H__ + +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> + +struct sockaddr_any +{ + size_t namelen; + union _sockaddr_any + { + /* The header */ + struct sockaddr a; + + /* The different types */ + struct sockaddr_un un; + struct sockaddr_in in; +#ifdef HAVE_INET6 + struct sockaddr_in6 in6; +#endif + } s; +}; + +#define SANY_ADDR(any) (&((any).s.a)) +#define SANY_LEN(any) ((any).namelen) +#define SANY_TYPE(any) ((any).s.a.sa_family) + +int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport); + +#endif /* __SOCK_ANY_H__ */ |