📄 nanoftp.c
字号:
static intxmlNanoFTPParseResponse(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 intxmlNanoFTPGetMore(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 intxmlNanoFTPReadResponse(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 */intxmlNanoFTPGetResponse(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 */intxmlNanoFTPCheckResponse(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 intxmlNanoFTPSendUser(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 intxmlNanoFTPSendPasswd(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 */intxmlNanoFTPQuit(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 */intxmlNanoFTPConnect(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); if (res > 3) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -