ftpcontrolsocket.cpp
来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 2,319 行 · 第 1/5 页
CPP
2,319 行
// FileZilla - a Windows ftp client
// Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// CFtpControlSocket.cpp: Implementierungsdatei
//
#include "stdafx.h"
#include "FtpControlSocket.h"
#include "mainthread.h"
#include "transfersocket.h"
#include "fileexistsdlg.h"
#include "pathfunctions.h"
#include "asyncproxysocketlayer.h"
#include "AsyncSslSocketLayer.h"
#include "AsyncGssSocketLayer.h"
#include "filezillaapi.h"
#include "misc/utf8.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
class CFtpControlSocket::CFileTransferData : public CFtpControlSocket::t_operation::COpData
{
public:
CFileTransferData()
{
pDirectoryListing=0;
nGotTransferEndReply=0;
nWaitNextOpState=0;
nMKDOpState=-1;
pFileTime=0;
pFileSize=0;
bUseAbsolutePaths = FALSE;
bTriedPortPasvOnce = FALSE;
askOnResumeFail = false;
};
~CFileTransferData()
{
if (pDirectoryListing)
delete pDirectoryListing;
pDirectoryListing=0;
delete pFileSize;
delete pFileTime;
};
CString rawpwd;
t_transferfile transferfile;
t_transferdata transferdata;
CString host;
int port;
BOOL bPasv;
int nGotTransferEndReply;
t_directory *pDirectoryListing;
int nWaitNextOpState;
CServerPath MKDCurrent;
std::list<CString> MKDSegments;
int nMKDOpState;
CTime ListStartTime;
CTime *pFileTime; //Used when downloading and OPTION_PRESERVEDOWNLOADFILETIME is set or when LIST fails
_int64 *pFileSize; //Used when LIST failes
BOOL bUseAbsolutePaths;
BOOL bTriedPortPasvOnce;
int newZlibLevel;
bool askOnResumeFail;
};
class CFtpControlSocket::CListData:public CFtpControlSocket::t_operation::COpData
{
public:
CListData()
{
pDirectoryListing = 0;
bTriedPortPasvOnce = FALSE;
lastCmdSentCDUP = false;
}
virtual ~CListData()
{
if (pDirectoryListing)
delete pDirectoryListing;
}
CString rawpwd;
CServerPath path;
CString subdir;
int nListMode;
BOOL bPasv;
CString host;
UINT port;
int nFinish;
t_directory *pDirectoryListing;
CTime ListStartTime;
BOOL bTriedPortPasvOnce;
int newZlibLevel;
bool lastCmdSentCDUP;
};
class CFtpControlSocket::CMakeDirData : public CFtpControlSocket::t_operation::COpData
{
public:
CMakeDirData() {}
virtual ~CMakeDirData() {}
CServerPath path;
CServerPath Current;
std::list<CString> Segments;
};
#define MKD_INIT -1
#define MKD_FINDPARENT 0
#define MKD_MAKESUBDIRS 1
#define MKD_CHANGETOSUBDIR 2
/////////////////////////////////////////////////////////////////////////////
// CFtpControlSocket
CFtpControlSocket::CFtpControlSocket(CMainThread *pMainThread) : CControlSocket(pMainThread)
{
ASSERT(pMainThread);
m_Operation.nOpMode=0;
m_Operation.nOpState=-1;
m_Operation.pData=0;
m_pTransferSocket=0;
m_pDataFile=0;
m_pDirectoryListing=0;
m_pOwner=pMainThread;
srand( (unsigned)time( NULL ) );
m_bKeepAliveActive=FALSE;
m_bCheckForTimeout=TRUE;
m_bDidRejectCertificate = FALSE;
m_useZlib = false;
m_zlibSupported = false;
m_zlibLevel = 8;
m_bUTF8 = false;
m_hasClntCmd = false;
m_awaitsReply = false;
m_skipReply = false;
m_sendBuffer = 0;
m_sendBufferLen = 0;
m_bProtP = false;
m_mayBeMvsFilesystem = false;
m_mayBeBS2000Filesystem = false;
}
CFtpControlSocket::~CFtpControlSocket()
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("~CFtpControlSocket()"));
DoClose();
if (m_pTransferSocket)
{
m_pTransferSocket->Close();
delete m_pTransferSocket;
m_pTransferSocket=0;
}
if (m_pDataFile)
{
delete m_pDataFile;
m_pDataFile=0;
}
}
/////////////////////////////////////////////////////////////////////////////
// Member-Funktion CFtpControlSocket
#define CONNECT_INIT -1
#define CONNECT_GSS_INIT -2
#define CONNECT_GSS_AUTHDONE -3
#define CONNECT_GSS_CWD -4
#define CONNECT_GSS_FAILED -5
#define CONNECT_GSS_NEEDPASS -6
#define CONNECT_GSS_NEEDUSER -7
#define CONNECT_SSL_INIT -8
#define CONNECT_SSL_NEGOTIATE -9
#define CONNECT_SSL_WAITDONE -10
#define CONNECT_SSL_PBSZ -11
#define CONNECT_SSL_PROT -12
#define CONNECT_FEAT -13
#define CONNECT_SYST -14
#define CONNECT_OPTSUTF8 -15
#define CONNECT_CLNT -16
void CFtpControlSocket::Connect(t_server &server)
{
USES_CONVERSION;
// Some sanity checks
if (m_pOwner->IsConnected())
{
ShowStatus(_T("Internal error: Connect called while still connected"), 1);
if (!m_Operation.nOpMode)
m_Operation.nOpMode = CSMODE_CONNECT;
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
if (m_Operation.nOpMode)
{
ShowStatus(_T("Internal error: m_Operation.nOpMode not zero in Connect"), 1);
m_Operation.nOpMode = CSMODE_CONNECT;
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
m_Operation.nOpMode = CSMODE_CONNECT;
if (m_pSslLayer)
{
ShowStatus(_T("Internal error: m_pSslLayer not zero in Connect"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
if (m_pProxyLayer)
{
ShowStatus(_T("Internal error: m_pProxyLayer not zero in Connect"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
if (server.nServerType & FZ_SERVERTYPE_LAYER_SSL_IMPLICIT ||
server.nServerType & FZ_SERVERTYPE_LAYER_SSL_EXPLICIT ||
server.nServerType & FZ_SERVERTYPE_LAYER_TLS_EXPLICIT)
{
m_pSslLayer = new CAsyncSslSocketLayer;
AddLayer(m_pSslLayer);
TCHAR buffer[1000];
GetModuleFileName(NULL, buffer, 1000);
CString filename = buffer;
int pos = filename.ReverseFind('\\');
if (pos != -1)
{
filename = filename.Left(pos + 1);
filename += _T("cacert.pem");
m_pSslLayer->SetCertStorage(filename);
}
else
filename = "cacert.pem";
}
if (!server.fwbypass)
{
int nProxyType = COptions::GetOptionVal(OPTION_PROXYTYPE);
if (nProxyType != PROXYTYPE_NOPROXY)
{
m_pProxyLayer = new CAsyncProxySocketLayer;
if (nProxyType == PROXYTYPE_SOCKS4)
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS4, T2CA(COptions::GetOption(OPTION_PROXYHOST)), COptions::GetOptionVal(OPTION_PROXYPORT));
else if (nProxyType==PROXYTYPE_SOCKS4A)
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS4A, T2CA(COptions::GetOption(OPTION_PROXYHOST)),COptions::GetOptionVal(OPTION_PROXYPORT));
else if (nProxyType==PROXYTYPE_SOCKS5)
if (COptions::GetOptionVal(OPTION_PROXYUSELOGON))
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS5, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
COptions::GetOptionVal(OPTION_PROXYPORT),
T2CA(COptions::GetOption(OPTION_PROXYUSER)),
T2CA(CCrypt::decrypt(COptions::GetOption(OPTION_PROXYPASS))));
else
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS5, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
COptions::GetOptionVal(OPTION_PROXYPORT));
else if (nProxyType==PROXYTYPE_HTTP11)
if (COptions::GetOptionVal(OPTION_PROXYUSELOGON))
m_pProxyLayer->SetProxy(PROXYTYPE_HTTP11, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
COptions::GetOptionVal(OPTION_PROXYPORT),
T2CA(COptions::GetOption(OPTION_PROXYUSER)),
T2CA(CCrypt::decrypt(COptions::GetOption(OPTION_PROXYPASS))));
else
m_pProxyLayer->SetProxy(PROXYTYPE_HTTP11, T2CA(COptions::GetOption(OPTION_PROXYHOST)) ,COptions::GetOptionVal(OPTION_PROXYPORT));
else
ASSERT(FALSE);
AddLayer(m_pProxyLayer);
}
}
BOOL bUseGSS = FALSE;
if (COptions::GetOptionVal(OPTION_USEGSS) && !m_pSslLayer)
{
CString GssServers=COptions::GetOption(OPTION_GSSSERVERS);
LPCSTR lpszAscii=T2CA(server.host);
hostent *fullname=gethostbyname(lpszAscii);
CString host;
if (fullname)
host=fullname->h_name;
else
host=server.host;
host.MakeLower();
int i;
while ((i=GssServers.Find(_T(";")))!=-1)
{
if (("."+GssServers.Left(i))==host.Right(GssServers.Left(i).GetLength()+1) || GssServers.Left(i)==host)
{
bUseGSS=TRUE;
break;
}
GssServers=GssServers.Mid(i+1);
}
}
if (bUseGSS)
{
m_pGssLayer = new CAsyncGssSocketLayer;
AddLayer(m_pGssLayer);
if (!m_pGssLayer->InitGSS())
{
ShowStatus(_T("Unable to initialize GSS api"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
}
m_Operation.nOpState = m_pGssLayer?CONNECT_GSS_INIT:CONNECT_INIT;
m_Operation.nOpMode = CSMODE_CONNECT;
if (!Create())
{
DoClose();
return;
}
AsyncSelect();
if (server.nServerType&FZ_SERVERTYPE_LAYER_SSL_IMPLICIT)
{
if (!m_pSslLayer)
{
ShowStatus(_T("Internal error: m_pSslLayer not initialized"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
int res = m_pSslLayer->InitSSLConnection(true);
if (res == SSL_FAILURE_LOADDLLS)
ShowStatus(IDS_ERRORMSG_CANTLOADSSLDLLS, 1);
else if (res == SSL_FAILURE_INITSSL)
ShowStatus(IDS_ERRORMSG_CANTINITSSL, 1);
if (!res)
PostMessage(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_SECURESERVER, 1), 0);
else
{
DoClose();
return;
}
}
int logontype = COptions::GetOptionVal(OPTION_LOGONTYPE);
int port;
CString buf,temp;
if (server.fwbypass)
logontype=0;
// are we connecting directly to the host (logon type 0) or via a firewall? (logon type>0)
CString fwhost;
int fwport;
if(!logontype)
{
temp=server.host;
port=server.port;
}
else
{
fwhost=COptions::GetOption(OPTION_FWHOST);
fwport=COptions::GetOptionVal(OPTION_FWPORT);
temp=fwhost;
port=fwport;
if(fwport!=21)
fwhost.Format( _T("%s:%d"), fwhost, fwport); // add port to fwhost (only if port is not 21)
}
m_CurrentServer = server;
CString hostname = server.host;
if(server.port!=21)
hostname.Format( _T("%s:%d"), hostname, server.port); // add port to hostname (only if port is not 21)
CString str;
str.Format(IDS_STATUSMSG_CONNECTING, hostname);
ShowStatus(str, 0);
if ((server.nServerType & FZ_SERVERTYPE_LAYERMASK) & (FZ_SERVERTYPE_LAYER_SSL_EXPLICIT | FZ_SERVERTYPE_LAYER_TLS_EXPLICIT))
m_Operation.nOpState = CONNECT_SSL_INIT;
if (!CControlSocket::Connect(temp, port))
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
DoClose();
return;
}
}
m_ServerName = logontype?fwhost:hostname;
m_LastRecvTime = m_LastSendTime = CTime::GetCurrentTime();
}
void CFtpControlSocket::LogOnToServer(BOOL bSkipReply /*=FALSE*/)
{
int logontype = m_pGssLayer ? 0 : COptions::GetOptionVal(OPTION_LOGONTYPE);
const int LO = -2, ER = -1;
CString buf, temp;
const int NUMLOGIN = 9; // currently supports 9 different login sequences
int logonseq[NUMLOGIN][20] = {
// this array stores all of the logon sequences for the various firewalls
// in blocks of 3 nums. 1st num is command to send, 2nd num is next point in logon sequence array
// if 200 series response is rec'd from server as the result of the command, 3rd num is next
// point in logon sequence if 300 series rec'd
{0,LO,3, 1,LO,6, 12,LO,ER}, // no firewall
{3,6,3, 4,6,ER, 5,9,9, 0,LO,12, 1,LO,15, 12,LO,ER}, // SITE hostname
{3,6,3, 4,6,ER, 6,LO,9, 1,LO,12, 12,LO,ER}, // USER after logon
{7,3,3, 0,LO,6, 1,LO,9, 12,LO,ER}, //proxy OPEN
{3,6,3, 4,6,ER, 0,LO,9, 1,LO,12, 12,LO,ER}, // Transparent
{6,LO,3, 1,LO,6, 12,LO,ER}, // USER remoteID@remotehost
{8,6,3, 4,6,ER, 0,LO,9, 1,LO,12, 12,LO,ER}, //USER fireID@remotehost
{9,ER,3, 1,LO,6, 2,LO,ER}, //USER remoteID@remotehost fireID
{10,LO,3,11,LO,6,2,LO,ER} // USER remoteID@fireID@remotehost
};
if (m_CurrentServer.fwbypass)
logontype = 0;
if (m_Operation.nOpState == CONNECT_SSL_INIT)
{
if (m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYER_SSL_EXPLICIT)
{
if (!Send("AUTH SSL"))
return;
}
else
{
if (!Send("AUTH TLS"))
return;
}
m_Operation.nOpState = CONNECT_SSL_NEGOTIATE;
return;
}
else if (m_Operation.nOpState == CONNECT_SSL_NEGOTIATE)
{
int res = GetReplyCode();
if (res!=2 && res!=3)
{
DoClose();
return;
}
else
{
if (!m_pSslLayer)
{
ShowStatus(_T("Internal error: m_pSslLayer not initialized"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
int res = m_pSslLayer->InitSSLConnection(true);
if (res == SSL_FAILURE_LOADDLLS)
ShowStatus(IDS_ERRORMSG_CANTLOADSSLDLLS, 1);
else if (res == SSL_FAILURE_INITSSL)
ShowStatus(IDS_ERRORMSG_CANTINITSSL, 1);
if (res)
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?