项目中新增对FTP的支持,需求的变更是开发过程中不可避免的事情,只是变更的时间越靠近项目末期,就越是灾难。还好这个需求可以设计的相对独立,做到尽量不影响已实现部分。
说的FTP,就想起曾经写的一个FTP接口对象,由于现在FTP的实现库到处都是,因此在写好此对象时,被同事称为:做轮子的人~我的想法是,组装车和制作车应该还是有区别的~
不扯了,下面是实现的代码,比较啰嗦~
#ifndef __FTPOPERAOBJECT_H__
#define __FTPOPERAOBJECT_H__
#include <fstream>
#include <string>
#include "ace/INET_Addr.h"
#include "acex/NB_Tcp_Client.h"
#include "acex/NB_Tcp_Server.h"
//OK, support both PORT and PASV mode NOW.
const int REPLY_CODE_541 = 541;
const int REPLY_CODE_542 = 542;
const int REPLY_CODE_543 = 543;
const int REPLY_CODE_544 = 544;
const int REPLY_CODE_545 = 545;
const int REPLY_CODE_546 = 546;
const std::string REPLY_COMMENT_541 = "(inner)Control connection is break.";
const std::string REPLY_COMMENT_542 = "(inner)Control connection is timeout for waiting for remote reply.";
const std::string REPLY_COMMENT_543 = "(inner)Control connection gets a NULL reply.";
const std::string REPLY_COMMENT_544 = "(inner)Reply result is empty.";
const std::string REPLY_COMMENT_545 = "(inner)Syntax error, reply unrecognized.";
const std::string REPLY_COMMENT_546 = "(inner)Syntax error, reply is not expected.";
class CFTPDataTcpObject;
class CFTPCtrlTcpObject
{
public:
struct ResultInfo_t
{
int m_iResult;
std::string m_strInfo;
};
typedef std::auto_ptr<CFTPDataTcpObject> TDataTcpObjectPtr;
public:
CFTPCtrlTcpObject(const size_t buf_size = 64 * 1024, const ACE_Time_Value& connect_timeout = ACE_Time_Value(2), const ACE_Time_Value& select_timeout = ACE_Time_Value(2));
virtual ~CFTPCtrlTcpObject();
public:
int Open(const ACE_INET_Addr& stAddr);
int Connect(const std::string& strUser, const std::string& strPasswd);
int Close();
int CmdChgDir(const std::string& strDir);
int CmdChgLocalDir(const std::string& strDir);
int CmdMkDir(const std::string& strDir);
int CmdDelFile(const std::string& strFile);
int CmdType(bool bASCII = true);
int CmdNoop();
int CmdRenFile(const std::string& strOldFile, const std::string& strNewFile);
int CmdGetFile(const std::string& strRemoteFile, const std::string& strLocalFile);
int CmdPutFile(const std::string& strLocalFile, const std::string& strRemoteFile);
int CmdNLst(const std::string& strFilter, std::string& strOutput);
int CmdList(const std::string& strFilter, std::string& strOutput);
int SendCmdWithDataStream(const std::string& strCmd, std::ostream& os);
int SendCmdWithDataStream(const std::string& strCmd, char* pchData, size_t& szDataRead);
bool IsConnected() const { return _bConnected; }
bool IsASCII() const { return _bASCII; }
const ResultInfo_t& GetResultInfo() const;
size_t AffectedSize() const;
void PortMode() { _bPortMode = true; }
void PasvMode() { _bPortMode = false; }
void SetStopFlag(bool bStop) { _bTransStop = bStop; }
public:
int SendCommand(const std::string& strCmd);
int RecvResult(ResultInfo_t& stResult);
int Is200Result(const ResultInfo_t& stResult) const;
int Is100Result(const ResultInfo_t& stResult) const;
int Is300Result(const ResultInfo_t& stResult) const;
int GetLocalAddr(ACE_INET_Addr& stAddr);
unsigned short GetRandPort();
std::string AnalyseAddr(const ACE_INET_Addr& stAddr) const;
ACE_INET_Addr AnalyseAddr(const std::string& strAddr) const;
public:
int RecvResult();
int ResultCode() const;
const std::string& ResultInfo() const;
int Is200Result() const;
int Is100Result() const;
int Is300Result() const;
protected:
bool _bConnected;
ACE_RANDR_TYPE _seed;
char _acResultBuf[2048];
size_t _szResultSize;
bool _bASCII;
size_t _szAffectedSize;//can used after get or put command.
bool _bTransStop;
bool _bPortMode;
private:
size_t _szBufSize;
ACE_Time_Value _stConnTimeout;
ACE_Time_Value _stSelectTimeout;
std::auto_ptr<ACEX_TcpStream> _stTcpStreamPtr;
ACE_SOCK_Connector _stConnector;
private:
ResultInfo_t _stResultInfo;
};
//
class CFTPDataTcpObject
{
public:
enum TransStatus { TS_UNKNWON = -1, TS_READ = 0, TS_WRITE, TS_TIMEOUT };
public:
CFTPDataTcpObject(CFTPCtrlTcpObject& ctrlobject, size_t buffsize, const ACE_Time_Value& timeout)
: _stCtrlObject(ctrlobject), _szBuffSize(buffsize), _stTimeout(timeout)
, _stTcpStreamPtr(NULL)
, _bStop(false), _bOpen(false)
{
}
virtual ~CFTPDataTcpObject();
virtual int Get(const std::string& remote, const std::string& local, size_t& size) = 0;
virtual int Put(const std::string& remote, const std::string& local, size_t& size) = 0;
virtual int SendCmd(const std::string& strCmd, std::ostream& os) = 0;
virtual int SendCmd(const std::string& strCmd, char*& pchData, size_t& szDataRead) = 0;
void Stop() { _bStop = true; }
virtual void Close();
protected:
TransStatus SelectRead(size_t& size);
TransStatus SelectWrite();
int Read(char*& data, size_t& size);
int Write(const char* data, size_t size);
int Read(std::ofstream& ofile, size_t& size);
int Write(std::ifstream& ifile, size_t& size);
int Read(std::ostream& os, size_t& size);
protected:
CFTPCtrlTcpObject& _stCtrlObject;
size_t _szBuffSize;
ACE_Time_Value _stTimeout;
protected:
ACE_INET_Addr _stLocalAddr;
ACE_INET_Addr _stRemoteAddr;
std::auto_ptr<ACEX_TcpStream> _stTcpStreamPtr;
protected:
bool _bStop;
bool _bOpen;
};
//
class CFTPPortDataTcpObject : public CFTPDataTcpObject
{
public:
CFTPPortDataTcpObject(CFTPCtrlTcpObject& ctrlobject, size_t buffsize= 64 * 1024, const ACE_Time_Value& timeout = ACE_Time_Value(2));
virtual ~CFTPPortDataTcpObject();
virtual int Get(const std::string& remote, const std::string& local, size_t& size);
virtual int Put(const std::string& remote, const std::string& local, size_t& size);
virtual int SendCmd(const std::string& strCmd, char*& pchData, size_t& szDataRead);
virtual int SendCmd(const std::string& strCmd, std::ostream& os);
protected:
int Open();
int Port();
int Accept();
private:
ACE_SOCK_Acceptor _stAcceptor;
};
//
class CFTPPasvDataTcpObject : public CFTPDataTcpObject
{
public:
CFTPPasvDataTcpObject(CFTPCtrlTcpObject& ctrlobject, size_t buffsize = 64 * 1024, const ACE_Time_Value& timeout = ACE_Time_Value(2));
virtual ~CFTPPasvDataTcpObject();
virtual int Get(const std::string& remote, const std::string& local, size_t& size);
virtual int Put(const std::string& remote, const std::string& local, size_t& size);
virtual int SendCmd(const std::string& strCmd, char*& pchData, size_t& szDataRead);
virtual int SendCmd(const std::string& strCmd, std::ostream& os);
protected:
int Pasv();
int Connect();
private:
ACE_SOCK_Connector _stConnector;
};
#endif
#include <stdexcept>
#include <sstream>
#include "ace/Handle_Set.h"
#include "ace/OS_NS_time.h"
#include "acex/ACEX.h"
#include "FTPOperaObject.h"
CFTPCtrlTcpObject::CFTPCtrlTcpObject(const size_t buf_size, const ACE_Time_Value& connect_timeout, const ACE_Time_Value& select_timeout)
: _bConnected(false)
, _seed(ACE_OS::time(NULL))
, _szResultSize(0)
, _bASCII(false)
, _szAffectedSize(0)
, _bTransStop(false)
, _bPortMode(true)
, _szBufSize(buf_size)
, _stConnTimeout(connect_timeout)
, _stSelectTimeout(select_timeout)
{
}
CFTPCtrlTcpObject::~CFTPCtrlTcpObject()
{
Close();
}
int CFTPCtrlTcpObject::SendCommand(const std::string& strCmd)
{
if(!_stTcpStreamPtr->good())
return -1;
std::string str = strCmd + "\r\n";
_stTcpStreamPtr->write(str.c_str(), str.size());
_stTcpStreamPtr->flush();
ACEX_LOG_OS(LM_DEBUG, "<<CFTPCtrlTcpObject>>SendCommand() cmd :" << str << std::endl);
return _stTcpStreamPtr->good() ? 0 : -1;
}
int CFTPCtrlTcpObject::RecvResult(ResultInfo_t& stResult)
{
if(!_stTcpStreamPtr->good())
{
stResult.m_iResult = REPLY_CODE_541;
stResult.m_strInfo = REPLY_COMMENT_541;
return -1;
}
ACE_Handle_Set rd_set;
rd_set.reset();
rd_set.set_bit(_stTcpStreamPtr->get_handle());
int iMaxFd = 0;
#if !defined(_WIN32)
iMaxFd = _stTcpStreamPtr->get_handle() + 1;
#endif
if(ACE::select(iMaxFd, &rd_set, NULL, NULL, &_stSelectTimeout) <= 0)
{//timeout
stResult.m_iResult = REPLY_CODE_542;
stResult.m_strInfo = REPLY_COMMENT_542;
return -1;
}
_stTcpStreamPtr->under_flow();
if(!_stTcpStreamPtr->good())
{
stResult.m_iResult = REPLY_CODE_541;
stResult.m_strInfo = REPLY_COMMENT_541;
return -1;
}
size_t szRead = _stTcpStreamPtr->in_avail();
if(szRead <= 0)
{
stResult.m_iResult = REPLY_CODE_543;
stResult.m_strInfo = REPLY_COMMENT_543;
return -1;
}
while(szRead > 0)
{
_stTcpStreamPtr->read(_acResultBuf + _szResultSize, szRead);
_szResultSize += szRead;
szRead = _stTcpStreamPtr->in_avail();
}
std::string strInfo;
strInfo.assign(_acResultBuf, _szResultSize);
stResult.m_strInfo = "";
try
{
std::string::size_type szPos = strInfo.find_first_of("\r\n");
while(szPos != std::string::npos)
{
stResult.m_strInfo = strInfo.substr(0, szPos);
strInfo = strInfo.substr(szPos + 2);
szPos = strInfo.find_first_of("\r\n");
}
if(stResult.m_strInfo.empty())
{
stResult.m_iResult = REPLY_CODE_544;
stResult.m_strInfo = REPLY_COMMENT_544;
return -1;
}
szPos = stResult.m_strInfo.find_first_of(" ");
if(szPos == std::string::npos)
{
stResult.m_iResult = REPLY_CODE_545;
stResult.m_strInfo = REPLY_COMMENT_545;
return -1;
}
stResult.m_iResult = atoi(stResult.m_strInfo.substr(0, szPos).c_str());
stResult.m_strInfo = stResult.m_strInfo.substr(szPos + 1);
}
catch(std::out_of_range& e)
{
ACEX_LOG_OS(LM_WARNING, "<<CFTPCtrlTcpObject>>RecvResult() exception(out_of_range) - remote maybe not FTP server." << std::endl);
stResult.m_iResult = REPLY_CODE_546;
stResult.m_strInfo = REPLY_COMMENT_546;
return -1;
}
_szResultSize = 0;
return 0;
}
int CFTPCtrlTcpObject::RecvResult()
{
if(RecvResult(_stResultInfo) == 0)
{
ACEX_LOG_OS(LM_DEBUG, "<<CFTPCtrlTcpObject>>RecvResult() Result(" << _stResultInfo.m_iResult << ")" << _stResultInfo.m_strInfo << std::endl);
return 0;
}
else
{
ACEX_LOG_OS(LM_WARNING, "<<CFTPCtrlTcpObject>>RecvResult() Result(" << _stResultInfo.m_iResult << ")" << _stResultInfo.m_strInfo << std::endl);
return -1;
}
}
int CFTPCtrlTcpObject::ResultCode() const
{
return _stResultInfo.m_iResult;
}
const std::string& CFTPCtrlTcpObject::ResultInfo() const
{
return _stResultInfo.m_strInfo;
}
int CFTPCtrlTcpObject::Open(const ACE_INET_Addr& stAddr)
{
_stTcpStreamPtr.reset(new ACEX_TcpStream(_szBufSize));
ACE_Time_Value st(5,0);
if(_stConnector.connect(*_stTcpStreamPtr.get(), stAddr, &st) == 0)
{
_stTcpStreamPtr->block(0);
RecvResult();
if(Is200Result() == 0)
{
_bConnected = true;
return 0;
}
else
{
Close();
}
}
return -1;
}
int CFTPCtrlTcpObject::Connect(const std::string& strUser, const std::string& strPasswd)
{
//if(_bConnected)
//{
// SendCommand("USER " + strUser);
// RecvResult();
// if(_stResultInfo.m_iResult == 331)
// {
// SendCommand("PASS " + strPasswd);
// RecvResult();
// if(Is200Result() == 0)
// {//set default trans mode
// return CmdType(_bASCII);
// }
// }
//}
//return -1;
if(_bConnected)
{
SendCommand("USER " + strUser);
while(RecvResult() == 0)
{
if(_stResultInfo.m_iResult == 331)
{
SendCommand("PASS " + strPasswd);
RecvResult();
if(Is200Result() == 0)
{//set default trans mode
return CmdType(_bASCII);
}
}
}
}
return -1;
}
int CFTPCtrlTcpObject::Close()
{
if(_bConnected)
{
SendCommand("QUIT");
RecvResult();
_stTcpStreamPtr->close();
_bConnected = false;
}
return 0;
}
const CFTPCtrlTcpObject::ResultInfo_t& CFTPCtrlTcpObject::GetResultInfo() const
{
return _stResultInfo;
}
int CFTPCtrlTcpObject::Is200Result(const ResultInfo_t& stResult) const
{
if(stResult.m_iResult >=200 && stResult.m_iResult < 300)
return 0;
else
return -1;
}
int CFTPCtrlTcpObject::Is100Result(const ResultInfo_t& stResult) const
{
if(stResult.m_iResult >=100 && stResult.m_iResult < 200)
return 0;
else
return -1;
}
int CFTPCtrlTcpObject::Is300Result(const ResultInfo_t& stResult) const
{
if(stResult.m_iResult >=300 && stResult.m_iResult < 400)
return 0;
else
return -1;
}
int CFTPCtrlTcpObject::Is200Result() const
{
return Is200Result(_stResultInfo);
}
int CFTPCtrlTcpObject::Is100Result() const
{
return Is100Result(_stResultInfo);
}
int CFTPCtrlTcpObject::Is300Result() const
{
return Is300Result(_stResultInfo);
}
//////////////////////////////////////////////////////////////////////////
int CFTPCtrlTcpObject::CmdChgDir(const std::string& strDir)
{
SendCommand("CWD " + strDir);
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdChgLocalDir(const std::string& strDir)
{
return ACE_OS::chdir(strDir.c_str());
}
int CFTPCtrlTcpObject::CmdMkDir(const std::string& strDir)
{
SendCommand("MKD " + strDir);
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdDelFile(const std::string& strFile)
{
SendCommand("DELE " + strFile);
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdType(bool bASCII /* = true */)
{
_bASCII = bASCII;
if(bASCII)
{
SendCommand("TYPE A");
}
else
{
SendCommand("TYPE I");
}
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdNoop()
{
SendCommand("NOOP");
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdRenFile(const std::string& strOldFile, const std::string& strNewFile)
{
SendCommand("RNFR " + strOldFile);
RecvResult();
if(_stResultInfo.m_iResult == 350)
{
SendCommand("RNTO " + strNewFile);
RecvResult();
return Is200Result();
}
else
{
return -1;
}
}
int CFTPCtrlTcpObject::CmdGetFile(const std::string& strRemoteFile, const std::string& strLocalFile)
{
_szAffectedSize = 0;
TDataTcpObjectPtr ptr(NULL);
if(_bPortMode)
ptr.reset(new CFTPPortDataTcpObject(*this));
else
ptr.reset(new CFTPPasvDataTcpObject(*this));
if(ptr->Get(strRemoteFile, strLocalFile, _szAffectedSize) != 0)
return -1;
ptr->Close();
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdPutFile(const std::string& strLocalFile, const std::string& strRemoteFile)
{
_szAffectedSize = 0;
TDataTcpObjectPtr ptr(NULL);
if(_bPortMode)
ptr.reset(new CFTPPortDataTcpObject(*this));
else
ptr.reset(new CFTPPasvDataTcpObject(*this));
if(ptr->Put(strRemoteFile, strLocalFile, _szAffectedSize) != 0)
return -1;
ptr->Close();
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::CmdNLst(const std::string& strFilter, std::string& strOutput)
{
std::string strCmd = "NLST";
if(!strFilter.empty())
strCmd += " " + strFilter;
std::ostringstream ostr;
if(SendCmdWithDataStream(strCmd, ostr) != 0)
return -1;
strOutput = ostr.str();
return 0;
}
int CFTPCtrlTcpObject::CmdList(const std::string& strFilter, std::string& strOutput)
{
std::string strCmd = "LIST";
if(!strFilter.empty())
strCmd += " " + strFilter;
std::ostringstream ostr;
if(SendCmdWithDataStream(strCmd, ostr) != 0)
return -1;
strOutput = ostr.str();
return 0;
}
int CFTPCtrlTcpObject::SendCmdWithDataStream(const std::string& strCmd, std::ostream& os)
{
TDataTcpObjectPtr ptr(NULL);
if(_bPortMode)
ptr.reset(new CFTPPortDataTcpObject(*this));
else
ptr.reset(new CFTPPasvDataTcpObject(*this));
if(ptr->SendCmd(strCmd, os) != 0)
return -1;
ptr->Close();
RecvResult();
return Is200Result();
}
int CFTPCtrlTcpObject::SendCmdWithDataStream(const std::string& strCmd, char* pchData, size_t& szDataRead)
{
TDataTcpObjectPtr ptr(NULL);
if(_bPortMode)
ptr.reset(new CFTPPortDataTcpObject(*this));
else
ptr.reset(new CFTPPasvDataTcpObject(*this));
if(ptr->SendCmd(strCmd, pchData, szDataRead) != 0)
return -1;
ptr->Close();
RecvResult();
return Is200Result();
}
size_t CFTPCtrlTcpObject::AffectedSize() const
{
return _szAffectedSize;
}
int CFTPCtrlTcpObject::GetLocalAddr(ACE_INET_Addr& stAddr)
{
if(!_bConnected)
return -1;
_stTcpStreamPtr->get_local_addr(stAddr);
return 0;
}
unsigned short CFTPCtrlTcpObject::GetRandPort()
{
int iRand = ACE_OS::rand_r(_seed);
while(iRand < 20000)
{
iRand = ACE_OS::rand_r(_seed);
}
return iRand;
}
std::string CFTPCtrlTcpObject::AnalyseAddr(const ACE_INET_Addr& stAddr) const
{
std::ostringstream ostr;
ostr << stAddr.get_host_addr();
ostr << "," << stAddr.get_port_number() / 256 << "," << stAddr.get_port_number() % 256;
std::string str = ostr.str();
std::string::size_type st = str.find_first_of(".");
while(st != std::string::npos)
{
str = str.replace(st, 1, ",");
st = str.find_first_of(".");
}
return str;
}
ACE_INET_Addr CFTPCtrlTcpObject::AnalyseAddr(const std::string& strAddr) const
{
std::string str = strAddr;
std::ostringstream ostr;
std::string::size_type pos = str.find(',');
if(pos != std::string::npos)
ostr << str.substr(0, pos) << ".";
else
return ACE_INET_Addr("0.0.0.0:0");
str = str.substr(pos + 1);
pos = str.find(',');
if(pos != std::string::npos)
ostr << str.substr(0, pos) << ".";
else
return ACE_INET_Addr("0.0.0.0:0");
str = str.substr(pos + 1);
pos = str.find(',');
if(pos != std::string::npos)
ostr << str.substr(0, pos) << ".";
else
return ACE_INET_Addr("0.0.0.0:0");
str = str.substr(pos + 1);
pos = str.find(',');
if(pos != std::string::npos)
ostr << str.substr(0, pos) << ":";
else
return ACE_INET_Addr("0.0.0.0:0");
str = str.substr(pos + 1);
pos = str.find(',');
if(pos != std::string::npos)
ostr << atoi(str.substr(0, pos).c_str()) * 256 + atoi(str.substr(pos + 1).c_str());
return ACE_INET_Addr(ostr.str().c_str());
}
//////////////////////////////////////////////////////////////////////////
CFTPDataTcpObject::~CFTPDataTcpObject()
{
Close();
}
CFTPDataTcpObject::TransStatus CFTPDataTcpObject::SelectRead(size_t &size)
{
if(!_stTcpStreamPtr->good())
return TS_UNKNWON;
ACE_Handle_Set rd_set;
rd_set.reset();
rd_set.set_bit(_stTcpStreamPtr->get_handle());
int iMaxFd = 0;
#if !defined(_WIN32)
iMaxFd = _stTcpStreamPtr->get_handle() + 1;
#endif
if(ACE::select(iMaxFd, &rd_set, NULL, NULL, &_stTimeout) <= 0)
{
return TS_TIMEOUT;
}
_stTcpStreamPtr->under_flow();
size = _stTcpStreamPtr->in_avail();
return TS_READ;
}
CFTPDataTcpObject::TransStatus CFTPDataTcpObject::SelectWrite()
{
if(!_stTcpStreamPtr->good())
return TS_UNKNWON;
ACE_Handle_Set wr_set;
wr_set.reset();
wr_set.set_bit(_stTcpStreamPtr->get_handle());
int iMaxFd = 0;
#if !defined(_WIN32)
iMaxFd = _stTcpStreamPtr->get_handle() + 1;
#endif
if(ACE::select(iMaxFd, NULL, &wr_set, NULL, &_stTimeout) <= 0)
{
return TS_TIMEOUT;
}
return TS_WRITE;
}
int CFTPDataTcpObject::Read(char*& data, size_t& size)
{
size = 0;
data = NULL;
while(_stTcpStreamPtr->good())
{
if(_bStop)
return -1;
size_t szRead = 0;
TransStatus eTrans = SelectRead(szRead);
if(eTrans == TS_READ)
{
if(szRead == 0)
break;
char* pch = new char[szRead];
if(_stTcpStreamPtr->read(pch, szRead).good())
{
if(data != NULL)
{
delete [] data;
data = new char[size + szRead];
}
memcpy(data + size, pch, szRead);
size += szRead;
}
else
{
delete [] pch;
return -1;
}
delete [] pch;
}
else if(eTrans == CFTPDataTcpObject::TS_TIMEOUT)
{
continue;
}
else
{
return -1;
}
}
return 0;
}
int CFTPDataTcpObject::Write(const char* data, size_t size)
{
size_t szWrite = 0;
while(szWrite < size)
{
if(_bStop)
return -1;
TransStatus eTrans = SelectWrite();
if(eTrans == CFTPDataTcpObject::TS_WRITE)
{
if(size - szWrite >= 5120)
{
_stTcpStreamPtr->write(data + szWrite, 5120);
if(!_stTcpStreamPtr->flush().good())
return -1;
}
else
{
_stTcpStreamPtr->write(data + szWrite, size - szWrite);
if(!_stTcpStreamPtr->flush().good())
return -1;
}
szWrite += 5120;
}
else if(eTrans == CFTPDataTcpObject::TS_TIMEOUT)
{
continue;
}
else
{
break;
}
}
return 0;
}
int CFTPDataTcpObject::Read(std::ofstream &ofile, size_t& size)
{
if(!ofile.good())
return -1;
size = 0;
while(_stTcpStreamPtr->good())
{
if(_bStop)
return -1;
size_t szRead = 0;
TransStatus eTrans = SelectRead(szRead);
if(eTrans == TS_READ)
{
if(szRead == 0)
break;
char* pch = new char[szRead];
if(_stTcpStreamPtr->read(pch, szRead).good())
{
ofile.write(pch, szRead);
size += szRead;
if(!ofile.good())
{
delete [] pch;
return -1;
}
}
else
{
delete [] pch;
return -1;
}
delete [] pch;
}
else if(eTrans == CFTPDataTcpObject::TS_TIMEOUT)
{
continue;
}
else
{
return -1;
}
}
return 0;
}
int CFTPDataTcpObject::Write(std::ifstream &ifile, size_t &size)
{
if(!ifile.good())
return -1;
size = 0;
char buf[5120];
while(!ifile.eof() && ifile.good())
{
if(_bStop)
return -1;
TransStatus eTrans = SelectWrite();
if(eTrans == CFTPDataTcpObject::TS_WRITE)
{
size_t szRead = ifile.read(buf, 5120).gcount();
if(szRead > 0)
{
_stTcpStreamPtr->write(buf, szRead);
if(!_stTcpStreamPtr->flush().good())
return -1;
size += szRead;
}
else
{
break;
}
}
else if(eTrans == CFTPDataTcpObject::TS_TIMEOUT)
{
continue;
}
else
{
break;
}
}
return 0;
}
int CFTPDataTcpObject::Read(std::ostream &os, size_t& size)
{
if(!os.good())
return -1;
size = 0;
while(_stTcpStreamPtr->good())
{
if(_bStop)
return -1;
size_t szRead = 0;
TransStatus eTrans = SelectRead(szRead);
if(eTrans == TS_READ)
{
if(szRead == 0)
break;
char* pch = new char[szRead];
if(_stTcpStreamPtr->read(pch, szRead).good())
{
os.write(pch, szRead);
size += szRead;
if(!os.good())
{
delete [] pch;
return -1;
}
}
else
{
delete [] pch;
return -1;
}
delete [] pch;
}
else if(eTrans == CFTPDataTcpObject::TS_TIMEOUT)
{
continue;
}
else
{
return -1;
}
}
return 0;
}
void CFTPDataTcpObject::Close()
{
if(_stTcpStreamPtr.get() != NULL)
{
_stTcpStreamPtr->close();
_stTcpStreamPtr.reset(NULL);
}
}
////
CFTPPortDataTcpObject::CFTPPortDataTcpObject(CFTPCtrlTcpObject &ctrlobject, size_t buffsize, const ACE_Time_Value &timeout)
: CFTPDataTcpObject(ctrlobject, buffsize, timeout)
{
}
CFTPPortDataTcpObject::~CFTPPortDataTcpObject()
{
}
int CFTPPortDataTcpObject::Get(const std::string &remote, const std::string &local, size_t& size)
{
if(!_stCtrlObject.IsConnected())
return -1;
std::ios_base::openmode mode = std::ios::trunc | std::ios::out;
if(!_stCtrlObject.IsASCII())
mode |= std::ios_base::binary;
std::ofstream ofile(local.c_str(), mode);
if(!ofile.is_open() || !ofile.good())
return -1;
if(Open() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Get>open() failed." << std::endl);
return -1;
}
if(Port() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Get>port() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand("RETR " + remote);
_stCtrlObject.RecvResult();
if(_stCtrlObject.Is100Result() != 0)
// if(result.m_iResult < 100 || result.m_iResult > 199)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Get>RETR command failed." << std::endl);
return -1;
}
if(Accept() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Get>accept() failed." << std::endl);
return -1;
}
if(Read(ofile, size) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Get>Read() failed." << std::endl);
return -1;
}
ofile.close();
return 0;
}
int CFTPPortDataTcpObject::Put(const std::string& remote, const std::string& local, size_t& size)
{
if(!_stCtrlObject.IsConnected())
return -1;
std::ios_base::openmode mode = std::ios_base::in;
if(!_stCtrlObject.IsASCII())
mode |= std::ios_base::binary;
std::ifstream ifile(local.c_str(), mode);
if(!ifile.is_open() || !ifile.good())
return -1;
if(Open() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Put>open() failed." << std::endl);
return -1;
}
if(Port() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Put>port() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand("STOR " + remote);
_stCtrlObject.RecvResult();
// if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Put>STOR command failed." << std::endl);
return -1;
}
if(Accept() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Put>accept() failed." << std::endl);
return -1;
}
if(Write(ifile, size) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::Put>Write() failed." << std::endl);
return -1;
}
ifile.close();
return 0;
}
int CFTPPortDataTcpObject::SendCmd(const std::string& strCmd, char*& pchData, size_t& szDataRead)
{
if(!_stCtrlObject.IsConnected())
return -1;
if(Open() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>open() failed." << std::endl);
return -1;
}
if(Port() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>port() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand(strCmd);
_stCtrlObject.RecvResult();
// if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>" << strCmd << " command failed." << std::endl);
return -1;
}
if(Accept() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>accept() failed." << std::endl);
return -1;
}
if(Read(pchData, szDataRead) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>Read() failed." << std::endl);
return -1;
}
return 0;
}
int CFTPPortDataTcpObject::SendCmd(const std::string& strCmd, std::ostream& os)
{
if(!_stCtrlObject.IsConnected())
return -1;
if(Open() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>open() failed." << std::endl);
return -1;
}
if(Port() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>port() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand(strCmd);
_stCtrlObject.RecvResult();
//if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>" << strCmd << " command failed." << std::endl);
return -1;
}
if(Accept() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>accept() failed." << std::endl);
return -1;
}
size_t szDataRead = 0;
if(Read(os, szDataRead) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPortDataTcpObject::SendCmd>Read() failed." << std::endl);
return -1;
}
return 0;
}
int CFTPPortDataTcpObject::Open()
{
_stCtrlObject.GetLocalAddr(_stLocalAddr);
_stLocalAddr.set_port_number(_stCtrlObject.GetRandPort());
while(_stAcceptor.open(_stLocalAddr) != 0)
{
_stLocalAddr.set_port_number(_stCtrlObject.GetRandPort());
}
_bOpen = true;
return 0;
}
int CFTPPortDataTcpObject::Port()
{
// CFTPCtrlTcpObject::ResultInfo_t result;
std::string strPort = _stCtrlObject.AnalyseAddr(_stLocalAddr);
_stCtrlObject.SendCommand("PORT " + strPort);
_stCtrlObject.RecvResult();
if(_stCtrlObject.Is200Result() != 0)
return -1;
return 0;
}
int CFTPPortDataTcpObject::Accept()
{
ACE_Handle_Set rd_set;
rd_set.reset();
rd_set.set_bit(_stAcceptor.get_handle());
int iMaxFd = 0;
#if !defined(_WIN32)
iMaxFd = _stAcceptor.get_handle() + 1;
#endif
if(ACE::select(iMaxFd, &rd_set, NULL, NULL, &_stTimeout) > 0)
{
if(rd_set.is_set(_stAcceptor.get_handle()))
{
_stTcpStreamPtr.reset(new ACEX_TcpStream(_szBuffSize));
if(_stAcceptor.accept(*_stTcpStreamPtr.get()) == 0)
{
_stTcpStreamPtr->block(0);
}
else
{
_stTcpStreamPtr.reset(NULL);
}
}
}
_stAcceptor.close();
if(_stTcpStreamPtr.get() != NULL)
return 0;
_bOpen = false;
return -1;
}
//
CFTPPasvDataTcpObject::CFTPPasvDataTcpObject(CFTPCtrlTcpObject& ctrlobject, size_t buffsize /* = 64 * 1024 */, const ACE_Time_Value& timeout /* = ACE_Time_Value */)
: CFTPDataTcpObject(ctrlobject, buffsize, timeout)
{
}
CFTPPasvDataTcpObject::~CFTPPasvDataTcpObject()
{
}
int CFTPPasvDataTcpObject::Get(const std::string &remote, const std::string &local, size_t &size)
{
if(!_stCtrlObject.IsConnected())
return -1;
std::ios_base::openmode mode = std::ios::trunc | std::ios::out;
if(!_stCtrlObject.IsASCII())
mode |= std::ios_base::binary;
std::ofstream ofile(local.c_str(), mode);
if(!ofile.is_open() || !ofile.good())
return -1;
if(Pasv() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Get>Pasv() failed." << std::endl);
return -1;
}
if(Connect() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Get>Connect() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand("RETR " + remote);
_stCtrlObject.RecvResult();
// if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Get>RETR command failed." << std::endl);
return -1;
}
if(Read(ofile, size) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Get>Read() failed." << std::endl);
return -1;
}
ofile.close();
return 0;
}
int CFTPPasvDataTcpObject::Put(const std::string& remote, const std::string& local, size_t& size)
{
if(!_stCtrlObject.IsConnected())
return -1;
std::ios_base::openmode mode = std::ios_base::in;
if(!_stCtrlObject.IsASCII())
mode |= std::ios_base::binary;
std::ifstream ifile(local.c_str(), mode);
if(!ifile.is_open() || !ifile.good())
return -1;
if(Pasv() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Put>Pasv() failed." << std::endl);
return -1;
}
if(Connect() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Put>Connect() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand("STOR " + remote);
_stCtrlObject.RecvResult();
// if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Put>STOR command failed." << std::endl);
return -1;
}
if(Write(ifile, size) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::Put>Write() failed." << std::endl);
return -1;
}
ifile.close();
return 0;
}
int CFTPPasvDataTcpObject::SendCmd(const std::string& strCmd, char*& pchData, size_t& szDataRead)
{
if(!_stCtrlObject.IsConnected())
return -1;
if(Pasv() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>Pasv() failed." << std::endl);
return -1;
}
if(Connect() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>Connect() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand(strCmd);
_stCtrlObject.RecvResult();
// if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>" << strCmd << " command failed." << std::endl);
return -1;
}
if(Read(pchData, szDataRead) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>Read() failed." << std::endl);
return -1;
}
return 0;
}
int CFTPPasvDataTcpObject::SendCmd(const std::string& strCmd, std::ostream& os)
{
if(!_stCtrlObject.IsConnected())
return -1;
if(Pasv() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>Pasv() failed." << std::endl);
return -1;
}
if(Connect() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>Connect() failed." << std::endl);
return -1;
}
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand(strCmd);
_stCtrlObject.RecvResult();
// if(result.m_iResult < 100 || result.m_iResult > 199)
if(_stCtrlObject.Is100Result() != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>" << strCmd << " command failed." << std::endl);
return -1;
}
size_t szDataRead = 0;
if(Read(os, szDataRead) != 0)
{
ACEX_LOG_OS(LM_ERROR, "<CFTPPasvDataTcpObject::SendCmd>Read() failed." << std::endl);
return -1;
}
return 0;
}
int CFTPPasvDataTcpObject::Pasv()
{
// CFTPCtrlTcpObject::ResultInfo_t result;
_stCtrlObject.SendCommand("PASV");
_stCtrlObject.RecvResult();
if(_stCtrlObject.ResultCode() != 227)
{
return -1;
}
std::string info = _stCtrlObject.ResultInfo();
std::string str = "";
// unsigned short port = 0;
// size_t pos = 0;
for(std::string::const_iterator it = info.begin(); it != info.end(); ++ it)
{
if((*it >= '0' && *it <= '9') || (*it == ','))
{
str += *it;
}
}
_stRemoteAddr = _stCtrlObject.AnalyseAddr(str);
return 0;
}
int CFTPPasvDataTcpObject::Connect()
{
_stTcpStreamPtr.reset(new ACEX_TcpStream(_szBuffSize));
if(_stConnector.connect(*_stTcpStreamPtr.get(), _stRemoteAddr, &_stTimeout) == 0)
{
_stTcpStreamPtr->block(0);
}
else
{
_stTcpStreamPtr.reset(NULL);
}
if(_stTcpStreamPtr.get() != NULL)
return 0;
_bOpen = false;
return -1;
}