📄 nanoftp.c
字号:
if (res > 3) {
closesocket(ctxt->controlFd);
ctxt->controlFd = -1;
return(-1);
}
break;
case 1:
break;
case 4:
case 5:
case -1:
default:
closesocket(ctxt->controlFd);
ctxt->controlFd = -1;
return(-1);
}
}
/*
* We assume we don't need more authentication to the proxy
* and that it succeeded :-\
*/
switch (proxyType) {
case 0:
/* we will try in sequence */
case 1:
/* Using SITE command */
snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
if (res == 2) {
/* we assume it worked :-\ 1 is error for SITE command */
proxyType = 1;
break;
}
if (proxyType == 1) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
case 2:
/* USER user@host command */
if (ctxt->user == NULL)
snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
ctxt->hostname);
else
snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
ctxt->user, ctxt->hostname);
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
if ((res == 1) || (res == 2)) {
/* we assume it worked :-\ */
proxyType = 2;
return(0);
}
if (ctxt->passwd == NULL)
snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
else
snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
if ((res == 1) || (res == 2)) {
/* we assume it worked :-\ */
proxyType = 2;
return(0);
}
if (proxyType == 2) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
case 3:
/*
* If you need support for other Proxy authentication scheme
* send the code or at least the sequence in use.
*/
default:
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
}
/*
* Non-proxy handling.
*/
res = xmlNanoFTPSendUser(ctxt);
if (res < 0) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
res = xmlNanoFTPGetResponse(ctxt);
switch (res) {
case 2:
return(0);
case 3:
break;
case 1:
case 4:
case 5:
case -1:
default:
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
res = xmlNanoFTPSendPasswd(ctxt);
if (res < 0) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
res = xmlNanoFTPGetResponse(ctxt);
switch (res) {
case 2:
break;
case 3:
__xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
"FTP server asking for ACCNT on anonymous\n");
case 1:
case 4:
case 5:
case -1:
default:
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
return(0);
}
/**
* xmlNanoFTPConnectTo:
* @server: an FTP server name
* @port: the port (use 21 if 0)
*
* Tries to open a control connection to the given server/port
*
* Returns an fTP context or NULL if it failed
*/
void*
xmlNanoFTPConnectTo(const char *server, int port) {
xmlNanoFTPCtxtPtr ctxt;
int res;
xmlNanoFTPInit();
if (server == NULL)
return(NULL);
if (port <= 0)
return(NULL);
ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
ctxt->hostname = xmlMemStrdup(server);
if (port != 0)
ctxt->port = port;
res = xmlNanoFTPConnect(ctxt);
if (res < 0) {
xmlNanoFTPFreeCtxt(ctxt);
return(NULL);
}
return(ctxt);
}
/**
* xmlNanoFTPCwd:
* @ctx: an FTP context
* @directory: a directory on the server
*
* Tries to change the remote directory
*
* Returns -1 incase of error, 1 if CWD worked, 0 if it failed
*/
int
xmlNanoFTPCwd(void *ctx, const char *directory) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[400];
int len;
int res;
if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
if (directory == NULL) return 0;
/*
* Expected response code for CWD:
*
* CWD
* 250
* 500, 501, 502, 421, 530, 550
*/
snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
if (res == 4) {
return(-1);
}
if (res == 2) return(1);
if (res == 5) {
return(0);
}
return(0);
}
/**
* xmlNanoFTPDele:
* @ctx: an FTP context
* @file: a file or directory on the server
*
* Tries to delete an item (file or directory) from server
*
* Returns -1 incase of error, 1 if DELE worked, 0 if it failed
*/
int
xmlNanoFTPDele(void *ctx, const char *file) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[400];
int len;
int res;
if ((ctxt == NULL) || (ctxt->controlFd < 0) || (file == NULL)) return(-1);
if (file == NULL) return (0);
/*
* Expected response code for DELE:
*
* DELE
* 250
* 450, 550
* 500, 501, 502, 421, 530
*/
snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
if (res == 4) {
return(-1);
}
if (res == 2) return(1);
if (res == 5) {
return(0);
}
return(0);
}
/**
* xmlNanoFTPGetConnection:
* @ctx: an FTP context
*
* Try to open a data connection to the server. Currently only
* passive mode is supported.
*
* Returns -1 incase of error, 0 otherwise
*/
int
xmlNanoFTPGetConnection(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[200], *cur;
int len, i;
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
XML_SOCKLEN_T dataAddrLen;
if (ctxt == NULL) 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);
}
if (ctxt->dataFd < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "socket failed");
return (-1);
}
if (ctxt->passive) {
#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
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(res);
}
res = xmlNanoFTPReadResponse(ctx);
if (res != 2) {
if (res == 5) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-1);
} else {
/*
* retry with an active connection
*/
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
ctxt->passive = 0;
}
}
cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
#ifdef SUPPORT_IP6
if ((ctxt->ftpAddr).ss_family == AF_INET6) {
if (sscanf (cur, "%u", &temp[0]) != 1) {
__xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
"Invalid answer to EPSV\n");
if (ctxt->dataFd != -1) {
closesocket (ctxt->dataFd); ctxt->dataFd = -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]);
}
else
#endif
{
if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
&temp[3], &temp[4], &temp[5]) != 6) {
__xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
"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) {
__xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return (-1);
}
} else {
getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
#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) {
__xmlIOErr(XML_FROM_FTP, 0, "bind failed");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return (-1);
}
getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
if (listen(ctxt->dataFd, 1) < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "listen failed");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return (-1);
}
#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 = (unsigned char *) 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
xmlGenericError(xmlGenericErrorContext, "%s", buf);
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
if (res != 2) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-1);
}
}
return(ctxt->dataFd);
}
/**
* xmlNanoFTPCloseConnection:
* @ctx: an FTP context
*
* Close the data connection from the server
*
* Returns -1 incase of error, 0 otherwise
*/
int
xmlNanoFTPCloseConnection(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
int res;
fd_set rfd, efd;
struct timeval tv;
if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
tv.tv_sec = 15;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(ctxt->controlFd, &rfd);
FD_ZERO(&efd);
FD_SET(ctxt->controlFd, &efd);
res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
if (res < 0) {
#ifdef DEBUG_FTP
perror("select");
#endif
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
return(-1);
}
if (res == 0) {
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoFTPCloseConnection: timeout\n");
#endif
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
} else {
res = xmlNanoFTPGetResponse(ctxt);
if (res != 2) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
return(-1);
}
}
return(0);
}
/**
* xmlNanoFTPParseList:
* @list: some data listing received from the server
* @callback: the user callback
* @userData: the user callback data
*
* Parse at most one entry from the listing.
*
* Returns -1 incase of error, the length of data parsed otherwise
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -