void FTPSetUploadSocketBufferSize(const FTPCIPtr cip) { /* If dataSocketSBufSize is non-zero, it means you * want to explicitly try to set the size of the * socket's I/O buffer. * * If it is zero, it means you want to just use the * TCP stack's default value, which is typically * between 8 and 64 kB. * * If you try to set the buffer larger than 64 kB, * the TCP stack should try to use RFC 1323 to * negotiate "TCP Large Windows" which may yield * significant performance gains. */ if ((cip->numUploads == 0) && (cip->dataSocketSBufSize != 0)) { if (cip->hasSITE_STORBUFSIZE == kCommandAvailable) (void) FTPCmd(cip, "SITE STORBUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); else if (cip->hasSITE_SBUFSIZ == kCommandAvailable) (void) FTPCmd(cip, "SITE SBUFSIZ %lu", (unsigned long) cip->dataSocketSBufSize); else if (cip->hasSITE_SBUFSZ == kCommandAvailable) (void) FTPCmd(cip, "SITE SBUFSZ %lu", (unsigned long) cip->dataSocketSBufSize); /* At least one server implemenation has RBUFSZ but not * SBUFSZ and instead uses RBUFSZ for both. */ else if ((cip->hasSITE_SBUFSZ != kCommandAvailable) && (cip->hasSITE_RBUFSZ == kCommandAvailable)) (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketSBufSize); else if (cip->hasSITE_BUFSIZE == kCommandAvailable) (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); } } /* FTPSetUploadSocketBufferSize */
int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob) { FTPLineList fileList; FTPLinePtr filePtr; char *file; int onceResult, batchResult; if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); if (batchResult != kNoErr) return (batchResult); for (batchResult = kNoErr, filePtr = fileList.first; filePtr != NULL; filePtr = filePtr->next) { file = filePtr->line; if (file == NULL) { batchResult = kErrBadLineList; cip->errNo = kErrBadLineList; break; } onceResult = FTPCmd(cip, "DELE %s", file); if (onceResult < 0) { batchResult = onceResult; break; } if (onceResult != 2) { if (recurse != kRecursiveYes) { batchResult = kErrDELEFailed; cip->errNo = kErrDELEFailed; } else { onceResult = FTPCmd(cip, "RMD %s", file); if (onceResult < 0) { batchResult = onceResult; break; } if (onceResult != 2) { onceResult = FTPRmdirRecursive(cip, file); if (onceResult < 0) { batchResult = kErrRMDFailed; cip->errNo = kErrRMDFailed; } } } } } DisposeLineListContents(&fileList); return (batchResult); } /* FTPDelete */
int FTPUmask(const FTPCIPtr cip, const char *const umsk) { if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); if ((umsk == NULL) || (umsk[0] == '\0')) return (kErrBadParameter); if (FTPCmd(cip, "SITE UMASK %s", umsk) == 2) return (kNoErr); cip->errNo = kErrUmaskFailed; return (kErrUmaskFailed); } /* FTPUmask */
int FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob) { FTPLineList fileList; FTPLinePtr filePtr; char *file; int onceResult, batchResult; if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); if (batchResult != kNoErr) return (batchResult); for (batchResult = kNoErr, filePtr = fileList.first; filePtr != NULL; filePtr = filePtr->next) { file = filePtr->line; if (file == NULL) { batchResult = kErrBadLineList; cip->errNo = kErrBadLineList; break; } onceResult = FTPCmd(cip, "SITE CHMOD %s %s", mode, file); if (onceResult < 0) { batchResult = onceResult; break; } if (onceResult != 2) { batchResult = kErrChmodFailed; cip->errNo = kErrChmodFailed; } } DisposeLineListContents(&fileList); return (batchResult); } /* FTPChmod */
/******************************************************** * function:CreateListenSocket * purpose:create listen socket (let it choose the port) & start the socket listening * return: FTP_SUCCEED 成功 , FTP_FAIL 失败 * ********************************************************/ int CFTPClient::CreateListenSocket ( void ) { struct sockaddr_in sockAddr; /* 分配套接口 */ if ( ( m_hListenSocket = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { perror( "socket()" ); return -1; } if( m_iPassive ==1 ) { //被动模式 char sRemote[50]; if(FTPCmd(PASV, 0, sRemote, 50)!=0 ) return -1; char *pTmp; for(int i=0; i<3; i++) { pTmp=strchr(sRemote, ',' ); if(pTmp==NULL)return -1; *pTmp='.'; } pTmp=strchr(sRemote, ',' ); if(pTmp==NULL)return -1; *pTmp=0; unsigned int iPortTmp=atoi(++pTmp); pTmp=strchr(pTmp, ',' ); if(pTmp==NULL)return -1; iPortTmp=iPortTmp*256+atoi(++pTmp); unsigned long lRemote = inet_addr( sRemote ); sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons( iPortTmp ); sockAddr.sin_addr.s_addr = lRemote; if ( connect ( m_hListenSocket, reinterpret_cast < struct sockaddr * > (&sockAddr), sizeof(sockAddr) ) < 0 ) { close( m_hListenSocket ); perror( "connect()" ); return -1; } return 0; } /* Let the system assign a socket address */ sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons( 0 ); /* htons() is just a reminder.*/ sockAddr.sin_addr.s_addr = INADDR_ANY; /* Bind the socket */ if ( bind ( m_hListenSocket, reinterpret_cast < struct sockaddr * > (&sockAddr), sizeof(sockAddr) ) ) { close( m_hListenSocket ); perror( "bind()" ); return -1; } int tmpint = fcntl( m_hListenSocket, F_GETFL, 0 ); if ( fcntl( m_hListenSocket, F_SETFL, tmpint | O_NONBLOCK ) < 0 ) { close( m_hListenSocket ); perror( "fcntl" ); return -1; } /* Listen for the FTP server connection */ if ( listen( m_hListenSocket, 3 ) ) { close( m_hListenSocket ); perror( "listen()" ); return -1; } /* Ask the server to connect to the port monitored by the listener socket*/ #if defined( _AIX ) || defined( __linux__ ) socklen_t iLength = sizeof( sockAddr ); #else int iLength = sizeof( sockAddr ); #endif /* 发送PORT命令 */ /* Get port number */ if ( getsockname ( m_hListenSocket, reinterpret_cast < struct sockaddr * > (&sockAddr), &iLength ) < 0 ) { close( m_hListenSocket ); printf( "getsockname" ); return -1; } int iPort = sockAddr.sin_port; /* Get local ip address */ if ( getsockname ( m_hControlChannel, reinterpret_cast < struct sockaddr * > (&sockAddr), &iLength ) < 0 ) { close( m_hListenSocket ); printf( "getsockname" ); return -1; } char strCmd[128]; //PORT h1,h2,h3,h4,p1,p2 //where h1 is the high order 8 bits of the internet host address. if ( m_IsBigOrder == 1 ) { sprintf ( strCmd, "PORT %d,%d,%d,%d,%d,%d\r\n", ( sockAddr.sin_addr.s_addr >> 24 ) & 0x000000ff, ( sockAddr.sin_addr.s_addr >> 16 ) & 0x000000ff, ( sockAddr.sin_addr.s_addr >> 8 ) & 0x000000ff, ( sockAddr.sin_addr.s_addr ) & 0x000000ff, iPort >> 8, iPort & 0xFF ); }
int FTPGetFileToMemory( const FTPCIPtr cip, const char *const file, char *memBuf, const size_t maxNumberOfBytesToWriteToMemBuf, size_t *const numberOfBytesWrittenToMemBuf, const longest_int startPoint, const int deleteflag ) { int tmpResult; volatile int result; int atEOF; longest_int expectedSize; size_t ntoread; read_return_t nread; size_t numberOfBytesLeftInMemBuf; #if !defined(NO_SIGNALS) volatile FTPSigProc osigpipe; volatile FTPCIPtr vcip; int sj; #endif /* NO_SIGNALS */ result = kNoErr; atEOF = 1; cip->usingTAR = 0; numberOfBytesLeftInMemBuf = maxNumberOfBytesToWriteToMemBuf; if (numberOfBytesWrittenToMemBuf != NULL) *numberOfBytesWrittenToMemBuf = 0; if ((file == NULL) || (file[0] == '\0') || (memBuf == NULL) || (maxNumberOfBytesToWriteToMemBuf == 0)) { return (kErrBadParameter); } FTPCheckForRestartModeAvailability(cip); if ((startPoint != 0) && (cip->hasREST == kCommandNotAvailable)) { cip->errNo = kErrRESTNotAvailable; return (cip->errNo); } (void) FTPFileSize(cip, file, &expectedSize, kTypeBinary); if ((expectedSize != (longest_int) 0) && (startPoint > expectedSize)) { /* Don't go to all the trouble of downloading nothing. */ if (deleteflag == kDeleteYes) (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); return (kNoErr); } if ((cip->numDownloads == 0) && (cip->dataSocketRBufSize != 0)) { /* If dataSocketSBufSize is non-zero, it means you * want to explicitly try to set the size of the * socket's I/O buffer. * * If it is zero, it means you want to just use the * TCP stack's default value, which is typically * between 8 and 64 kB. * * If you try to set the buffer larger than 64 kB, * the TCP stack should try to use RFC 1323 to * negotiate "TCP Large Windows" which may yield * significant performance gains. */ if (cip->hasSITE_RETRBUFSIZE == kCommandAvailable) (void) FTPCmd(cip, "SITE RETRBUFSIZE %lu", (unsigned long) cip->dataSocketRBufSize); else if (cip->hasSITE_RBUFSIZ == kCommandAvailable) (void) FTPCmd(cip, "SITE RBUFSIZ %lu", (unsigned long) cip->dataSocketRBufSize); else if (cip->hasSITE_RBUFSZ == kCommandAvailable) (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketRBufSize); else if (cip->hasSITE_BUFSIZE == kCommandAvailable) (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); } #ifdef NO_SIGNALS #else /* NO_SIGNALS */ vcip = cip; osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData); gGotBrokenData = 0; gCanBrokenDataJmp = 0; #ifdef HAVE_SIGSETJMP sj = sigsetjmp(gBrokenDataJmp, 1); #else sj = setjmp(gBrokenDataJmp); #endif /* HAVE_SIGSETJMP */ if (sj != 0) { (void) signal(SIGPIPE, (FTPSigProc) osigpipe); FTPShutdownHost(vcip); vcip->errNo = kErrRemoteHostClosedConnection; return(vcip->errNo); } gCanBrokenDataJmp = 1; #endif /* NO_SIGNALS */ tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, startPoint, "RETR %s", file); if (tmpResult < 0) { result = tmpResult; if (result == kErrGeneric) result = kErrRETRFailed; cip->errNo = result; #if !defined(NO_SIGNALS) (void) signal(SIGPIPE, (FTPSigProc) osigpipe); #endif /* NO_SIGNALS */ return (result); } if ((startPoint != 0) && (cip->startPoint == 0)) { /* Remote could not or would not set the start offset * to what we wanted. */ cip->errNo = kErrSetStartPoint; #if !defined(NO_SIGNALS) (void) signal(SIGPIPE, (FTPSigProc) osigpipe); #endif /* NO_SIGNALS */ return (cip->errNo); } FTPInitIOTimer(cip); cip->expectedSize = expectedSize; cip->lname = NULL; /* could be NULL */ cip->rname = file; FTPStartIOTimer(cip); /* Binary */ for (;;) { if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */ cip->errNo = result = kErrDataTimedOut; FTPLogError(cip, kDontPerror, "Remote read timed out.\n"); break; } if (cip->cancelXfer > 0) { FTPAbortDataTransfer(cip); result = cip->errNo = kErrDataTransferAborted; break; } ntoread = numberOfBytesLeftInMemBuf; if (ntoread > cip->bufSize) ntoread = cip->bufSize; /* Break it up into blocks. */ #ifdef NO_SIGNALS nread = (read_return_t) SRead(cip->dataSocket, memBuf, ntoread, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect); if (nread == kTimeoutErr) { cip->errNo = result = kErrDataTimedOut; FTPLogError(cip, kDontPerror, "Remote read timed out.\n"); break; } else if (nread < 0) { if (errno == EPIPE) { result = cip->errNo = kErrSocketReadFailed; errno = EPIPE; FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n"); } else if (errno == EINTR) { continue; } else { FTPLogError(cip, kDoPerror, "Remote read failed.\n"); result = kErrSocketReadFailed; cip->errNo = kErrSocketReadFailed; } break; } else if (nread == 0) { break; } #else gCanBrokenDataJmp = 1; if (cip->xferTimeout > 0) (void) alarm(cip->xferTimeout); nread = read(cip->dataSocket, memBuf, (read_size_t) ntoread); if (nread < 0) { if ((gGotBrokenData != 0) || (errno == EPIPE)) { result = cip->errNo = kErrSocketReadFailed; errno = EPIPE; FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n"); } else if (errno == EINTR) { continue; } else { result = cip->errNo = kErrSocketReadFailed; FTPLogError(cip, kDoPerror, "Remote read failed.\n"); } (void) shutdown(cip->dataSocket, 2); break; } else if (nread == 0) { /* At EOF. */ break; } gCanBrokenDataJmp = 0; #endif /* NO_SIGNALS */ memBuf += nread; if (numberOfBytesWrittenToMemBuf != NULL) *numberOfBytesWrittenToMemBuf += (size_t) nread; cip->bytesTransferred += (longest_int) nread; FTPUpdateIOTimer(cip); if ((size_t) nread > numberOfBytesLeftInMemBuf) { /* assertion failure */ result = cip->errNo = kErrBugInLibrary; break; } numberOfBytesLeftInMemBuf -= nread; if (numberOfBytesLeftInMemBuf == 0) { /* Done (but maybe not at EOF of remote file). */ atEOF = 0; if ((cip->bytesTransferred + startPoint) == expectedSize) atEOF = 1; break; } } #if !defined(NO_SIGNALS) if (cip->xferTimeout > 0) (void) alarm(0); gCanBrokenDataJmp = 0; #endif /* NO_SIGNALS */ /* If there hasn't been an error, and you limited * the number of bytes, we need to abort the * remaining data. */ if ((result == kNoErr) && (atEOF == 0)) { FTPAbortDataTransfer(cip); tmpResult = FTPEndDataCmd(cip, 1); if ((tmpResult < 0) && (result == 0) && (tmpResult != kErrDataTransferFailed)) { result = kErrRETRFailed; cip->errNo = kErrRETRFailed; } } else { tmpResult = FTPEndDataCmd(cip, 1); if ((tmpResult < 0) && (result == 0)) { result = kErrRETRFailed; cip->errNo = kErrRETRFailed; } } FTPStopIOTimer(cip); #if !defined(NO_SIGNALS) (void) signal(SIGPIPE, (FTPSigProc) osigpipe); #endif /* NO_SIGNALS */ if (result == kNoErr) { cip->numDownloads++; if (deleteflag == kDeleteYes) { result = FTPDelete(cip, file, kRecursiveNo, kGlobNo); } } return (result); } /* FTPGetOneF */