mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
Ability to connect via http connect proxy to internet server
This commit is contained in:
parent
0e37e77148
commit
c63aafeb9a
@ -304,6 +304,7 @@
|
||||
<ClCompile Include="OutputStream.cpp" />
|
||||
<ClCompile Include="PipeThrottler.cpp" />
|
||||
<ClCompile Include="Query.cpp" />
|
||||
<ClCompile Include="SChannelPipe.cpp" />
|
||||
<ClCompile Include="SelectThread.cpp" />
|
||||
<ClCompile Include="Server.cpp" />
|
||||
<ClCompile Include="ServerWin32.cpp" />
|
||||
@ -352,6 +353,7 @@
|
||||
<ClInclude Include="OutputStream.h" />
|
||||
<ClInclude Include="PipeThrottler.h" />
|
||||
<ClInclude Include="Query.h" />
|
||||
<ClInclude Include="SChannelPipe.h" />
|
||||
<ClInclude Include="SelectThread.h" />
|
||||
<ClInclude Include="Server.h" />
|
||||
<ClInclude Include="ServiceAcceptor.h" />
|
||||
|
||||
@ -159,6 +159,9 @@
|
||||
<ClCompile Include="Mutex_std.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SChannelPipe.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AcceptThread.h">
|
||||
@ -374,5 +377,8 @@
|
||||
<ClInclude Include="Condition_std.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SChannelPipe.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -143,6 +143,7 @@ public:
|
||||
|
||||
virtual void StartCustomStreamService(IService *pService, std::string pServiceName, unsigned short pPort, int pMaxClientsPerThread=-1, BindTarget bindTarget=BindTarget_All)=0;
|
||||
virtual IPipe* ConnectStream(std::string pServer, unsigned short pPort, unsigned int pTimeoutms=0)=0;
|
||||
virtual IPipe* ConnectSslStream(const std::string& pServer, unsigned short pPort, unsigned int pTimeoutms) = 0;
|
||||
virtual IPipe *PipeFromSocket(SOCKET pSocket)=0;
|
||||
virtual void DisconnectStream(IPipe *pipe)=0;
|
||||
virtual std::string LookupHostname(const std::string& pIp)=0;
|
||||
|
||||
560
SChannelPipe.cpp
Normal file
560
SChannelPipe.cpp
Normal file
@ -0,0 +1,560 @@
|
||||
#include "SChannelPipe.h"
|
||||
#include "Server.h"
|
||||
#include "stringtools.h"
|
||||
#include <ntsecapi.h>
|
||||
#include <sspi.h>
|
||||
#include <schnlsp.h>
|
||||
|
||||
|
||||
PSecurityFunctionTableW SChannelPipe::sec = NULL;
|
||||
|
||||
SChannelPipe::SChannelPipe(CStreamPipe * bpipe)
|
||||
: bpipe(bpipe), has_cred_handle(false),
|
||||
has_ctxt_handle(false), decbuf_pos(0),
|
||||
sendbuf_pos(0), last_flush_time(0),
|
||||
has_error(false)
|
||||
{
|
||||
}
|
||||
|
||||
SChannelPipe::~SChannelPipe()
|
||||
{
|
||||
if (has_cred_handle)
|
||||
{
|
||||
sec->FreeCredentialsHandle(&cred_handle);
|
||||
}
|
||||
|
||||
if (has_ctxt_handle)
|
||||
{
|
||||
sec->DeleteSecurityContext(&ctxt_handle);
|
||||
}
|
||||
|
||||
delete bpipe;
|
||||
}
|
||||
|
||||
bool SChannelPipe::ssl_connect(const std::string& p_hostname, int timeoutms)
|
||||
{
|
||||
hostname = p_hostname;
|
||||
int64 starttime = Server->getTimeMS();
|
||||
|
||||
SCHANNEL_CRED cred_data = {};
|
||||
|
||||
cred_data.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
cred_data.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
cred_data.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
|
||||
|
||||
HRESULT res = sec->AcquireCredentialsHandleW(NULL, UNISP_NAME_W,
|
||||
SECPKG_CRED_OUTBOUND, NULL, &cred_data, NULL, NULL, &cred_handle, &time_stamp);
|
||||
|
||||
if (res != SEC_E_OK)
|
||||
{
|
||||
Server->Log("AcquireCredentialsHandleW failed with result " + convert((int64)res), LL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
has_cred_handle = true;
|
||||
|
||||
SecBuffer outbuf = {};
|
||||
outbuf.BufferType = SECBUFFER_EMPTY;
|
||||
SecBufferDesc outbuf_desc;
|
||||
outbuf_desc.ulVersion = SECBUFFER_VERSION;
|
||||
outbuf_desc.cBuffers = 1;
|
||||
outbuf_desc.pBuffers = &outbuf;
|
||||
|
||||
std::wstring hostname_w = Server->ConvertToWchar(hostname);
|
||||
|
||||
unsigned long flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
|
||||
ISC_REQ_STREAM;
|
||||
|
||||
unsigned long ret_flags = 0;
|
||||
res = sec->InitializeSecurityContextW(&cred_handle, NULL, const_cast<wchar_t*>(hostname_w.c_str()), flags,
|
||||
0, 0, NULL, 0, &ctxt_handle, &outbuf_desc, &ret_flags, &time_stamp);
|
||||
|
||||
if (res != SEC_I_CONTINUE_NEEDED)
|
||||
{
|
||||
Server->Log("InitializeSecurityContextW failed with result " + convert((int64)res), LL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
has_ctxt_handle = true;
|
||||
|
||||
if (flags != ret_flags)
|
||||
{
|
||||
Server->Log("Setting security context flags failed " + convert((int64)flags) + "!=" + convert((int64)ret_flags), LL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bpipe->Write(reinterpret_cast<char*>(outbuf.pvBuffer), outbuf.cbBuffer, timeoutms, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
last_flush_time = Server->getTimeMS();
|
||||
int64 passed_time = last_flush_time - starttime;
|
||||
int64 remaining_time = timeoutms == -1 ? -1 : (passed_time < timeoutms ? (timeoutms - passed_time) : 0);
|
||||
return ssl_connect_negotiate(static_cast<int>(remaining_time), true);
|
||||
}
|
||||
|
||||
bool SChannelPipe::ssl_connect_negotiate(int timeoutms, bool do_read)
|
||||
{
|
||||
const size_t encbuf_size_incr = 4096;
|
||||
|
||||
bool connected = false;
|
||||
|
||||
int64 starttime = Server->getTimeMS();
|
||||
|
||||
unsigned long flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
|
||||
ISC_REQ_STREAM;
|
||||
|
||||
unsigned long ret_flags;
|
||||
|
||||
std::wstring hostname_w = Server->ConvertToWchar(hostname);
|
||||
|
||||
int64 passed_time;
|
||||
encbuf_pos = 0;
|
||||
while (timeoutms == -1
|
||||
|| (passed_time = Server->getTimeMS() - starttime)<timeoutms)
|
||||
{
|
||||
if (timeoutms == -1)
|
||||
passed_time = Server->getTimeMS() - starttime;
|
||||
|
||||
if (do_read)
|
||||
{
|
||||
do_read = false;
|
||||
|
||||
if (!bpipe->isReadable(timeoutms == -1 ? timeoutms : (timeoutms - passed_time)))
|
||||
return false;
|
||||
|
||||
if (encbuf.size() - encbuf_pos < encbuf_size_incr)
|
||||
{
|
||||
encbuf.resize(encbuf.size() + encbuf_size_incr);
|
||||
}
|
||||
size_t read = bpipe->Read(&encbuf[encbuf_pos], encbuf_size_incr, 0);
|
||||
|
||||
if (read == 0)
|
||||
return false;
|
||||
|
||||
encbuf_pos += read;
|
||||
}
|
||||
|
||||
SecBuffer inbuf2[2] = {};
|
||||
inbuf2[0].BufferType = SECBUFFER_TOKEN;
|
||||
inbuf2[0].cbBuffer = encbuf_pos;
|
||||
inbuf2[0].pvBuffer = encbuf.data();
|
||||
inbuf2[1].BufferType = SECBUFFER_EMPTY;
|
||||
|
||||
SecBufferDesc inbuf2_desc;
|
||||
inbuf2_desc.cBuffers = 2;
|
||||
inbuf2_desc.pBuffers = inbuf2;
|
||||
inbuf2_desc.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
SecBuffer outbuf[3] = {};
|
||||
outbuf[0].BufferType = SECBUFFER_TOKEN;
|
||||
outbuf[1].BufferType = SECBUFFER_ALERT;
|
||||
outbuf[2].BufferType = SECBUFFER_EMPTY;
|
||||
|
||||
SecBufferDesc outbuf_desc;
|
||||
outbuf_desc.cBuffers = 3;
|
||||
outbuf_desc.pBuffers = outbuf;
|
||||
outbuf_desc.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
HRESULT res = sec->InitializeSecurityContextW(&cred_handle, &ctxt_handle,
|
||||
const_cast<wchar_t*>(hostname_w.c_str()), flags, 0, 0, &inbuf2_desc,
|
||||
0, NULL, &outbuf_desc, &ret_flags, &time_stamp);
|
||||
|
||||
if (res == SEC_E_INCOMPLETE_MESSAGE)
|
||||
{
|
||||
do_read = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inbuf2[1].BufferType == SECBUFFER_EXTRA
|
||||
&& inbuf2[1].cbBuffer>0)
|
||||
{
|
||||
encbuf.erase(encbuf.begin(), encbuf.begin() + (encbuf_pos - inbuf2[1].cbBuffer));
|
||||
encbuf_pos -= encbuf_pos - inbuf2[1].cbBuffer;
|
||||
|
||||
if (res == SEC_I_CONTINUE_NEEDED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encbuf.clear();
|
||||
encbuf_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == SEC_E_OK
|
||||
|| res == SEC_I_CONTINUE_NEEDED)
|
||||
{
|
||||
bool has_error = false;
|
||||
for (size_t i = 0; i < outbuf_desc.cBuffers; ++i)
|
||||
{
|
||||
SecBuffer& buf = outbuf_desc.pBuffers[i];
|
||||
if (buf.BufferType == SECBUFFER_TOKEN
|
||||
&& buf.cbBuffer > 0
|
||||
&& !has_error)
|
||||
{
|
||||
passed_time = Server->getTimeMS() - starttime;
|
||||
int64 remaining_time = timeoutms == -1 ? -1 : (passed_time < timeoutms ? (timeoutms - passed_time) : 0);
|
||||
if (!bpipe->Write(reinterpret_cast<char*>(buf.pvBuffer), buf.cbBuffer, static_cast<int>(remaining_time), true))
|
||||
{
|
||||
has_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf.pvBuffer != NULL)
|
||||
sec->FreeContextBuffer(buf.pvBuffer);
|
||||
}
|
||||
|
||||
if (has_error)
|
||||
return false;
|
||||
|
||||
if (res == SEC_E_OK)
|
||||
{
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_read = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (connected)
|
||||
{
|
||||
HRESULT res = sec->QueryContextAttributesW(&ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &stream_sizes);
|
||||
|
||||
if (res != SEC_E_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
header_buf.resize(stream_sizes.cbHeader);
|
||||
trailer_buf.resize(stream_sizes.cbTrailer);
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
|
||||
void SChannelPipe::init()
|
||||
{
|
||||
HMODULE mod = LoadLibraryW(L"secur32.dll");
|
||||
|
||||
if (mod == NULL)
|
||||
{
|
||||
Server->Log("Error loading libarary secur32.dll. Errno: " + convert((int64)GetLastError()), LL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
INIT_SECURITY_INTERFACE_W init_sec = reinterpret_cast<INIT_SECURITY_INTERFACE_W>(GetProcAddress(mod, "InitSecurityInterfaceW"));
|
||||
|
||||
if (init_sec == NULL)
|
||||
{
|
||||
Server->Log("Error getting proc InitSecurityInterfaceW in secur32.dll. Errno: " + convert((int64)GetLastError()), LL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
sec = init_sec();
|
||||
}
|
||||
|
||||
size_t SChannelPipe::Read(char * buffer, size_t bsize, int timeoutms)
|
||||
{
|
||||
const size_t encbuf_size_incr = 1024;
|
||||
|
||||
if (has_error)
|
||||
return 0;
|
||||
|
||||
if (decbuf_pos>0)
|
||||
{
|
||||
size_t toread = (std::min)(decbuf_pos, bsize);
|
||||
memcpy(buffer, decbuf.data(), toread);
|
||||
decbuf.erase(decbuf.begin(), decbuf.begin() + toread);
|
||||
decbuf_pos -= toread;
|
||||
return toread;
|
||||
}
|
||||
|
||||
int64 starttime = Server->getTimeMS();
|
||||
|
||||
if (encbuf.size() - encbuf_pos < bsize)
|
||||
{
|
||||
encbuf.resize(encbuf.size() + bsize);
|
||||
}
|
||||
|
||||
size_t read = bpipe->Read(&encbuf[encbuf_pos], bsize, timeoutms);
|
||||
|
||||
if (read == 0)
|
||||
return 0;
|
||||
|
||||
encbuf_pos += read;
|
||||
|
||||
size_t orig_bsize = bsize;
|
||||
|
||||
HRESULT res = SEC_E_OK;
|
||||
while ( (res == SEC_E_OK || res== SEC_E_INCOMPLETE_MESSAGE)
|
||||
&& encbuf_pos > 0 && bsize>0)
|
||||
{
|
||||
if (res == SEC_E_INCOMPLETE_MESSAGE)
|
||||
{
|
||||
if (encbuf.size() - encbuf_pos < encbuf_size_incr)
|
||||
{
|
||||
encbuf.resize(encbuf.size() + encbuf_size_incr);
|
||||
}
|
||||
|
||||
int64 passed_time = Server->getTimeMS() - starttime;
|
||||
int remaining_time = timeoutms == -1 ? -1 : ((timeoutms - passed_time) < 0 ? 0 : (timeoutms - passed_time));
|
||||
|
||||
size_t read = bpipe->Read(&encbuf[encbuf_pos], encbuf_size_incr, remaining_time);
|
||||
|
||||
if (read == 0)
|
||||
return 0;
|
||||
|
||||
encbuf_pos += read;
|
||||
}
|
||||
|
||||
SecBuffer inbuf[4] = {};
|
||||
inbuf[0].BufferType = SECBUFFER_DATA;
|
||||
inbuf[0].pvBuffer = encbuf.data();
|
||||
inbuf[0].cbBuffer = encbuf_pos;
|
||||
inbuf[1].BufferType = SECBUFFER_EMPTY;
|
||||
inbuf[2].BufferType = SECBUFFER_EMPTY;
|
||||
inbuf[3].BufferType = SECBUFFER_EMPTY;
|
||||
|
||||
SecBufferDesc inbuf_desc;
|
||||
inbuf_desc.ulVersion = SECBUFFER_VERSION;
|
||||
inbuf_desc.cBuffers = 4;
|
||||
inbuf_desc.pBuffers = inbuf;
|
||||
|
||||
res = sec->DecryptMessage(&ctxt_handle, &inbuf_desc, 0, NULL);
|
||||
|
||||
if (res == SEC_E_OK
|
||||
|| res== SEC_I_RENEGOTIATE)
|
||||
{
|
||||
if (inbuf[1].BufferType == SECBUFFER_DATA
|
||||
&& inbuf[1].cbBuffer>0)
|
||||
{
|
||||
size_t toread = 0;
|
||||
if (bsize > 0)
|
||||
{
|
||||
toread = (std::min)(bsize, (size_t)inbuf[1].cbBuffer);
|
||||
memcpy(buffer, inbuf[1].pvBuffer, toread);
|
||||
inbuf[1].cbBuffer -= toread;
|
||||
bsize -= toread;
|
||||
buffer += toread;
|
||||
}
|
||||
|
||||
if (inbuf[1].cbBuffer > 0)
|
||||
{
|
||||
if (decbuf.size() - decbuf_pos < inbuf[1].cbBuffer)
|
||||
{
|
||||
decbuf.resize(decbuf.size() + inbuf[1].cbBuffer);
|
||||
}
|
||||
|
||||
memcpy(&decbuf[decbuf_pos], reinterpret_cast<char*>(inbuf[1].pvBuffer) + toread, inbuf[1].cbBuffer);
|
||||
decbuf_pos += inbuf[1].cbBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (inbuf[3].BufferType == SECBUFFER_EXTRA
|
||||
&& inbuf[3].cbBuffer>0)
|
||||
{
|
||||
encbuf.erase(encbuf.begin(), encbuf.begin() + (encbuf_pos - inbuf[3].cbBuffer));
|
||||
encbuf_pos -= encbuf_pos - inbuf[3].cbBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
encbuf.clear();
|
||||
encbuf_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == SEC_I_RENEGOTIATE)
|
||||
{
|
||||
if (!ssl_connect_negotiate(timeoutms, false))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == SEC_I_CONTEXT_EXPIRED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return orig_bsize-bsize;
|
||||
}
|
||||
|
||||
bool SChannelPipe::Write(const char * buffer, size_t bsize, int timeoutms, bool flush)
|
||||
{
|
||||
if (has_error)
|
||||
return false;
|
||||
|
||||
if (sendbuf_pos + bsize > sendbuf.size())
|
||||
{
|
||||
sendbuf.resize(sendbuf_pos + bsize);
|
||||
}
|
||||
|
||||
memcpy(&sendbuf[sendbuf_pos], buffer, bsize);
|
||||
sendbuf_pos += bsize;
|
||||
|
||||
if ((flush || sendbuf_pos>128 * 1024 || sendbuf_pos>= stream_sizes.cbMaximumMessage || (Server->getTimeMS() - last_flush_time)>200)
|
||||
&& sendbuf_pos>0)
|
||||
{
|
||||
return Flush(timeoutms);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t SChannelPipe::Read(std::string * ret, int timeoutms)
|
||||
{
|
||||
if (has_error)
|
||||
return 0;
|
||||
|
||||
char buf[1024];
|
||||
size_t read = Read(buf, sizeof(buf), timeoutms);
|
||||
if (read > 0)
|
||||
ret->assign(buf, read);
|
||||
return read;
|
||||
}
|
||||
|
||||
bool SChannelPipe::Write(const std::string & str, int timeoutms, bool flush)
|
||||
{
|
||||
return Write(str.data(), str.size(), timeoutms, flush);
|
||||
}
|
||||
|
||||
bool SChannelPipe::Flush(int timeoutms)
|
||||
{
|
||||
if (has_error)
|
||||
return false;
|
||||
|
||||
size_t sendbuf_off = 0;
|
||||
while (sendbuf_pos- sendbuf_off> 0)
|
||||
{
|
||||
size_t toflush = (std::min)((size_t)stream_sizes.cbMaximumMessage, sendbuf_pos- sendbuf_off);
|
||||
|
||||
SecBuffer outbuf[4] = {};
|
||||
outbuf[0].BufferType = SECBUFFER_STREAM_HEADER;
|
||||
outbuf[0].cbBuffer = header_buf.size();
|
||||
outbuf[0].pvBuffer = header_buf.data();
|
||||
outbuf[1].BufferType = SECBUFFER_DATA;
|
||||
outbuf[1].cbBuffer = toflush;
|
||||
outbuf[1].pvBuffer = &sendbuf[sendbuf_off];
|
||||
outbuf[2].BufferType = SECBUFFER_STREAM_TRAILER;
|
||||
outbuf[2].cbBuffer = trailer_buf.size();
|
||||
outbuf[2].pvBuffer = trailer_buf.data();
|
||||
outbuf[3].BufferType = SECBUFFER_EMPTY;
|
||||
|
||||
SecBufferDesc outbuf_desc;
|
||||
outbuf_desc.ulVersion = SECBUFFER_VERSION;
|
||||
outbuf_desc.cBuffers = 4;
|
||||
outbuf_desc.pBuffers = outbuf;
|
||||
|
||||
HRESULT res = sec->EncryptMessage(&ctxt_handle, 0, &outbuf_desc, 0);
|
||||
|
||||
if (res != SEC_E_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outbuf[0].cbBuffer > 0)
|
||||
{
|
||||
if (!bpipe->Write(reinterpret_cast<char*>(outbuf[0].pvBuffer), outbuf[0].cbBuffer, timeoutms, false))
|
||||
{
|
||||
has_error = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (outbuf[1].cbBuffer > 0)
|
||||
{
|
||||
if (!bpipe->Write(reinterpret_cast<char*>(outbuf[1].pvBuffer), outbuf[1].cbBuffer, timeoutms, false))
|
||||
{
|
||||
has_error = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (outbuf[2].cbBuffer > 0)
|
||||
{
|
||||
if (!bpipe->Write(reinterpret_cast<char*>(outbuf[2].pvBuffer), outbuf[2].cbBuffer, timeoutms, false))
|
||||
{
|
||||
has_error = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sendbuf_off += toflush;
|
||||
}
|
||||
|
||||
sendbuf_pos -= sendbuf_off;
|
||||
|
||||
return bpipe->Flush(timeoutms);
|
||||
}
|
||||
|
||||
bool SChannelPipe::isWritable(int timeoutms)
|
||||
{
|
||||
if (has_error)
|
||||
return false;
|
||||
|
||||
return bpipe->isWritable(timeoutms);
|
||||
}
|
||||
|
||||
bool SChannelPipe::isReadable(int timeoutms)
|
||||
{
|
||||
if (has_error)
|
||||
return false;
|
||||
|
||||
return bpipe->isReadable(timeoutms);
|
||||
}
|
||||
|
||||
bool SChannelPipe::hasError(void)
|
||||
{
|
||||
return has_error || bpipe->hasError();
|
||||
}
|
||||
|
||||
void SChannelPipe::shutdown(void)
|
||||
{
|
||||
bpipe->shutdown();
|
||||
}
|
||||
|
||||
size_t SChannelPipe::getNumElements(void)
|
||||
{
|
||||
return bpipe->getNumElements();
|
||||
}
|
||||
|
||||
void SChannelPipe::addThrottler(IPipeThrottler * throttler)
|
||||
{
|
||||
bpipe->addThrottler(throttler);
|
||||
}
|
||||
|
||||
void SChannelPipe::addOutgoingThrottler(IPipeThrottler * throttler)
|
||||
{
|
||||
bpipe->addOutgoingThrottler(throttler);
|
||||
}
|
||||
|
||||
void SChannelPipe::addIncomingThrottler(IPipeThrottler * throttler)
|
||||
{
|
||||
bpipe->addIncomingThrottler(throttler);
|
||||
}
|
||||
|
||||
_i64 SChannelPipe::getTransferedBytes(void)
|
||||
{
|
||||
return bpipe->getTransferedBytes();
|
||||
}
|
||||
|
||||
void SChannelPipe::resetTransferedBytes(void)
|
||||
{
|
||||
bpipe->resetTransferedBytes();
|
||||
}
|
||||
76
SChannelPipe.h
Normal file
76
SChannelPipe.h
Normal file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "Interface/Pipe.h"
|
||||
#include "StreamPipe.h"
|
||||
#define SECURITY_WIN32
|
||||
#include <Windows.h>
|
||||
#include <security.h>
|
||||
|
||||
class SChannelPipe : public IPipe
|
||||
{
|
||||
public:
|
||||
SChannelPipe(CStreamPipe* bpipe);
|
||||
|
||||
~SChannelPipe();
|
||||
|
||||
bool ssl_connect(const std::string& p_hostname, int timeoutms);
|
||||
|
||||
static void init();
|
||||
|
||||
// Inherited via IPipe
|
||||
virtual size_t Read(char * buffer, size_t bsize, int timeoutms = -1);
|
||||
|
||||
virtual bool Write(const char * buffer, size_t bsize, int timeoutms = -1, bool flush = true);
|
||||
|
||||
virtual size_t Read(std::string * ret, int timeoutms = -1);
|
||||
|
||||
virtual bool Write(const std::string & str, int timeoutms = -1, bool flush = true);
|
||||
|
||||
virtual bool Flush(int timeoutms = -1);
|
||||
|
||||
virtual bool isWritable(int timeoutms = 0);
|
||||
|
||||
virtual bool isReadable(int timeoutms = 0);
|
||||
|
||||
virtual bool hasError(void);
|
||||
|
||||
virtual void shutdown(void);
|
||||
|
||||
virtual size_t getNumElements(void);
|
||||
|
||||
virtual void addThrottler(IPipeThrottler * throttler);
|
||||
|
||||
virtual void addOutgoingThrottler(IPipeThrottler * throttler);
|
||||
|
||||
virtual void addIncomingThrottler(IPipeThrottler * throttler);
|
||||
|
||||
virtual _i64 getTransferedBytes(void);
|
||||
|
||||
virtual void resetTransferedBytes(void);
|
||||
|
||||
private:
|
||||
bool ssl_connect_negotiate(int timeoutms, bool do_read);
|
||||
|
||||
CStreamPipe* bpipe;
|
||||
|
||||
static PSecurityFunctionTableW sec;
|
||||
|
||||
bool has_cred_handle;
|
||||
CredHandle cred_handle;
|
||||
TimeStamp time_stamp;
|
||||
bool has_ctxt_handle;
|
||||
CtxtHandle ctxt_handle;
|
||||
std::vector<char> encbuf;
|
||||
size_t encbuf_pos;
|
||||
std::vector<char> decbuf;
|
||||
size_t decbuf_pos;
|
||||
std::vector<char> sendbuf;
|
||||
size_t sendbuf_pos;
|
||||
std::string hostname;
|
||||
int64 last_flush_time;
|
||||
std::vector<char> header_buf;
|
||||
std::vector<char> trailer_buf;
|
||||
bool has_error;
|
||||
|
||||
SecPkgContext_StreamSizes stream_sizes;
|
||||
};
|
||||
28
Server.cpp
28
Server.cpp
@ -57,8 +57,7 @@
|
||||
#include "PipeThrottler.h"
|
||||
#include "mt19937ar.h"
|
||||
#include "Query.h"
|
||||
|
||||
|
||||
#include "SChannelPipe.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <condition_variable>
|
||||
@ -91,6 +90,7 @@
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
|
||||
const size_t SEND_BLOCKSIZE=8192;
|
||||
const size_t MAX_THREAD_ID=std::string::npos;
|
||||
|
||||
@ -207,6 +207,8 @@ void CServer::setup(void)
|
||||
#ifdef MODE_WIN
|
||||
File::init_mutex();
|
||||
#endif
|
||||
|
||||
SChannelPipe::init();
|
||||
}
|
||||
|
||||
void CServer::destroyAllDatabases(void)
|
||||
@ -1137,6 +1139,28 @@ IPipe* CServer::ConnectStream(std::string pServer, unsigned short pPort, unsigne
|
||||
}
|
||||
}
|
||||
|
||||
IPipe * CServer::ConnectSslStream(const std::string & pServer, unsigned short pPort, unsigned int pTimeoutms)
|
||||
{
|
||||
int64 starttime = Server->getTimeMS();
|
||||
CStreamPipe* bpipe = static_cast<CStreamPipe*>(ConnectStream(pServer, pPort, pTimeoutms));
|
||||
|
||||
if (bpipe == NULL)
|
||||
return NULL;
|
||||
|
||||
int64 remaining_time = pTimeoutms - (Server->getTimeMS() - starttime);
|
||||
if (remaining_time < 0) remaining_time = 0;
|
||||
|
||||
SChannelPipe* ssl_pipe = new SChannelPipe(bpipe);
|
||||
|
||||
if (!ssl_pipe->ssl_connect(pServer, static_cast<int>(remaining_time)))
|
||||
{
|
||||
delete ssl_pipe;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ssl_pipe;
|
||||
}
|
||||
|
||||
IPipe *CServer::PipeFromSocket(SOCKET pSocket)
|
||||
{
|
||||
return new CStreamPipe(pSocket);
|
||||
|
||||
1
Server.h
1
Server.h
@ -137,6 +137,7 @@ public:
|
||||
|
||||
virtual void StartCustomStreamService(IService *pService, std::string pServiceName, unsigned short pPort, int pMaxClientsPerThread=-1, IServer::BindTarget bindTarget=IServer::BindTarget_All);
|
||||
virtual IPipe* ConnectStream(std::string pServer, unsigned short pPort, unsigned int pTimeoutms);
|
||||
virtual IPipe* ConnectSslStream(const std::string& pServer, unsigned short pPort, unsigned int pTimeoutms);
|
||||
virtual IPipe *PipeFromSocket(SOCKET pSocket);
|
||||
virtual void DisconnectStream(IPipe *pipe);
|
||||
virtual std::string LookupHostname(const std::string& pIp);
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Interface/Pipe.h"
|
||||
#include "socket_header.h"
|
||||
#include <vector>
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../cryptoplugin/ICryptoFactory.h"
|
||||
|
||||
@ -221,7 +222,7 @@ void InternetClient::operator()(void)
|
||||
{
|
||||
if(n_connections<spare_connections)
|
||||
{
|
||||
Server->getThreadPool()->execute(new InternetClientThread(NULL, server_settings), "internet client");
|
||||
Server->getThreadPool()->execute(new InternetClientThread(NULL, server_settings, NULL), "internet client");
|
||||
newConnection();
|
||||
}
|
||||
else
|
||||
@ -278,6 +279,7 @@ void InternetClient::doUpdateSettings(void)
|
||||
std::string server_name;
|
||||
std::string computername;
|
||||
std::string server_port="55415";
|
||||
std::string server_proxy;
|
||||
std::string authkey;
|
||||
if(!settings->getValue("internet_authkey", &authkey) && !settings->getValue("internet_authkey_def", &authkey))
|
||||
{
|
||||
@ -299,6 +301,8 @@ void InternetClient::doUpdateSettings(void)
|
||||
{
|
||||
computername=(IndexThread::getFileSrv()->getServerName());
|
||||
}
|
||||
if (!settings->getValue("internet_server_proxy", &server_proxy))
|
||||
settings->getValue("internet_server_proxy_def", &server_proxy);
|
||||
if( (settings->getValue("internet_server", &server_name) || settings->getValue("internet_server_def", &server_name))
|
||||
&& !server_name.empty() )
|
||||
{
|
||||
@ -311,18 +315,27 @@ void InternetClient::doUpdateSettings(void)
|
||||
std::vector<std::string> server_ports;
|
||||
Tokenize(server_port, server_ports, ";");
|
||||
|
||||
std::vector<std::string> server_proxies;
|
||||
Tokenize(server_proxy, server_proxies, ";");
|
||||
|
||||
for(size_t i=0;i<server_names.size();++i)
|
||||
{
|
||||
SServerConnectionSettings connection_settings;
|
||||
connection_settings.hostname = server_names[i];
|
||||
if(i<server_ports.size())
|
||||
{
|
||||
server_settings.servers.push_back(std::make_pair(server_names[i],
|
||||
static_cast<unsigned short>(atoi(server_ports[i].c_str()))));
|
||||
connection_settings.port = static_cast<unsigned short>(atoi(server_ports[i].c_str()));
|
||||
}
|
||||
else
|
||||
else if(!server_ports.empty())
|
||||
{
|
||||
server_settings.servers.push_back(std::make_pair(server_names[i],
|
||||
static_cast<unsigned short>(atoi(server_ports[server_ports.size()-1].c_str()))));
|
||||
connection_settings.port = static_cast<unsigned short>(atoi(server_ports[server_ports.size() - 1].c_str()));
|
||||
}
|
||||
if (i < server_proxies.size())
|
||||
connection_settings.proxy = server_proxies[i];
|
||||
else if(!server_proxies.empty())
|
||||
connection_settings.proxy = server_proxies[server_proxies.size()-1];
|
||||
|
||||
server_settings.servers.push_back(connection_settings);
|
||||
}
|
||||
server_settings.clientname=computername;
|
||||
server_settings.authkey=authkey;
|
||||
@ -340,6 +353,7 @@ void InternetClient::doUpdateSettings(void)
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
server_settings.internet_compress=true;
|
||||
if(settings->getValue("internet_compress", &tmp) || settings->getValue("internet_compress_def", &tmp) )
|
||||
@ -378,20 +392,20 @@ bool InternetClient::tryToConnect(IScopedLock *lock)
|
||||
|
||||
for(size_t i=0;i<server_settings.servers.size();++i)
|
||||
{
|
||||
std::string name=server_settings.servers[i].first;
|
||||
|
||||
unsigned short port=server_settings.servers[i].second;
|
||||
SServerConnectionSettings selected_server_settings = server_settings.servers[i];
|
||||
|
||||
lock->relock(NULL);
|
||||
Server->Log("Trying to connect to internet server \""+name+"\" at port "+convert(port), LL_DEBUG);
|
||||
IPipe *cs=Server->ConnectStream(name, port, 10000);
|
||||
Server->Log("Trying to connect to internet server \""+ selected_server_settings .hostname+"\" at port "+convert(selected_server_settings.port)
|
||||
+ (selected_server_settings.proxy.empty() ? "" : (" via HTTP proxy "+ selected_server_settings.proxy)), LL_DEBUG);
|
||||
std::auto_ptr<CTCPStack> tcpstack(new CTCPStack);
|
||||
IPipe *cs = connect(selected_server_settings, *tcpstack);
|
||||
lock->relock(mutex);
|
||||
if(cs!=NULL)
|
||||
{
|
||||
server_settings.selected_server=i;
|
||||
Server->Log("Successfully connected.", LL_DEBUG);
|
||||
setStatusMsg("connected");
|
||||
Server->getThreadPool()->execute(new InternetClientThread(cs, server_settings), "internet client");
|
||||
Server->getThreadPool()->execute(new InternetClientThread(cs, server_settings, tcpstack.release()), "internet client");
|
||||
newConnection();
|
||||
return true;
|
||||
}
|
||||
@ -486,9 +500,16 @@ void InternetClient::setStatusMsg(const std::string& msg)
|
||||
status_msg=msg;
|
||||
}
|
||||
|
||||
InternetClientThread::InternetClientThread(IPipe *cs, const SServerSettings &server_settings)
|
||||
: cs(cs), server_settings(server_settings)
|
||||
InternetClientThread::InternetClientThread(IPipe *cs, const SServerSettings &server_settings, CTCPStack* tcpstack)
|
||||
: cs(cs), server_settings(server_settings), tcpstack(tcpstack)
|
||||
{
|
||||
if (this->tcpstack == NULL)
|
||||
this->tcpstack = new CTCPStack(true);
|
||||
}
|
||||
|
||||
InternetClientThread::~InternetClientThread()
|
||||
{
|
||||
delete tcpstack;
|
||||
}
|
||||
|
||||
char *InternetClientThread::getReply(CTCPStack *tcpstack, IPipe *pipe, size_t &replysize, unsigned int timeoutms)
|
||||
@ -513,7 +534,6 @@ char *InternetClientThread::getReply(CTCPStack *tcpstack, IPipe *pipe, size_t &r
|
||||
|
||||
void InternetClientThread::operator()(void)
|
||||
{
|
||||
CTCPStack tcpstack(true);
|
||||
bool finish_ok=false;
|
||||
bool rm_connection=true;
|
||||
|
||||
@ -522,20 +542,20 @@ void InternetClientThread::operator()(void)
|
||||
int tries=10;
|
||||
while(tries>0 && cs==NULL)
|
||||
{
|
||||
cs=Server->ConnectStream(server_settings.servers[server_settings.selected_server].first,
|
||||
server_settings.servers[server_settings.selected_server].second, 10000);
|
||||
cs = InternetClient::connect(server_settings.servers[server_settings.selected_server], *tcpstack);
|
||||
--tries;
|
||||
InternetClient::setStatusMsg("connecting_failed");
|
||||
if(cs==NULL && tries>0)
|
||||
{
|
||||
Server->Log("Connecting to server "+server_settings.servers[server_settings.selected_server].first
|
||||
+ " failed. Retrying in 30s...", LL_INFO);
|
||||
Server->Log("Connecting to server "+server_settings.servers[server_settings.selected_server].hostname
|
||||
+(server_settings.servers[server_settings.selected_server].proxy.empty() ? "" : (" via HTTP proxy " + server_settings.servers[server_settings.selected_server].proxy)) + " failed. Retrying in 30s...", LL_INFO);
|
||||
Server->wait(30000);
|
||||
}
|
||||
}
|
||||
if(cs==NULL)
|
||||
{
|
||||
Server->Log("Connecting to server "+server_settings.servers[server_settings.selected_server].first
|
||||
Server->Log("Connecting to server "+server_settings.servers[server_settings.selected_server].hostname
|
||||
+(server_settings.servers[server_settings.selected_server].proxy.empty() ? "" : (" via HTTP proxy " + server_settings.servers[server_settings.selected_server].proxy))
|
||||
+ " failed", LL_INFO);
|
||||
InternetClient::rmConnection();
|
||||
InternetClient::setHasConnection(false);
|
||||
@ -572,7 +592,7 @@ void InternetClientThread::operator()(void)
|
||||
{
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
buf=getReply(&tcpstack, cs, bufsize, ic_auth_timeout);
|
||||
buf=getReply(tcpstack, cs, bufsize, ic_auth_timeout);
|
||||
if(buf==NULL)
|
||||
{
|
||||
Server->Log("Error receiving challenge packet");
|
||||
@ -663,7 +683,7 @@ void InternetClientThread::operator()(void)
|
||||
|
||||
data.addString(client_challenge);
|
||||
data.addUInt(pbkdf2_iterations);
|
||||
tcpstack.Send(cs, data);
|
||||
tcpstack->Send(cs, data);
|
||||
|
||||
challenge_response=crypto_fak->generateBinaryPasswordHash(hmac_key, client_challenge, 1);
|
||||
}
|
||||
@ -671,7 +691,7 @@ void InternetClientThread::operator()(void)
|
||||
{
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
buf=getReply(&tcpstack, cs, bufsize, ic_auth_timeout);
|
||||
buf=getReply(tcpstack, cs, bufsize, ic_auth_timeout);
|
||||
if(buf==NULL)
|
||||
{
|
||||
Server->Log("Error receiving authentication response");
|
||||
@ -746,7 +766,7 @@ void InternetClientThread::operator()(void)
|
||||
|
||||
data.addUInt(capa);
|
||||
|
||||
tcpstack.Send(ics_pipe, data);
|
||||
tcpstack->Send(ics_pipe, data);
|
||||
}
|
||||
|
||||
comm_pipe=cs;
|
||||
@ -784,7 +804,7 @@ void InternetClientThread::operator()(void)
|
||||
ping_timeout=ic_ping_timeout;
|
||||
}
|
||||
|
||||
buf=getReply(&tcpstack, comm_pipe, bufsize, ping_timeout);
|
||||
buf=getReply(tcpstack, comm_pipe, bufsize, ping_timeout);
|
||||
if(buf==NULL)
|
||||
{
|
||||
goto cleanup;
|
||||
@ -801,7 +821,7 @@ void InternetClientThread::operator()(void)
|
||||
{
|
||||
CWData data;
|
||||
data.addChar(ID_ISC_PONG);
|
||||
tcpstack.Send(comm_pipe, data);
|
||||
tcpstack->Send(comm_pipe, data);
|
||||
}
|
||||
else if(id==ID_ISC_CONNECT)
|
||||
{
|
||||
@ -812,7 +832,7 @@ void InternetClientThread::operator()(void)
|
||||
{
|
||||
CWData data;
|
||||
data.addChar(ID_ISC_CONNECT_OK);
|
||||
tcpstack.Send(comm_pipe, data);
|
||||
tcpstack->Send(comm_pipe, data);
|
||||
|
||||
InternetClient::rmConnection();
|
||||
rm_connection=false;
|
||||
@ -868,7 +888,7 @@ cleanup:
|
||||
|
||||
void InternetClientThread::runServiceWrapper(IPipe *pipe, ICustomClient *client)
|
||||
{
|
||||
client->Init(Server->getThreadID(), pipe, server_settings.servers[server_settings.selected_server].first);
|
||||
client->Init(Server->getThreadID(), pipe, server_settings.servers[server_settings.selected_server].hostname);
|
||||
ClientConnector * cc=dynamic_cast<ClientConnector*>(client);
|
||||
if(cc!=NULL)
|
||||
{
|
||||
@ -934,3 +954,167 @@ void InternetClientThread::printInfo( IPipe * pipe )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IPipe * InternetClient::connect(const SServerConnectionSettings & selected_server_settings, CTCPStack& tcpstack)
|
||||
{
|
||||
std::string proxy = selected_server_settings.proxy;
|
||||
if (!proxy.empty())
|
||||
{
|
||||
bool ssl = false;
|
||||
if (next(proxy, 0, "http://"))
|
||||
{
|
||||
ssl = false;
|
||||
proxy = proxy.substr(7);
|
||||
}
|
||||
else if (next(proxy, 0, "https://"))
|
||||
{
|
||||
ssl = true;
|
||||
proxy = proxy.substr(7);
|
||||
}
|
||||
|
||||
std::string authorization;
|
||||
if (proxy.find("@") != std::string::npos)
|
||||
{
|
||||
std::string udata = getuntil("@", proxy);
|
||||
proxy = getafter("@", proxy);
|
||||
|
||||
std::string username = getuntil(":", proxy);
|
||||
std::string password = getafter(":", proxy);
|
||||
std::string adata = username + ":" + password;
|
||||
|
||||
authorization = "Authorization: Basic " + base64_encode(reinterpret_cast<const unsigned char*>(adata.c_str()), adata.size())+"\r\n";
|
||||
}
|
||||
|
||||
unsigned short port = ssl ? 443 : 80;
|
||||
if (proxy.find(":") != std::string::npos)
|
||||
{
|
||||
port = static_cast<unsigned short>(watoi(getafter(":", proxy)));
|
||||
proxy = getuntil(":", proxy);
|
||||
}
|
||||
|
||||
IPipe* cs;
|
||||
if (ssl)
|
||||
cs = Server->ConnectSslStream(proxy, port, 10000);
|
||||
else
|
||||
cs = Server->ConnectStream(proxy, port, 10000);
|
||||
|
||||
if (cs == NULL)
|
||||
return cs;
|
||||
|
||||
std::string connect_data = "CONNECT " + selected_server_settings.hostname + ":" + convert(selected_server_settings.port) + " HTTP/1.1\r\n"
|
||||
+"Host: "+ selected_server_settings.hostname+"\r\n"
|
||||
+ authorization+"\r\n";
|
||||
|
||||
if (!cs->Write(connect_data))
|
||||
{
|
||||
Server->destroy(cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buf[512];
|
||||
int64 starttime = Server->getTimeMS();
|
||||
int state = 0;
|
||||
std::string state_data;
|
||||
int http_code = 0;
|
||||
do
|
||||
{
|
||||
size_t rc = cs->Read(buf, sizeof(buf), 10000);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < rc; ++i)
|
||||
{
|
||||
char ch = buf[i];
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (ch == ' ')
|
||||
{
|
||||
if (strlower(state_data) != "http/1.1"
|
||||
&& strlower(state_data) != "http/1.0")
|
||||
{
|
||||
Server->Log("Unknown HTTP protocol: " + state_data, LL_ERROR);
|
||||
Server->destroy(cs);
|
||||
return NULL;
|
||||
}
|
||||
state_data.clear();
|
||||
++state;
|
||||
}
|
||||
else
|
||||
state_data += ch;
|
||||
}break;
|
||||
case 1:
|
||||
{
|
||||
if (ch == ' ')
|
||||
{
|
||||
http_code = watoi(state_data);
|
||||
state_data.clear();
|
||||
++state;
|
||||
}
|
||||
else
|
||||
state_data += ch;
|
||||
}break;
|
||||
case 2:
|
||||
{
|
||||
if (ch == '\n')
|
||||
{
|
||||
if (http_code != 200)
|
||||
{
|
||||
Server->Log("HTTP proxy returned error code " + convert(http_code) + " message \"" + state_data + "\"", LL_ERROR);
|
||||
Server->destroy(cs);
|
||||
return NULL;
|
||||
}
|
||||
state_data.clear();
|
||||
++state;
|
||||
}
|
||||
else if (ch != '\r')
|
||||
{
|
||||
state_data += ch;
|
||||
}
|
||||
} break;
|
||||
case 3:
|
||||
{
|
||||
if (ch == '\n')
|
||||
{
|
||||
if (i + 1 < rc)
|
||||
{
|
||||
tcpstack.AddData(&buf[i + 1], rc - i - 1);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
else if (ch != '\r')
|
||||
{
|
||||
++state;
|
||||
}
|
||||
} break;
|
||||
case 4:
|
||||
{
|
||||
if (ch == '\n')
|
||||
{
|
||||
state = 3;
|
||||
}
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
assert(false);
|
||||
Server->destroy(cs);
|
||||
return NULL;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (Server->getTimeMS() - starttime < 10000);
|
||||
|
||||
Server->Log("Timeout connecting via http proxy");
|
||||
|
||||
Server->destroy(cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Server->ConnectStream(selected_server_settings.hostname,
|
||||
selected_server_settings.port, 10000);
|
||||
}
|
||||
|
||||
@ -13,9 +13,16 @@ class ICustomClient;
|
||||
class IScopedLock;
|
||||
class ICondition;
|
||||
|
||||
struct SServerConnectionSettings
|
||||
{
|
||||
std::string hostname;
|
||||
std::string proxy;
|
||||
unsigned short port;
|
||||
};
|
||||
|
||||
struct SServerSettings
|
||||
{
|
||||
std::vector<std::pair<std::string, unsigned short> > servers;
|
||||
std::vector<SServerConnectionSettings> servers;
|
||||
size_t selected_server;
|
||||
std::string clientname;
|
||||
std::string authkey;
|
||||
@ -58,6 +65,8 @@ public:
|
||||
|
||||
static void setStatusMsg(const std::string& msg);
|
||||
|
||||
static IPipe* connect(const SServerConnectionSettings& selected_settings, CTCPStack& tcpstack);
|
||||
|
||||
private:
|
||||
|
||||
static IMutex *mutex;
|
||||
@ -77,7 +86,8 @@ private:
|
||||
class InternetClientThread : public IThread
|
||||
{
|
||||
public:
|
||||
InternetClientThread(IPipe *cs, const SServerSettings &server_settings);
|
||||
InternetClientThread(IPipe *cs, const SServerSettings &server_settings, CTCPStack* tcpstack);
|
||||
~InternetClientThread();
|
||||
void operator()(void);
|
||||
|
||||
char *getReply(CTCPStack *tcpstack, IPipe *pipe, size_t &replysize, unsigned int timeoutms);
|
||||
@ -88,5 +98,6 @@ private:
|
||||
std::string generateRandomBinaryAuthKey(void);
|
||||
void printInfo( IPipe * pipe );
|
||||
IPipe *cs;
|
||||
CTCPStack* tcpstack;
|
||||
SServerSettings server_settings;
|
||||
};
|
||||
|
||||
@ -56,6 +56,7 @@ std::vector<std::string> getSettingsList(void)
|
||||
ret.push_back("image_letters");
|
||||
ret.push_back("internet_server");
|
||||
ret.push_back("internet_server_port");
|
||||
ret.push_back("internet_server_proxy");
|
||||
ret.push_back("internet_authkey");
|
||||
ret.push_back("internet_speed");
|
||||
ret.push_back("local_speed");
|
||||
@ -146,6 +147,7 @@ std::vector<std::string> getGlobalizedSettingsList(void)
|
||||
std::vector<std::string> ret;
|
||||
ret.push_back("internet_server");
|
||||
ret.push_back("internet_server_port");
|
||||
ret.push_back("internet_server_proxy");
|
||||
ret.push_back("server_url");
|
||||
return ret;
|
||||
}
|
||||
@ -172,6 +174,7 @@ std::vector<std::string> getGlobalSettingsList(void)
|
||||
ret.push_back("backup_database");
|
||||
ret.push_back("internet_server");
|
||||
ret.push_back("internet_server_port");
|
||||
ret.push_back("internet_server_proxy");
|
||||
ret.push_back("global_local_speed");
|
||||
ret.push_back("global_internet_speed");
|
||||
ret.push_back("use_tmpfiles");
|
||||
|
||||
@ -369,6 +369,7 @@ void ServerSettings::readSettingsDefault(ISettingsReader* settings_default,
|
||||
settings->image_letters=settings_default->getValue("image_letters", "C");
|
||||
settings->backup_database=(settings_global->getValue("backup_database", "true")=="true");
|
||||
settings->internet_server_port=(unsigned short)(atoi(settings_global->getValue("internet_server_port", "55415").c_str()));
|
||||
settings->internet_server_proxy = settings_global->getValue("internet_server_proxy", "");
|
||||
settings->client_set_settings=false;
|
||||
settings->internet_server= settings_global->getValue("internet_server", "");
|
||||
settings->internet_image_backups=(settings_default->getValue("internet_image_backups", "false")=="true");
|
||||
|
||||
@ -79,6 +79,7 @@ struct SSettings
|
||||
std::string internet_server;
|
||||
bool client_set_settings;
|
||||
unsigned short internet_server_port;
|
||||
std::string internet_server_proxy;
|
||||
std::string internet_authkey;
|
||||
bool internet_full_file_backups;
|
||||
bool internet_image_backups;
|
||||
|
||||
@ -29,6 +29,7 @@ ACTION_IMPL(add_client)
|
||||
ret.set("new_authkey", new_authkey);
|
||||
ret.set("internet_server", s->internet_server);
|
||||
ret.set("internet_server_port", s->internet_server_port);
|
||||
ret.set("internet_server_proxy", s->internet_server_proxy);
|
||||
ret.set("added_new_client", true);
|
||||
}
|
||||
else
|
||||
|
||||
@ -55,6 +55,7 @@ namespace
|
||||
ret+="internet_mode_enabled="+convert(settingsptr->internet_mode_enabled)+"\r\n";
|
||||
ret+="internet_server="+settingsptr->internet_server+"\r\n";
|
||||
ret+="internet_server_port="+convert(settingsptr->internet_server_port)+"\r\n";
|
||||
ret += "internet_server_proxy=" + settingsptr->internet_server_proxy + "\r\n";
|
||||
ret+="internet_authkey="+(authkey.empty() ? settingsptr->internet_authkey : authkey ) +"\r\n";
|
||||
if(!clientname.empty())
|
||||
{
|
||||
|
||||
@ -234,6 +234,7 @@ void getGeneralSettings(JSON::Object& obj, IDatabase *db, ServerSettings &settin
|
||||
SET_SETTING(backup_database);
|
||||
SET_SETTING(internet_server);
|
||||
SET_SETTING(internet_server_port);
|
||||
SET_SETTING(internet_server_proxy);
|
||||
SET_SETTING(global_local_speed);
|
||||
SET_SETTING(global_soft_fs_quota);
|
||||
SET_SETTING(global_internet_speed);
|
||||
|
||||
@ -464,6 +464,12 @@
|
||||
<input type="text" class="form-control" id="internet_server_port" value="{internet_server_port}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label" for="internet_server_proxy">{tConnect via HTTP(S) proxy (leave empty to connect without)}:</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" id="internet_server_proxy" value="{internet_server_proxy|s}"/>
|
||||
</div>
|
||||
</div>
|
||||
{/global_settings}
|
||||
{?main_client}
|
||||
{^global_settings}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user