summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--include/apr_lib.h3
-rw-r--r--strings/apr_snprintf.c34
3 files changed, 31 insertions, 9 deletions
diff --git a/CHANGES b/CHANGES
index 4696cc225..ab285e3ac 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,8 @@
Changes with APR b1
+ *) apr_snprintf()'s %pI format string now takes apr_sockaddr_t *
+ instead of sockaddr_in *. [Jeff Trawick]
+
*) Fix a bug in apr_accept() for Win32 and Unix where the local
apr_sockaddr_t in the new connected socket was not initialized
properly. This could result in a bad string for apr_get_ipaddr(),
diff --git a/include/apr_lib.h b/include/apr_lib.h
index 9b216fdc8..dc35ac028 100644
--- a/include/apr_lib.h
+++ b/include/apr_lib.h
@@ -157,7 +157,8 @@ APR_DECLARE(const char *) apr_filename_of_pathname(const char *pathname);
* The extensions are:
*
* %pA takes a struct in_addr *, and prints it as a.b.c.d
- * %pI takes a struct sockaddr_in * and prints it as a.b.c.d:port
+ * %pI takes an apr_sockaddr_t * and prints it as a.b.c.d:port or
+ * [ipv6-address]:port
* %pp takes a void * and outputs it in hex
*
* The %p hacks are to force gcc's printf warning code to skip
diff --git a/strings/apr_snprintf.c b/strings/apr_snprintf.c
index f525a79a0..0f21c6d6b 100644
--- a/strings/apr_snprintf.c
+++ b/strings/apr_snprintf.c
@@ -60,6 +60,7 @@
#include "apr_private.h"
#include "apr_lib.h"
+#include "apr_network_io.h"
#include <math.h>
#ifdef HAVE_CTYPE_H
#include <ctype.h>
@@ -488,15 +489,32 @@ static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len)
-static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
+static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, int *len)
{
char *p = buf_end;
bool_int is_negative;
int sub_len;
+ char *ipaddr_str;
- p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len);
+ /* XXX IPv6: this assumes sin_port and sin6_port are at same offset */
+ p = conv_10(ntohs(sa->sa.sin.sin_port), TRUE, &is_negative, p, &sub_len);
*--p = ':';
- p = conv_in_addr(&si->sin_addr, p, &sub_len);
+ apr_get_ipaddr(&ipaddr_str, sa);
+ sub_len = strlen(ipaddr_str);
+#if APR_HAVE_IPV6
+ if (sa->sa.sin.sin_family == APR_INET6 &&
+ !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) {
+ *(p - 1) = ']';
+ p -= sub_len + 2;
+ *p = '[';
+ memcpy(p + 1, ipaddr_str, sub_len);
+ }
+ else
+#endif
+ {
+ p -= sub_len;
+ memcpy(p, ipaddr_str, sub_len);
+ }
*len = buf_end - p;
return (p);
@@ -1038,14 +1056,14 @@ APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *),
pad_char = ' ';
break;
- /* print a struct sockaddr_in as a.b.c.d:port */
+ /* print an apr_sockaddr_t as a.b.c.d:port */
case 'I':
{
- struct sockaddr_in *si;
+ apr_sockaddr_t *sa;
- si = va_arg(ap, struct sockaddr_in *);
- if (si != NULL) {
- s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len);
+ sa = va_arg(ap, apr_sockaddr_t *);
+ if (sa != NULL) {
+ s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len);
if (adjust_precision && precision < s_len)
s_len = precision;
}