Limit the concurrent connection attempts in Windows XP. Its's only a hack.

Problem:
RetroShare connects to all ssl's at once. In Windows XP there is a build-in connection limit of concurrent incomplete connections.

Quote:
"The TCP/IP stack in Windows XP with Service Pack 2 (SP2) installed limits the number of concurrent, incomplete outbound TCP connection attempts. When the limit is reached, subsequent connection attempts are put in a queue and resolved at a fixed rate so that there are only a limited number of connections in the incomplete state."

This results in a high usage of the nonepaged pool and when it runs over the limit it results in the following error in the system log:
German:  "TCP/IP hat das Sicherheitslimit erreicht, das für die Anzahl gleichzeitiger TCP-Verbindungsversuche festgelegt wurde."
English: "TCP/IP has reached the security limit imposed on the number of concurrent (incomplete) TCP connect attempts."

After a longer runtime of RetroShare and a very high usage of the nonepaged pool all connections of all running programs are lost and no new connections can be made. At the end it can cause a blue screen.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3631 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
thunder2 2010-10-07 11:17:42 +00:00
parent c134b5f605
commit f4bbd3e933
6 changed files with 188 additions and 4 deletions

View File

@ -1453,6 +1453,19 @@ void p3ConnectMgr::tickMonitors()
(*mit)->statusChange(actionList);
}
}
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
/* notify all monitors */
std::list<pqiMonitor *>::iterator mit;
for(mit = clients.begin(); mit != clients.end(); mit++) {
(*mit)->statusChanged();
}
///////////////////////////////////////////////////////////
#endif
}

View File

@ -112,6 +112,14 @@ virtual ~pqiMonitor() { return; }
*@param plist contains list of states and actions of the client's peers
*/
virtual void statusChange(const std::list<pqipeer> &plist) = 0;
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
virtual void statusChanged() {};
///////////////////////////////////////////////////////////
#endif
//virtual void ownStatusChange(pqipeer &) { return; } // SIGNAL reset or similar.
//virtual void peerStatus(std::string id, uint32_t mode) = 0;

View File

@ -32,6 +32,15 @@
const int pqipersongrpzone = 354;
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
#include "retroshare/rsinit.h"
static std::list<std::string> waitingIds;
#define MAX_CONNECT_COUNT 5
///////////////////////////////////////////////////////////
#endif
/****
*#define PGRP_DEBUG 1
****/
@ -296,6 +305,73 @@ void pqipersongrp::statusChange(const std::list<pqipeer> &plist)
}
}
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
void pqipersongrp::statusChanged()
{
#warning "Windows connection limited hacked together - please fix"
if (RsInit::isWindowsXP() == false) {
/* the problem only exist in Windows XP */
waitingIds.clear();
return;
}
/* check for active connections and start waiting id's */
long connect_count = 0;
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
/* get address from p3connmgr */
if (!mConnMgr) {
return;
}
/* check for active connections and start waiting id's */
std::list<std::string> peers;
mConnMgr->getFriendList(peers);
/* count connection attempts */
std::list<std::string>::iterator peer;
for (peer = peers.begin(); peer != peers.end(); peer++) {
peerConnectState state;
if (mConnMgr->getFriendNetStatus(*peer, state) == false) {
continue;
}
if (state.inConnAttempt) {
connect_count++;
if (connect_count >= MAX_CONNECT_COUNT) {
#ifdef PGRP_DEBUG
std::cerr << "pqipersongrp::connectPeer() Too many connections due to windows limitations. There are " << waitingIds.size() << " waiting connections." << std::endl;
#endif
return;
}
}
}
} /* UNLOCKED */
#ifdef PGRP_DEBUG
std::cerr << "pqipersongrp::connectPeer() There are " << connect_count << " connection attempts and " << waitingIds.size() << " waiting connections. Can start " << (MAX_CONNECT_COUNT - connect_count) << " connection attempts." << std::endl;
#endif
/* there is no need for a mutex for waitingIds */
/* start some waiting id's */
for (int i = connect_count; i < MAX_CONNECT_COUNT; i++) {
if (waitingIds.empty()) {
break;
}
std::string waitingId = waitingIds.front();
waitingIds.pop_front();
connectPeer(waitingId, true);
}
}
///////////////////////////////////////////////////////////
#endif
int pqipersongrp::addPeer(std::string id)
@ -393,7 +469,14 @@ int pqipersongrp::tagHeartbeatRecvd(std::string id)
int pqipersongrp::connectPeer(std::string id)
int pqipersongrp::connectPeer(std::string id
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
, bool bConnect /*= false*/
///////////////////////////////////////////////////////////
#endif
)
{
/* get status from p3connectMgr */
#ifdef PGRP_DEBUG
@ -423,6 +506,33 @@ int pqipersongrp::connectPeer(std::string id)
if (!mConnMgr)
return 0;
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
if (RsInit::isWindowsXP()) {
/* the problem only exist in Windows XP */
if (bConnect == false) {
/* check for id is waiting */
if (std::find(waitingIds.begin(), waitingIds.end(), id) != waitingIds.end()) {
/* id is waiting for a connection */
return 0;
}
/* add id to waiting */
waitingIds.push_back(id);
/* wait for call to connectPeer with empty id */
return 0;
}
/* remove id from waiting */
waitingIds.remove(id);
}
///////////////////////////////////////////////////////////
#endif
struct sockaddr_in addr;
uint32_t delay;
uint32_t period;

View File

@ -64,10 +64,24 @@ int load_config();
/*************** pqiMonitor callback ***********************/
virtual void statusChange(const std::list<pqipeer> &plist);
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
virtual void statusChanged();
///////////////////////////////////////////////////////////
#endif
/******************* Peer Control **************************/
virtual int addPeer(std::string id); /* can be overloaded for testing */
int removePeer(std::string id);
int connectPeer(std::string id);
int connectPeer(std::string id
#ifdef WINDOWS_SYS
///////////////////////////////////////////////////////////
// hack for too many connections
, bool bConnect = false
///////////////////////////////////////////////////////////
#endif
);
/* Work-around to dodgy pointer stuff */
int tagHeartbeatRecvd(std::string id);

View File

@ -67,7 +67,7 @@ class RsInit
*/
static char dirSeperator();
static bool isPortable();
static bool isWindowsXP();
/*!
* Account Details (Combined GPG+SSL Setup)

View File

@ -76,6 +76,7 @@ class RsInitConfig
static std::string homePath;
#ifdef WINDOWS_SYS
static bool portable;
static bool isWindowsXP;
#endif
static std::list<accountId> accountIds;
@ -169,6 +170,7 @@ std::string RsInitConfig::basedir;
std::string RsInitConfig::homePath;
#ifdef WINDOWS_SYS
bool RsInitConfig::portable = false;
bool RsInitConfig::isWindowsXP = false;
#endif
/* Listening Port */
@ -256,6 +258,34 @@ void RsInit::InitRsConfig()
// use portable version
RsInitConfig::portable = true;
}
// test for Windows XP
OSVERSIONINFOEX osvi;
memset(&osvi, 0, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (GetVersionEx((OSVERSIONINFO*) &osvi)) {
if (osvi.dwMajorVersion == 5) {
if (osvi.dwMinorVersion == 1) {
/* Windows XP */
RsInitConfig::isWindowsXP = true;
} else if (osvi.dwMinorVersion == 2) {
SYSTEM_INFO si;
memset(&si, 0, sizeof(si));
GetSystemInfo(&si);
if (osvi.wProductType == VER_NT_WORKSTATION && si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) {
/* Windows XP Professional x64 Edition */
RsInitConfig::isWindowsXP = true;
}
}
}
}
if (RsInitConfig::isWindowsXP) {
std::cerr << "Running Windows XP" << std::endl;
} else {
std::cerr << "Not running Windows XP" << std::endl;
}
#endif
/* Setup the Debugging */
@ -1988,6 +2018,15 @@ bool RsInit::isPortable()
#endif
}
bool RsInit::isWindowsXP()
{
#ifdef WINDOWS_SYS
return RsInitConfig::isWindowsXP;
#else
return false;
#endif
}
std::string RsInit::RsConfigDirectory()
{
return RsInitConfig::basedir;