Commit de2a67b4 authored by Daniel Veillard's avatar Daniel Veillard

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
parent e8b5b0f1
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
......
......@@ -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
......@@ -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
......
......@@ -192,6 +192,42 @@ AC_TRY_COMPILE2([
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)]))
......
......@@ -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 @@ typedef struct xmlNanoFTPCtxt {
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 *proxyUser = NULL; /* user for proxy authentication */
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 @@ xmlNanoFTPScanURL(void *ctx, const char *URL) {
}
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 @@ xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
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 @@ xmlNanoFTPScanProxy(const char *URL) {
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 @@ xmlNanoFTPConnect(void *ctx) {
struct hostent *hp;
int port;
int res;
int addrlen;
if (ctxt == NULL)
return(-1);
......@@ -874,19 +1008,6 @@ xmlNanoFTPConnect(void *ctx) {
/*
* 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 @@ xmlNanoFTPConnect(void *ctx) {
}
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 @@ xmlNanoFTPConnect(void *ctx) {
* 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 @@ xmlNanoFTPGetConnection(void *ctx) {
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);
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);
}
if (ctxt->dataFd < 0) {
xmlGenericError(xmlGenericErrorContext,
xmlGenericError (xmlGenericErrorContext,
"xmlNanoFTPGetConnection: failed to create socket\n");
return(-1);
return (-1);
}
dataAddrLen = sizeof(dataAddr);
memset(&dataAddr, 0, dataAddrLen);
dataAddr.sin_family = AF_INET;
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 @@ xmlNanoFTPGetConnection(void *ctx) {
}
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 @@ xmlNanoFTPGetConnection(void *ctx) {
}
} 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 @@ xmlNanoFTPGetConnection(void *ctx) {
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
......
......@@ -77,6 +77,7 @@
#include <libxml/nanohttp.h>
#include <libxml/globals.h>
#include <libxml/uri.h>