📄 nanoftp.c
字号:
/** * ftp.c: basic handling of an FTP command connection to check for * directory availability. No transfer is needed. * * Reference: RFC 959 */#include "global.h"#ifdef WIN32#define INCLUDE_WINSOCK#include "win32config.h"#else#include "config.h"#endif#include "xmlversion.h"#ifdef LIBXML_FTP_ENABLED#include <stdio.h>#include <string.h>#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <sys/types.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h> #endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_RESOLV_H#include <resolv.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif#include <libxml/xmlmemory.h>#include <libxml/nanoftp.h>/* #define DEBUG_FTP 1 */#ifdef STANDALONE#ifndef DEBUG_FTP#define DEBUG_FTP 1#endif#endifstatic char hostname[100];#define FTP_COMMAND_OK 200#define FTP_SYNTAX_ERROR 500#define FTP_GET_PASSWD 331typedef struct xmlNanoFTPCtxt { char *protocol; /* the protocol name */ char *hostname; /* the host name */ int port; /* the port */ char *path; /* the path within the URL */ char *user; /* user string */ char *passwd; /* passwd string */ struct sockaddr_in ftpAddr; /* the socket address struct */ int passive; /* currently we support only passive !!! */ int controlFd; /* the file descriptor for the control socket */ int dataFd; /* the file descriptor for the data socket */ int state; /* WRITE / READ / CLOSED */ int returnValue; /* the protocol return value */} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;static int initialized = 0;static char *proxy = NULL; /* the proxy name if any */static int proxyPort = 0; /* the proxy port if any */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 ? *//** * xmlNanoFTPInit: * * Initialize the FTP protocol layer. * Currently it just checks for proxy informations, * and get the hostname */voidxmlNanoFTPInit(void) { const char *env; if (initialized) return; gethostname(hostname, sizeof(hostname)); proxyPort = 21; env = getenv("no_proxy"); if (env != NULL) return; env = getenv("ftp_proxy"); if (env != NULL) { xmlNanoFTPScanProxy(env); } else { env = getenv("FTP_PROXY"); if (env != NULL) { xmlNanoFTPScanProxy(env); } } env = getenv("ftp_proxy_user"); if (env != NULL) { proxyUser = xmlMemStrdup(env); } env = getenv("ftp_proxy_password"); if (env != NULL) { proxyPasswd = xmlMemStrdup(env); } initialized = 1;}/** * xmlNanoFTPClenup: * * Cleanup the FTP protocol layer. This cleanup proxy informations. */voidxmlNanoFTPCleanup(void) { if (proxy != NULL) { xmlFree(proxy); proxy = NULL; } if (proxyUser != NULL) { xmlFree(proxyUser); proxyUser = NULL; } if (proxyPasswd != NULL) { xmlFree(proxyPasswd); proxyPasswd = NULL; } hostname[0] = 0; initialized = 0; return;}/** * xmlNanoFTPProxy: * @host: the proxy host name * @port: the proxy port * @user: the proxy user name * @passwd: the proxy password * @type: the type of proxy 1 for using SITE, 2 for USER a@b * * Setup the FTP proxy informations. * This can also be done by using ftp_proxy ftp_proxy_user and * ftp_proxy_password environment variables. */voidxmlNanoFTPProxy(const char *host, int port, const char *user, const char *passwd, int type) { if (proxy != NULL) xmlFree(proxy); if (proxyUser != NULL) xmlFree(proxyUser); if (proxyPasswd != NULL) xmlFree(proxyPasswd); if (host) proxy = xmlMemStrdup(host); if (user) proxyUser = xmlMemStrdup(user); if (passwd) proxyPasswd = xmlMemStrdup(passwd); proxyPort = port; proxyType = type;}/** * xmlNanoFTPScanURL: * @ctx: an FTP context * @URL: The URL used to initialize the context * * (Re)Initialize an FTP context by parsing the URL and finding * the protocol host port and path it indicates. */static voidxmlNanoFTPScanURL(void *ctx, const char *URL) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; const char *cur = URL; char buf[4096]; int index = 0; int port = 0; if (ctxt->protocol != NULL) { xmlFree(ctxt->protocol); ctxt->protocol = NULL; } if (ctxt->hostname != NULL) { xmlFree(ctxt->hostname); ctxt->hostname = NULL; } if (ctxt->path != NULL) { xmlFree(ctxt->path); ctxt->path = NULL; } if (URL == NULL) return; buf[index] = 0; while (*cur != 0) { if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { buf[index] = 0; ctxt->protocol = xmlMemStrdup(buf); index = 0; cur += 3; break; } buf[index++] = *cur++; } if (*cur == 0) return; buf[index] = 0; while (1) { if (cur[0] == ':') { buf[index] = 0; ctxt->hostname = xmlMemStrdup(buf); index = 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[index] = 0; ctxt->hostname = xmlMemStrdup(buf); index = 0; break; } buf[index++] = *cur++; } if (*cur == 0) ctxt->path = xmlMemStrdup("/"); else { index = 0; buf[index] = 0; while (*cur != 0) buf[index++] = *cur++; buf[index] = 0; ctxt->path = xmlMemStrdup(buf); } }/** * xmlNanoFTPUpdateURL: * @ctx: an FTP context * @URL: The URL used to update the context * * Update an FTP context by parsing the URL and finding * new path it indicates. If there is an error in the * protocol, hostname, port or other information, the * error is raised. It indicates a new connection has to * be established. * * Returns 0 if Ok, -1 in case of error (other host). */intxmlNanoFTPUpdateURL(void *ctx, const char *URL) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; const char *cur = URL; char buf[4096]; int index = 0; int port = 0; if (URL == NULL) return(-1); if (ctxt == NULL) return(-1); if (ctxt->protocol == NULL) return(-1); if (ctxt->hostname == NULL) return(-1); buf[index] = 0; while (*cur != 0) { if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { buf[index] = 0; if (strcmp(ctxt->protocol, buf)) return(-1); index = 0; cur += 3; break; } buf[index++] = *cur++; } if (*cur == 0) return(-1); buf[index] = 0; while (1) { if (cur[0] == ':') { buf[index] = 0; if (strcmp(ctxt->hostname, buf)) return(-1); index = 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[index] = 0; if (strcmp(ctxt->hostname, buf)) return(-1); index = 0; break; } buf[index++] = *cur++; } if (ctxt->path != NULL) { xmlFree(ctxt->path); ctxt->path = NULL; } if (*cur == 0) ctxt->path = xmlMemStrdup("/"); else { index = 0; buf[index] = 0; while (*cur != 0) buf[index++] = *cur++; buf[index] = 0; ctxt->path = xmlMemStrdup(buf); } return(0);}/** * xmlNanoFTPScanProxy: * @URL: The proxy URL used to initialize the proxy context * * (Re)Initialize the FTP Proxy context by parsing the URL and finding * the protocol host port it indicates. * Should be like ftp://myproxy/ or ftp://myproxy:3128/ * A NULL URL cleans up proxy informations. */voidxmlNanoFTPScanProxy(const char *URL) { const char *cur = URL; char buf[4096]; int index = 0; int port = 0; if (proxy != NULL) { xmlFree(proxy); proxy = NULL; } if (proxyPort != 0) { proxyPort = 0; }#ifdef DEBUG_FTP if (URL == NULL) printf("Removing FTP proxy info\n"); else printf("Using FTP proxy %s\n", URL);#endif if (URL == NULL) return; buf[index] = 0; while (*cur != 0) { if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { buf[index] = 0; index = 0; cur += 3; break; } buf[index++] = *cur++; } if (*cur == 0) return; buf[index] = 0; while (1) { if (cur[0] == ':') { buf[index] = 0; proxy = xmlMemStrdup(buf); index = 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[index] = 0; proxy = xmlMemStrdup(buf); index = 0; break; } buf[index++] = *cur++; }}/** * xmlNanoFTPNewCtxt: * @URL: The URL used to initialize the context * * Allocate and initialize a new FTP context. * * Returns an FTP context or NULL in case of error. */void *xmlNanoFTPNewCtxt(const char *URL) { xmlNanoFTPCtxtPtr ret; ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt)); if (ret == NULL) return(NULL); memset(ret, 0, sizeof(xmlNanoFTPCtxt)); ret->port = 21; ret->passive = 1; ret->returnValue = 0; if (URL != NULL) xmlNanoFTPScanURL(ret, URL); return(ret);}/** * xmlNanoFTPFreeCtxt: * @ctx: an FTP context * * Frees the context after closing the connection. */voidxmlNanoFTPFreeCtxt(void * ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; if (ctxt == NULL) return; if (ctxt->hostname != NULL) xmlFree(ctxt->hostname); if (ctxt->protocol != NULL) xmlFree(ctxt->protocol); if (ctxt->path != NULL) xmlFree(ctxt->path); ctxt->passive = 1; if (ctxt->controlFd >= 0) close(ctxt->controlFd); ctxt->controlFd = -1; xmlFree(ctxt);}/** * Parsing of the server answer, we just extract the code. * return 0 for errors * +XXX for last line of response * -XXX for response to be continued */static intxmlNanoFTPParseResponse(void *ctx, 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);}/** * xmlNanoFTPReadResponse: * @ctx: an FTP context * @buf: buffer to read in * @size: buffer length * * Read the response from the FTP server after a command. * Returns the code number */static intxmlNanoFTPReadResponse(void *ctx, char *buf, int size) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char *ptr, *end; int len; int res = -1; if (size <= 0) return(-1);get_more: if ((len = recv(ctxt->controlFd, buf, size - 1, 0)) < 0) { close(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); } if (len == 0) { return(-1); } end = &buf[len]; *end = 0;#ifdef DEBUG_FTP printf(buf);#endif ptr = buf; while (ptr < end) { res = xmlNanoFTPParseResponse(ctxt, ptr, end - ptr); if (res > 0) break; if (res == 0) {#ifdef DEBUG_FTP fprintf(stderr, "xmlNanoFTPReadResponse failed: %s\n", ptr);#endif return(-1); } while ((ptr < end) && (*ptr != '\n')) ptr++; if (ptr >= end) {#ifdef DEBUG_FTP fprintf(stderr, "xmlNanoFTPReadResponse: unexpected end %s\n", buf);#endif return((-res) / 100); } if (*ptr != '\r') ptr++; } if (res < 0) goto get_more;#ifdef DEBUG_FTP printf("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) { char buf[16 * 1024 + 1];/************** fd_set rfd; struct timeval tv; int res; tv.tv_sec = 10; tv.tv_usec = 0; FD_ZERO(&rfd); FD_SET(ctxt->controlFd, &rfd); res = select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv); if (res <= 0) return(res); **************/ return(xmlNanoFTPReadResponse(ctx, buf, 16 * 1024));}/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -