Package: klibido
Version: 0.2.5-7+b1
Severity: important
Tags: patch ipv6

With the current connection scheme, only a connection to the first IP address 
of any address family is tried; a connection over IPv6 is only attempted if 
there is no IPv4 address.

This means that klibido breaks if the "first" server in a cluster is down
or refusing connections.
And of course IPv6-only systems break if the server is dual-stack.

The attached patch is a revision of my previous patch, it uses getaddrinfo 
to determine the addresses to connect to, connect (in myConnect()) is called 
in a loop. I'm also attaching an incremental patch.

Thank you!

Martin
--- a/src/nntpthreadsocket.cpp
+++ b/src/nntpthreadsocket.cpp
@@ -26,6 +26,7 @@
 #include <assert.h>
 #include <netdb.h>
 #include <sys/poll.h>
+#include <arpa/inet.h>
 #include "queueparts.h"
 
 
@@ -241,24 +242,70 @@
 			}
 		ha.setAddress(addrList[0]);
 	*/
-	hostent *he=gethostbyname(nHost->hostName );
-	if (!he) {
+	QString s;
+	char tempstr[64];
+	struct addrinfo *result;
+	struct addrinfo *res;
+	struct addrinfo hints;
+	bool connected = false;
+
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_UNSPEC;    // Allow IPv4 or IPv6
+	hints.ai_flags = AI_ADDRCONFIG; // only return families supported by local system
+
+	if (getaddrinfo(nHost->hostName, NULL, &hints, &result) != 0) {
 		qDebug("Cannot resolve hostname");
 		errorString="Cannot resolve " + nHost->hostName;
 		error=NntpThreadSocket::Comm_Err;
 		reset();
 		return false;
 	}
-	QString address=QString::number( (unsigned char) he->h_addr[0]);
-	QString s;
-	
-	for (int i = 1; i < he->h_length; i++) {
-		address+='.' + QString::number( (unsigned char) he->h_addr[i]);
+
+	for (res = result; res != NULL; res = res->ai_next) {
+		if (res->ai_family == AF_INET6) {
+			// IPv6
+			if (useIPv6 != true) {
+				useIPv6 = true;
+				// new QSocketDevice for IPv6 (assigning v6 address to a standard socket
+				// doesn't work)
+				kes->close();
+				delete kes;
+				kes = new QSocketDevice(QSocketDevice::Stream, QSocketDevice::IPv6, 0);
+			}
+			inet_ntop(AF_INET6, &(((sockaddr_in6 const *)res->ai_addr)->sin6_addr), tempstr, 64);
+			// qDebug("will connect to IPv6 address %s", tempstr);
+			ha.setAddress(tempstr);
+	    } else {
+			// IPv4
+			if (useIPv6 != false) {
+				useIPv6 = false;
+				// new QSocketDevice
+				kes->close();
+				delete kes;
+				kes = new QSocketDevice(QSocketDevice::Stream);
+			}
+			inet_ntop(AF_INET,&(((sockaddr_in const *)res->ai_addr)->sin_addr), tempstr, 64);
+			// qDebug("will connect to IPv4 address %s", tempstr);
+			ha.setAddress(tempstr);
 		}
-	
-// 	qDebug("Address: %s", (const char *) address);
-	ha.setAddress(address);
-	
+
+		if (! myConnect(ha, nHost->port) ) {
+			qDebug("Cannot connect to %s", tempstr);
+			// don't return yet, there may be other addresses to connect to!
+		} else {
+			qDebug("connected to %s!", tempstr);
+			connected = true;
+			break;
+		}
+	}
+	freeaddrinfo(result);
+
+	if (! connected) {
+		// error was set by myConnect
+		return false;
+	}
+//	qDebug("Address: %s", ha.toString().latin1());
 	/*
 	//Debug!--------------------
 	qDebug("Connecting");
@@ -337,12 +384,7 @@
 				return false;
 			}
 	}*/
-	//New, experimental connection code...
-	if (! myConnect(ha, nHost->port) ) {
-		qDebug("Cannot connect");
-		return false;
-	}
-	
+
 	kes->setBlocking(true);
 		
 // 		qDebug("Connected, going on");
@@ -363,7 +405,11 @@
 			error=NntpThreadSocket::Comm_Err;
 			kes->close();
 			delete kes;
-			kes = new QSocketDevice(QSocketDevice::Stream);
+			if ( useIPv6 ) {
+				kes = new QSocketDevice(QSocketDevice::Stream, QSocketDevice::IPv6, 0);
+			} else {
+				kes = new QSocketDevice(QSocketDevice::Stream);
+			}
 			kes->setBlocking(true);
 			isLoggedIn=false;
 			watermark=buffer;
@@ -382,7 +428,11 @@
             qDebug("Bad response to the \"user\" cmd");
 			kes->close();
 			delete kes;
-			kes = new QSocketDevice(QSocketDevice::Stream);
+			if ( useIPv6 ) {
+				kes = new QSocketDevice(QSocketDevice::Stream, QSocketDevice::IPv6, 0);
+			} else {
+				kes = new QSocketDevice(QSocketDevice::Stream);
+			}
 			kes->setBlocking(true);
 			isLoggedIn=false;
 			watermark=buffer;
@@ -1779,6 +1829,7 @@
 	pause=false;
 	status=Ready;
 	
+	useIPv6 = false;
 	
 	lineBufSize=1000;
     line=new char[lineBufSize];
@@ -2234,7 +2285,11 @@
 {
 	kes->close();
 	delete kes;
-	kes = new QSocketDevice(QSocketDevice::Stream);
+	if ( useIPv6 ) {
+		kes = new QSocketDevice(QSocketDevice::Stream, QSocketDevice::IPv6, 0);
+	} else {
+		kes = new QSocketDevice(QSocketDevice::Stream);
+	}
 	isLoggedIn=false;
 // 	*status=NntpThreadSocket::Ready;
 	watermark=buffer; //buffer emptyied :)
--- a/src/nntpthreadsocket.h
+++ b/src/nntpthreadsocket.h
@@ -238,6 +238,7 @@
 		void setHost(NntpHost *nh);
 		bool m_sendCmd( QString& cmd, int response );
 		QTime prevTime, currentTime;
+		bool useIPv6;
 		
 		
 	public:
--- a/src/nntpthreadsocket.cpp
+++ b/src/nntpthreadsocket.cpp
@@ -244,37 +244,68 @@
 	*/
 	QString s;
 	char tempstr[64];
-	hostent *he=gethostbyname(nHost->hostName );
-	if (!he) {
-		// possibly IPV6
-		he = gethostbyname2(nHost->hostName, AF_INET6);
-		if (he) {
-			// IPV6 lookup successful
-			
-			// extra v6 socket (assigning v6 address to a standard socket leads to errors)
-			// not needed for reconnects
-			if ( false == useIPv6 ) {
+	struct addrinfo *result;
+	struct addrinfo *res;
+	struct addrinfo hints;
+	bool connected = false;
+
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_UNSPEC;    // Allow IPv4 or IPv6
+	hints.ai_flags = AI_ADDRCONFIG; // only return families supported by local system
+
+	if (getaddrinfo(nHost->hostName, NULL, &hints, &result) != 0) {
+		qDebug("Cannot resolve hostname");
+		errorString="Cannot resolve " + nHost->hostName;
+		error=NntpThreadSocket::Comm_Err;
+		reset();
+		return false;
+	}
+
+	for (res = result; res != NULL; res = res->ai_next) {
+		if (res->ai_family == AF_INET6) {
+			// IPv6
+			if (useIPv6 != true) {
+				useIPv6 = true;
+				// new QSocketDevice for IPv6 (assigning v6 address to a standard socket
+				// doesn't work)
 				kes->close();
 				delete kes;
 				kes = new QSocketDevice(QSocketDevice::Stream, QSocketDevice::IPv6, 0);
-				useIPv6 = true;
 			}
-
-			inet_ntop(AF_INET6, he->h_addr, tempstr, 64);
+			inet_ntop(AF_INET6, &(((sockaddr_in6 const *)res->ai_addr)->sin6_addr), tempstr, 64);
+			// qDebug("will connect to IPv6 address %s", tempstr);
+			ha.setAddress(tempstr);
+	    } else {
+			// IPv4
+			if (useIPv6 != false) {
+				useIPv6 = false;
+				// new QSocketDevice
+				kes->close();
+				delete kes;
+				kes = new QSocketDevice(QSocketDevice::Stream);
+			}
+			inet_ntop(AF_INET,&(((sockaddr_in const *)res->ai_addr)->sin_addr), tempstr, 64);
+			// qDebug("will connect to IPv4 address %s", tempstr);
 			ha.setAddress(tempstr);
+		}
+
+		if (! myConnect(ha, nHost->port) ) {
+			qDebug("Cannot connect to %s", tempstr);
+			// don't return yet, there may be other addresses to connect to!
 		} else {
-			qDebug("Cannot resolve hostname");
-			errorString="Cannot resolve " + nHost->hostName;
-			error=NntpThreadSocket::Comm_Err;
-			reset();
-			return false;
+			qDebug("connected to %s!", tempstr);
+			connected = true;
+			break;
 		}
-	} else {
-		// IPv4
-		inet_ntop(AF_INET, he->h_addr, tempstr, 64);
-		ha.setAddress(tempstr);
 	}
-//	qDebug("Address: %s", ha.toString().latin1());	
+	freeaddrinfo(result);
+
+	if (! connected) {
+		// error was set by myConnect
+		return false;
+	}
+//	qDebug("Address: %s", ha.toString().latin1());
 	/*
 	//Debug!--------------------
 	qDebug("Connecting");
@@ -353,12 +384,7 @@
 				return false;
 			}
 	}*/
-	//New, experimental connection code...
-	if (! myConnect(ha, nHost->port) ) {
-		qDebug("Cannot connect");
-		return false;
-	}
-	
+
 	kes->setBlocking(true);
 		
 // 		qDebug("Connected, going on");
_______________________________________________
pkg-kde-extras mailing list
pkg-kde-extras@lists.alioth.debian.org
http://lists.alioth.debian.org/mailman/listinfo/pkg-kde-extras

Reply via email to