📄 nanoftp.c
字号:
*/
static int
xmlNanoFTPParseResponse(char *buf, int len) {
int val = 0;
if (len < 3) return(-1);
if ((*buf >= '0') && (*buf <= '9'))
val = val * 10 + (*buf - '0');
else
return(0);
buf++;
if ((*buf >= '0') && (*buf <= '9'))
val = val * 10 + (*buf - '0');
else
return(0);
buf++;
if ((*buf >= '0') && (*buf <= '9'))
val = val * 10 + (*buf - '0');
else
return(0);
buf++;
if (*buf == '-')
return(-val);
return(val);
}
/**
* xmlNanoFTPGetMore:
* @ctx: an FTP context
*
* Read more information from the FTP control connection
* Returns the number of bytes read, < 0 indicates an error
*/
static int
xmlNanoFTPGetMore(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
int len;
int size;
if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoFTPGetMore : controlBufIndex = %d\n",
ctxt->controlBufIndex);
#endif
return(-1);
}
if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoFTPGetMore : controlBufUsed = %d\n",
ctxt->controlBufUsed);
#endif
return(-1);
}
if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
ctxt->controlBufIndex, ctxt->controlBufUsed);
#endif
return(-1);
}
/*
* First pack the control buffer
*/
if (ctxt->controlBufIndex > 0) {
memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
ctxt->controlBufUsed - ctxt->controlBufIndex);
ctxt->controlBufUsed -= ctxt->controlBufIndex;
ctxt->controlBufIndex = 0;
}
size = FTP_BUF_SIZE - ctxt->controlBufUsed;
if (size == 0) {
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
#endif
return(0);
}
/*
* Read the amount left on the control connection
*/
if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
size, 0)) < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
ctxt->controlBufUsed, ctxt->controlBufUsed + len);
#endif
ctxt->controlBufUsed += len;
ctxt->controlBuf[ctxt->controlBufUsed] = 0;
return(len);
}
/**
* xmlNanoFTPReadResponse:
* @ctx: an FTP context
*
* Read the response from the FTP server after a command.
* Returns the code number
*/
static int
xmlNanoFTPReadResponse(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char *ptr, *end;
int len;
int res = -1, cur = -1;
if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
get_more:
/*
* Assumes everything up to controlBuf[controlBufIndex] has been read
* and analyzed.
*/
len = xmlNanoFTPGetMore(ctx);
if (len < 0) {
return(-1);
}
if ((ctxt->controlBufUsed == 0) && (len == 0)) {
return(-1);
}
ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
end = &ctxt->controlBuf[ctxt->controlBufUsed];
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext,
"\n<<<\n%s\n--\n", ptr);
#endif
while (ptr < end) {
cur = xmlNanoFTPParseResponse(ptr, end - ptr);
if (cur > 0) {
/*
* Successfully scanned the control code, scratch
* till the end of the line, but keep the index to be
* able to analyze the result if needed.
*/
res = cur;
ptr += 3;
ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
while ((ptr < end) && (*ptr != '\n')) ptr++;
if (*ptr == '\n') ptr++;
if (*ptr == '\r') ptr++;
break;
}
while ((ptr < end) && (*ptr != '\n')) ptr++;
if (ptr >= end) {
ctxt->controlBufIndex = ctxt->controlBufUsed;
goto get_more;
}
if (*ptr != '\r') ptr++;
}
if (res < 0) goto get_more;
ctxt->controlBufIndex = ptr - ctxt->controlBuf;
#ifdef DEBUG_FTP
ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
#endif
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
#endif
return(res / 100);
}
/**
* xmlNanoFTPGetResponse:
* @ctx: an FTP context
*
* Get the response from the FTP server after a command.
* Returns the code number
*/
int
xmlNanoFTPGetResponse(void *ctx) {
int res;
res = xmlNanoFTPReadResponse(ctx);
return(res);
}
/**
* xmlNanoFTPCheckResponse:
* @ctx: an FTP context
*
* Check if there is a response from the FTP server after a command.
* Returns the code number, or 0
*/
int
xmlNanoFTPCheckResponse(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
fd_set rfd;
struct timeval tv;
if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(ctxt->controlFd, &rfd);
switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
case 0:
return(0);
case -1:
__xmlIOErr(XML_FROM_FTP, 0, "select");
return(-1);
}
return(xmlNanoFTPReadResponse(ctx));
}
/**
* Send the user authentication
*/
static int
xmlNanoFTPSendUser(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[200];
int len;
int res;
if (ctxt->user == NULL)
snprintf(buf, sizeof(buf), "USER anonymous\r\n");
else
snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
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);
}
return(0);
}
/**
* Send the password authentication
*/
static int
xmlNanoFTPSendPasswd(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[200];
int len;
int res;
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");
return(res);
}
return(0);
}
/**
* xmlNanoFTPQuit:
* @ctx: an FTP context
*
* Send a QUIT command to the server
*
* Returns -1 in case of error, 0 otherwise
*/
int
xmlNanoFTPQuit(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[200];
int len, res;
if ((ctxt == NULL) || (ctxt->controlFd < 0)) return(-1);
snprintf(buf, sizeof(buf), "QUIT\r\n");
len = strlen(buf);
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
#endif
res = send(ctxt->controlFd, buf, len, 0);
if (res < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
return(res);
}
return(0);
}
/**
* xmlNanoFTPConnect:
* @ctx: an FTP context
*
* Tries to open a control connection
*
* Returns -1 in case of error, 0 otherwise
*/
int
xmlNanoFTPConnect(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
struct hostent *hp;
int port;
int res;
int addrlen = sizeof (struct sockaddr_in);
if (ctxt == NULL)
return(-1);
if (ctxt->hostname == NULL)
return(-1);
/*
* do the blocking DNS query.
*/
if (proxy) {
port = proxyPort;
} else {
port = ctxt->port;
}
if (port == 0)
port = 21;
memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
#ifdef SUPPORT_IP6
if (have_ipv6 ()) {
struct addrinfo hints, *tmp, *result;
result = NULL;
memset (&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
if (proxy) {
if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
return (-1);
}
}
else
if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
return (-1);
}
for (tmp = result; tmp; tmp = tmp->ai_next)
if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
break;
if (!tmp) {
if (result)
freeaddrinfo (result);
__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
return (-1);
}
if (tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
__xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
return (-1);
}
if (tmp->ai_family == AF_INET6) {
memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
}
else {
memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
}
addrlen = tmp->ai_addrlen;
freeaddrinfo (result);
}
else
#endif
{
if (proxy)
hp = gethostbyname (proxy);
else
hp = gethostbyname (ctxt->hostname);
if (hp == NULL) {
__xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
return (-1);
}
if ((unsigned int) hp->h_length >
sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
__xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
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) {
__xmlIOErr(XML_FROM_FTP, 0, "socket failed");
return(-1);
}
/*
* Do the connect.
*/
if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
addrlen) < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
/*
* Wait for the HELLO from the server.
*/
res = xmlNanoFTPGetResponse(ctxt);
if (res != 2) {
closesocket(ctxt->controlFd); ctxt->controlFd = -1;
ctxt->controlFd = -1;
return(-1);
}
/*
* State diagram for the login operation on the FTP server
*
* Reference: RFC 959
*
* 1
* +---+ USER +---+------------->+---+
* | B |---------->| W | 2 ---->| E |
* +---+ +---+------ | -->+---+
* | | | | |
* 3 | | 4,5 | | |
* -------------- ----- | | |
* | | | | |
* | | | | |
* | --------- |
* | 1| | | |
* V | | | |
* +---+ PASS +---+ 2 | ------>+---+
* | |---------->| W |------------->| S |
* +---+ +---+ ---------->+---+
* | | | | |
* 3 | |4,5| | |
* -------------- -------- |
* | | | | |
* | | | | |
* | -----------
* | 1,3| | | |
* V | 2| | |
* +---+ ACCT +---+-- | ----->+---+
* | |---------->| W | 4,5 -------->| F |
* +---+ +---+------------->+---+
*
* Of course in case of using a proxy this get really nasty and is not
* standardized at all :-(
*/
if (proxy) {
int len;
char buf[400];
if (proxyUser != NULL) {
/*
* We need proxy auth
*/
snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
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;
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
switch (res) {
case 2:
if (proxyPasswd == NULL)
break;
case 3:
if (proxyPasswd != NULL)
snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
else
snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
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;
return(res);
}
res = xmlNanoFTPGetResponse(ctxt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -