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