Applying IPv6 patch from Archana Shah <archana.shah@wipro.com>
closing bug #114837
* configure.in: Added checks for IPv6 support and getaddrinfo().
* acconfig.h: Defined HAVE_GETADDRINFO and SUPPORT_IP6.
* config.h.in: Defined HAVE_GETADDRINFO and SUPPORT_IP6.
* nanoftp.c: Structure xmlNanoFTPCtxt contains either sockaddr_storage
field or sockaddr_in field, depending upon the availability of IPv6
support.
have_ipv6(): Added to check for run-time IPv6 support.
(xmlNanoFTPScanURL), (xmlNanoFTPUpdateURL), (xmlNanoFTPScanProxy):
Modified to parse a URI with IPv6 address given in [].
(xmlNanoFTPConnect): Changed to use getaddrinfo for address
resolution, if it is available on the system, as gethostbyname
does not return IPv6 addresses on some platforms.
(xmlNanoFTPGetConnection): Modified type of dataAddr variable to
sockaddr_storage or sockaddr_in depending upon the IPv6 support.
Sending EPSV, EPRT or PASV, PORT depending upon the type of address
we are dealing with.
* nanohttp.c: (have_ipv6): Added to check for run-time IPv6 support.
(xmlNanoHTTPScanURL), (xmlNanoHTTPScanProxy): Modified to parse
a URI with IPv6 address given in [].
(xmlNanoHTTPConnectHost): Modified to use getaddrinfo if it is
available on the system. Also IPv6 addresses will be resolved by
gethostbyname only if IPv6 run-time support is available.
(xmlNanoHTTPConnectAttempt): Modified to deal with IPv6 address.
Daniel
diff --git a/ChangeLog b/ChangeLog
index aba71d0..6f769dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+Sat Jun 21 16:10:24 CEST 2003 Daniel Veillard <daniel@veillard.com>
+
+ Applying IPv6 patch from Archana Shah <archana.shah@wipro.com>
+ closing bug #114837
+
+ * configure.in: Added checks for IPv6 support and getaddrinfo().
+
+ * acconfig.h: Defined HAVE_GETADDRINFO and SUPPORT_IP6.
+
+ * config.h.in: Defined HAVE_GETADDRINFO and SUPPORT_IP6.
+
+ * nanoftp.c: Structure xmlNanoFTPCtxt contains either sockaddr_storage
+ field or sockaddr_in field, depending upon the availability of IPv6
+ support.
+ have_ipv6(): Added to check for run-time IPv6 support.
+ (xmlNanoFTPScanURL), (xmlNanoFTPUpdateURL), (xmlNanoFTPScanProxy):
+ Modified to parse a URI with IPv6 address given in [].
+ (xmlNanoFTPConnect): Changed to use getaddrinfo for address
+ resolution, if it is available on the system, as gethostbyname
+ does not return IPv6 addresses on some platforms.
+ (xmlNanoFTPGetConnection): Modified type of dataAddr variable to
+ sockaddr_storage or sockaddr_in depending upon the IPv6 support.
+ Sending EPSV, EPRT or PASV, PORT depending upon the type of address
+ we are dealing with.
+
+ * nanohttp.c: (have_ipv6): Added to check for run-time IPv6 support.
+ (xmlNanoHTTPScanURL), (xmlNanoHTTPScanProxy): Modified to parse
+ a URI with IPv6 address given in [].
+ (xmlNanoHTTPConnectHost): Modified to use getaddrinfo if it is
+ available on the system. Also IPv6 addresses will be resolved by
+ gethostbyname only if IPv6 run-time support is available.
+ (xmlNanoHTTPConnectAttempt): Modified to deal with IPv6 address.
+
Sat Jun 14 18:46:51 CEST 2003 Igor Zlatkovic <igor@zlatkovic.com>
* win32/configure.js include/win32config.h
diff --git a/acconfig.h b/acconfig.h
index 5a2d3a0..7e4d9b8 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -9,3 +9,9 @@
#undef SOCKLEN_T
#undef HAVE_LIBPTHREAD
#undef HAVE_PTHREAD_H
+
+/* Define if IPV6 support is there */
+#undef SUPPORT_IP6
+
+/* Define if getaddrinfo is there */
+#undef HAVE_GETADDRINFO
diff --git a/config.h.in b/config.h.in
index a5d52cb..3464eee 100644
--- a/config.h.in
+++ b/config.h.in
@@ -11,6 +11,12 @@
#undef HAVE_LIBPTHREAD
#undef HAVE_PTHREAD_H
+/* Define if IPv6 support is there. */
+#undef SUPPORT_IP6
+
+/* Define if you have the getaddrinfo function. */
+#undef HAVE_GETADDRINFO
+
/* Define to 1 if you have the <ansidecl.h> header file. */
#undef HAVE_ANSIDECL_H
diff --git a/configure.in b/configure.in
index a2dfa32..ae9b177 100644
--- a/configure.in
+++ b/configure.in
@@ -192,6 +192,42 @@
AC_MSG_WARN(could not determine)])])])
AC_DEFINE_UNQUOTED(SOCKLEN_T, $SOCKLEN_T)
+dnl ***********************Checking for availability of IPv6*******************
+
+AC_MSG_CHECKING([whether to enable IPv6])
+AC_ARG_ENABLE(ipv6, [ --enable-ipv6=[yes/no] enables compilation of IPv6 code],, enable_ipv6=yes)
+if test $enable_ipv6 = yes; then
+ have_ipv6=no
+ AC_TRY_COMPILE([
+ #include <sys/socket.h>
+ #include <sys/types.h>], [
+ struct sockaddr_storage ss;
+ socket(AF_INET6, SOCK_STREAM, 0)
+ ],
+ have_ipv6=yes,
+ have_ipv6=no
+ )
+ AC_MSG_RESULT($have_ipv6)
+
+ if test $have_ipv6=yes; then
+ AC_DEFINE(SUPPORT_IP6)
+
+ have_getaddrinfo=no
+ AC_CHECK_FUNC(getaddrinfo, have_getaddrinfo=yes)
+ if test $have_getaddrinfo != yes; then
+ for lib in bsd socket inet; do
+ AC_CHECK_LIB($lib, getaddrinfo, [LIBS="$LIBS -l$lib";have_getaddrinfo=yes;break])
+ done
+ fi
+
+ if test $have_getaddrinfo=yes; then
+ AC_DEFINE(HAVE_GETADDRINFO)
+ fi
+ fi
+fi
+
+dnl ******************************End IPv6 checks******************************
+
dnl Checks for isnan in libm if not in libc
AC_CHECK_FUNC(isnan, , AC_CHECK_LIB(m, isnan,
[AC_DEFINE(HAVE_ISNAN)]))
diff --git a/nanoftp.c b/nanoftp.c
index 8df6f29..bd3f0d5 100644
--- a/nanoftp.c
+++ b/nanoftp.c
@@ -62,6 +62,7 @@
#include <libxml/uri.h>
#include <libxml/nanoftp.h>
#include <libxml/globals.h>
+#include <config.h>
/* #define DEBUG_FTP 1 */
#ifdef STANDALONE
@@ -93,7 +94,11 @@
char *path; /* the path within the URL */
char *user; /* user string */
char *passwd; /* passwd string */
+#ifdef SUPPORT_IP6
+ struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
+#else
struct sockaddr_in ftpAddr; /* the socket address struct */
+#endif
int passive; /* currently we support only passive !!! */
SOCKET controlFd; /* the file descriptor for the control socket */
SOCKET dataFd; /* the file descriptor for the data socket */
@@ -113,6 +118,19 @@
static char *proxyPasswd = NULL;/* passwd for proxy authentication */
static int proxyType = 0; /* uses TYPE or a@b ? */
+#ifdef SUPPORT_IP6
+static int have_ipv6() {
+ int s;
+
+ s = socket (AF_INET6, SOCK_STREAM, 0);
+ if (s != -1) {
+ close (s);
+ return (1);
+ }
+ return (0);
+}
+#endif
+
/**
* xmlNanoFTPInit:
*
@@ -289,26 +307,64 @@
}
while (1) {
- if (cur[0] == ':') {
+ if ((strchr (cur, '[') && !strchr (cur, ']')) ||
+ (!strchr (cur, '[') && strchr (cur, ']'))) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanURL: %s",
+ "Syntax Error\n");
+ return;
+ }
+
+ if (cur[0] == '[') {
+ cur++;
+ while (cur[0] != ']')
+ buf[indx++] = *cur++;
+
+ if (!strchr (buf, ':')) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanURL: %s",
+ "Use [IPv6]/IPv4 format\n");
+ return;
+ }
+
buf[indx] = 0;
- ctxt->hostname = xmlMemStrdup(buf);
+ ctxt->hostname = xmlMemStrdup (buf);
indx = 0;
cur += 1;
- while ((*cur >= '0') && (*cur <= '9')) {
- port *= 10;
- port += *cur - '0';
+ if (cur[0] == ':') {
cur++;
+ while (*cur >= '0' && *cur <= '9') {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+
+ if (port != 0) ctxt->port = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
}
- if (port != 0) ctxt->port = port;
- while ((cur[0] != '/') && (*cur != 0))
- cur++;
break;
}
- if ((*cur == '/') || (*cur == 0)) {
- buf[indx] = 0;
- ctxt->hostname = xmlMemStrdup(buf);
- indx = 0;
- break;
+ else { /* address is an IPv4 one*/
+ if (cur[0] == ':') {
+ buf[indx] = 0;
+ ctxt->hostname = xmlMemStrdup (buf);
+ indx = 0;
+ cur += 1;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+ if (port != 0) ctxt->port = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
+ break;
+ }
+ if ((*cur == '/') || (*cur == 0)) {
+ buf[indx] = 0;
+ ctxt->hostname = xmlMemStrdup (buf);
+ indx = 0;
+ break;
+ }
}
buf[indx++] = *cur++;
}
@@ -371,29 +427,69 @@
buf[indx] = 0;
while (1) {
- if (cur[0] == ':') {
+ if ((strchr (cur, '[') && !strchr (cur, ']')) ||
+ (!strchr (cur, '[') && strchr (cur, ']'))) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPUpdateURL: %s",
+ "Syntax Error\n");
+ return (-1);
+ }
+
+ if (cur[0] == '[') {
+ cur++;
+ while (cur[0] != ']')
+ buf[indx++] = *cur++;
+
+ if (!strchr (buf, ':')) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPUpdateURL: %s",
+ "Use [IPv6]/IPv4 format\n");
+ return (-1);
+ }
+
buf[indx] = 0;
- if (strcmp(ctxt->hostname, buf))
- return(-1);
+ if (strcmp (ctxt->hostname, buf))
+ return (-1);
indx = 0;
cur += 1;
- while ((*cur >= '0') && (*cur <= '9')) {
- port *= 10;
- port += *cur - '0';
+ if (cur[0] == ':') {
cur++;
+ while (*cur >= '0' && *cur <= '9') {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+
+ if (port != ctxt->port)
+ return (-1);
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
}
- if (port != ctxt->port)
- return(-1);
- while ((cur[0] != '/') && (*cur != 0))
- cur++;
break;
}
- if ((*cur == '/') || (*cur == 0)) {
- buf[indx] = 0;
- if (strcmp(ctxt->hostname, buf))
- return(-1);
- indx = 0;
- break;
+ else {
+ if (cur[0] == ':') {
+ buf[indx] = 0;
+ if (strcmp (ctxt->hostname, buf))
+ return (-1);
+ indx = 0;
+ cur += 1;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+ if (port != ctxt->port)
+ return (-1);
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
+ break;
+ }
+ if ((*cur == '/') || (*cur == 0)) {
+ buf[indx] = 0;
+ if (strcmp (ctxt->hostname, buf))
+ return (-1);
+ indx = 0;
+ break;
+ }
}
buf[indx++] = *cur++;
}
@@ -460,26 +556,63 @@
buf[indx] = 0;
while (1) {
- if (cur[0] == ':') {
+ if ((strchr (cur, '[') && !strchr (cur, ']')) ||
+ (!strchr (cur, '[') && strchr (cur, ']'))) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanProxy: %s",
+ "Syntax error\n");
+ return;
+ }
+
+ if (cur[0] == '[') {
+ cur++;
+ while (cur[0] != ']')
+ buf[indx++] = *cur++;
+ if (!strchr (buf, ':')) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanProxy: %s",
+ "Use [IPv6]/IPv4 format\n");
+ return;
+ }
+
buf[indx] = 0;
- proxy = xmlMemStrdup(buf);
+ proxy = xmlMemStrdup (buf);
indx = 0;
cur += 1;
- while ((*cur >= '0') && (*cur <= '9')) {
- port *= 10;
- port += *cur - '0';
+ if (cur[0] == ':') {
cur++;
+ while (*cur >= '0' && *cur <= '9') {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+
+ if (port != 0) proxyPort = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
}
- if (port != 0) proxyPort = port;
- while ((cur[0] != '/') && (*cur != 0))
- cur++;
break;
}
- if ((*cur == '/') || (*cur == 0)) {
- buf[indx] = 0;
- proxy = xmlMemStrdup(buf);
- indx = 0;
- break;
+ else {
+ if (cur[0] == ':') {
+ buf[indx] = 0;
+ proxy = xmlMemStrdup (buf);
+ indx = 0;
+ cur += 1;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+ if (port != 0) proxyPort = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
+ break;
+ }
+ if ((*cur == '/') || (*cur == 0)) {
+ buf[indx] = 0;
+ proxy = xmlMemStrdup (buf);
+ indx = 0;
+ break;
+ }
}
buf[indx++] = *cur++;
}
@@ -865,6 +998,7 @@
struct hostent *hp;
int port;
int res;
+ int addrlen;
if (ctxt == NULL)
return(-1);
@@ -874,19 +1008,6 @@
/*
* do the blocking DNS query.
*/
- if (proxy)
- hp = gethostbyname(proxy);
- else
- hp = gethostbyname(ctxt->hostname);
- if (hp == NULL)
- return(-1);
-
- /*
- * Prepare the socket
- */
- memset(&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
- ctxt->ftpAddr.sin_family = AF_INET;
- memcpy(&ctxt->ftpAddr.sin_addr, hp->h_addr_list[0], hp->h_length);
if (proxy) {
port = proxyPort;
} else {
@@ -894,8 +1015,65 @@
}
if (port == 0)
port = 21;
- ctxt->ftpAddr.sin_port = htons(port);
- ctxt->controlFd = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
+
+#ifdef SUPPORT_IP6
+ if (have_ipv6 ()) {
+ struct addrinfo hints, *res, *result;
+
+ result = NULL;
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (proxy) {
+ if (getaddrinfo (proxy, NULL, &hints, &result) != 0)
+ return (-1);
+ }
+ else
+ if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0)
+ return (-1);
+
+ for (res = result; res; res = res->ai_next)
+ if (res->ai_family == AF_INET || res->ai_family == AF_INET6)
+ break;
+
+ if (res) {
+ if (res->ai_family == AF_INET6) {
+ memcpy (&ctxt->ftpAddr, res->ai_addr, res->ai_addrlen);
+ ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
+ ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
+ }
+ else {
+ memcpy (&ctxt->ftpAddr, res->ai_addr, res->ai_addrlen);
+ ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
+ ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
+ }
+ addrlen = res->ai_addrlen;
+ freeaddrinfo (result);
+ }
+ }
+ else
+#endif
+ {
+ if (proxy)
+ hp = gethostbyname (proxy);
+ else
+ hp = gethostbyname (ctxt->hostname);
+ if (hp == NULL)
+ return (-1);
+
+ /*
+ * Prepare the socket
+ */
+ ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
+ memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
+ hp->h_addr_list[0], hp->h_length);
+ ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = htons (port);
+ ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
+ addrlen = sizeof (struct sockaddr_in);
+ }
+
if (ctxt->controlFd < 0)
return(-1);
@@ -903,7 +1081,7 @@
* Do the connect.
*/
if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
- sizeof(struct sockaddr_in)) < 0) {
+ addrlen) < 0) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
@@ -1293,22 +1471,41 @@
int res;
unsigned char ad[6], *adp, *portp;
unsigned int temp[6];
+#ifdef SUPPORT_IP6
+ struct sockaddr_storage dataAddr;
+#else
struct sockaddr_in dataAddr;
+#endif
SOCKLEN_T dataAddrLen;
- ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (ctxt->dataFd < 0) {
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoFTPGetConnection: failed to create socket\n");
- return(-1);
+ memset (&dataAddr, 0, sizeof(dataAddr));
+#ifdef SUPPORT_IP6
+ if ((ctxt->ftpAddr).ss_family == AF_INET6) {
+ ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
+ dataAddrLen = sizeof(struct sockaddr_in6);
+ } else
+#endif
+ {
+ ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
+ dataAddrLen = sizeof (struct sockaddr_in);
}
- dataAddrLen = sizeof(dataAddr);
- memset(&dataAddr, 0, dataAddrLen);
- dataAddr.sin_family = AF_INET;
+
+ if (ctxt->dataFd < 0) {
+ xmlGenericError (xmlGenericErrorContext,
+ "xmlNanoFTPGetConnection: failed to create socket\n");
+ return (-1);
+ }
if (ctxt->passive) {
- snprintf(buf, sizeof(buf), "PASV\r\n");
- len = strlen(buf);
+#ifdef SUPPORT_IP6
+ if ((ctxt->ftpAddr).ss_family == AF_INET6)
+ snprintf (buf, sizeof(buf), "EPSV\r\n");
+ else
+#endif
+ snprintf (buf, sizeof(buf), "PASV\r\n");
+ len = strlen (buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
@@ -1332,18 +1529,36 @@
}
cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
- if (sscanf(cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
- &temp[3], &temp[4], &temp[5]) != 6) {
- xmlGenericError(xmlGenericErrorContext,
- "Invalid answer to PASV\n");
- if (ctxt->dataFd != -1) {
- closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+#ifdef SUPPORT_IP6
+ if ((ctxt->ftpAddr).ss_family == AF_INET6) {
+ if (sscanf (cur, "%u", &temp[0]) != 1) {
+ xmlGenericError (xmlGenericErrorContext,
+ "Invalid answer to EPSV\n");
+ if (ctxt->dataFd != -1) {
+ closesocket (ctxt->dataFd); ctxt->dataFd = -1;
+ }
+ return (-1);
}
- return(-1);
+ memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
+ ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
}
- for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
- memcpy(&dataAddr.sin_addr, &ad[0], 4);
- memcpy(&dataAddr.sin_port, &ad[4], 2);
+ else
+#endif
+ {
+ if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
+ &temp[3], &temp[4], &temp[5]) != 6) {
+ xmlGenericError (xmlGenericErrorContext,
+ "Invalid answer to PASV\n");
+ if (ctxt->dataFd != -1) {
+ closesocket (ctxt->dataFd); ctxt->dataFd = -1;
+ }
+ return (-1);
+ }
+ for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
+ memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
+ memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
+ }
+
if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
xmlGenericError(xmlGenericErrorContext,
"Failed to create a data connection\n");
@@ -1352,7 +1567,13 @@
}
} else {
getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
- dataAddr.sin_port = 0;
+#ifdef SUPPORT_IP6
+ if ((ctxt->ftpAddr).ss_family == AF_INET6)
+ ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
+ else
+#endif
+ ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
+
if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
xmlGenericError(xmlGenericErrorContext,
"Failed to bind a port\n");
@@ -1362,17 +1583,37 @@
getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
if (listen(ctxt->dataFd, 1) < 0) {
- xmlGenericError(xmlGenericErrorContext,
- "Could not listen on port %d\n",
- ntohs(dataAddr.sin_port));
+#ifdef SUPPORT_IP6
+ if ((ctxt->ftpAddr).ss_family == AF_INET6)
+ xmlGenericError (xmlGenericErrorContext,
+ "Could not listen on port %d\n",
+ ntohs (((struct sockaddr_in6 *)&dataAddr)->sin6_port));
+ else
+#endif
+ xmlGenericError (xmlGenericErrorContext,
+ "Could not listen on port %d\n",
+ ntohs (((struct sockaddr_in *)&dataAddr)->sin_port));
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return (-1);
}
- adp = (unsigned char *) &dataAddr.sin_addr;
- portp = (unsigned char *) &dataAddr.sin_port;
- snprintf(buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
- adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
- portp[0] & 0xff, portp[1] & 0xff);
+#ifdef SUPPORT_IP6
+ if ((ctxt->ftpAddr).ss_family == AF_INET6) {
+ char buf6[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
+ buf6, INET6_ADDRSTRLEN);
+ adp = buf6;
+ portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
+ snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
+ } else
+#endif
+ {
+ adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
+ portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
+ snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
+ adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
+ portp[0] & 0xff, portp[1] & 0xff);
+ }
+
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
#ifdef DEBUG_FTP
diff --git a/nanohttp.c b/nanohttp.c
index 8c5f995..d94f6d9 100644
--- a/nanohttp.c
+++ b/nanohttp.c
@@ -77,6 +77,7 @@
#include <libxml/nanohttp.h>
#include <libxml/globals.h>
#include <libxml/uri.h>
+#include <config.h>
/**
* A couple portability macros
@@ -149,6 +150,19 @@
#endif
}
+#ifdef SUPPORT_IP6
+static int have_ipv6() {
+ int s;
+
+ s = socket (AF_INET6, SOCK_STREAM, 0);
+ if (s != -1) {
+ close (s);
+ return (1);
+ }
+ return (0);
+}
+#endif
+
/**
* xmlNanoHTTPInit:
*
@@ -253,26 +267,64 @@
buf[indx] = 0;
while (1) {
- if (cur[0] == ':') {
+ if ((strchr (cur, '[') && !strchr (cur, ']')) ||
+ (!strchr (cur, '[') && strchr (cur, ']'))) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanURL: %s",
+ "Syntax Error\n");
+ return;
+ }
+
+ if (cur[0] == '[') {
+ cur++;
+ while (cur[0] != ']')
+ buf[indx++] = *cur++;
+
+ if (!strchr (buf, ':')) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanURL: %s",
+ "Use [IPv6]/IPv4 format\n");
+ return;
+ }
+
buf[indx] = 0;
- ctxt->hostname = xmlMemStrdup(buf);
+ ctxt->hostname = xmlMemStrdup (buf);
indx = 0;
cur += 1;
- while ((*cur >= '0') && (*cur <= '9')) {
- port *= 10;
- port += *cur - '0';
+ if (cur[0] == ':') {
cur++;
+ while (*cur >= '0' && *cur <= '9') {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+
+ if (port != 0) ctxt->port = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
}
- if (port != 0) ctxt->port = port;
- while ((cur[0] != '/') && (*cur != 0))
- cur++;
break;
- }
- if ((*cur == '/') || (*cur == 0)) {
- buf[indx] = 0;
- ctxt->hostname = xmlMemStrdup(buf);
- indx = 0;
- break;
+ }
+ else {
+ if (cur[0] == ':') {
+ buf[indx] = 0;
+ ctxt->hostname = xmlMemStrdup (buf);
+ indx = 0;
+ cur += 1;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+ if (port != 0) ctxt->port = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
+ break;
+ }
+ if ((*cur == '/') || (*cur == 0)) {
+ buf[indx] = 0;
+ ctxt->hostname = xmlMemStrdup (buf);
+ indx = 0;
+ break;
+ }
}
buf[indx++] = *cur++;
}
@@ -335,26 +387,64 @@
buf[indx] = 0;
while (1) {
- if (cur[0] == ':') {
+ if ((strchr (cur, '[') && !strchr (cur, ']')) ||
+ (!strchr (cur, '[') && strchr (cur, ']'))) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanProxy: %s",
+ "Syntax error\n");
+ return;
+ }
+
+ if (cur[0] == '[') {
+ cur++;
+ while (cur[0] != ']')
+ buf[indx++] = *cur++;
+
+ if (!strchr (buf, ':')) {
+ xmlGenericError (xmlGenericErrorContext, "\nxmlNanoHTTPScanProxy: %s",
+ "Use [IPv6]/IPv4 format\n");
+ return;
+ }
+
buf[indx] = 0;
- proxy = xmlMemStrdup(buf);
+ proxy = xmlMemStrdup (buf);
indx = 0;
cur += 1;
- while ((*cur >= '0') && (*cur <= '9')) {
- port *= 10;
- port += *cur - '0';
- cur++;
- }
- if (port != 0) proxyPort = port;
- while ((cur[0] != '/') && (*cur != 0))
+ if (cur[0] == ':') {
cur++;
+ while (*cur >= '0' && *cur <= '9') {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+
+ if (port != 0) proxyPort = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur ++;
+ }
break;
}
- if ((*cur == '/') || (*cur == 0)) {
- buf[indx] = 0;
- proxy = xmlMemStrdup(buf);
- indx = 0;
- break;
+ else {
+ if (cur[0] == ':') {
+ buf[indx] = 0;
+ proxy = xmlMemStrdup (buf);
+ indx = 0;
+ cur += 1;
+ while ((*cur >= '0') && (*cur <= '9')) {
+ port *= 10;
+ port += *cur - '0';
+ cur++;
+ }
+ if (port != 0) proxyPort = port;
+ while ((cur[0] != '/') && (*cur != 0))
+ cur++;
+ break;
+ }
+ if ((*cur == '/') || (*cur == 0)) {
+ buf[indx] = 0;
+ proxy = xmlMemStrdup (buf);
+ indx = 0;
+ break;
+ }
}
buf[indx++] = *cur++;
}
@@ -711,11 +801,23 @@
static int
xmlNanoHTTPConnectAttempt(struct sockaddr *addr)
{
- SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
fd_set wfd;
struct timeval tv;
int status;
+ int addrlen;
+ SOCKET s;
+#ifdef SUPPORT_IP6
+ if (addr->sa_family == AF_INET6) {
+ s = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ addrlen = sizeof (struct sockaddr_in6);
+ }
+ else
+#endif
+ {
+ s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ addrlen = sizeof (struct sockaddr_in);
+ }
if (s==-1) {
#ifdef DEBUG_HTTP
perror("socket");
@@ -764,7 +866,7 @@
#endif /* !VMS */
#endif /* !_WINSOCKAPI_ */
- if ((connect(s, addr, sizeof(*addr))==-1)) {
+ if (connect (s, addr, addrlen) == -1) {
switch (socket_errno()) {
case EINPROGRESS:
case EWOULDBLOCK:
@@ -862,13 +964,64 @@
int i;
int s;
-#if defined(SUPPORT_IP6) && defined(RES_USE_INET6)
- if (!(_res.options & RES_INIT))
- res_init();
- _res.options |= RES_USE_INET6;
+ memset (&sockin, 0, sizeof(sockin));
+#ifdef SUPPORT_IP6
+ memset (&sockin6, 0, sizeof(sockin6));
+ if (have_ipv6 ())
+ {
+#if !defined(HAVE_GETADDRINFO) && defined(RES_USE_INET6)
+ if (!(_res.options & RES_INIT))
+ res_init();
+ _res.options |= RES_USE_INET6;
+ }
+#elif defined(HAVE_GETADDRINFO)
+ int status;
+ struct addrinfo hints, *res, *result;
+
+ result = NULL;
+ memset (&hints, 0,sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+
+ status = getaddrinfo (host, NULL, &hints, &result);
+ if (status) {
+ xmlGenericError (xmlGenericErrorContext,
+ "xmlNanoHTTPConnectHost: %s '%s' - %s",
+ "Failed to resolve host", host, gai_strerror (status));
+
+ return (-1);
+ }
+
+ for (res = result; res; res = res->ai_next) {
+ if (res) {
+ if (res->ai_family == AF_INET6) {
+ memcpy (&sockin6, res->ai_addr, res->ai_addrlen);
+ sockin6.sin6_port = htons (port);
+ addr = (struct sockaddr *)&sockin6;
+ }
+
+ if (res->ai_family == AF_INET) {
+ memcpy (&sockin, res->ai_addr, res->ai_addrlen);
+ sockin.sin_port = htons (port);
+ addr = (struct sockaddr *)&sockin;
+ }
+
+ s = xmlNanoHTTPConnectAttempt (addr);
+ if (s != -1) {
+ freeaddrinfo (result);
+ return (s);
+ }
+ }
+ else {
+ freeaddrinfo (result);
+ return (-1);
+ }
+ }
+ } else
#endif
- h = gethostbyname(host);
- if (h == NULL) {
+#endif
+ {
+ h = gethostbyname (host);
+ if (h == NULL) {
/*
* Okay, I got fed up by the non-portability of this error message
@@ -876,68 +1029,68 @@
* and one want to enable it, send me the defined(foobar) needed
*/
#if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(linux)
- const char *h_err_txt = "";
+ const char *h_err_txt = "";
- switch (h_errno) {
- case HOST_NOT_FOUND:
- h_err_txt = "Authoritive host not found";
- break;
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+ h_err_txt = "Authoritive host not found";
+ break;
- case TRY_AGAIN:
- h_err_txt =
- "Non-authoritive host not found or server failure.";
- break;
+ case TRY_AGAIN:
+ h_err_txt =
+ "Non-authoritive host not found or server failure.";
+ break;
- case NO_RECOVERY:
- h_err_txt =
- "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
- break;
+ case NO_RECOVERY:
+ h_err_txt =
+ "Non-recoverable errors: FORMERR, REFUSED, or NOTIMP.";
+ break;
- case NO_ADDRESS:
- h_err_txt =
- "Valid name, no data record of requested type.";
- break;
+ case NO_ADDRESS:
+ h_err_txt =
+ "Valid name, no data record of requested type.";
+ break;
- default:
- h_err_txt = "No error text defined.";
- break;
- }
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoHTTPConnectHost: %s '%s' - %s",
- "Failed to resolve host", host, h_err_txt);
+ default:
+ h_err_txt = "No error text defined.";
+ break;
+ }
+ xmlGenericError (xmlGenericErrorContext,
+ "xmlNanoHTTPConnectHost: %s '%s' - %s",
+ "Failed to resolve host", host, h_err_txt);
#else
- xmlGenericError(xmlGenericErrorContext,
- "xmlNanoHTTPConnectHost: %s '%s'",
- "Failed to resolve host", host);
+ xmlGenericError (xmlGenericErrorContext,
+ "xmlNanoHTTPConnectHost: %s '%s'",
+ "Failed to resolve host", host);
#endif
- return (-1);
- }
+ return (-1);
+ }
- for (i = 0; h->h_addr_list[i]; i++) {
- if (h->h_addrtype == AF_INET) {
- /* A records (IPv4) */
- memcpy(&ia, h->h_addr_list[i], h->h_length);
- sockin.sin_family = h->h_addrtype;
- sockin.sin_addr = ia;
- sockin.sin_port = htons(port);
- addr = (struct sockaddr *) &sockin;
+ for (i = 0; h->h_addr_list[i]; i++) {
+ if (h->h_addrtype == AF_INET) {
+ /* A records (IPv4) */
+ memcpy (&ia, h->h_addr_list[i], h->h_length);
+ sockin.sin_family = h->h_addrtype;
+ sockin.sin_addr = ia;
+ sockin.sin_port = htons (port);
+ addr = (struct sockaddr *) &sockin;
#ifdef SUPPORT_IP6
- } else if (h->h_addrtype == AF_INET6) {
- /* AAAA records (IPv6) */
- memcpy(&ia6, h->h_addr_list[i], h->h_length);
- sockin6.sin_family = h->h_addrtype;
- sockin6.sin_addr = ia6;
- sockin6.sin_port = htons(port);
- addr = (struct sockaddr *) &sockin6;
+ } else if (have_ipv6 () && (h->h_addrtype == AF_INET6)) {
+ /* AAAA records (IPv6) */
+ memcpy (&ia6, h->h_addr_list[i], h->h_length);
+ sockin6.sin6_family = h->h_addrtype;
+ sockin6.sin6_addr = ia6;
+ sockin6.sin6_port = htons (port);
+ addr = (struct sockaddr *) &sockin6;
#endif
- } else
- break; /* for */
+ } else
+ break; /* for */
- s = xmlNanoHTTPConnectAttempt(addr);
- if (s != -1)
- return (s);
+ s = xmlNanoHTTPConnectAttempt (addr);
+ if (s != -1)
+ return (s);
+ }
}
-
#ifdef DEBUG_HTTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoHTTPConnectHost: unable to connect to '%s'.\n",