Skip to content

Commit

Permalink
1) added button "Test Connection" to make a news server connection te…
Browse files Browse the repository at this point in the history
…st from web-interface; 2) improved timeout handling when connecting to news servers which have multiple addresses; 3) improved error handling when communicating with secure servers (do not trying to send quit-command if connection could not be established or was interrupted; this avoids unnecessary timeout)
  • Loading branch information
hugbug committed Mar 31, 2015
1 parent 2390b58 commit 1552194
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 46 deletions.
75 changes: 53 additions & 22 deletions daemon/connect/Connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
#include <fcntl.h>
#endif

#include <vector>
#include <algorithm>

#include "nzbget.h"
#include "Connection.h"
#include "Log.h"
Expand All @@ -63,7 +66,6 @@ Mutex* Connection::m_pMutexGetHostByName = NULL;
#endif
#endif


void Connection::Init()
{
debug("Initializing global connection data");
Expand Down Expand Up @@ -129,6 +131,7 @@ Connection::Connection(const char* szHost, int iPort, bool bTLS)
m_bSuppressErrors = true;
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
m_iTotalBytesRead = 0;
m_bBroken = false;
#ifndef DISABLE_TLS
m_pTLSSocket = NULL;
m_bTLSError = false;
Expand Down Expand Up @@ -255,10 +258,11 @@ bool Connection::Bind()
int res = getaddrinfo(m_szHost, iPortStr, &addr_hints, &addr_list);
if (res != 0)
{
error("Could not resolve hostname %s", m_szHost);
ReportError("Could not resolve hostname %s", m_szHost, false, 0);
return false;
}

m_bBroken = false;
m_iSocket = INVALID_SOCKET;
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
{
Expand Down Expand Up @@ -349,6 +353,10 @@ int Connection::WriteLine(const char* pBuffer)
}

int iRes = send(m_iSocket, pBuffer, strlen(pBuffer), 0);
if (iRes <= 0)
{
m_bBroken = true;
}

return iRes;
}
Expand All @@ -368,6 +376,7 @@ bool Connection::Send(const char* pBuffer, int iSize)
int iRes = send(m_iSocket, pBuffer + iBytesSent, iSize-iBytesSent, 0);
if (iRes <= 0)
{
m_bBroken = true;
return false;
}
iBytesSent += iRes;
Expand Down Expand Up @@ -396,6 +405,7 @@ char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
if (iBufAvail < 0)
{
ReportError("Could not receive data on socket", NULL, true, 0);
m_bBroken = true;
break;
}
else if (iBufAvail == 0)
Expand Down Expand Up @@ -534,6 +544,7 @@ bool Connection::DoConnect()
debug("Do connecting");

m_iSocket = INVALID_SOCKET;
m_bBroken = false;

#ifdef HAVE_GETADDRINFO
struct addrinfo addr_hints, *addr_list, *addr;
Expand All @@ -552,36 +563,46 @@ bool Connection::DoConnect()
return false;
}

std::vector<SockAddr> triedAddr;
bool bConnected = false;

for (addr = addr_list; addr != NULL; addr = addr->ai_next)
{
bool bLastAddr = !addr->ai_next;
// don't try the same combinations of ai_family, ai_socktype, ai_protocol multiple times
SockAddr sa = { addr->ai_family, addr->ai_socktype, addr->ai_protocol };
if (std::find(triedAddr.begin(), triedAddr.end(), sa) != triedAddr.end())
{
continue;
}
triedAddr.push_back(sa);

m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifdef WIN32
SetHandleInformation((HANDLE)m_iSocket, HANDLE_FLAG_INHERIT, 0);
#endif
if (m_iSocket != INVALID_SOCKET)
if (m_iSocket == INVALID_SOCKET)
{
if (ConnectWithTimeout(addr->ai_addr, addr->ai_addrlen))
{
// Connection established
break;
}
// Connection failed
if (bLastAddr)
{
ReportError("Connection to %s failed", m_szHost, true, 0);
}
closesocket(m_iSocket);
m_iSocket = INVALID_SOCKET;
ReportError("Socket creation failed for %s", m_szHost, true, 0);
break;
}
else if (bLastAddr)

if (ConnectWithTimeout(addr->ai_addr, addr->ai_addrlen))
{
ReportError("Socket creation failed for %s", m_szHost, true, 0);
// Connection established
bConnected = true;
break;
}
}

freeaddrinfo(addr_list);

if (!bConnected && m_iSocket != INVALID_SOCKET)
{
ReportError("Connection to %s failed", m_szHost, true, 0);
closesocket(m_iSocket);
m_iSocket = INVALID_SOCKET;
}

if (m_iSocket == INVALID_SOCKET)
{
return false;
Expand Down Expand Up @@ -822,12 +843,15 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
char szErrPrefix[1024];
snprintf(szErrPrefix, 1024, szMsgPrefix, szMsgArg);
szErrPrefix[1024-1] = '\0';


char szMessage[1024];

if (PrintErrCode)
{
#ifdef WIN32
int ErrCode = WSAGetLastError();
char szErrMsg[1024];
szErrMsg[0] = '\0';
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrCode, 0, szErrMsg, 1024, NULL);
szErrMsg[1024-1] = '\0';
#else
Expand All @@ -849,7 +873,9 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
}
else
{
error("%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
snprintf(szMessage, sizeof(szMessage), "%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
szMessage[sizeof(szMessage) - 1] = '\0';
PrintError(szMessage);
}
}
else
Expand All @@ -860,18 +886,23 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
}
else
{
error(szErrPrefix);
PrintError(szErrPrefix);
}
}
}

void Connection::PrintError(const char* szErrMsg)
{
error("%s", szErrMsg);
}

#ifndef DISABLE_TLS
bool Connection::StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile)
{
debug("Starting TLS");

delete m_pTLSSocket;
m_pTLSSocket = new TLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher);
m_pTLSSocket = new ConTLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher, this);
m_pTLSSocket->SetSuppressErrors(m_bSuppressErrors);

return m_pTLSSocket->Start();
Expand Down
28 changes: 26 additions & 2 deletions daemon/connect/Connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <[email protected]>
* Copyright (C) 2007-2014 Andrey Prygunkov <[email protected]>
* Copyright (C) 2007-2015 Andrey Prygunkov <[email protected]>
*
* 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
Expand Down Expand Up @@ -61,8 +61,31 @@ class Connection
bool m_bSuppressErrors;
char m_szRemoteAddr[20];
int m_iTotalBytesRead;
bool m_bBroken;

struct SockAddr
{
int ai_family;
int ai_socktype;
int ai_protocol;
bool operator==(const SockAddr& rhs) const
{ return memcmp(this, &rhs, sizeof(SockAddr)) == 0; }
};

#ifndef DISABLE_TLS
TLSSocket* m_pTLSSocket;
class ConTLSSocket: public TLSSocket
{
private:
Connection* m_pOwner;
protected:
virtual void PrintError(const char* szErrMsg) { m_pOwner->PrintError(szErrMsg); }
public:
ConTLSSocket(SOCKET iSocket, bool bIsClient, const char* szCertFile,
const char* szKeyFile, const char* szCipher, Connection* pOwner):
TLSSocket(iSocket, bIsClient, szCertFile, szKeyFile, szCipher), m_pOwner(pOwner) {}
};

ConTLSSocket* m_pTLSSocket;
bool m_bTLSError;
#endif
#ifndef HAVE_GETADDRINFO
Expand All @@ -73,6 +96,7 @@ class Connection

Connection(SOCKET iSocket, bool bTLS);
void ReportError(const char* szMsgPrefix, const char* szMsgArg, bool PrintErrCode, int herrno);
virtual void PrintError(const char* szErrMsg);
bool DoConnect();
bool DoDisconnect();
bool InitSocketOpts();
Expand Down
19 changes: 15 additions & 4 deletions daemon/connect/TLS.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2013 Andrey Prygunkov <[email protected]>
* Copyright (C) 2008-2015 Andrey Prygunkov <[email protected]>
*
* 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
Expand Down Expand Up @@ -283,6 +283,8 @@ TLSSocket::~TLSSocket()

void TLSSocket::ReportError(const char* szErrMsg)
{
char szMessage[1024];

#ifdef HAVE_LIBGNUTLS
const char* errstr = gnutls_strerror(m_iRetCode);
if (m_bSuppressErrors)
Expand All @@ -291,7 +293,9 @@ void TLSSocket::ReportError(const char* szErrMsg)
}
else
{
error("%s: %s", szErrMsg, errstr);
snprintf(szMessage, sizeof(szMessage), "%s: %s", szErrMsg, errstr);
szMessage[sizeof(szMessage) - 1] = '\0';
PrintError(szMessage);
}
#endif /* HAVE_LIBGNUTLS */

Expand All @@ -311,16 +315,23 @@ void TLSSocket::ReportError(const char* szErrMsg)
}
else if (errcode != 0)
{
error("%s: %s", szErrMsg, errstr);
snprintf(szMessage, sizeof(szMessage), "%s: %s", szErrMsg, errstr);
szMessage[sizeof(szMessage) - 1] = '\0';
PrintError(szMessage);
}
else
{
error("%s", szErrMsg);
PrintError(szErrMsg);
}
} while (errcode);
#endif /* HAVE_OPENSSL */
}

void TLSSocket::PrintError(const char* szErrMsg)
{
error("%s", szErrMsg);
}

bool TLSSocket::Start()
{
#ifdef HAVE_LIBGNUTLS
Expand Down
7 changes: 5 additions & 2 deletions daemon/connect/TLS.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2013 Andrey Prygunkov <[email protected]>
* Copyright (C) 2008-2015 Andrey Prygunkov <[email protected]>
*
* 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
Expand Down Expand Up @@ -46,9 +46,12 @@ class TLSSocket

void ReportError(const char* szErrMsg);

protected:
virtual void PrintError(const char* szErrMsg);

public:
TLSSocket(SOCKET iSocket, bool bIsClient, const char* szCertFile, const char* szKeyFile, const char* szCipher);
~TLSSocket();
virtual ~TLSSocket();
static void Init();
static void Final();
bool Start();
Expand Down
11 changes: 7 additions & 4 deletions daemon/nntp/NNTPConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <[email protected]>
* Copyright (C) 2007-2013 Andrey Prygunkov <[email protected]>
* Copyright (C) 2007-2015 Andrey Prygunkov <[email protected]>
*
* 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
Expand Down Expand Up @@ -99,8 +99,8 @@ bool NNTPConnection::Authenticate()
{
if (strlen(m_pNewsServer->GetUser()) == 0 || strlen(m_pNewsServer->GetPassword()) == 0)
{
error("%c%s (%s) requested authorization but username/password are not set in settings",
toupper(m_pNewsServer->GetName()[0]), m_pNewsServer->GetName() + 1, m_pNewsServer->GetHost());
ReportError("Could not connect to %s: server requested authorization but username/password are not set in settings",
m_pNewsServer->GetHost(), false, 0);
m_bAuthError = true;
return false;
}
Expand Down Expand Up @@ -264,7 +264,10 @@ bool NNTPConnection::Disconnect()
{
if (m_eStatus == csConnected)
{
Request("quit\r\n");
if (!m_bBroken)
{
Request("quit\r\n");
}
free(m_szActiveGroup);
m_szActiveGroup = NULL;
}
Expand Down
3 changes: 2 additions & 1 deletion daemon/nntp/NNTPConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <[email protected]>
* Copyright (C) 2007-2008 Andrey Prygunkov <[email protected]>
* Copyright (C) 2007-2015 Andrey Prygunkov <[email protected]>
*
* 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
Expand Down Expand Up @@ -53,6 +53,7 @@ class NNTPConnection : public Connection
const char* Request(const char* req);
const char* JoinGroup(const char* grp);
bool GetAuthError() { return m_bAuthError; }

};

#endif
Expand Down
Loading

0 comments on commit 1552194

Please sign in to comment.