You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

804 lines
16 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "../Source/FTPManager.h"
static int SplitString( std::string strSrc, std::list<std::string> &strArray , std::string strFlag)
{
int pos = 1;
while((pos = (int)strSrc.find_first_of(strFlag.c_str())) > 0)
{
strArray.insert(strArray.end(), strSrc.substr(0 , pos));
strSrc = strSrc.substr(pos + 1, strSrc.length() - pos - 1);
}
strArray.insert(strArray.end(), strSrc.substr(0, strSrc.length()));
return 0;
}
CFTPManager::CFTPManager(void): m_bLogin(false)
{
m_cmdSocket = socket(AF_INET, SOCK_STREAM, 0);
}
CFTPManager::~CFTPManager(void)
{
std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");
Send(m_cmdSocket, strCmdLine.c_str());
close(m_cmdSocket);
m_bLogin = false;
}
FTP_API CFTPManager::login2Server(const std::string &serverIP)
{
std::string strPort;
int pos = serverIP.find_first_of(":");
if (pos > 0)
{
strPort = serverIP.substr(pos + 1, serverIP.length() - pos);
}
else
{
pos = serverIP.length();
strPort = FTP_DEFAULT_PORT;
}
m_strServerIP = serverIP.substr(0, pos);
m_nServerPort = atol(strPort.c_str());
trace("IP: %s port: %d\n", m_strServerIP.c_str(), m_nServerPort);
if (Connect(m_cmdSocket, m_strServerIP, m_nServerPort) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
printf("@@@@Response: %s", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
FTP_API CFTPManager::inputUserName(const std::string &userName)
{
std::string strCommandLine = parseCommand(FTP_COMMAND_USERNAME, userName);
m_strUserName = userName;
if (Send(m_cmdSocket, strCommandLine) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
printf("Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
FTP_API CFTPManager::inputPassWord(const std::string &password)
{
std::string strCmdLine = parseCommand(FTP_COMMAND_PASSWORD, password);
m_strPassWord = password;
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
else
{
m_bLogin = true;
m_strResponse = serverResponse(m_cmdSocket);
printf("Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
}
FTP_API CFTPManager::quitServer(void)
{
std::string strCmdLine = parseCommand(FTP_COMMAND_QUIT, "");
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
else
{
m_strResponse = serverResponse(m_cmdSocket);
printf("Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
}
const std::string CFTPManager::PWD()
{
std::string strCmdLine = parseCommand(FTP_COMMAND_CURRENT_PATH, "");
if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)
{
return "";
}
else
{
return serverResponse(m_cmdSocket);
}
}
FTP_API CFTPManager::setTransferMode(type mode)
{
std::string strCmdLine;
switch (mode)
{
case binary:
strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "I");
break;
case ascii:
strCmdLine = parseCommand(FTP_COMMAND_TYPE_MODE, "A");
break;
default:
break;
}
if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)
{
assert(false);
}
else
{
m_strResponse = serverResponse(m_cmdSocket);
printf("@@@@Response: %s", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
}
const std::string CFTPManager::Pasv()
{
std::string strCmdLine = parseCommand(FTP_COMMAND_PSAV_MODE, "");
if (Send(m_cmdSocket, strCmdLine.c_str()) < 0)
{
return "";
}
else
{
m_strResponse = serverResponse(m_cmdSocket);
return m_strResponse;
}
}
const std::string CFTPManager::Dir(const std::string &path)
{
int dataSocket = socket(AF_INET, SOCK_STREAM, 0);
if (createDataLink(dataSocket) < 0)
{
return "";
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳɹ<D3B3>
std::string strCmdLine = parseCommand(FTP_COMMAND_DIR, path);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
close(dataSocket);
return "";
}
else
{
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
m_strResponse = serverResponse(dataSocket);
trace("@@@@Response: \n%s\n", m_strResponse.c_str());
close(dataSocket);
return m_strResponse;
}
}
FTP_API CFTPManager::CD(const std::string &path)
{
assert(m_cmdSocket != INVALID_SOCKET);
std::string strCmdLine = parseCommand(FTP_COMMAND_CHANGE_DIRECTORY, path);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
trace("@@@@Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
FTP_API CFTPManager::DeleteFile(const std::string &strRemoteFile)
{
assert(m_cmdSocket != INVALID_SOCKET);
std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_FILE, strRemoteFile);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
printf("@@@@Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
FTP_API CFTPManager::DeleteDirectory(const std::string &strRemoteDir)
{
assert(m_cmdSocket != INVALID_SOCKET);
std::string strCmdLine = parseCommand(FTP_COMMAND_DELETE_DIRECTORY, strRemoteDir);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
trace("@@@@Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
FTP_API CFTPManager::CreateDirectory(const std::string &strRemoteDir)
{
assert(m_cmdSocket != INVALID_SOCKET);
std::string strCmdLine = parseCommand(FTP_COMMAND_CREATE_DIRECTORY, strRemoteDir);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
trace("@@@@Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
FTP_API CFTPManager::Rename(const std::string &strRemoteFile, const std::string &strNewFile)
{
assert(m_cmdSocket != INVALID_SOCKET);
std::string strCmdLine = parseCommand(FTP_COMMAND_RENAME_BEGIN, strRemoteFile);
Send(m_cmdSocket, strCmdLine);
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
Send(m_cmdSocket, parseCommand(FTP_COMMAND_RENAME_END, strNewFile));
m_strResponse = serverResponse(m_cmdSocket);
trace("@@@@Response: %s\n", m_strResponse.c_str());
return parseResponse(m_strResponse);
}
long CFTPManager::getFileLength(const std::string &strRemoteFile)
{
assert(m_cmdSocket != INVALID_SOCKET);
std::string strCmdLine = parseCommand(FTP_COMMAND_FILE_SIZE, strRemoteFile);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
m_strResponse = serverResponse(m_cmdSocket);
trace("@@@@Response: %s\n", m_strResponse.c_str());
std::string strData = m_strResponse.substr(0, 3);
unsigned long val = atol(strData.c_str());
if (val == 213)
{
strData = m_strResponse.substr(4);
trace("strData: %s\n", strData.c_str());
val = atol(strData.c_str());
return val;
}
return -1;
}
void CFTPManager::Close(int sock)
{
shutdown(sock, SHUT_RDWR);
close(sock);
sock = INVALID_SOCKET;
}
FTP_API CFTPManager::Get(const std::string &strRemoteFile, const std::string &strLocalFile)
{
return downLoad(strRemoteFile, strLocalFile);
}
FTP_API CFTPManager::Put(const std::string &strRemoteFile, const std::string &strLocalFile)
{
std::string strCmdLine;
const unsigned long dataLen = FTP_DEFAULT_BUFFER;
char strBuf[dataLen] = {0};
unsigned long nSize = getFileLength(strRemoteFile);
unsigned long nLen = 0;
// struct stat sBuf;
//
// assert(stat(strLocalFile.c_str(), &sBuf) == 0);
// trace("size: %d\n", sBuf.st_size);
FILE *pFile = fopen(strLocalFile.c_str(), "rb"); // <20><>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD> <20><><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
assert(pFile != NULL);
int data_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(data_fd != -1);
if (createDataLink(data_fd) < 0)
{
return -1;
}
if (nSize == -1)
{
strCmdLine = parseCommand(FTP_COMMAND_UPLOAD_FILE, strRemoteFile);
}
else
{
strCmdLine = parseCommand(FTP_COMMAND_APPEND_FILE, strRemoteFile);
}
if (Send(m_cmdSocket, strCmdLine) < 0)
{
Close(data_fd);
return -1;
}
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
fseek(pFile, nSize, SEEK_SET);
while (!feof(pFile))
{
nLen = fread(strBuf, 1, dataLen, pFile);
if (nLen < 0)
{
break;
}
if (Send(data_fd, strBuf) < 0)
{
Close(data_fd);
return -1;
}
}
trace("@@@@Response: %s\n", serverResponse(data_fd).c_str());
Close(data_fd);
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
fclose(pFile);
return 0;
}
const std::string CFTPManager::parseCommand(const unsigned int command, const std::string &strParam)
{
if (command < FTP_COMMAND_BASE || command > FTP_COMMAND_END)
{
return "";
}
std::string strCommandLine;
m_nCurrentCommand = command;
m_commandStr.clear();
switch (command)
{
case FTP_COMMAND_USERNAME:
strCommandLine = "USER ";
break;
case FTP_COMMAND_PASSWORD:
strCommandLine = "PASS ";
break;
case FTP_COMMAND_QUIT:
strCommandLine = "QUIT ";
break;
case FTP_COMMAND_CURRENT_PATH:
strCommandLine = "PWD ";
break;
case FTP_COMMAND_TYPE_MODE:
strCommandLine = "TYPE ";
break;
case FTP_COMMAND_PSAV_MODE:
strCommandLine = "PASV ";
break;
case FTP_COMMAND_DIR:
strCommandLine = "LIST ";
break;
case FTP_COMMAND_CHANGE_DIRECTORY:
strCommandLine = "CWD ";
break;
case FTP_COMMAND_DELETE_FILE:
strCommandLine = "DELE ";
break;
case FTP_COMMAND_DELETE_DIRECTORY:
strCommandLine = "RMD ";
break;
case FTP_COMMAND_CREATE_DIRECTORY:
strCommandLine = "MKD ";
break;
case FTP_COMMAND_RENAME_BEGIN:
strCommandLine = "RNFR ";
break;
case FTP_COMMAND_RENAME_END:
strCommandLine = "RNTO ";
break;
case FTP_COMMAND_FILE_SIZE:
strCommandLine = "SIZE ";
break;
case FTP_COMMAND_DOWNLOAD_FILE:
strCommandLine = "RETR ";
break;
case FTP_COMMAND_DOWNLOAD_POS:
strCommandLine = "REST ";
break;
case FTP_COMMAND_UPLOAD_FILE:
strCommandLine = "STOR ";
break;
case FTP_COMMAND_APPEND_FILE:
strCommandLine = "APPE ";
break;
default :
break;
}
strCommandLine += strParam;
strCommandLine += "\r\n";
m_commandStr = strCommandLine;
trace("parseCommand: %s\n", m_commandStr.c_str());
return m_commandStr;
}
FTP_API CFTPManager::Connect(int socketfd, const std::string &serverIP, unsigned int nPort)
{
if (socketfd == INVALID_SOCKET)
{
return -1;
}
unsigned int argp = 1;
int error = -1;
int len = sizeof(int);
struct sockaddr_in addr;
bool ret = false;
timeval stime;
fd_set set;
ioctl(socketfd, FIONBIO, &argp); //<2F><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(nPort);
addr.sin_addr.s_addr = inet_addr(serverIP.c_str());
bzero(&(addr.sin_zero), 8);
trace("Address: %s %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if (connect(socketfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1) //<2F><>ֱ<EFBFBD>ӷ<EFBFBD><D3B7><EFBFBD> <20><>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><DABD><EFBFBD>TCP<43><50><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
stime.tv_sec = 20; //<2F><><EFBFBD><EFBFBD>Ϊ1<CEAA>볬ʱ
stime.tv_usec = 0;
FD_ZERO(&set);
FD_SET(socketfd, &set);
if (select(socketfd + 1, NULL, &set, NULL, &stime) > 0) ///<2F><><EFBFBD><EFBFBD><EFBFBD>ߵȴ<DFB5> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ؿ<EFBFBD><D8BF>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>߳<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>0 <20><><EFBFBD>߳<EFBFBD><DFB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-1
{
getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len);
if (error == 0)
{
ret = true;
}
else
{
ret = false;
}
}
}
else
{ trace("Connect Immediately!!!\n");
ret = true;
}
argp = 0;
ioctl(socketfd, FIONBIO, &argp);
if (!ret)
{
close(socketfd);
fprintf(stderr, "cannot connect server!!\n");
return -1;
}
//fprintf(stdout, "Connect!!!\n");
return 0;
}
const std::string CFTPManager::serverResponse(int sockfd)
{
if (sockfd == INVALID_SOCKET)
{
return "";
}
int nRet = -1;
char buf[MAX_PATH] = {0};
m_strResponse.clear();
while ((nRet = getData(sockfd, buf, MAX_PATH)) > 0)
{
buf[MAX_PATH - 1] = '\0';
m_strResponse += buf;
}
return m_strResponse;
}
FTP_API CFTPManager::getData(int fd, char *strBuf, unsigned long length)
{
assert(strBuf != NULL);
if (fd == INVALID_SOCKET)
{
return -1;
}
memset(strBuf, 0, length);
timeval stime;
int nLen;
stime.tv_sec = 1;
stime.tv_usec = 0;
fd_set readfd;
FD_ZERO( &readfd );
FD_SET(fd, &readfd );
if (select(fd + 1, &readfd, 0, 0, &stime) > 0)
{
if ((nLen = recv(fd, strBuf, length, 0)) > 0)
{
return nLen;
}
else
{
return -2;
}
}
return 0;
}
FTP_API CFTPManager::Send(int fd, const std::string &cmd)
{
if (fd == INVALID_SOCKET)
{
return -1;
}
return Send(fd, cmd.c_str(), cmd.length());
}
FTP_API CFTPManager::Send(int fd, const char *cmd, const size_t len)
{
if((FTP_COMMAND_USERNAME != m_nCurrentCommand)
&&(FTP_COMMAND_PASSWORD != m_nCurrentCommand)
&&(!m_bLogin))
{
return -1;
}
timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
fd_set writefd;
FD_ZERO(&writefd);
FD_SET(fd, &writefd);
if(select(fd + 1, 0, &writefd , 0 , &timeout) > 0)
{
size_t nlen = len;
int nSendLen = 0;
while (nlen >0)
{
nSendLen = send(fd, cmd , (int)nlen , 0);
if(nSendLen == -1)
return -2;
nlen = nlen - nSendLen;
cmd += nSendLen;
}
return 0;
}
return -1;
}
FTP_API CFTPManager::createDataLink(int data_fd)
{
assert(data_fd != INVALID_SOCKET);
std::string strData;
unsigned long nPort = 0 ;
std::string strServerIp ;
std::list<std::string> strArray ;
std::string parseStr = Pasv();
if (parseStr.size() <= 0)
{
return -1;
}
//trace("parseInfo: %s\n", parseStr.c_str());
size_t nBegin = parseStr.find_first_of("(");
size_t nEnd = parseStr.find_first_of(")");
strData = parseStr.substr(nBegin + 1, nEnd - nBegin - 1);
//trace("ParseAfter: %s\n", strData.c_str());
if( SplitString( strData , strArray , "," ) <0)
return -1;
if( ParseString( strArray , nPort , strServerIp) < 0)
return -1;
//trace("nPort: %ld IP: %s\n", nPort, strServerIp.c_str());
if (Connect(data_fd, strServerIp, nPort) < 0)
{
return -1;
}
return 0;
}
FTP_API CFTPManager::ParseString(std::list<std::string> strArray, unsigned long & nPort ,std::string & strServerIp)
{
if (strArray.size() < 6 )
return -1 ;
std::list<std::string>::iterator citor;
citor = strArray.begin();
strServerIp = *citor;
strServerIp += ".";
citor ++;
strServerIp += *citor;
strServerIp += ".";
citor ++ ;
strServerIp += *citor;
strServerIp += ".";
citor ++ ;
strServerIp += *citor;
citor = strArray.end();
citor--;
nPort = atol( (*citor).c_str());
citor--;
nPort += atol( (*(citor)).c_str()) * 256 ;
return 0 ;
}
FILE *CFTPManager::createLocalFile(const std::string &strLocalFile)
{
return fopen(strLocalFile.c_str(), "w+b");
}
FTP_API CFTPManager::downLoad(const std::string &strRemoteFile, const std::string &strLocalFile, const int pos, const unsigned int length)
{
assert(length >= 0);
FILE *file = NULL;
unsigned long nDataLen = FTP_DEFAULT_BUFFER;
char strPos[MAX_PATH] = {0};
int data_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(data_fd != -1);
if ((length != 0) && (length < nDataLen))
{
nDataLen = length;
}
char *dataBuf = new char[nDataLen];
assert(dataBuf != NULL);
sprintf(strPos, "%d", pos);
if (createDataLink(data_fd) < 0)
{
trace("@@@@ Create Data Link error!!!\n");
return -1;
}
std::string strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_POS, strPos);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
strCmdLine = parseCommand(FTP_COMMAND_DOWNLOAD_FILE, strRemoteFile);
if (Send(m_cmdSocket, strCmdLine) < 0)
{
return -1;
}
trace("@@@@Response: %s\n", serverResponse(m_cmdSocket).c_str());
file = createLocalFile(std::string(FTP_DEFAULT_PATH + strLocalFile));
assert(file != NULL);
int len = 0;
int nReceiveLen = 0;
while ((len = getData(data_fd, dataBuf, nDataLen)) > 0)
{
nReceiveLen += len;
int num = fwrite(dataBuf, 1, len, file);
memset(dataBuf, 0, sizeof(dataBuf));
//trace("%s", dataBuf);
trace("Num:%d\n", num);
if (nReceiveLen == length && length != 0)
break;
if ((nReceiveLen + nDataLen) > length && length != 0)
{
delete []dataBuf;
nDataLen = length - nReceiveLen;
dataBuf = new char[nDataLen];
}
}
Close(data_fd);
fclose(file);
delete []dataBuf;
return 0;
}
FTP_API CFTPManager::parseResponse(const std::string &str)
{
assert(!str.empty());
std::string strData = str.substr(0, 3);
unsigned int val = atoi(strData.c_str());
return val;
}