#include "FileZilla.h"
#include "logging_private.h"
#include "ControlSocket.h"
#include <idna.h>
#include "asynchostresolver.h"
#include "directorycache.h"
DECLARE_EVENT_TYPE(fzOBTAINLOCK, -1)
DEFINE_EVENT_TYPE(fzOBTAINLOCK)
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
std::list<CControlSocket::t_lockInfo> CControlSocket::m_lockInfoList;
BEGIN_EVENT_TABLE(CControlSocket, wxEvtHandler)
EVT_TIMER(wxID_ANY, CControlSocket::OnTimer)
EVT_COMMAND(wxID_ANY, fzOBTAINLOCK, CControlSocket::OnObtainLock)
END_EVENT_TABLE();
COpData::COpData(enum Command op_Id)
: opId(op_Id)
{
opState = 0;
pNextOpData = 0;
waitForAsyncRequest = false;
}
COpData::~COpData()
{
delete pNextOpData;
}
CControlSocket::CControlSocket(CFileZillaEnginePrivate *pEngine)
: CLogging(pEngine)
{
m_pEngine = pEngine;
m_pCurOpData = 0;
m_pCurrentServer = 0;
m_pTransferStatus = 0;
m_transferStatusSendState = 0;
m_pCSConv = 0;
m_useUTF8 = false;
m_timer.SetOwner(this);
m_closed = false;
m_invalidateCurrentPath = false;
}
CControlSocket::~CControlSocket()
{
DoClose();
delete m_pCSConv;
m_pCSConv = 0;
}
int CControlSocket::Disconnect()
{
LogMessage(Status, _("Disconnected from server"));
DoClose();
return FZ_REPLY_OK;
}
enum Command CControlSocket::GetCurrentCommandId() const
{
if (m_pCurOpData)
return m_pCurOpData->opId;
return m_pEngine->GetCurrentCommandId();
}
int CControlSocket::ResetOperation(int nErrorCode)
{
LogMessage(Debug_Verbose, _T("CControlSocket::ResetOperation(%d)"), nErrorCode);
if (nErrorCode & FZ_REPLY_WOULDBLOCK)
{
LogMessage(::Debug_Warning, _T("ResetOperation with FZ_REPLY_WOULDBLOCK in nErrorCode (%d)"), nErrorCode);
}
if (m_pCurOpData && m_pCurOpData->opId != cmd_rawtransfer)
{
UnlockCache();
}
if (m_pCurOpData && m_pCurOpData->pNextOpData)
{
COpData *pNext = m_pCurOpData->pNextOpData;
m_pCurOpData->pNextOpData = 0;
delete m_pCurOpData;
m_pCurOpData = pNext;
if (nErrorCode == FZ_REPLY_OK ||
nErrorCode == FZ_REPLY_ERROR ||
nErrorCode == FZ_REPLY_CRITICALERROR)
{
return SendNextCommand(nErrorCode);
}
else
return ResetOperation(nErrorCode);
}
if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR)
LogMessage(::Error, _("Critical error"));
if (m_pCurOpData)
{
const enum Command commandId = m_pCurOpData->opId;
switch (commandId)
{
case cmd_none:
break;
case cmd_connect:
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
LogMessage(::Error, _("Connection attempt interrupted by user"));
else if (nErrorCode != FZ_REPLY_OK)
LogMessage(::Error, _("Could not connect to server"));
break;
case cmd_list:
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
LogMessage(::Error, _("Directory listing aborted by user"));
else if (nErrorCode != FZ_REPLY_OK)
LogMessage(::Error, _("Failed to retrieve directory listing"));
else
LogMessage(Status, _("Directory listing successful"));
break;
case cmd_transfer:
{
CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData);
if (!pData->download && pData->transferInitiated)
{
if (!m_pCurrentServer)
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("m_pCurrentServer is 0"));
else
{
CDirectoryCache cache;
bool updated = cache.UpdateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1);
if (updated)
m_pEngine->SendDirectoryListingNotification(pData->remotePath, false, true, false);
}
}
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
LogMessage(::Error, _("Transfer aborted by user"));
else if (nErrorCode == FZ_REPLY_OK)
LogMessage(Status, _("File transfer successful"));
}
break;
default:
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
LogMessage(::Error, _("Interrupted by user"));
break;
}
delete m_pCurOpData;
m_pCurOpData = 0;
}
ResetTransferStatus();
SetWait(false);
if (m_invalidateCurrentPath)
{
m_CurrentPath.Clear();
m_invalidateCurrentPath = false;
}
return m_pEngine->ResetOperation(nErrorCode);
}
int CControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/)
{
if (m_closed)
{
wxASSERT(!m_pCurOpData);
return nErrorCode;
}
m_closed = true;
nErrorCode = ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED | nErrorCode);
delete m_pCurrentServer;
m_pCurrentServer = 0;
return nErrorCode;
}
wxString CControlSocket::ConvertDomainName(wxString domain)
{
const wxWCharBuffer buffer = wxConvCurrent->cWX2WC(domain);
int len = 0;
while (buffer.data()[len])
len++;
char *utf8 = new char[len * 2 + 2];
wxMBConvUTF8 conv;
conv.WC2MB(utf8, buffer, len * 2 + 2);
char *output;
if (idna_to_ascii_8z(utf8, &output, IDNA_ALLOW_UNASSIGNED))
{
delete [] utf8;
LogMessage(::Debug_Warning, _T("Could not convert domain name"));
return domain;
}
delete [] utf8;
wxString result = wxConvCurrent->cMB2WX(output);
free(output);
return result;
}
void CControlSocket::Cancel()
{
if (GetCurrentCommandId() != cmd_none)
{
if (GetCurrentCommandId() == cmd_connect)
DoClose(FZ_REPLY_CANCELED);
else
ResetOperation(FZ_REPLY_CANCELED);
}
}
void CControlSocket::ResetTransferStatus()
{
delete m_pTransferStatus;
m_pTransferStatus = 0;
m_pEngine->AddNotification(new CTransferStatusNotification(0));
m_transferStatusSendState = 0;
}
void CControlSocket::InitTransferStatus(wxFileOffset totalSize, wxFileOffset startOffset, bool list)
{
if (startOffset < 0)
startOffset = 0;
delete m_pTransferStatus;
m_pTransferStatus = new CTransferStatus();
m_pTransferStatus->list = list;
m_pTransferStatus->totalSize = totalSize;
m_pTransferStatus->startOffset = startOffset;
m_pTransferStatus->currentOffset = startOffset;
}
void CControlSocket::SetTransferStatusStartTime()
{
if (!m_pTransferStatus)
return;
m_pTransferStatus->started = wxDateTime::Now();
}
void CControlSocket::UpdateTransferStatus(wxFileOffset transferredBytes)
{
if (!m_pTransferStatus)
return;
m_pTransferStatus->currentOffset += transferredBytes;
if (!m_transferStatusSendState)
m_pEngine->AddNotification(new CTransferStatusNotification(new CTransferStatus(*m_pTransferStatus)));
m_transferStatusSendState = 2;
}
bool CControlSocket::GetTransferStatus(CTransferStatus &status, bool &changed)
{
if (!m_pTransferStatus)
{
changed = false;
m_transferStatusSendState = 0;
return false;
}
status = *m_pTransferStatus;
if (m_transferStatusSendState == 2)
{
changed = true;
m_transferStatusSendState = 1;
return true;
}
else
{
changed = false;
m_transferStatusSendState = 0;
return true;
}
}
const CServer* CControlSocket::GetCurrentServer() const
{
return m_pCurrentServer;
}
bool CControlSocket::ParsePwdReply(wxString reply, bool unquoted /*=false*/, const CServerPath& defaultPath /*=CServerPath()*/)
{
if (!unquoted)
{
int pos1 = reply.Find('"');
int pos2 = reply.Find('"', true);
if (pos1 == -1 || pos1 >= pos2)
{
int pos1 = reply.Find('\'');
int pos2 = reply.Find('\'', true);
if (pos1 != -1 && pos1 < pos2)
LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Broken server sending single-quoted path instead of double-quoted path."));
}
if (pos1 == -1 || pos1 >= pos2)
{
LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("No quoted path found in pwd reply, trying first token as path"));
pos1 = reply.Find(' ');
if (pos1 != -1)
{
pos2 = reply.Mid(pos1 + 1).Find(' ');
if (pos2 == -1)
pos2 = (int)reply.Length();
reply = reply.Mid(pos1 + 1, pos2 - pos1 - 1);
}
else
reply = _T("");
}
else
reply = reply.Mid(pos1 + 1, pos2 - pos1 - 1);
}
m_CurrentPath.SetType(m_pCurrentServer->GetType());
if (reply == _T("") || !m_CurrentPath.SetPath(reply))
{
if (reply != _T(""))
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Failed to parse returned path."));
else
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Server returned empty path."));
if (!defaultPath.IsEmpty())
{
LogMessage(Debug_Warning, _T("Assuming path is '%s'."), defaultPath.GetPath().c_str());
m_CurrentPath = defaultPath;
return true;
}
return false;
}
return true;
}
int CControlSocket::CheckOverwriteFile()
{
if (!m_pCurOpData)
{
LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData"));
ResetOperation(FZ_REPLY_INTERNALERROR);
return FZ_REPLY_ERROR;
}
CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData);
if (pData->download)
{
if (!wxFile::Exists(pData->localFile))
return FZ_REPLY_OK;
}
CDirentry entry;
bool dirDidExist;
bool matchedCase;
CDirectoryCache cache;
bool found = cache.LookupFile(entry, *m_pCurrentServer, pData->tryAbsolutePath ? pData->remotePath : m_CurrentPath, pData->remoteFile, dirDidExist, matchedCase);
// Ignore entries with wrong case
if (found && !matchedCase)
found = false;
if (!pData->download)
{
if (!found && pData->remoteFileSize == -1 && !pData->fileTime.IsValid())
return FZ_REPLY_OK;
}
CFileExistsNotification *pNotification = new CFileExistsNotification;
pNotification->download = pData->download;
pNotification->localFile = pData->localFile;
pNotification->remoteFile = pData->remoteFile;
pNotification->remotePath = pData->remotePath;
pNotification->localSize = pData->localFileSize;
pNotification->remoteSize = pData->remoteFileSize;
pNotification->ascii = !pData->transferSettings.binary;
wxStructStat buf;
int result;
result = wxStat(pData->localFile, &buf);
if (!result)
{
pNotification->localTime = wxDateTime(buf.st_mtime);
if (!pNotification->localTime.IsValid())
pNotification->localTime = wxDateTime(buf.st_ctime);
}
if (pData->fileTime.IsValid())
pNotification->remoteTime = pData->fileTime;
if (found)
{
if (!pData->fileTime.IsValid())
{
if (entry.hasDate)
{
pNotification->remoteTime = entry.time;
pData->fileTime = entry.time;
}
}
}
pNotification->requestNumber = m_pEngine->GetNextAsyncRequestNumber();
pData->waitForAsyncRequest = true;
m_pEngine->AddNotification(pNotification);
return FZ_REPLY_WOULDBLOCK;
}
CFileTransferOpData::CFileTransferOpData() :
COpData(cmd_transfer),
localFileSize(-1), remoteFileSize(-1),
tryAbsolutePath(false), resume(false), transferInitiated(false)
{
}
CFileTransferOpData::~CFileTransferOpData()
{
}
wxString CControlSocket::ConvToLocal(const char* buffer)
{
if (m_useUTF8)
{
wxChar* out = ConvToLocalBuffer(buffer, wxConvUTF8);
if (out)
{
wxString str = out;
delete [] out;
return str;
}
// Fall back to local charset on error
if (m_pCurrentServer->GetEncodingType() != ENCODING_UTF8)
{
LogMessage(Status, _("Invalid character sequence received, disabling UTF-8. Select UTF-8 option in site manager to force UTF-8."));
m_useUTF8 = false;
}
}
if (m_pCSConv)
{
wxChar* out = ConvToLocalBuffer(buffer, *m_pCSConv);
if (out)
{
wxString str = out;
delete [] out;
return str;
}
}
wxCSConv conv(_T("ISO-8859-1"));
wxString str = conv.cMB2WX(buffer);
if (str == _T(""))
str = wxConvCurrent->cMB2WX(buffer);
return str;
}
wxChar* CControlSocket::ConvToLocalBuffer(const char* buffer, wxMBConv& conv)
{
size_t len = conv.MB2WC(0, buffer, 0);
if (!len || len == wxCONV_FAILED)
return 0;
wchar_t* unicode = new wchar_t[len + 1];
conv.MB2WC(unicode, buffer, len + 1);
#if wxUSE_UNICODE
return unicode;
#else
len = wxConvCurrent->WC2MB(0, unicode, 0);
if (!len)
{
delete [] unicode;
return 0;
}
wxChar* output = new wxChar[len + 1];
wxConvCurrent->WC2MB(output, unicode, len + 1);
delete [] unicode;
return output;
#endif
}
wxChar* CControlSocket::ConvToLocalBuffer(const char* buffer)
{
if (m_useUTF8)
{
wxChar* res = ConvToLocalBuffer(buffer, wxConvUTF8);
if (res && *res)
return res;
// Fall back to local charset on error
if (m_pCurrentServer->GetEncodingType() != ENCODING_UTF8)
{
LogMessage(Status, _("Invalid character sequence received, disabling UTF-8. Select UTF-8 option in site manager to force UTF-8."));
m_useUTF8 = false;
}
}
if (m_pCSConv)
{
wxChar* res = ConvToLocalBuffer(buffer, *m_pCSConv);
if (res && *res)
return res;
}
// Fallback: Conversion using current locale
#if wxUSE_UNICODE
wxChar* res = ConvToLocalBuffer(buffer, *wxConvCurrent);
#else
// No conversion needed, just copy
wxChar* res = new wxChar[strlen(buffer) + 1];
strcpy(res, buffer);
#endif
return res;
}
wxCharBuffer CControlSocket::ConvToServer(const wxString& str)
{
if (m_useUTF8)
{
#if wxUSE_UNICODE
wxCharBuffer buffer = wxConvUTF8.cWX2MB(str);
#else
wxWCharBuffer unicode = wxConvCurrent->cMB2WC(str);
wxCharBuffer buffer;
if (unicode)
buffer = wxConvUTF8.cWC2MB(unicode);
#endif
if (buffer)
return buffer;
}
if (m_pCSConv)
{
#if wxUSE_UNICODE
wxCharBuffer buffer = m_pCSConv->cWX2MB(str);
#else
wxWCharBuffer unicode = wxConvCurrent->cMB2WC(str);
wxCharBuffer buffer;
if (unicode)
buffer = m_pCSConv->cWC2MB(unicode);
#endif
if (buffer)
return buffer;
}
wxCharBuffer buffer = wxConvCurrent->cWX2MB(str);
if (!buffer)
buffer = wxCSConv(_T("ISO8859-1")).cWX2MB(str);
return buffer;
}
void CControlSocket::OnTimer(wxTimerEvent& event)
{
int timeout = m_pEngine->GetOptions()->GetOptionVal(OPTION_TIMEOUT);
if (!timeout)
return;
if (m_pCurOpData && m_pCurOpData->waitForAsyncRequest)
return;
if (m_stopWatch.Time() > (timeout * 1000))
{
LogMessage(::Error, _("Connection timed out"));
DoClose(FZ_REPLY_TIMEOUT);
wxASSERT(!m_timer.IsRunning());
}
}
void CControlSocket::SetAlive()
{
m_stopWatch.Start();
}
void CControlSocket::SetWait(bool wait)
{
if (wait)
{
if (m_timer.IsRunning())
return;
m_stopWatch.Start();
m_timer.Start(1000);
}
else if (m_timer.IsRunning())
m_timer.Stop();
}
int CControlSocket::SendNextCommand(int prevResult /*=FZ_REPLY_OK*/)
{
ResetOperation(prevResult);
return FZ_REPLY_ERROR;
}
const std::list<CControlSocket::t_lockInfo>::iterator CControlSocket::GetLockStatus()
{
std::list<t_lockInfo>::iterator iter;
for (iter = m_lockInfoList.begin(); iter != m_lockInfoList.end(); iter++)
if (iter->pControlSocket == this)
break;
return iter;
}
bool CControlSocket::TryLockCache(const CServerPath& directory)
{
wxASSERT(m_pCurrentServer);
std::list<t_lockInfo>::iterator own = GetLockStatus();
if (own == m_lockInfoList.end())
{
t_lockInfo info;
info.directory = directory;
info.pControlSocket = this;
info.waiting = true;
m_lockInfoList.push_back(info);
own = --m_lockInfoList.end();
}
else
{
wxASSERT(own->waiting);
}
// Try to find other instance holding the lock
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
{
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
continue;
if (directory == iter->directory)
{
// Some other instance is holding the lock
return false;
}
}
own->waiting = false;
return true;
}
void CControlSocket::UnlockCache()
{
std::list<t_lockInfo>::iterator iter = GetLockStatus();
if (iter == m_lockInfoList.end())
return;
CServerPath directory = iter->directory;
m_lockInfoList.erase(iter);
// Find other instance waiting for the lock
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != m_lockInfoList.end(); iter++)
{
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
continue;
if (iter->directory != directory)
continue;
// Send notification
wxCommandEvent evt(fzOBTAINLOCK);
iter->pControlSocket->AddPendingEvent(evt);
break;
}
}
bool CControlSocket::ObtainLockFromEvent()
{
std::list<t_lockInfo>::iterator own = GetLockStatus();
if (own == m_lockInfoList.end())
return false;
if (!own->waiting)
return false;
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
{
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
continue;
if (iter->directory == own->directory)
return false;
}
own->waiting = false;
return true;
}
bool CControlSocket::HasLock()
{
std::list<t_lockInfo>::iterator own = GetLockStatus();
if (own == m_lockInfoList.end())
return false;
if (own->waiting)
return false;
return true;
}
void CControlSocket::OnObtainLock(wxCommandEvent& event)
{
if (!ObtainLockFromEvent())
return;
SendNextCommand();
UnlockCache();
}
void CControlSocket::InvalidateCurrentWorkingDir(const CServerPath& path)
{
wxASSERT(!path.IsEmpty());
if (m_CurrentPath.IsEmpty())
return;
if (m_CurrentPath == path || path.IsParentOf(m_CurrentPath, false))
{
if (m_pCurOpData)
m_invalidateCurrentPath = true;
else
m_CurrentPath.Clear();
}
}
// ------------------
// CRealControlSocket
// ------------------
BEGIN_EVENT_TABLE(CRealControlSocket, CControlSocket)
EVT_SOCKET(wxID_ANY, CRealControlSocket::OnSocketEvent)
END_EVENT_TABLE()
CRealControlSocket::CRealControlSocket(CFileZillaEnginePrivate *pEngine)
: CControlSocket(pEngine), wxSocketClient(wxSOCKET_NOWAIT)
{
m_pBackend = new CSocketBackend(this, this);
m_pSendBuffer = 0;
m_nSendBufferLen = 0;
m_onConnectCalled = false;
}
CRealControlSocket::~CRealControlSocket()
{
delete m_pBackend;
m_pBackend = 0;
}
bool CRealControlSocket::Send(const char *buffer, int len)
{
SetWait(true);
if (m_pSendBuffer)
{
char *tmp = m_pSendBuffer;
m_pSendBuffer = new char[m_nSendBufferLen + len];
memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len);
m_nSendBufferLen += len;
delete [] tmp;
}
else
{
m_pBackend->Write(buffer, len);
int numsent = 0;
if (m_pBackend->Error())
{
if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
{
DoClose();
return false;
}
}
else
numsent = m_pBackend->LastCount();
if (numsent)
m_pEngine->SetActive(false);
if (numsent < len)
{
char *tmp = m_pSendBuffer;
m_pSendBuffer = new char[m_nSendBufferLen + len - numsent];
memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len - numsent);
m_nSendBufferLen += len - numsent;
delete [] tmp;
}
}
return true;
}
void CRealControlSocket::OnSocketEvent(wxSocketEvent &event)
{
if (!m_pBackend)
return;
if (event.GetId() != m_pBackend->GetId())
return;
switch (event.GetSocketEvent())
{
case wxSOCKET_CONNECTION:
m_onConnectCalled = true;
OnConnect();
break;
case wxSOCKET_INPUT:
if (!m_onConnectCalled)
{
m_onConnectCalled = true;
OnConnect();
}
OnReceive();
break;
case wxSOCKET_OUTPUT:
OnSend();
break;
case wxSOCKET_LOST:
OnClose();
break;
}
}
void CRealControlSocket::OnConnect()
{
}
void CRealControlSocket::OnReceive()
{
}
void CRealControlSocket::OnSend()
{
if (m_pSendBuffer)
{
if (!m_nSendBufferLen)
{
delete [] m_pSendBuffer;
m_pSendBuffer = 0;
return;
}
m_pBackend->Write(m_pSendBuffer, m_nSendBufferLen);
if (m_pBackend->Error())
{
if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
DoClose();
return;
}
int numsent = m_pBackend->LastCount();
if (numsent)
{
SetAlive();
m_pEngine->SetActive(false);
}
if (numsent == m_nSendBufferLen)
{
m_nSendBufferLen = 0;
delete [] m_pSendBuffer;
m_pSendBuffer = 0;
}
else
{
memmove(m_pSendBuffer, m_pSendBuffer + numsent, m_nSendBufferLen - numsent);
m_nSendBufferLen -= numsent;
}
}
}
void CRealControlSocket::OnClose()
{
LogMessage(Debug_Verbose, _T("CRealControlSocket::OnClose()"));
if (GetCurrentCommandId() != cmd_connect)
LogMessage(::Error, _("Disconnected from server"));
DoClose();
}
int CRealControlSocket::Connect(const CServer &server)
{
SetWait(true);
if (server.GetEncodingType() == ENCODING_CUSTOM)
m_pCSConv = new wxCSConv(server.GetCustomEncoding());
if (m_pCurrentServer)
delete m_pCurrentServer;
m_pCurrentServer = new CServer(server);
const wxString & host = server.GetHost();
if (!IsIpAddress(host))
{
LogMessage(Status, _("Resolving IP-Address for %s"), host.c_str());
CAsyncHostResolver *resolver = new CAsyncHostResolver(m_pEngine, ConvertDomainName(host));
m_pEngine->AddNewAsyncHostResolver(resolver);
resolver->Create();
resolver->Run();
}
else
{
wxIPV4address addr;
addr.Hostname(host);
return ContinueConnect(&addr);
}
return FZ_REPLY_WOULDBLOCK;
}
int CRealControlSocket::ContinueConnect(const wxIPV4address *address)
{
LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CRealControlSocket::ContinueConnect(%p) m_pEngine=%p"), address, m_pEngine);
if (GetCurrentCommandId() != cmd_connect ||
!m_pCurrentServer)
{
LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer);
return DoClose(FZ_REPLY_INTERNALERROR);
}
if (!address)
{
LogMessage(::Error, _("Invalid hostname or host not found"));
return DoClose(FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR);
}
const unsigned int port = m_pCurrentServer->GetPort();
LogMessage(Status, _("Connecting to %s:%d..."), address->IPAddress().c_str(), port);
wxIPV4address addr = *address;
addr.Service(port);
bool res = wxSocketClient::Connect(addr, false);
if (!res && LastError() != wxSOCKET_WOULDBLOCK)
return DoClose();
return FZ_REPLY_WOULDBLOCK;
}
int CRealControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/)
{
ResetSocket();
return CControlSocket::DoClose(nErrorCode);
}
void CRealControlSocket::ResetSocket()
{
Close();
if (m_pSendBuffer)
{
delete [] m_pSendBuffer;
m_pSendBuffer = 0;
m_nSendBufferLen = 0;
}
m_onConnectCalled = false;
delete m_pBackend;
m_pBackend = 0;
}
wxString CRealControlSocket::GetLocalIP() const
{
wxIPV4address addr;
if (!GetLocal(addr))
return _T("");
return addr.IPAddress();
}
wxString CRealControlSocket::GetPeerIP() const
{
wxIPV4address addr;
if (!GetPeer(addr))
return _T("");
return addr.IPAddress();
}
syntax highlighted by Code2HTML, v. 0.9.1