mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Add another function to parse the common address:port combination formats into a sockaddr.
svn:r984
This commit is contained in:
parent
0d9d5cfe22
commit
cfbd168008
92
evutil.c
92
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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user