398 lines
7.4 KiB
C++
398 lines
7.4 KiB
C++
|
// FileZilla Server - a Windows ftp server
|
||
|
|
||
|
// 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.
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "ExternalIpCheck.h"
|
||
|
#include "ServerThread.h"
|
||
|
#include "Options.h"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// Konstruktion/Destruktion
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define TIMERINTERVAL 30
|
||
|
|
||
|
CExternalIpCheck::CExternalIpCheck(CServerThread *pOwner)
|
||
|
{
|
||
|
ASSERT(pOwner);
|
||
|
m_pOwner = pOwner;
|
||
|
|
||
|
m_bActive = FALSE;
|
||
|
m_nRetryCount = 0;
|
||
|
m_nTimerID = SetTimer(0, 0, TIMERINTERVAL * 1000, 0);
|
||
|
m_bTriggerUpdateCalled = FALSE;
|
||
|
m_nFailedConnections = 0;
|
||
|
m_nElapsedSeconds = 0;
|
||
|
|
||
|
if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE))
|
||
|
return;
|
||
|
|
||
|
if (m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE) == 2)
|
||
|
Start();
|
||
|
else if (m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE) == 1)
|
||
|
{
|
||
|
CStdString hostname = m_pOwner->m_pOptions->GetOption(OPTION_CUSTOMPASVIP);
|
||
|
SOCKADDR_IN sockAddr;
|
||
|
memset(&sockAddr, 0, sizeof(sockAddr));
|
||
|
|
||
|
sockAddr.sin_family = AF_INET;
|
||
|
#ifdef _UNICODE
|
||
|
sockAddr.sin_addr.s_addr = inet_addr(ConvToLocal(hostname));
|
||
|
#else
|
||
|
sockAddr.sin_addr.s_addr = inet_addr(hostname);
|
||
|
#endif
|
||
|
|
||
|
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
|
||
|
{
|
||
|
LPHOSTENT lphost;
|
||
|
#ifdef _UNICODE
|
||
|
lphost = gethostbyname(ConvToLocal(hostname));
|
||
|
#else
|
||
|
lphost = gethostbyname(hostname);
|
||
|
#endif
|
||
|
if (lphost != NULL)
|
||
|
|
||
|
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
|
||
|
else
|
||
|
{
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char *ip = inet_ntoa(sockAddr.sin_addr);
|
||
|
|
||
|
if (!ip)
|
||
|
return;
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
m_IP = ConvFromLocal(ip);
|
||
|
#else
|
||
|
m_IP = ip;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CExternalIpCheck::~CExternalIpCheck()
|
||
|
{
|
||
|
Close();
|
||
|
}
|
||
|
|
||
|
void CExternalIpCheck::OnReceive(int nErrorCode)
|
||
|
{
|
||
|
if (!m_bActive)
|
||
|
return;
|
||
|
|
||
|
if (nErrorCode)
|
||
|
{
|
||
|
m_bActive = FALSE;
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
return;
|
||
|
}
|
||
|
char buffer[1000];
|
||
|
int len = Receive(buffer, 999);
|
||
|
|
||
|
if (len == SOCKET_ERROR)
|
||
|
{
|
||
|
if (GetLastError() == WSAEWOULDBLOCK)
|
||
|
return;
|
||
|
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
buffer[len] = 0;
|
||
|
char *p = strstr(buffer, "\r\n\r\n");
|
||
|
if (!p)
|
||
|
p = strstr(buffer, "\n\n");
|
||
|
|
||
|
if (!p)
|
||
|
{
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
while (*p && (*p == '\n' || *p == '\r'))
|
||
|
p++;
|
||
|
|
||
|
if (!*p)
|
||
|
{
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
char * ip = p;
|
||
|
while (*p && *p != '\n' && *p != '\r')
|
||
|
p++;
|
||
|
*p = 0;
|
||
|
|
||
|
SOCKADDR_IN sockAddr;
|
||
|
memset(&sockAddr,0,sizeof(sockAddr));
|
||
|
|
||
|
sockAddr.sin_family = AF_INET;
|
||
|
sockAddr.sin_addr.s_addr = inet_addr(ip);
|
||
|
|
||
|
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
|
||
|
{
|
||
|
LPHOSTENT lphost;
|
||
|
lphost = gethostbyname(ip);
|
||
|
if (lphost != NULL)
|
||
|
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
|
||
|
else
|
||
|
{
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ip = inet_ntoa(sockAddr.sin_addr);
|
||
|
|
||
|
if (!ip)
|
||
|
{
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
m_IP = ConvFromLocal(ip);
|
||
|
#else
|
||
|
m_IP = ip;
|
||
|
#endif
|
||
|
|
||
|
m_nFailedConnections = 0;
|
||
|
|
||
|
Close();
|
||
|
m_nRetryCount = 0;
|
||
|
m_bActive = FALSE;
|
||
|
}
|
||
|
|
||
|
void CExternalIpCheck::OnConnect(int nErrorCode)
|
||
|
{
|
||
|
if (!m_bActive)
|
||
|
return;
|
||
|
|
||
|
if (nErrorCode)
|
||
|
{
|
||
|
m_bActive = FALSE;
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CStdStringA address = "GET " + m_pOwner->m_pOptions->GetOption(OPTION_CUSTOMPASVIPSERVER) + " HTTP/1.0\r\nUser-Agent: FileZilla Server\r\n\r\n";
|
||
|
const char *buffer = address;
|
||
|
int len = strlen(buffer);
|
||
|
if (Send(buffer, len) != len)
|
||
|
{
|
||
|
m_bActive = FALSE;
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
}
|
||
|
|
||
|
OnReceive(0);
|
||
|
}
|
||
|
|
||
|
void CExternalIpCheck::OnTimer()
|
||
|
{
|
||
|
if (m_nElapsedSeconds <= 1000000)
|
||
|
m_nElapsedSeconds += TIMERINTERVAL;
|
||
|
|
||
|
if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE))
|
||
|
{
|
||
|
m_nRetryCount = 0;
|
||
|
Close();
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
else if (m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE) == 1)
|
||
|
{
|
||
|
m_nRetryCount = 0;
|
||
|
Close();
|
||
|
m_bActive = FALSE;
|
||
|
|
||
|
CStdString hostname = m_pOwner->m_pOptions->GetOption(OPTION_CUSTOMPASVIP);
|
||
|
SOCKADDR_IN sockAddr;
|
||
|
memset(&sockAddr,0,sizeof(sockAddr));
|
||
|
|
||
|
sockAddr.sin_family = AF_INET;
|
||
|
#ifdef _UNICODE
|
||
|
sockAddr.sin_addr.s_addr = inet_addr(ConvToLocal(hostname));
|
||
|
#else
|
||
|
sockAddr.sin_addr.s_addr = inet_addr(hostname);
|
||
|
#endif
|
||
|
|
||
|
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
|
||
|
{
|
||
|
LPHOSTENT lphost;
|
||
|
#ifdef _UNICODE
|
||
|
lphost = gethostbyname(ConvToLocal(hostname));
|
||
|
#else
|
||
|
lphost = gethostbyname(hostname);
|
||
|
#endif
|
||
|
if (lphost != NULL)
|
||
|
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
|
||
|
else
|
||
|
{
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_bActive = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char *ip = inet_ntoa(sockAddr.sin_addr);
|
||
|
|
||
|
if (!ip)
|
||
|
return;
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
m_IP = ConvFromLocal(ip);
|
||
|
#else
|
||
|
m_IP = ip;
|
||
|
#endif
|
||
|
m_nFailedConnections = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!m_bActive && m_nRetryCount)
|
||
|
{
|
||
|
if (m_nElapsedSeconds > 60 && m_nRetryCount < 5)
|
||
|
{
|
||
|
Start();
|
||
|
return;
|
||
|
}
|
||
|
else if (m_nElapsedSeconds > 300 && m_nRetryCount < 10)
|
||
|
{
|
||
|
Start();
|
||
|
return;
|
||
|
}
|
||
|
else if (m_nElapsedSeconds > 900 && m_nRetryCount < 20)
|
||
|
{
|
||
|
Start();
|
||
|
return;
|
||
|
}
|
||
|
else if (m_nElapsedSeconds > 3600)
|
||
|
{
|
||
|
Start();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if (m_bActive)
|
||
|
{
|
||
|
if (m_nElapsedSeconds > 30)
|
||
|
{
|
||
|
m_bActive = FALSE;
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
m_nElapsedSeconds = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (m_nElapsedSeconds > 300 && m_bTriggerUpdateCalled)
|
||
|
Start();
|
||
|
else if (m_nElapsedSeconds > 3600)
|
||
|
Start();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CExternalIpCheck::OnClose(int nErrorCode)
|
||
|
{
|
||
|
if (m_bActive)
|
||
|
{
|
||
|
m_bActive = FALSE;
|
||
|
Close();
|
||
|
m_nRetryCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CExternalIpCheck::Start()
|
||
|
{
|
||
|
if (m_bActive)
|
||
|
return;
|
||
|
|
||
|
CStdString address = m_pOwner->m_pOptions->GetOption(OPTION_CUSTOMPASVIPSERVER);
|
||
|
if (address.Left(7) == _T("http://"))
|
||
|
address = address.Mid(7);
|
||
|
int pos = address.Find('/');
|
||
|
if (pos != -1)
|
||
|
address = address.Left(pos);
|
||
|
if (address == _T(""))
|
||
|
return;
|
||
|
|
||
|
m_bTriggerUpdateCalled = FALSE;
|
||
|
|
||
|
m_nElapsedSeconds = 0;
|
||
|
Create();
|
||
|
|
||
|
BOOL res = Connect(address, 80);
|
||
|
if (res == SOCKET_ERROR && GetLastError() != WSAEWOULDBLOCK)
|
||
|
m_nRetryCount++;
|
||
|
else
|
||
|
m_bActive = TRUE;
|
||
|
}
|
||
|
|
||
|
void CExternalIpCheck::TriggerUpdate()
|
||
|
{
|
||
|
if (m_bActive)
|
||
|
return;
|
||
|
|
||
|
m_bTriggerUpdateCalled = TRUE;
|
||
|
if (m_nFailedConnections < 100000)
|
||
|
m_nFailedConnections++;
|
||
|
}
|
||
|
|
||
|
CStdString CExternalIpCheck::GetIP(const CStdString& localIP)
|
||
|
{
|
||
|
if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE))
|
||
|
return _T("");
|
||
|
|
||
|
CStdString ip;
|
||
|
switch (m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE))
|
||
|
{
|
||
|
case 0:
|
||
|
return _T("");
|
||
|
case 2:
|
||
|
if (!m_bActive && !m_nRetryCount && localIP != _T(""))
|
||
|
{
|
||
|
if (localIP == m_IP)
|
||
|
m_nElapsedSeconds = 0;
|
||
|
}
|
||
|
case 1:
|
||
|
ip = m_IP;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ip;
|
||
|
}
|