summaryrefslogtreecommitdiff
path: root/common/sock_any.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/sock_any.c')
-rw-r--r--common/sock_any.c152
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;
+}
+