← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2159: c-c error handling: increase reconnect intervals after timeouts; no reconnect after a protocol error

 

------------------------------------------------------------
revno: 2159
committer: poy <poy@xxxxxxxxxx>
branch nick: repo
timestamp: Sat 2010-06-12 19:59:19 +0200
message:
  c-c error handling: increase reconnect intervals after timeouts; no reconnect after a protocol error
modified:
  changelog.txt
  dcpp/ConnectionManager.cpp
  dcpp/ConnectionManager.h
  dcpp/DownloadManager.cpp
  dcpp/DownloadManager.h
  dcpp/UserConnection.cpp
  dcpp/UserConnection.h
  dcpp/UserConnectionListener.h


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'changelog.txt'
--- changelog.txt	2010-05-25 18:28:09 +0000
+++ changelog.txt	2010-06-12 17:59:19 +0000
@@ -1,5 +1,7 @@
 * [L#550300] Catch more potential file corruptions (thanks bigmuscle)
 * [ADC] NAT traversal to allow passive-passive connections (thanks cologic)
+* Reduce donwload reconnect attempts after connection failures (poy)
+* [ADC] Handle fatal client-client STA commands (poy)
 
 -- 0.762 2010-05-16 --
 * Stability improvement related to menus (poy)

=== modified file 'dcpp/ConnectionManager.cpp'
--- dcpp/ConnectionManager.cpp	2010-02-11 21:44:13 +0000
+++ dcpp/ConnectionManager.cpp	2010-06-12 17:59:19 +0000
@@ -153,7 +153,14 @@
 					continue;
 				}
 
-				if(cqi->getLastAttempt() == 0 || (((cqi->getLastAttempt() + 60*1000) < aTick) && !attemptDone)) {
+				if(cqi->getErrors() == -1 && cqi->getLastAttempt() != 0) {
+					// protocol error, don't reconnect except after a forced attempt
+					continue;
+				}
+
+				if(cqi->getLastAttempt() == 0 || (!attemptDone &&
+					cqi->getLastAttempt() + 60 * 1000 * max(1, cqi->getErrors()) < aTick))
+				{
 					cqi->setLastAttempt(aTick);
 
 					QueueItem::Priority prio = QueueManager::getInstance()->hasDownload(cqi->getUser());
@@ -178,7 +185,8 @@
 					} else if(cqi->getState() == ConnectionQueueItem::NO_DOWNLOAD_SLOTS && startDown) {
 						cqi->setState(ConnectionQueueItem::WAITING);
 					}
-				} else if(((cqi->getLastAttempt() + 50*1000) < aTick) && (cqi->getState() == ConnectionQueueItem::CONNECTING)) {
+				} else if(cqi->getState() == ConnectionQueueItem::CONNECTING && cqi->getLastAttempt() + 50 * 1000 < aTick) {
+					cqi->setErrors(cqi->getErrors() + 1);
 					fire(ConnectionManagerListener::Failed(), cqi, _("Connection timeout"));
 					cqi->setState(ConnectionQueueItem::WAITING);
 				}
@@ -459,6 +467,7 @@
 		Lock l(cs);
 		for(ConnectionQueueItem::Iter i = downloads.begin(); i != downloads.end(); ++i) {
 			ConnectionQueueItem* cqi = *i;
+			cqi->setErrors(0);
 			if((cqi->getState() == ConnectionQueueItem::CONNECTING || cqi->getState() == ConnectionQueueItem::WAITING) &&
 				cqi->getUser().user->getCID() == cid)
 			{
@@ -664,6 +673,8 @@
 		ConnectionQueueItem::Iter i = find(downloads.begin(), downloads.end(), aSource->getUser());
 
 		if(i != downloads.end()) {
+			(*i)->setErrors(0);
+
 			const string& to = (*i)->getToken();
 
 			// 0.698 would send an empty token in some cases...remove this bugfix at some point
@@ -694,7 +705,7 @@
 	(*i)->setLastAttempt(0);
 }
 
-void ConnectionManager::on(UserConnectionListener::Failed, UserConnection* aSource, const string& aError) throw() {
+void ConnectionManager::failed(UserConnection* aSource, const string& aError, bool protocolError) {
 	Lock l(cs);
 
 	if(aSource->isSet(UserConnection::FLAG_ASSOCIATED)) {
@@ -704,6 +715,7 @@
 			ConnectionQueueItem* cqi = *i;
 			cqi->setState(ConnectionQueueItem::WAITING);
 			cqi->setLastAttempt(GET_TICK());
+			cqi->setErrors(protocolError ? (cqi->getErrors() + 1) : -1);
 			fire(ConnectionManagerListener::Failed(), cqi, aError);
 		} else if(aSource->isSet(UserConnection::FLAG_UPLOAD)) {
 			ConnectionQueueItem::Iter i = find(uploads.begin(), uploads.end(), aSource->getUser());
@@ -715,6 +727,14 @@
 	putConnection(aSource);
 }
 
+void ConnectionManager::on(UserConnectionListener::Failed, UserConnection* aSource, const string& aError) throw() {
+	failed(aSource, aError, false);
+}
+
+void ConnectionManager::on(UserConnectionListener::ProtocolError, UserConnection* aSource, const string& aError) throw() {
+	failed(aSource, aError, true);
+}
+
 void ConnectionManager::disconnect(const UserPtr& aUser) {
 	Lock l(cs);
 	for(UserConnectionList::iterator i = userConnections.begin(); i != userConnections.end(); ++i) {

=== modified file 'dcpp/ConnectionManager.h'
--- dcpp/ConnectionManager.h	2010-02-11 21:44:13 +0000
+++ dcpp/ConnectionManager.h	2010-06-12 17:59:19 +0000
@@ -47,10 +47,11 @@
 	};
 
 	ConnectionQueueItem(const HintedUser& aUser, bool aDownload) : token(Util::toString(Util::rand())),
-		lastAttempt(0), state(WAITING), download(aDownload), user(aUser) { }
+		lastAttempt(0), errors(0), state(WAITING), download(aDownload), user(aUser) { }
 
 	GETSET(string, token, Token);
 	GETSET(uint64_t, lastAttempt, LastAttempt);
+	GETSET(int, errors, Errors); // Number of connection errors, or -1 after a protocol error
 	GETSET(State, state, State);
 	GETSET(bool, download, Download);
 
@@ -174,9 +175,12 @@
 
 	void accept(const Socket& sock, bool secure) throw();
 
+	void failed(UserConnection* aSource, const string& aError, bool protocolError);
+
 	// UserConnectionListener
 	virtual void on(Connected, UserConnection*) throw();
 	virtual void on(Failed, UserConnection*, const string&) throw();
+	virtual void on(ProtocolError, UserConnection*, const string&) throw();
 	virtual void on(CLock, UserConnection*, const string&, const string&) throw();
 	virtual void on(Key, UserConnection*, const string&) throw();
 	virtual void on(Direction, UserConnection*, const string&, const string&) throw();

=== modified file 'dcpp/DownloadManager.cpp'
--- dcpp/DownloadManager.cpp	2010-05-25 18:28:09 +0000
+++ dcpp/DownloadManager.cpp	2010-06-12 17:59:19 +0000
@@ -429,7 +429,7 @@
 	failDownload(aSource, _("No slots available"));
 }
 
-void DownloadManager::on(UserConnectionListener::Failed, UserConnection* aSource, const string& aError) throw() {
+void DownloadManager::onFailed(UserConnection* aSource, const string& aError) {
 	{
 		Lock l(cs);
  		idlers.erase(remove(idlers.begin(), idlers.end(), aSource), idlers.end());

=== modified file 'dcpp/DownloadManager.h'
--- dcpp/DownloadManager.h	2010-02-11 21:44:13 +0000
+++ dcpp/DownloadManager.h	2010-06-12 17:59:19 +0000
@@ -84,9 +84,12 @@
 	void startData(UserConnection* aSource, int64_t start, int64_t newSize, bool z);
 	void endData(UserConnection* aSource);
 
+	void onFailed(UserConnection* aSource, const string& aError);
+
 	// UserConnectionListener
 	virtual void on(Data, UserConnection*, const uint8_t*, size_t) throw();
-	virtual void on(Failed, UserConnection*, const string&) throw();
+	virtual void on(Failed, UserConnection* aSource, const string& aError) throw() { onFailed(aSource, aError); }
+	virtual void on(ProtocolError, UserConnection* aSource, const string& aError) throw() { onFailed(aSource, aError); }
 	virtual void on(MaxedOut, UserConnection*) throw();
 	virtual	void on(FileNotAvailable, UserConnection*) throw();
 	virtual void on(Updated, UserConnection*) throw();

=== modified file 'dcpp/UserConnection.cpp'
--- dcpp/UserConnection.cpp	2010-02-11 21:44:13 +0000
+++ dcpp/UserConnection.cpp	2010-06-12 17:59:19 +0000
@@ -46,12 +46,14 @@
 
 void UserConnection::on(BufferedSocketListener::Line, const string& aLine) throw () {
 
-	if(aLine.length() < 2)
+	if(aLine.length() < 2) {
+		fire(UserConnectionListener::ProtocolError(), this, _("Invalid data"));
 		return;
+	}
 
 	if(aLine[0] == 'C' && !isSet(FLAG_NMDC)) {
 		if(!Text::validateUtf8(aLine)) {
-			// @todo Report to user?
+			fire(UserConnectionListener::ProtocolError(), this, _("Non-UTF-8 data in an ADC connection"));
 			return;
 		}
 		dispatch(aLine);
@@ -59,10 +61,10 @@
 	} else if(aLine[0] == '$') {
 		setFlag(FLAG_NMDC);
 	} else {
-		// We shouldn't be here?
-		dcdebug("Unknown UserConnection command: %.50s\n", aLine.c_str());
+		fire(UserConnectionListener::ProtocolError(), this, _("Invalid data"));
 		return;
 	}
+
 	string cmd;
 	string param;
 
@@ -88,9 +90,7 @@
 			param.rfind(/*path/file*/" no more exists") != string::npos) {
 			fire(UserConnectionListener::FileNotAvailable(), this);
 		} else {
-			dcdebug("Unknown $Error %s\n", param.c_str());
-			fire(UserConnectionListener::Failed(), this, param);
-			disconnect(true);
+			fire(UserConnectionListener::ProtocolError(), this, param);
 		}
 	} else if(cmd == "$GetListLen") {
 		fire(UserConnectionListener::GetListLength(), this);
@@ -129,7 +129,7 @@
 	} else if(cmd.compare(0, 4, "$ADC") == 0) {
 		dispatch(aLine, true);
 	} else {
-		dcdebug("Unknown NMDC command: %.50s\n", aLine.c_str());
+		fire(UserConnectionListener::ProtocolError(), this, _("Invalid data"));
 	}
 }
 
@@ -172,6 +172,18 @@
 	send("$Supports " + x + '|');
 }
 
+void UserConnection::handle(AdcCommand::STA t, const AdcCommand& c) {
+	if(c.getParameters().size() >= 2) {
+		const string& code = c.getParam(0);
+		if(!code.empty() && code[0] - '0' == AdcCommand::SEV_FATAL) {
+			fire(UserConnectionListener::ProtocolError(), this, c.getParam(1));
+			return;
+		}
+	}
+
+	fire(t, this, c);
+}
+
 void UserConnection::on(Connected) throw() {
 	lastActivity = GET_TICK();
 	fire(UserConnectionListener::Connected(), this);

=== modified file 'dcpp/UserConnection.h'
--- dcpp/UserConnection.h	2010-02-11 21:44:13 +0000
+++ dcpp/UserConnection.h	2010-06-12 17:59:19 +0000
@@ -155,7 +155,7 @@
 	void handle(AdcCommand::INF t, const AdcCommand& c) { fire(t, this, c); }
 	void handle(AdcCommand::GET t, const AdcCommand& c) { fire(t, this, c); }
 	void handle(AdcCommand::SND t, const AdcCommand& c) { fire(t, this, c);	}
-	void handle(AdcCommand::STA t, const AdcCommand& c) { fire(t, this, c);	}
+	void handle(AdcCommand::STA t, const AdcCommand& c);
 	void handle(AdcCommand::RES t, const AdcCommand& c) { fire(t, this, c); }
 	void handle(AdcCommand::GFI t, const AdcCommand& c) { fire(t, this, c);	}
 

=== modified file 'dcpp/UserConnectionListener.h'
--- dcpp/UserConnectionListener.h	2010-02-11 21:44:13 +0000
+++ dcpp/UserConnectionListener.h	2010-06-12 17:59:19 +0000
@@ -46,12 +46,14 @@
 	typedef X<16> MyNick;
 	typedef X<17> TransmitDone;
 	typedef X<18> Supports;
-	typedef X<19> FileNotAvailable;
+	typedef X<19> ProtocolError;
+	typedef X<20> FileNotAvailable;
 
 	virtual void on(BytesSent, UserConnection*, size_t, size_t) throw() { }
 	virtual void on(Connected, UserConnection*) throw() { }
 	virtual void on(Data, UserConnection*, const uint8_t*, size_t) throw() { }
 	virtual void on(Failed, UserConnection*, const string&) throw() { }
+	virtual void on(ProtocolError, UserConnection*, const string&) throw() { }
 	virtual void on(CLock, UserConnection*, const string&, const string&) throw() { }
 	virtual void on(Key, UserConnection*, const string&) throw() { }
 	virtual void on(Direction, UserConnection*, const string&, const string&) throw() { }