]> granicus.if.org Git - libevent/commitdiff
Add another function to parse the common address:port combination formats into a...
authorNick Mathewson <nickm@torproject.org>
Fri, 2 Jan 2009 20:46:26 +0000 (20:46 +0000)
committerNick Mathewson <nickm@torproject.org>
Fri, 2 Jan 2009 20:46:26 +0000 (20:46 +0000)
svn:r984

evutil.c
include/event2/util.h
test/regress_util.c

index bf161be230afad7adbdce4ad20a3289888662f26..553219237992a81279e7513d79a7f4dc7f1ec38f 100644 (file)
--- a/evutil.c
+++ b/evutil.c
@@ -567,3 +567,95 @@ evutil_inet_pton(int af, const char *src, void *dst)
        }
 #endif
 }
+
+int
+evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int outlen)
+{
+       int port;
+       char buf[128];
+       const char *cp, *addr_part, *port_part;
+       int is_ipv6;
+       /* recognized formats are:
+        * [ipv6]:port
+        * ipv6
+        * [ipv6]
+        * ipv4:port
+        * ipv4
+        */
+
+       cp = strchr(ip_as_string, ':');
+       if (*ip_as_string == '[') {
+               int len;
+               if (!(cp = strchr(ip_as_string, ']'))) {
+                       return -1;
+               }
+               len = cp-(ip_as_string + 1);
+               if (len > (int)sizeof(buf)-1) {
+                       return -1;
+               }
+               memcpy(buf, ip_as_string+1, len);
+               buf[len] = '\0';
+               addr_part = buf;
+               if (cp[1] == ':')
+                       port_part = cp+2;
+               else
+                       port_part = NULL;
+               is_ipv6 = 1;
+       } else if (cp && strchr(cp+1, ':')) {
+               is_ipv6 = 1;
+               addr_part = ip_as_string;
+               port_part = NULL;
+       } else if (cp) {
+               is_ipv6 = 0;
+               if (cp - ip_as_string > (int)sizeof(buf)-1) {
+                       return -1;
+               }
+               memcpy(buf, ip_as_string, cp-ip_as_string);
+               buf[cp-ip_as_string] = '\0';
+               addr_part = buf;
+               port_part = cp+1;
+       } else {
+               addr_part = ip_as_string;
+               port_part = NULL;
+               is_ipv6 = 0;
+       }
+
+       if (port_part == NULL) {
+               port = 0;
+       } else {
+               port = atoi(port_part);
+               if (port <= 0 || port > 65535) {
+                       return -1;
+               }
+       }
+
+       if (!addr_part)
+               return -1; /* Should be impossible. */
+       if (is_ipv6) {
+               struct sockaddr_in6 sin6;
+               memset(&sin6, 0, sizeof(sin6));
+               sin6.sin6_len = sizeof(sin6);
+               sin6.sin6_family = AF_INET6;
+               sin6.sin6_port = htons(port);
+               if (1 != evutil_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr))
+                       return -1;
+               if (sizeof(sin6) > outlen)
+                       return -1;
+               memset(out, 0, outlen);
+               memcpy(out, &sin6, sizeof(sin6));
+               return 0;
+       } else {
+               struct sockaddr_in sin;
+               memset(&sin, 0, sizeof(sin));
+               sin.sin_len = sizeof(sin);
+               sin.sin_family = AF_INET;
+               sin.sin_port = htons(port);
+               if (1 != evutil_inet_pton(AF_INET, addr_part, &sin.sin_addr))
+                       return -1;
+               if (sizeof(sin) > outlen)
+                       return -1;
+               memset(out, 0, outlen);
+               memcpy(out, &sin, sizeof(sin));
+               return 0;
+       }
+}
index ddbe689f825cf0568a0c9e48cf7b8712ee575e35..7735a157bf8418c19b7b513d26410517d0aae8d1 100644 (file)
@@ -215,6 +215,9 @@ int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
 
 const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len);
 int evutil_inet_pton(int af, const char *src, void *dst);
+struct sockaddr;
+int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int outlen);
+
 
 #ifdef __cplusplus
 }
index 5d9b459772fe4050196b669e38919e4ada77d5d9..990685b0c1379697237d13ec1ce1def0fd55ff04 100644 (file)
@@ -217,10 +217,87 @@ regress_ipv6_parse(void)
 #endif
 }
 
+static struct sa_port_ent {
+       const char *parse;
+       int sa_family;
+       const char *addr;
+       int port;
+} sa_port_ents[] = {
+       { "[ffff::1]:1000", AF_INET6, "ffff::1", 1000 },
+       { "[ffff::1]", AF_INET6, "ffff::1", 0 },
+       { "[ffff::1", 0, NULL, 0 },
+       { "::1", AF_INET6, "::1", 0 },
+       { "1:2::1", AF_INET6, "1:2::1", 0 },
+       { "192.168.0.1:50", AF_INET, "192.168.0.1", 50 },
+       { "1.2.3.4", AF_INET, "1.2.3.4", 0 },
+       { NULL, 0, NULL, 0 },
+};
+
+static void
+regress_sockaddr_port_parse(void)
+{
+       struct sockaddr_storage ss;
+       int ok = 1;
+       int i, r;
+
+       for (i = 0; sa_port_ents[i].parse; ++i) {
+               struct sa_port_ent *ent = &sa_port_ents[i];
+               memset(&ss, 0, sizeof(ss));
+               r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, sizeof(ss));
+               if (r < 0) {
+                       if (ent->sa_family) {
+                               printf("Couldn't parse %s!\n", ent->parse);
+                               ok = 0;
+                       }
+                       continue;
+               } else if (! ent->sa_family) {
+                       printf("Shouldn't have been able to parse %s!\n",
+                                  ent->parse);
+                       ok = 0;
+                       continue;
+               }
+               if (ent->sa_family == AF_INET) {
+                       struct sockaddr_in sin;
+                       memset(&sin, 0, sizeof(sin));
+                       sin.sin_len = sizeof(sin);
+                       sin.sin_family = AF_INET;
+                       sin.sin_port = htons(ent->port);
+                       r = evutil_inet_pton(AF_INET, ent->addr, &sin.sin_addr);
+                       if (1 != r) {
+                               printf("Couldn't parse ipv4 target %s.\n", ent->addr);
+                               ok = 0;
+                       } else if (memcmp(&sin, &ss, sizeof(sin))) {
+                               printf("Parse for %s was not as expected.\n", ent->parse);
+                               ok = 0;
+                       }
+               } else {
+                       struct sockaddr_in6 sin6;
+                       memset(&sin6, 0, sizeof(sin6));
+                       sin6.sin6_len = sizeof(sin6);
+                       sin6.sin6_family = AF_INET6;
+                       sin6.sin6_port = htons(ent->port);
+                       r = evutil_inet_pton(AF_INET6, ent->addr, &sin6.sin6_addr);
+                       if (1 != r) {
+                               printf("Couldn't parse ipv6 target %s.\n", ent->addr);
+                               ok = 0;
+                       } else if (memcmp(&sin6, &ss, sizeof(sin6))) {
+                               printf("Parse for %s was not as expected.\n", ent->parse);
+                               ok = 0;
+                       }
+               }
+       }
+
+       if (!ok) {
+               printf("FAILED\n");
+               exit(1);
+       }
+       printf("OK\n");
+}
 
 void
 util_suite(void)
 {
        regress_ipv4_parse();
        regress_ipv6_parse();
+       regress_sockaddr_port_parse();
 }