Logo Search packages:      
Sourcecode: filezilla version File versions

ControlSocket.cpp

#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();
}

Generated by  Doxygen 1.6.0   Back to index