Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygennanoftp.c
Go to the documentation of this file.
00001 /* 00002 * nanoftp.c: basic FTP client support 00003 * 00004 * Reference: RFC 959 00005 */ 00006 00007 #ifdef TESTING 00008 #define STANDALONE 00009 #define HAVE_STDLIB_H 00010 #define HAVE_UNISTD_H 00011 #define HAVE_SYS_SOCKET_H 00012 #define HAVE_NETINET_IN_H 00013 #define HAVE_NETDB_H 00014 #define HAVE_SYS_TIME_H 00015 #else /* TESTING */ 00016 #define NEED_SOCKETS 00017 #endif /* TESTING */ 00018 00019 #define IN_LIBXML 00020 #include "libxml.h" 00021 00022 #ifdef LIBXML_FTP_ENABLED 00023 #include <string.h> 00024 00025 #ifdef HAVE_STDLIB_H 00026 #include <stdlib.h> 00027 #endif 00028 #ifdef HAVE_UNISTD_H 00029 #include <unistd.h> 00030 #endif 00031 #ifdef HAVE_SYS_SOCKET_H 00032 #include <sys/socket.h> 00033 #endif 00034 #ifdef HAVE_NETINET_IN_H 00035 #include <netinet/in.h> 00036 #endif 00037 #ifdef HAVE_ARPA_INET_H 00038 #include <arpa/inet.h> 00039 #endif 00040 #ifdef HAVE_NETDB_H 00041 #include <netdb.h> 00042 #endif 00043 #ifdef HAVE_FCNTL_H 00044 #include <fcntl.h> 00045 #endif 00046 #ifdef HAVE_ERRNO_H 00047 #include <errno.h> 00048 #endif 00049 #ifdef HAVE_SYS_TIME_H 00050 #include <sys/time.h> 00051 #endif 00052 #ifdef HAVE_SYS_SELECT_H 00053 #include <sys/select.h> 00054 #endif 00055 #ifdef HAVE_SYS_SOCKET_H 00056 #include <sys/socket.h> 00057 #endif 00058 #ifdef HAVE_SYS_TYPES_H 00059 #include <sys/types.h> 00060 #endif 00061 #ifdef HAVE_STRINGS_H 00062 #include <strings.h> 00063 #endif 00064 00065 #include <libxml/xmlmemory.h> 00066 #include <libxml/parser.h> 00067 #include <libxml/xmlerror.h> 00068 #include <libxml/uri.h> 00069 #include <libxml/nanoftp.h> 00070 #include <libxml/globals.h> 00071 00072 /* #define DEBUG_FTP 1 */ 00073 #ifdef STANDALONE 00074 #ifndef DEBUG_FTP 00075 #define DEBUG_FTP 1 00076 #endif 00077 #endif 00078 00079 00080 #if defined(__MINGW32__) || defined(_WIN32_WCE) 00081 #ifndef _WINSOCKAPI_ 00082 #define _WINSOCKAPI_ 00083 #endif 00084 #include <wsockcompat.h> 00085 #include <winsock2.h> 00086 #undef XML_SOCKLEN_T 00087 #define XML_SOCKLEN_T unsigned int 00088 #endif 00089 00093 #ifndef _WINSOCKAPI_ 00094 #if !defined(__BEOS__) || defined(__HAIKU__) 00095 #define closesocket(s) close(s) 00096 #endif 00097 #endif 00098 00099 #ifdef __BEOS__ 00100 #ifndef PF_INET 00101 #define PF_INET AF_INET 00102 #endif 00103 #endif 00104 00105 #ifdef _AIX 00106 #ifdef HAVE_BROKEN_SS_FAMILY 00107 #define ss_family __ss_family 00108 #endif 00109 #endif 00110 00111 #ifndef XML_SOCKLEN_T 00112 #define XML_SOCKLEN_T unsigned int 00113 #endif 00114 00115 #define FTP_COMMAND_OK 200 00116 #define FTP_SYNTAX_ERROR 500 00117 #define FTP_GET_PASSWD 331 00118 #define FTP_BUF_SIZE 1024 00119 00120 #define XML_NANO_MAX_URLBUF 4096 00121 00122 typedef struct xmlNanoFTPCtxt { 00123 char *protocol; /* the protocol name */ 00124 char *hostname; /* the host name */ 00125 int port; /* the port */ 00126 char *path; /* the path within the URL */ 00127 char *user; /* user string */ 00128 char *passwd; /* passwd string */ 00129 #ifdef SUPPORT_IP6 00130 struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/ 00131 #else 00132 struct sockaddr_in ftpAddr; /* the socket address struct */ 00133 #endif 00134 int passive; /* currently we support only passive !!! */ 00135 SOCKET controlFd; /* the file descriptor for the control socket */ 00136 SOCKET dataFd; /* the file descriptor for the data socket */ 00137 int state; /* WRITE / READ / CLOSED */ 00138 int returnValue; /* the protocol return value */ 00139 /* buffer for data received from the control connection */ 00140 char controlBuf[FTP_BUF_SIZE + 1]; 00141 int controlBufIndex; 00142 int controlBufUsed; 00143 int controlBufAnswer; 00144 } xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr; 00145 00146 static int initialized = 0; 00147 static char *proxy = NULL; /* the proxy name if any */ 00148 static int proxyPort = 0; /* the proxy port if any */ 00149 static char *proxyUser = NULL; /* user for proxy authentication */ 00150 static char *proxyPasswd = NULL;/* passwd for proxy authentication */ 00151 static int proxyType = 0; /* uses TYPE or a@b ? */ 00152 00153 #ifdef SUPPORT_IP6 00154 static 00155 int have_ipv6(void) { 00156 int s; 00157 00158 s = socket (AF_INET6, SOCK_STREAM, 0); 00159 if (s != -1) { 00160 close (s); 00161 return (1); 00162 } 00163 return (0); 00164 } 00165 #endif 00166 00173 static void 00174 xmlFTPErrMemory(const char *extra) 00175 { 00176 __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra); 00177 } 00178 00187 void 00188 xmlNanoFTPInit(void) { 00189 const char *env; 00190 #ifdef _WINSOCKAPI_ 00191 WSADATA wsaData; 00192 #endif 00193 00194 if (initialized) 00195 return; 00196 00197 #ifdef _WINSOCKAPI_ 00198 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) 00199 return; 00200 #endif 00201 00202 proxyPort = 21; 00203 env = getenv("no_proxy"); 00204 if (env && ((env[0] == '*' ) && (env[1] == 0))) 00205 return; 00206 env = getenv("ftp_proxy"); 00207 if (env != NULL) { 00208 xmlNanoFTPScanProxy(env); 00209 } else { 00210 env = getenv("FTP_PROXY"); 00211 if (env != NULL) { 00212 xmlNanoFTPScanProxy(env); 00213 } 00214 } 00215 env = getenv("ftp_proxy_user"); 00216 if (env != NULL) { 00217 proxyUser = xmlMemStrdup(env); 00218 } 00219 env = getenv("ftp_proxy_password"); 00220 if (env != NULL) { 00221 proxyPasswd = xmlMemStrdup(env); 00222 } 00223 initialized = 1; 00224 } 00225 00232 void 00233 xmlNanoFTPCleanup(void) { 00234 if (proxy != NULL) { 00235 xmlFree(proxy); 00236 proxy = NULL; 00237 } 00238 if (proxyUser != NULL) { 00239 xmlFree(proxyUser); 00240 proxyUser = NULL; 00241 } 00242 if (proxyPasswd != NULL) { 00243 xmlFree(proxyPasswd); 00244 proxyPasswd = NULL; 00245 } 00246 #ifdef _WINSOCKAPI_ 00247 if (initialized) 00248 WSACleanup(); 00249 #endif 00250 initialized = 0; 00251 } 00252 00266 void 00267 xmlNanoFTPProxy(const char *host, int port, const char *user, 00268 const char *passwd, int type) { 00269 if (proxy != NULL) { 00270 xmlFree(proxy); 00271 proxy = NULL; 00272 } 00273 if (proxyUser != NULL) { 00274 xmlFree(proxyUser); 00275 proxyUser = NULL; 00276 } 00277 if (proxyPasswd != NULL) { 00278 xmlFree(proxyPasswd); 00279 proxyPasswd = NULL; 00280 } 00281 if (host) 00282 proxy = xmlMemStrdup(host); 00283 if (user) 00284 proxyUser = xmlMemStrdup(user); 00285 if (passwd) 00286 proxyPasswd = xmlMemStrdup(passwd); 00287 proxyPort = port; 00288 proxyType = type; 00289 } 00290 00300 static void 00301 xmlNanoFTPScanURL(void *ctx, const char *URL) { 00302 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00303 xmlURIPtr uri; 00304 00305 /* 00306 * Clear any existing data from the context 00307 */ 00308 if (ctxt->protocol != NULL) { 00309 xmlFree(ctxt->protocol); 00310 ctxt->protocol = NULL; 00311 } 00312 if (ctxt->hostname != NULL) { 00313 xmlFree(ctxt->hostname); 00314 ctxt->hostname = NULL; 00315 } 00316 if (ctxt->path != NULL) { 00317 xmlFree(ctxt->path); 00318 ctxt->path = NULL; 00319 } 00320 if (URL == NULL) return; 00321 00322 uri = xmlParseURIRaw(URL, 1); 00323 if (uri == NULL) 00324 return; 00325 00326 if ((uri->scheme == NULL) || (uri->server == NULL)) { 00327 xmlFreeURI(uri); 00328 return; 00329 } 00330 00331 ctxt->protocol = xmlMemStrdup(uri->scheme); 00332 ctxt->hostname = xmlMemStrdup(uri->server); 00333 if (uri->path != NULL) 00334 ctxt->path = xmlMemStrdup(uri->path); 00335 else 00336 ctxt->path = xmlMemStrdup("/"); 00337 if (uri->port != 0) 00338 ctxt->port = uri->port; 00339 00340 if (uri->user != NULL) { 00341 char *cptr; 00342 if ((cptr=strchr(uri->user, ':')) == NULL) 00343 ctxt->user = xmlMemStrdup(uri->user); 00344 else { 00345 ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user, 00346 (cptr - uri->user)); 00347 ctxt->passwd = xmlMemStrdup(cptr+1); 00348 } 00349 } 00350 00351 xmlFreeURI(uri); 00352 00353 } 00354 00369 int 00370 xmlNanoFTPUpdateURL(void *ctx, const char *URL) { 00371 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00372 xmlURIPtr uri; 00373 00374 if (URL == NULL) 00375 return(-1); 00376 if (ctxt == NULL) 00377 return(-1); 00378 if (ctxt->protocol == NULL) 00379 return(-1); 00380 if (ctxt->hostname == NULL) 00381 return(-1); 00382 00383 uri = xmlParseURIRaw(URL, 1); 00384 if (uri == NULL) 00385 return(-1); 00386 00387 if ((uri->scheme == NULL) || (uri->server == NULL)) { 00388 xmlFreeURI(uri); 00389 return(-1); 00390 } 00391 if ((strcmp(ctxt->protocol, uri->scheme)) || 00392 (strcmp(ctxt->hostname, uri->server)) || 00393 ((uri->port != 0) && (ctxt->port != uri->port))) { 00394 xmlFreeURI(uri); 00395 return(-1); 00396 } 00397 00398 if (uri->port != 0) 00399 ctxt->port = uri->port; 00400 00401 if (ctxt->path != NULL) { 00402 xmlFree(ctxt->path); 00403 ctxt->path = NULL; 00404 } 00405 00406 if (uri->path == NULL) 00407 ctxt->path = xmlMemStrdup("/"); 00408 else 00409 ctxt->path = xmlMemStrdup(uri->path); 00410 00411 xmlFreeURI(uri); 00412 00413 return(0); 00414 } 00415 00426 void 00427 xmlNanoFTPScanProxy(const char *URL) { 00428 xmlURIPtr uri; 00429 00430 if (proxy != NULL) { 00431 xmlFree(proxy); 00432 proxy = NULL; 00433 } 00434 proxyPort = 0; 00435 00436 #ifdef DEBUG_FTP 00437 if (URL == NULL) 00438 xmlGenericError(xmlGenericErrorContext, 00439 "Removing FTP proxy info\n"); 00440 else 00441 xmlGenericError(xmlGenericErrorContext, 00442 "Using FTP proxy %s\n", URL); 00443 #endif 00444 if (URL == NULL) return; 00445 00446 uri = xmlParseURIRaw(URL, 1); 00447 if ((uri == NULL) || (uri->scheme == NULL) || 00448 (strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) { 00449 __xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n"); 00450 if (uri != NULL) 00451 xmlFreeURI(uri); 00452 return; 00453 } 00454 00455 proxy = xmlMemStrdup(uri->server); 00456 if (uri->port != 0) 00457 proxyPort = uri->port; 00458 00459 xmlFreeURI(uri); 00460 } 00461 00471 void* 00472 xmlNanoFTPNewCtxt(const char *URL) { 00473 xmlNanoFTPCtxtPtr ret; 00474 char *unescaped; 00475 00476 ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt)); 00477 if (ret == NULL) { 00478 xmlFTPErrMemory("allocating FTP context"); 00479 return(NULL); 00480 } 00481 00482 memset(ret, 0, sizeof(xmlNanoFTPCtxt)); 00483 ret->port = 21; 00484 ret->passive = 1; 00485 ret->returnValue = 0; 00486 ret->controlBufIndex = 0; 00487 ret->controlBufUsed = 0; 00488 ret->controlFd = INVALID_SOCKET; 00489 00490 unescaped = xmlURIUnescapeString(URL, 0, NULL); 00491 if (unescaped != NULL) { 00492 xmlNanoFTPScanURL(ret, unescaped); 00493 xmlFree(unescaped); 00494 } else if (URL != NULL) 00495 xmlNanoFTPScanURL(ret, URL); 00496 00497 return(ret); 00498 } 00499 00507 void 00508 xmlNanoFTPFreeCtxt(void * ctx) { 00509 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00510 if (ctxt == NULL) return; 00511 if (ctxt->hostname != NULL) xmlFree(ctxt->hostname); 00512 if (ctxt->protocol != NULL) xmlFree(ctxt->protocol); 00513 if (ctxt->path != NULL) xmlFree(ctxt->path); 00514 ctxt->passive = 1; 00515 if (ctxt->controlFd != INVALID_SOCKET) closesocket(ctxt->controlFd); 00516 ctxt->controlFd = INVALID_SOCKET; 00517 ctxt->controlBufIndex = -1; 00518 ctxt->controlBufUsed = -1; 00519 xmlFree(ctxt); 00520 } 00521 00533 static int 00534 xmlNanoFTPParseResponse(char *buf, int len) { 00535 int val = 0; 00536 00537 if (len < 3) return(-1); 00538 if ((*buf >= '0') && (*buf <= '9')) 00539 val = val * 10 + (*buf - '0'); 00540 else 00541 return(0); 00542 buf++; 00543 if ((*buf >= '0') && (*buf <= '9')) 00544 val = val * 10 + (*buf - '0'); 00545 else 00546 return(0); 00547 buf++; 00548 if ((*buf >= '0') && (*buf <= '9')) 00549 val = val * 10 + (*buf - '0'); 00550 else 00551 return(0); 00552 buf++; 00553 if (*buf == '-') 00554 return(-val); 00555 return(val); 00556 } 00557 00565 static int 00566 xmlNanoFTPGetMore(void *ctx) { 00567 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00568 int len; 00569 int size; 00570 00571 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); 00572 00573 if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) { 00574 #ifdef DEBUG_FTP 00575 xmlGenericError(xmlGenericErrorContext, 00576 "xmlNanoFTPGetMore : controlBufIndex = %d\n", 00577 ctxt->controlBufIndex); 00578 #endif 00579 return(-1); 00580 } 00581 00582 if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) { 00583 #ifdef DEBUG_FTP 00584 xmlGenericError(xmlGenericErrorContext, 00585 "xmlNanoFTPGetMore : controlBufUsed = %d\n", 00586 ctxt->controlBufUsed); 00587 #endif 00588 return(-1); 00589 } 00590 if (ctxt->controlBufIndex > ctxt->controlBufUsed) { 00591 #ifdef DEBUG_FTP 00592 xmlGenericError(xmlGenericErrorContext, 00593 "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n", 00594 ctxt->controlBufIndex, ctxt->controlBufUsed); 00595 #endif 00596 return(-1); 00597 } 00598 00599 /* 00600 * First pack the control buffer 00601 */ 00602 if (ctxt->controlBufIndex > 0) { 00603 memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex], 00604 ctxt->controlBufUsed - ctxt->controlBufIndex); 00605 ctxt->controlBufUsed -= ctxt->controlBufIndex; 00606 ctxt->controlBufIndex = 0; 00607 } 00608 size = FTP_BUF_SIZE - ctxt->controlBufUsed; 00609 if (size == 0) { 00610 #ifdef DEBUG_FTP 00611 xmlGenericError(xmlGenericErrorContext, 00612 "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed); 00613 #endif 00614 return(0); 00615 } 00616 00617 /* 00618 * Read the amount left on the control connection 00619 */ 00620 if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex], 00621 size, 0)) < 0) { 00622 __xmlIOErr(XML_FROM_FTP, 0, "recv failed"); 00623 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 00624 ctxt->controlFd = INVALID_SOCKET; 00625 return(-1); 00626 } 00627 #ifdef DEBUG_FTP 00628 xmlGenericError(xmlGenericErrorContext, 00629 "xmlNanoFTPGetMore : read %d [%d - %d]\n", len, 00630 ctxt->controlBufUsed, ctxt->controlBufUsed + len); 00631 #endif 00632 ctxt->controlBufUsed += len; 00633 ctxt->controlBuf[ctxt->controlBufUsed] = 0; 00634 00635 return(len); 00636 } 00637 00645 static int 00646 xmlNanoFTPReadResponse(void *ctx) { 00647 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00648 char *ptr, *end; 00649 int len; 00650 int res = -1, cur = -1; 00651 00652 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); 00653 00654 get_more: 00655 /* 00656 * Assumes everything up to controlBuf[controlBufIndex] has been read 00657 * and analyzed. 00658 */ 00659 len = xmlNanoFTPGetMore(ctx); 00660 if (len < 0) { 00661 return(-1); 00662 } 00663 if ((ctxt->controlBufUsed == 0) && (len == 0)) { 00664 return(-1); 00665 } 00666 ptr = &ctxt->controlBuf[ctxt->controlBufIndex]; 00667 end = &ctxt->controlBuf[ctxt->controlBufUsed]; 00668 00669 #ifdef DEBUG_FTP 00670 xmlGenericError(xmlGenericErrorContext, 00671 "\n<<<\n%s\n--\n", ptr); 00672 #endif 00673 while (ptr < end) { 00674 cur = xmlNanoFTPParseResponse(ptr, end - ptr); 00675 if (cur > 0) { 00676 /* 00677 * Successfully scanned the control code, scratch 00678 * till the end of the line, but keep the index to be 00679 * able to analyze the result if needed. 00680 */ 00681 res = cur; 00682 ptr += 3; 00683 ctxt->controlBufAnswer = ptr - ctxt->controlBuf; 00684 while ((ptr < end) && (*ptr != '\n')) ptr++; 00685 if (*ptr == '\n') ptr++; 00686 if (*ptr == '\r') ptr++; 00687 break; 00688 } 00689 while ((ptr < end) && (*ptr != '\n')) ptr++; 00690 if (ptr >= end) { 00691 ctxt->controlBufIndex = ctxt->controlBufUsed; 00692 goto get_more; 00693 } 00694 if (*ptr != '\r') ptr++; 00695 } 00696 00697 if (res < 0) goto get_more; 00698 ctxt->controlBufIndex = ptr - ctxt->controlBuf; 00699 #ifdef DEBUG_FTP 00700 ptr = &ctxt->controlBuf[ctxt->controlBufIndex]; 00701 xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr); 00702 #endif 00703 00704 #ifdef DEBUG_FTP 00705 xmlGenericError(xmlGenericErrorContext, "Got %d\n", res); 00706 #endif 00707 return(res / 100); 00708 } 00709 00718 int 00719 xmlNanoFTPGetResponse(void *ctx) { 00720 int res; 00721 00722 res = xmlNanoFTPReadResponse(ctx); 00723 00724 return(res); 00725 } 00726 00735 int 00736 xmlNanoFTPCheckResponse(void *ctx) { 00737 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00738 fd_set rfd; 00739 struct timeval tv; 00740 00741 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); 00742 tv.tv_sec = 0; 00743 tv.tv_usec = 0; 00744 FD_ZERO(&rfd); 00745 FD_SET(ctxt->controlFd, &rfd); 00746 switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) { 00747 case 0: 00748 return(0); 00749 case -1: 00750 __xmlIOErr(XML_FROM_FTP, 0, "select"); 00751 return(-1); 00752 00753 } 00754 00755 return(xmlNanoFTPReadResponse(ctx)); 00756 } 00757 00762 static int 00763 xmlNanoFTPSendUser(void *ctx) { 00764 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00765 char buf[200]; 00766 int len; 00767 int res; 00768 00769 if (ctxt->user == NULL) 00770 snprintf(buf, sizeof(buf), "USER anonymous\r\n"); 00771 else 00772 snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user); 00773 buf[sizeof(buf) - 1] = 0; 00774 len = strlen(buf); 00775 #ifdef DEBUG_FTP 00776 xmlGenericError(xmlGenericErrorContext, "%s", buf); 00777 #endif 00778 res = send(ctxt->controlFd, buf, len, 0); 00779 if (res < 0) { 00780 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 00781 return(res); 00782 } 00783 return(0); 00784 } 00785 00790 static int 00791 xmlNanoFTPSendPasswd(void *ctx) { 00792 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00793 char buf[200]; 00794 int len; 00795 int res; 00796 00797 if (ctxt->passwd == NULL) 00798 snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); 00799 else 00800 snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); 00801 buf[sizeof(buf) - 1] = 0; 00802 len = strlen(buf); 00803 #ifdef DEBUG_FTP 00804 xmlGenericError(xmlGenericErrorContext, "%s", buf); 00805 #endif 00806 res = send(ctxt->controlFd, buf, len, 0); 00807 if (res < 0) { 00808 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 00809 return(res); 00810 } 00811 return(0); 00812 } 00813 00824 int 00825 xmlNanoFTPQuit(void *ctx) { 00826 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00827 char buf[200]; 00828 int len, res; 00829 00830 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); 00831 00832 snprintf(buf, sizeof(buf), "QUIT\r\n"); 00833 len = strlen(buf); 00834 #ifdef DEBUG_FTP 00835 xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */ 00836 #endif 00837 res = send(ctxt->controlFd, buf, len, 0); 00838 if (res < 0) { 00839 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 00840 return(res); 00841 } 00842 return(0); 00843 } 00844 00854 int 00855 xmlNanoFTPConnect(void *ctx) { 00856 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 00857 struct hostent *hp; 00858 int port; 00859 int res; 00860 int addrlen = sizeof (struct sockaddr_in); 00861 00862 if (ctxt == NULL) 00863 return(-1); 00864 if (ctxt->hostname == NULL) 00865 return(-1); 00866 00867 /* 00868 * do the blocking DNS query. 00869 */ 00870 if (proxy) { 00871 port = proxyPort; 00872 } else { 00873 port = ctxt->port; 00874 } 00875 if (port == 0) 00876 port = 21; 00877 00878 memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr)); 00879 00880 #ifdef SUPPORT_IP6 00881 if (have_ipv6 ()) { 00882 struct addrinfo hints, *tmp, *result; 00883 00884 result = NULL; 00885 memset (&hints, 0, sizeof(hints)); 00886 hints.ai_socktype = SOCK_STREAM; 00887 00888 if (proxy) { 00889 if (getaddrinfo (proxy, NULL, &hints, &result) != 0) { 00890 __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed"); 00891 return (-1); 00892 } 00893 } 00894 else 00895 if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) { 00896 __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed"); 00897 return (-1); 00898 } 00899 00900 for (tmp = result; tmp; tmp = tmp->ai_next) 00901 if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6) 00902 break; 00903 00904 if (!tmp) { 00905 if (result) 00906 freeaddrinfo (result); 00907 __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed"); 00908 return (-1); 00909 } 00910 if (tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) { 00911 __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch"); 00912 return (-1); 00913 } 00914 if (tmp->ai_family == AF_INET6) { 00915 memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen); 00916 ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port); 00917 ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0); 00918 } 00919 else { 00920 memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen); 00921 ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port); 00922 ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0); 00923 } 00924 addrlen = tmp->ai_addrlen; 00925 freeaddrinfo (result); 00926 } 00927 else 00928 #endif 00929 { 00930 if (proxy) 00931 hp = gethostbyname (proxy); 00932 else 00933 hp = gethostbyname (ctxt->hostname); 00934 if (hp == NULL) { 00935 __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed"); 00936 return (-1); 00937 } 00938 if ((unsigned int) hp->h_length > 00939 sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) { 00940 __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch"); 00941 return (-1); 00942 } 00943 00944 /* 00945 * Prepare the socket 00946 */ 00947 ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET; 00948 memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr, 00949 hp->h_addr_list[0], hp->h_length); 00950 ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = (u_short)htons ((unsigned short)port); 00951 ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0); 00952 addrlen = sizeof (struct sockaddr_in); 00953 } 00954 00955 if (ctxt->controlFd == INVALID_SOCKET) { 00956 __xmlIOErr(XML_FROM_FTP, 0, "socket failed"); 00957 return(-1); 00958 } 00959 00960 /* 00961 * Do the connect. 00962 */ 00963 if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr, 00964 addrlen) < 0) { 00965 __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection"); 00966 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 00967 ctxt->controlFd = INVALID_SOCKET; 00968 return(-1); 00969 } 00970 00971 /* 00972 * Wait for the HELLO from the server. 00973 */ 00974 res = xmlNanoFTPGetResponse(ctxt); 00975 if (res != 2) { 00976 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 00977 ctxt->controlFd = INVALID_SOCKET; 00978 return(-1); 00979 } 00980 00981 /* 00982 * State diagram for the login operation on the FTP server 00983 * 00984 * Reference: RFC 959 00985 * 00986 * 1 00987 * +---+ USER +---+------------->+---+ 00988 * | B |---------->| W | 2 ---->| E | 00989 * +---+ +---+------ | -->+---+ 00990 * | | | | | 00991 * 3 | | 4,5 | | | 00992 * -------------- ----- | | | 00993 * | | | | | 00994 * | | | | | 00995 * | --------- | 00996 * | 1| | | | 00997 * V | | | | 00998 * +---+ PASS +---+ 2 | ------>+---+ 00999 * | |---------->| W |------------->| S | 01000 * +---+ +---+ ---------->+---+ 01001 * | | | | | 01002 * 3 | |4,5| | | 01003 * -------------- -------- | 01004 * | | | | | 01005 * | | | | | 01006 * | ----------- 01007 * | 1,3| | | | 01008 * V | 2| | | 01009 * +---+ ACCT +---+-- | ----->+---+ 01010 * | |---------->| W | 4,5 -------->| F | 01011 * +---+ +---+------------->+---+ 01012 * 01013 * Of course in case of using a proxy this get really nasty and is not 01014 * standardized at all :-( 01015 */ 01016 if (proxy) { 01017 int len; 01018 char buf[400]; 01019 01020 if (proxyUser != NULL) { 01021 /* 01022 * We need proxy auth 01023 */ 01024 snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser); 01025 buf[sizeof(buf) - 1] = 0; 01026 len = strlen(buf); 01027 #ifdef DEBUG_FTP 01028 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01029 #endif 01030 res = send(ctxt->controlFd, buf, len, 0); 01031 if (res < 0) { 01032 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01033 closesocket(ctxt->controlFd); 01034 ctxt->controlFd = INVALID_SOCKET; 01035 return(res); 01036 } 01037 res = xmlNanoFTPGetResponse(ctxt); 01038 switch (res) { 01039 case 2: 01040 if (proxyPasswd == NULL) 01041 break; 01042 case 3: 01043 if (proxyPasswd != NULL) 01044 snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd); 01045 else 01046 snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); 01047 buf[sizeof(buf) - 1] = 0; 01048 len = strlen(buf); 01049 #ifdef DEBUG_FTP 01050 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01051 #endif 01052 res = send(ctxt->controlFd, buf, len, 0); 01053 if (res < 0) { 01054 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01055 closesocket(ctxt->controlFd); 01056 ctxt->controlFd = INVALID_SOCKET; 01057 return(res); 01058 } 01059 res = xmlNanoFTPGetResponse(ctxt); 01060 if (res > 3) { 01061 closesocket(ctxt->controlFd); 01062 ctxt->controlFd = INVALID_SOCKET; 01063 return(-1); 01064 } 01065 break; 01066 case 1: 01067 break; 01068 case 4: 01069 case 5: 01070 case -1: 01071 default: 01072 closesocket(ctxt->controlFd); 01073 ctxt->controlFd = INVALID_SOCKET; 01074 return(-1); 01075 } 01076 } 01077 01078 /* 01079 * We assume we don't need more authentication to the proxy 01080 * and that it succeeded :-\ 01081 */ 01082 switch (proxyType) { 01083 case 0: 01084 /* we will try in sequence */ 01085 case 1: 01086 /* Using SITE command */ 01087 snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname); 01088 buf[sizeof(buf) - 1] = 0; 01089 len = strlen(buf); 01090 #ifdef DEBUG_FTP 01091 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01092 #endif 01093 res = send(ctxt->controlFd, buf, len, 0); 01094 if (res < 0) { 01095 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01096 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01097 ctxt->controlFd = INVALID_SOCKET; 01098 return(res); 01099 } 01100 res = xmlNanoFTPGetResponse(ctxt); 01101 if (res == 2) { 01102 /* we assume it worked :-\ 1 is error for SITE command */ 01103 proxyType = 1; 01104 break; 01105 } 01106 if (proxyType == 1) { 01107 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01108 ctxt->controlFd = INVALID_SOCKET; 01109 return(-1); 01110 } 01111 case 2: 01112 /* USER user@host command */ 01113 if (ctxt->user == NULL) 01114 snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n", 01115 ctxt->hostname); 01116 else 01117 snprintf(buf, sizeof(buf), "USER %s@%s\r\n", 01118 ctxt->user, ctxt->hostname); 01119 buf[sizeof(buf) - 1] = 0; 01120 len = strlen(buf); 01121 #ifdef DEBUG_FTP 01122 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01123 #endif 01124 res = send(ctxt->controlFd, buf, len, 0); 01125 if (res < 0) { 01126 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01127 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01128 ctxt->controlFd = INVALID_SOCKET; 01129 return(res); 01130 } 01131 res = xmlNanoFTPGetResponse(ctxt); 01132 if ((res == 1) || (res == 2)) { 01133 /* we assume it worked :-\ */ 01134 proxyType = 2; 01135 return(0); 01136 } 01137 if (ctxt->passwd == NULL) 01138 snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); 01139 else 01140 snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); 01141 buf[sizeof(buf) - 1] = 0; 01142 len = strlen(buf); 01143 #ifdef DEBUG_FTP 01144 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01145 #endif 01146 res = send(ctxt->controlFd, buf, len, 0); 01147 if (res < 0) { 01148 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01149 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01150 ctxt->controlFd = INVALID_SOCKET; 01151 return(res); 01152 } 01153 res = xmlNanoFTPGetResponse(ctxt); 01154 if ((res == 1) || (res == 2)) { 01155 /* we assume it worked :-\ */ 01156 proxyType = 2; 01157 return(0); 01158 } 01159 if (proxyType == 2) { 01160 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01161 ctxt->controlFd = INVALID_SOCKET; 01162 return(-1); 01163 } 01164 case 3: 01165 /* 01166 * If you need support for other Proxy authentication scheme 01167 * send the code or at least the sequence in use. 01168 */ 01169 default: 01170 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01171 ctxt->controlFd = INVALID_SOCKET; 01172 return(-1); 01173 } 01174 } 01175 /* 01176 * Non-proxy handling. 01177 */ 01178 res = xmlNanoFTPSendUser(ctxt); 01179 if (res < 0) { 01180 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01181 ctxt->controlFd = INVALID_SOCKET; 01182 return(-1); 01183 } 01184 res = xmlNanoFTPGetResponse(ctxt); 01185 switch (res) { 01186 case 2: 01187 return(0); 01188 case 3: 01189 break; 01190 case 1: 01191 case 4: 01192 case 5: 01193 case -1: 01194 default: 01195 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01196 ctxt->controlFd = INVALID_SOCKET; 01197 return(-1); 01198 } 01199 res = xmlNanoFTPSendPasswd(ctxt); 01200 if (res < 0) { 01201 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01202 ctxt->controlFd = INVALID_SOCKET; 01203 return(-1); 01204 } 01205 res = xmlNanoFTPGetResponse(ctxt); 01206 switch (res) { 01207 case 2: 01208 break; 01209 case 3: 01210 __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT, 01211 "FTP server asking for ACCNT on anonymous\n"); 01212 case 1: 01213 case 4: 01214 case 5: 01215 case -1: 01216 default: 01217 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01218 ctxt->controlFd = INVALID_SOCKET; 01219 return(-1); 01220 } 01221 01222 return(0); 01223 } 01224 01235 void* 01236 xmlNanoFTPConnectTo(const char *server, int port) { 01237 xmlNanoFTPCtxtPtr ctxt; 01238 int res; 01239 01240 xmlNanoFTPInit(); 01241 if (server == NULL) 01242 return(NULL); 01243 if (port <= 0) 01244 return(NULL); 01245 ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL); 01246 ctxt->hostname = xmlMemStrdup(server); 01247 if (port != 0) 01248 ctxt->port = port; 01249 res = xmlNanoFTPConnect(ctxt); 01250 if (res < 0) { 01251 xmlNanoFTPFreeCtxt(ctxt); 01252 return(NULL); 01253 } 01254 return(ctxt); 01255 } 01256 01267 int 01268 xmlNanoFTPCwd(void *ctx, const char *directory) { 01269 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01270 char buf[400]; 01271 int len; 01272 int res; 01273 01274 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); 01275 if (directory == NULL) return 0; 01276 01277 /* 01278 * Expected response code for CWD: 01279 * 01280 * CWD 01281 * 250 01282 * 500, 501, 502, 421, 530, 550 01283 */ 01284 snprintf(buf, sizeof(buf), "CWD %s\r\n", directory); 01285 buf[sizeof(buf) - 1] = 0; 01286 len = strlen(buf); 01287 #ifdef DEBUG_FTP 01288 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01289 #endif 01290 res = send(ctxt->controlFd, buf, len, 0); 01291 if (res < 0) { 01292 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01293 return(res); 01294 } 01295 res = xmlNanoFTPGetResponse(ctxt); 01296 if (res == 4) { 01297 return(-1); 01298 } 01299 if (res == 2) return(1); 01300 if (res == 5) { 01301 return(0); 01302 } 01303 return(0); 01304 } 01305 01316 int 01317 xmlNanoFTPDele(void *ctx, const char *file) { 01318 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01319 char buf[400]; 01320 int len; 01321 int res; 01322 01323 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET) || (file == NULL)) return(-1); 01324 if (file == NULL) return (0); 01325 01326 /* 01327 * Expected response code for DELE: 01328 * 01329 * DELE 01330 * 250 01331 * 450, 550 01332 * 500, 501, 502, 421, 530 01333 */ 01334 01335 snprintf(buf, sizeof(buf), "DELE %s\r\n", file); 01336 buf[sizeof(buf) - 1] = 0; 01337 len = strlen(buf); 01338 #ifdef DEBUG_FTP 01339 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01340 #endif 01341 res = send(ctxt->controlFd, buf, len, 0); 01342 if (res < 0) { 01343 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01344 return(res); 01345 } 01346 res = xmlNanoFTPGetResponse(ctxt); 01347 if (res == 4) { 01348 return(-1); 01349 } 01350 if (res == 2) return(1); 01351 if (res == 5) { 01352 return(0); 01353 } 01354 return(0); 01355 } 01366 SOCKET 01367 xmlNanoFTPGetConnection(void *ctx) { 01368 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01369 char buf[200], *cur; 01370 int len, i; 01371 int res; 01372 unsigned char ad[6], *adp, *portp; 01373 unsigned int temp[6]; 01374 #ifdef SUPPORT_IP6 01375 struct sockaddr_storage dataAddr; 01376 #else 01377 struct sockaddr_in dataAddr; 01378 #endif 01379 XML_SOCKLEN_T dataAddrLen; 01380 01381 if (ctxt == NULL) return INVALID_SOCKET; 01382 01383 memset (&dataAddr, 0, sizeof(dataAddr)); 01384 #ifdef SUPPORT_IP6 01385 if ((ctxt->ftpAddr).ss_family == AF_INET6) { 01386 ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP); 01387 ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6; 01388 dataAddrLen = sizeof(struct sockaddr_in6); 01389 } else 01390 #endif 01391 { 01392 ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 01393 ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET; 01394 dataAddrLen = sizeof (struct sockaddr_in); 01395 } 01396 01397 if (ctxt->dataFd == INVALID_SOCKET) { 01398 __xmlIOErr(XML_FROM_FTP, 0, "socket failed"); 01399 return INVALID_SOCKET; 01400 } 01401 01402 if (ctxt->passive) { 01403 #ifdef SUPPORT_IP6 01404 if ((ctxt->ftpAddr).ss_family == AF_INET6) 01405 snprintf (buf, sizeof(buf), "EPSV\r\n"); 01406 else 01407 #endif 01408 snprintf (buf, sizeof(buf), "PASV\r\n"); 01409 len = strlen (buf); 01410 #ifdef DEBUG_FTP 01411 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01412 #endif 01413 res = send(ctxt->controlFd, buf, len, 0); 01414 if (res < 0) { 01415 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01416 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01417 return INVALID_SOCKET; 01418 } 01419 res = xmlNanoFTPReadResponse(ctx); 01420 if (res != 2) { 01421 if (res == 5) { 01422 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01423 return INVALID_SOCKET; 01424 } else { 01425 /* 01426 * retry with an active connection 01427 */ 01428 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01429 ctxt->passive = 0; 01430 } 01431 } 01432 cur = &ctxt->controlBuf[ctxt->controlBufAnswer]; 01433 while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++; 01434 #ifdef SUPPORT_IP6 01435 if ((ctxt->ftpAddr).ss_family == AF_INET6) { 01436 if (sscanf (cur, "%u", &temp[0]) != 1) { 01437 __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER, 01438 "Invalid answer to EPSV\n"); 01439 if (ctxt->dataFd != INVALID_SOCKET) { 01440 closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01441 } 01442 return INVALID_SOCKET; 01443 } 01444 memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr)); 01445 ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]); 01446 } 01447 else 01448 #endif 01449 { 01450 if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2], 01451 &temp[3], &temp[4], &temp[5]) != 6) { 01452 __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER, 01453 "Invalid answer to PASV\n"); 01454 if (ctxt->dataFd != INVALID_SOCKET) { 01455 closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01456 } 01457 return INVALID_SOCKET; 01458 } 01459 for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff); 01460 memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4); 01461 memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2); 01462 } 01463 01464 if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) { 01465 __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection"); 01466 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01467 return INVALID_SOCKET; 01468 } 01469 } else { 01470 getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen); 01471 #ifdef SUPPORT_IP6 01472 if ((ctxt->ftpAddr).ss_family == AF_INET6) 01473 ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0; 01474 else 01475 #endif 01476 ((struct sockaddr_in *)&dataAddr)->sin_port = 0; 01477 01478 if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) { 01479 __xmlIOErr(XML_FROM_FTP, 0, "bind failed"); 01480 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01481 return INVALID_SOCKET; 01482 } 01483 getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen); 01484 01485 if (listen(ctxt->dataFd, 1) < 0) { 01486 __xmlIOErr(XML_FROM_FTP, 0, "listen failed"); 01487 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01488 return INVALID_SOCKET; 01489 } 01490 #ifdef SUPPORT_IP6 01491 if ((ctxt->ftpAddr).ss_family == AF_INET6) { 01492 char buf6[INET6_ADDRSTRLEN]; 01493 inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr, 01494 buf6, INET6_ADDRSTRLEN); 01495 adp = (unsigned char *) buf6; 01496 portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port; 01497 snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp); 01498 } else 01499 #endif 01500 { 01501 adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr; 01502 portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port; 01503 snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n", 01504 adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff, 01505 portp[0] & 0xff, portp[1] & 0xff); 01506 } 01507 01508 buf[sizeof(buf) - 1] = 0; 01509 len = strlen(buf); 01510 #ifdef DEBUG_FTP 01511 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01512 #endif 01513 01514 res = send(ctxt->controlFd, buf, len, 0); 01515 if (res < 0) { 01516 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01517 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01518 return INVALID_SOCKET; 01519 } 01520 res = xmlNanoFTPGetResponse(ctxt); 01521 if (res != 2) { 01522 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01523 return INVALID_SOCKET; 01524 } 01525 } 01526 return(ctxt->dataFd); 01527 01528 } 01529 01539 int 01540 xmlNanoFTPCloseConnection(void *ctx) { 01541 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01542 int res; 01543 fd_set rfd, efd; 01544 struct timeval tv; 01545 01546 if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1); 01547 01548 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01549 tv.tv_sec = 15; 01550 tv.tv_usec = 0; 01551 FD_ZERO(&rfd); 01552 FD_SET(ctxt->controlFd, &rfd); 01553 FD_ZERO(&efd); 01554 FD_SET(ctxt->controlFd, &efd); 01555 res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv); 01556 if (res < 0) { 01557 #ifdef DEBUG_FTP 01558 perror("select"); 01559 #endif 01560 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01561 return(-1); 01562 } 01563 if (res == 0) { 01564 #ifdef DEBUG_FTP 01565 xmlGenericError(xmlGenericErrorContext, 01566 "xmlNanoFTPCloseConnection: timeout\n"); 01567 #endif 01568 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01569 } else { 01570 res = xmlNanoFTPGetResponse(ctxt); 01571 if (res != 2) { 01572 closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET; 01573 return(-1); 01574 } 01575 } 01576 return(0); 01577 } 01578 01590 static int 01591 xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) { 01592 const char *cur = list; 01593 char filename[151]; 01594 char attrib[11]; 01595 char owner[11]; 01596 char group[11]; 01597 char month[4]; 01598 int year = 0; 01599 int minute = 0; 01600 int hour = 0; 01601 int day = 0; 01602 unsigned long size = 0; 01603 int links = 0; 01604 int i; 01605 01606 if (!strncmp(cur, "total", 5)) { 01607 cur += 5; 01608 while (*cur == ' ') cur++; 01609 while ((*cur >= '0') && (*cur <= '9')) 01610 links = (links * 10) + (*cur++ - '0'); 01611 while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r')) 01612 cur++; 01613 return(cur - list); 01614 } else if (*list == '+') { 01615 return(0); 01616 } else { 01617 while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r')) 01618 cur++; 01619 if (*cur == 0) return(0); 01620 i = 0; 01621 while (*cur != ' ') { 01622 if (i < 10) 01623 attrib[i++] = *cur; 01624 cur++; 01625 if (*cur == 0) return(0); 01626 } 01627 attrib[10] = 0; 01628 while (*cur == ' ') cur++; 01629 if (*cur == 0) return(0); 01630 while ((*cur >= '0') && (*cur <= '9')) 01631 links = (links * 10) + (*cur++ - '0'); 01632 while (*cur == ' ') cur++; 01633 if (*cur == 0) return(0); 01634 i = 0; 01635 while (*cur != ' ') { 01636 if (i < 10) 01637 owner[i++] = *cur; 01638 cur++; 01639 if (*cur == 0) return(0); 01640 } 01641 owner[i] = 0; 01642 while (*cur == ' ') cur++; 01643 if (*cur == 0) return(0); 01644 i = 0; 01645 while (*cur != ' ') { 01646 if (i < 10) 01647 group[i++] = *cur; 01648 cur++; 01649 if (*cur == 0) return(0); 01650 } 01651 group[i] = 0; 01652 while (*cur == ' ') cur++; 01653 if (*cur == 0) return(0); 01654 while ((*cur >= '0') && (*cur <= '9')) 01655 size = (size * 10) + (*cur++ - '0'); 01656 while (*cur == ' ') cur++; 01657 if (*cur == 0) return(0); 01658 i = 0; 01659 while (*cur != ' ') { 01660 if (i < 3) 01661 month[i++] = *cur; 01662 cur++; 01663 if (*cur == 0) return(0); 01664 } 01665 month[i] = 0; 01666 while (*cur == ' ') cur++; 01667 if (*cur == 0) return(0); 01668 while ((*cur >= '0') && (*cur <= '9')) 01669 day = (day * 10) + (*cur++ - '0'); 01670 while (*cur == ' ') cur++; 01671 if (*cur == 0) return(0); 01672 if ((cur[1] == 0) || (cur[2] == 0)) return(0); 01673 if ((cur[1] == ':') || (cur[2] == ':')) { 01674 while ((*cur >= '0') && (*cur <= '9')) 01675 hour = (hour * 10) + (*cur++ - '0'); 01676 if (*cur == ':') cur++; 01677 while ((*cur >= '0') && (*cur <= '9')) 01678 minute = (minute * 10) + (*cur++ - '0'); 01679 } else { 01680 while ((*cur >= '0') && (*cur <= '9')) 01681 year = (year * 10) + (*cur++ - '0'); 01682 } 01683 while (*cur == ' ') cur++; 01684 if (*cur == 0) return(0); 01685 i = 0; 01686 while ((*cur != '\n') && (*cur != '\r')) { 01687 if (i < 150) 01688 filename[i++] = *cur; 01689 cur++; 01690 if (*cur == 0) return(0); 01691 } 01692 filename[i] = 0; 01693 if ((*cur != '\n') && (*cur != '\r')) 01694 return(0); 01695 while ((*cur == '\n') || (*cur == '\r')) 01696 cur++; 01697 } 01698 if (callback != NULL) { 01699 callback(userData, filename, attrib, owner, group, size, links, 01700 year, month, day, hour, minute); 01701 } 01702 return(cur - list); 01703 } 01704 01718 int 01719 xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, 01720 const char *filename) { 01721 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01722 char buf[4096 + 1]; 01723 int len, res; 01724 int indx = 0, base; 01725 fd_set rfd, efd; 01726 struct timeval tv; 01727 01728 if (ctxt == NULL) return (-1); 01729 if (filename == NULL) { 01730 if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1) 01731 return(-1); 01732 ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); 01733 if (ctxt->dataFd == INVALID_SOCKET) 01734 return(-1); 01735 snprintf(buf, sizeof(buf), "LIST -L\r\n"); 01736 } else { 01737 if (filename[0] != '/') { 01738 if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1) 01739 return(-1); 01740 } 01741 ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); 01742 if (ctxt->dataFd == INVALID_SOCKET) 01743 return(-1); 01744 snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename); 01745 } 01746 buf[sizeof(buf) - 1] = 0; 01747 len = strlen(buf); 01748 #ifdef DEBUG_FTP 01749 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01750 #endif 01751 res = send(ctxt->controlFd, buf, len, 0); 01752 if (res < 0) { 01753 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01754 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01755 return(res); 01756 } 01757 res = xmlNanoFTPReadResponse(ctxt); 01758 if (res != 1) { 01759 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01760 return(-res); 01761 } 01762 01763 do { 01764 tv.tv_sec = 1; 01765 tv.tv_usec = 0; 01766 FD_ZERO(&rfd); 01767 FD_SET(ctxt->dataFd, &rfd); 01768 FD_ZERO(&efd); 01769 FD_SET(ctxt->dataFd, &efd); 01770 res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv); 01771 if (res < 0) { 01772 #ifdef DEBUG_FTP 01773 perror("select"); 01774 #endif 01775 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01776 return(-1); 01777 } 01778 if (res == 0) { 01779 res = xmlNanoFTPCheckResponse(ctxt); 01780 if (res < 0) { 01781 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01782 ctxt->dataFd = INVALID_SOCKET; 01783 return(-1); 01784 } 01785 if (res == 2) { 01786 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01787 return(0); 01788 } 01789 01790 continue; 01791 } 01792 01793 if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) { 01794 __xmlIOErr(XML_FROM_FTP, 0, "recv"); 01795 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01796 ctxt->dataFd = INVALID_SOCKET; 01797 return(-1); 01798 } 01799 #ifdef DEBUG_FTP 01800 write(1, &buf[indx], len); 01801 #endif 01802 indx += len; 01803 buf[indx] = 0; 01804 base = 0; 01805 do { 01806 res = xmlNanoFTPParseList(&buf[base], callback, userData); 01807 base += res; 01808 } while (res > 0); 01809 01810 memmove(&buf[0], &buf[base], indx - base); 01811 indx -= base; 01812 } while (len != 0); 01813 xmlNanoFTPCloseConnection(ctxt); 01814 return(0); 01815 } 01816 01828 SOCKET 01829 xmlNanoFTPGetSocket(void *ctx, const char *filename) { 01830 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01831 char buf[300]; 01832 int res, len; 01833 if (ctx == NULL) 01834 return INVALID_SOCKET; 01835 if ((filename == NULL) && (ctxt->path == NULL)) 01836 return INVALID_SOCKET; 01837 ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); 01838 if (ctxt->dataFd == INVALID_SOCKET) 01839 return INVALID_SOCKET; 01840 01841 snprintf(buf, sizeof(buf), "TYPE I\r\n"); 01842 len = strlen(buf); 01843 #ifdef DEBUG_FTP 01844 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01845 #endif 01846 res = send(ctxt->controlFd, buf, len, 0); 01847 if (res < 0) { 01848 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01849 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01850 return INVALID_SOCKET; 01851 } 01852 res = xmlNanoFTPReadResponse(ctxt); 01853 if (res != 2) { 01854 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01855 return INVALID_SOCKET; 01856 } 01857 if (filename == NULL) 01858 snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path); 01859 else 01860 snprintf(buf, sizeof(buf), "RETR %s\r\n", filename); 01861 buf[sizeof(buf) - 1] = 0; 01862 len = strlen(buf); 01863 #ifdef DEBUG_FTP 01864 xmlGenericError(xmlGenericErrorContext, "%s", buf); 01865 #endif 01866 res = send(ctxt->controlFd, buf, len, 0); 01867 if (res < 0) { 01868 __xmlIOErr(XML_FROM_FTP, 0, "send failed"); 01869 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01870 return INVALID_SOCKET; 01871 } 01872 res = xmlNanoFTPReadResponse(ctxt); 01873 if (res != 1) { 01874 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01875 return INVALID_SOCKET; 01876 } 01877 return(ctxt->dataFd); 01878 } 01879 01893 int 01894 xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData, 01895 const char *filename) { 01896 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01897 char buf[4096]; 01898 int len = 0, res; 01899 fd_set rfd; 01900 struct timeval tv; 01901 01902 if (ctxt == NULL) return(-1); 01903 if ((filename == NULL) && (ctxt->path == NULL)) 01904 return(-1); 01905 if (callback == NULL) 01906 return(-1); 01907 if (xmlNanoFTPGetSocket(ctxt, filename) == INVALID_SOCKET) 01908 return(-1); 01909 01910 do { 01911 tv.tv_sec = 1; 01912 tv.tv_usec = 0; 01913 FD_ZERO(&rfd); 01914 FD_SET(ctxt->dataFd, &rfd); 01915 res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv); 01916 if (res < 0) { 01917 #ifdef DEBUG_FTP 01918 perror("select"); 01919 #endif 01920 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01921 return(-1); 01922 } 01923 if (res == 0) { 01924 res = xmlNanoFTPCheckResponse(ctxt); 01925 if (res < 0) { 01926 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01927 ctxt->dataFd = INVALID_SOCKET; 01928 return(-1); 01929 } 01930 if (res == 2) { 01931 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01932 return(0); 01933 } 01934 01935 continue; 01936 } 01937 if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) { 01938 __xmlIOErr(XML_FROM_FTP, 0, "recv failed"); 01939 callback(userData, buf, len); 01940 closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET; 01941 return(-1); 01942 } 01943 callback(userData, buf, len); 01944 } while (len != 0); 01945 01946 return(xmlNanoFTPCloseConnection(ctxt)); 01947 } 01948 01961 int 01962 xmlNanoFTPRead(void *ctx, void *dest, int len) { 01963 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 01964 01965 if (ctx == NULL) return(-1); 01966 if (ctxt->dataFd == INVALID_SOCKET) return(0); 01967 if (dest == NULL) return(-1); 01968 if (len <= 0) return(0); 01969 01970 len = recv(ctxt->dataFd, dest, len, 0); 01971 if (len <= 0) { 01972 if (len < 0) 01973 __xmlIOErr(XML_FROM_FTP, 0, "recv failed"); 01974 xmlNanoFTPCloseConnection(ctxt); 01975 } 01976 #ifdef DEBUG_FTP 01977 xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len); 01978 #endif 01979 return(len); 01980 } 01981 01991 void* 01992 xmlNanoFTPOpen(const char *URL) { 01993 xmlNanoFTPCtxtPtr ctxt; 01994 SOCKET sock; 01995 01996 xmlNanoFTPInit(); 01997 if (URL == NULL) return(NULL); 01998 if (strncmp("ftp://", URL, 6)) return(NULL); 01999 02000 ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL); 02001 if (ctxt == NULL) return(NULL); 02002 if (xmlNanoFTPConnect(ctxt) < 0) { 02003 xmlNanoFTPFreeCtxt(ctxt); 02004 return(NULL); 02005 } 02006 sock = xmlNanoFTPGetSocket(ctxt, ctxt->path); 02007 if (sock == INVALID_SOCKET) { 02008 xmlNanoFTPFreeCtxt(ctxt); 02009 return(NULL); 02010 } 02011 return(ctxt); 02012 } 02013 02023 int 02024 xmlNanoFTPClose(void *ctx) { 02025 xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; 02026 02027 if (ctxt == NULL) 02028 return(-1); 02029 02030 if (ctxt->dataFd != INVALID_SOCKET) { 02031 closesocket(ctxt->dataFd); 02032 ctxt->dataFd = INVALID_SOCKET; 02033 } 02034 if (ctxt->controlFd != INVALID_SOCKET) { 02035 xmlNanoFTPQuit(ctxt); 02036 closesocket(ctxt->controlFd); 02037 ctxt->controlFd = INVALID_SOCKET; 02038 } 02039 xmlNanoFTPFreeCtxt(ctxt); 02040 return(0); 02041 } 02042 02043 #ifdef STANDALONE 02044 /************************************************************************ 02045 * * 02046 * Basic test in Standalone mode * 02047 * * 02048 ************************************************************************/ 02049 static 02050 void ftpList(void *userData, const char *filename, const char* attrib, 02051 const char *owner, const char *group, unsigned long size, int links, 02052 int year, const char *month, int day, int hour, int minute) { 02053 xmlGenericError(xmlGenericErrorContext, 02054 "%s %s %s %ld %s\n", attrib, owner, group, size, filename); 02055 } 02056 static 02057 void ftpData(void *userData, const char *data, int len) { 02058 if (userData == NULL) return; 02059 if (len <= 0) { 02060 fclose((FILE*)userData); 02061 return; 02062 } 02063 fwrite(data, len, 1, (FILE*)userData); 02064 } 02065 02066 int main(int argc, char **argv) { 02067 void *ctxt; 02068 FILE *output; 02069 char *tstfile = NULL; 02070 02071 xmlNanoFTPInit(); 02072 if (argc > 1) { 02073 ctxt = xmlNanoFTPNewCtxt(argv[1]); 02074 if (xmlNanoFTPConnect(ctxt) < 0) { 02075 xmlGenericError(xmlGenericErrorContext, 02076 "Couldn't connect to %s\n", argv[1]); 02077 exit(1); 02078 } 02079 if (argc > 2) 02080 tstfile = argv[2]; 02081 } else 02082 ctxt = xmlNanoFTPConnectTo("localhost", 0); 02083 if (ctxt == NULL) { 02084 xmlGenericError(xmlGenericErrorContext, 02085 "Couldn't connect to localhost\n"); 02086 exit(1); 02087 } 02088 xmlNanoFTPList(ctxt, ftpList, NULL, tstfile); 02089 output = fopen("/tmp/tstdata", "w"); 02090 if (output != NULL) { 02091 if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0) 02092 xmlGenericError(xmlGenericErrorContext, 02093 "Failed to get file\n"); 02094 02095 } 02096 xmlNanoFTPClose(ctxt); 02097 xmlMemoryDump(); 02098 exit(0); 02099 } 02100 #endif /* STANDALONE */ 02101 #else /* !LIBXML_FTP_ENABLED */ 02102 #ifdef STANDALONE 02103 #include <stdio.h> 02104 int main(int argc, char **argv) { 02105 xmlGenericError(xmlGenericErrorContext, 02106 "%s : FTP support not compiled in\n", argv[0]); 02107 return(0); 02108 } 02109 #endif /* STANDALONE */ 02110 #endif /* LIBXML_FTP_ENABLED */ 02111 #define bottom_nanoftp 02112 #include "elfgcchack.h" Generated on Sat May 26 2012 04:33:19 for ReactOS by
1.7.6.1
|