summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2000-12-07 18:10:27 +0000
committertrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2000-12-07 18:10:27 +0000
commitfdf52cdf29edf195b5e1147047868317b7e516f6 (patch)
tree0e14b4f874cf77b49b5a0c359c36a2583779f17c
parent7b15744516297c9169556f253314926a43719d91 (diff)
downloadlibapr-fdf52cdf29edf195b5e1147047868317b7e516f6.tar.gz
Add apr_parse_addr_port() for parsing the hostname:port portion of
URLs and similar strings. Somebody with VC++ 6.0 needs to update the .dsp file(s) to include inet_pton.c. The BeOS Makefile.in wasn't updated because I think BeOS uses the unix code now. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@60916 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES2
-rw-r--r--aprlib.def1
-rw-r--r--include/apr_network_io.h33
-rw-r--r--libapr.def1
-rw-r--r--network_io/os2/Makefile.in1
-rw-r--r--network_io/unix/sa_common.c102
6 files changed, 140 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 8afae6533..a27e309ff 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,6 @@
Changes with APR a9
+ *) Add apr_parse_addr_port() for parsing the hostname:port portion
+ of URLs and similar strings. [Jeff Trawick]
*) Add Win32 MMAP support [William Rowe]
diff --git a/aprlib.def b/aprlib.def
index 04efde19f..3ed3b2e1e 100644
--- a/aprlib.def
+++ b/aprlib.def
@@ -88,6 +88,7 @@ EXPORTS
apr_get_port
apr_set_port
apr_get_inaddr
+ apr_parse_addr_port
;
;
diff --git a/include/apr_network_io.h b/include/apr_network_io.h
index 6683f555d..219fbfbde 100644
--- a/include/apr_network_io.h
+++ b/include/apr_network_io.h
@@ -306,6 +306,39 @@ apr_status_t apr_getaddrinfo(apr_sockaddr_t **sa,
apr_pool_t *p);
/**
+ * Parse hostname/IP address with scope id and port.
+ *
+ * Any of the following strings are accepted:
+ * 8080 (just the port number)
+ * www.apache.org (just the hostname)
+ * www.apache.org:8080 (hostname and port number)
+ * [fe80::1]:80 (IPv6 numeric address string only)
+ * [fe80::1%eth0] (IPv6 numeric address string and scope id)
+ *
+ * Invalid strings:
+ * (empty string)
+ * [abc] (not valid IPv6 numeric address string)
+ * abc:65536 (invalid port number)
+ *
+ * @param addr The new buffer containing just the hostname. On output, *addr
+ * will be NULL if no hostname/IP address was specfied.
+ * @param scope_id The new buffer containing just the scope id. On output,
+ * *scope_id will be NULL if no scope id was specified.
+ * @param port The port number. On output, *port will be 0 if no port was
+ * specified.
+ * @param str The input string to be parsed.
+ * @param p The pool from which *addr and *scope_id are allocated.
+ * @tip If scope id shouldn't be allowed, check for scope_id != NULL in addition
+ * to checking the return code. If addr/hostname should be required, check
+ * for addr == NULL in addition to checking the return code.
+ */
+apr_status_t apr_parse_addr_port(char **addr,
+ char **scope_id,
+ apr_port_t *port,
+ const char *str,
+ apr_pool_t *p);
+
+/**
* Get name of the current machine
* @param buf A buffer to store the hostname in.
* @param len The maximum length of the hostname that can be stored in the
diff --git a/libapr.def b/libapr.def
index 04efde19f..3ed3b2e1e 100644
--- a/libapr.def
+++ b/libapr.def
@@ -88,6 +88,7 @@ EXPORTS
apr_get_port
apr_set_port
apr_get_inaddr
+ apr_parse_addr_port
;
;
diff --git a/network_io/os2/Makefile.in b/network_io/os2/Makefile.in
index f23522533..e5077ea8a 100644
--- a/network_io/os2/Makefile.in
+++ b/network_io/os2/Makefile.in
@@ -17,6 +17,7 @@ OBJS=poll.o \
sockopt.o \
sockaddr.o \
inet_ntop.o \
+ inet_pton.o \
os2calls.o
.c.o:
diff --git a/network_io/unix/sa_common.c b/network_io/unix/sa_common.c
index f282df03f..3c0fa0c57 100644
--- a/network_io/unix/sa_common.c
+++ b/network_io/unix/sa_common.c
@@ -65,6 +65,10 @@
#include "apr.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
apr_status_t apr_set_port(apr_sockaddr_t *sockaddr, apr_port_t port)
{
/* XXX IPv6: assumes sin_port and sin6_port at same offset */
@@ -178,6 +182,104 @@ apr_status_t apr_get_sockaddr(apr_sockaddr_t **sa, apr_interface_e which, apr_so
return APR_SUCCESS;
}
+apr_status_t apr_parse_addr_port(char **addr,
+ char **scope_id,
+ apr_port_t *port,
+ const char *str,
+ apr_pool_t *p)
+{
+ const char *ch, *lastchar;
+ int big_port;
+ apr_size_t addrlen;
+
+ *addr = NULL; /* assume not specified */
+ *scope_id = NULL; /* assume not specified */
+ *port = 0; /* assume not specified */
+
+ /* First handle the optional port number. That may be all that
+ * is specified in the string.
+ */
+ ch = lastchar = str + strlen(str) - 1;
+ while (ch >= str && apr_isdigit(*ch)) {
+ --ch;
+ }
+
+ if (ch < str) { /* Entire string is the port. */
+ big_port = atoi(str);
+ if (big_port < 1 || big_port > 65535) {
+ return APR_EINVAL;
+ }
+ *port = big_port;
+ return APR_SUCCESS;
+ }
+
+ if (*ch == ':' && ch < lastchar) { /* host and port number specified */
+ if (ch == str) { /* string starts with ':' -- bad */
+ return APR_EINVAL;
+ }
+ big_port = atoi(ch + 1);
+ if (big_port < 1 || big_port > 65535) {
+ return APR_EINVAL;
+ }
+ *port = big_port;
+ lastchar = ch - 1;
+ }
+
+ /* now handle the hostname */
+ addrlen = lastchar - str + 1;
+
+#if APR_HAVE_IPV6 /* XXX don't require this; would need to pass char[] for ipaddr and always define APR_INET6 */
+ if (*str == '[') {
+ const char *end_bracket = memchr(str, ']', addrlen);
+ struct in6_addr ipaddr;
+ const char *scope_delim;
+
+ if (!end_bracket || end_bracket != lastchar) {
+ *port = 0;
+ return APR_EINVAL;
+ }
+
+ /* handle scope id; this is the only context where it is allowed */
+ scope_delim = memchr(str, '%', addrlen);
+ if (scope_delim) {
+ if (scope_delim == end_bracket - 1) { /* '%' without scope identifier */
+ *port = 0;
+ return APR_EINVAL;
+ }
+ addrlen = scope_delim - str - 1;
+ *scope_id = apr_palloc(p, end_bracket - scope_delim);
+ memcpy(*scope_id, scope_delim + 1, end_bracket - scope_delim - 1);
+ (*scope_id)[end_bracket - scope_delim - 1] = '\0';
+ }
+ else {
+ addrlen = addrlen - 2; /* minus 2 for '[' and ']' */
+ }
+
+ *addr = apr_palloc(p, addrlen + 1);
+ memcpy(*addr,
+ str + 1,
+ addrlen);
+ (*addr)[addrlen] = '\0';
+ if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) {
+ *addr = NULL;
+ *scope_id = NULL;
+ *port = 0;
+ return APR_EINVAL;
+ }
+ }
+ else
+#endif
+ {
+ /* XXX If '%' is not a valid char in a DNS name, we *could* check
+ * for bogus scope ids first.
+ */
+ *addr = apr_palloc(p, addrlen + 1);
+ memcpy(*addr, str, addrlen);
+ (*addr)[addrlen] = '\0';
+ }
+ return APR_SUCCESS;
+}
+
apr_status_t apr_getaddrinfo(apr_sockaddr_t **sa, const char *hostname,
apr_int32_t family, apr_port_t port,
apr_int32_t flags, apr_pool_t *p)