← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2593: Listen to both ipv4&6

 

------------------------------------------------------------
revno: 2593
committer: Jacek Sieka <arnetheduck@xxxxxxxxx>
branch nick: dcplusplus
timestamp: Fri 2011-08-19 20:07:56 +0200
message:
  Listen to both ipv4&6
modified:
  dcpp/ConnectionManager.cpp
  dcpp/SearchManager.cpp
  dcpp/Socket.cpp
  dcpp/Socket.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 'dcpp/ConnectionManager.cpp'
--- dcpp/ConnectionManager.cpp	2011-08-11 13:02:19 +0000
+++ dcpp/ConnectionManager.cpp	2011-08-19 18:07:56 +0000
@@ -213,7 +213,7 @@
 
 ConnectionManager::Server::Server(bool secure_, uint16_t aPort, const string& ip) : port(0), secure(secure_), die(false) {
 	sock.setLocalIp4(ip);
-	port = sock.listen(Util::toString(aPort), AF_INET);
+	port = sock.listen(Util::toString(aPort));
 
 	start();
 }
@@ -237,7 +237,7 @@
 		while(!die) {
 			try {
 				sock.disconnect();
-				port = sock.listen(Util::toString(port), AF_INET);
+				port = sock.listen(Util::toString(port));
 
 				if(failed) {
 					LogManager::getInstance()->message(_("Connectivity restored"));

=== modified file 'dcpp/SearchManager.cpp'
--- dcpp/SearchManager.cpp	2011-08-04 09:57:32 +0000
+++ dcpp/SearchManager.cpp	2011-08-19 18:07:56 +0000
@@ -93,7 +93,7 @@
 	try {
 		socket.reset(new Socket(Socket::TYPE_UDP));
 		socket->setLocalIp4(SETTING(BIND_ADDRESS));
-		port = socket->listen(Util::toString(SETTING(UDP_PORT)), AF_INET);
+		port = socket->listen(Util::toString(SETTING(UDP_PORT)));
 		socket->setBlocking(true);
 		start();
 	} catch(...) {
@@ -140,7 +140,7 @@
 		while(!stop) {
 			try {
 				socket->disconnect();
-				port = socket->listen(Util::toString(SETTING(UDP_PORT)), AF_INET);
+				port = socket->listen(Util::toString(SETTING(UDP_PORT)));
 				socket->setBlocking(true);
 				if(failed) {
 					LogManager::getInstance()->message(_("Search enabled again"));

=== modified file 'dcpp/Socket.cpp'
--- dcpp/Socket.cpp	2011-08-11 13:02:19 +0000
+++ dcpp/Socket.cpp	2011-08-19 18:07:56 +0000
@@ -134,6 +134,21 @@
 	return false;
 }
 
+inline int readable(socket_t sock0, socket_t sock1) {
+	fd_set rfd;
+	struct timeval tv = { 0 };
+
+	FD_ZERO(&rfd);
+	FD_SET(sock0, &rfd);
+	FD_SET(sock1, &rfd);
+
+    if(::select(std::max(sock0, sock1) + 1, &rfd, NULL, NULL, &tv) > 0) {
+        return FD_ISSET(sock0, &rfd) ? sock0 : sock1;
+    }
+
+	return sock0;
+}
+
 }
 
 Socket::addr Socket::udpAddr;
@@ -243,7 +258,9 @@
 	addr sock_addr = { { 0 } };
 	socklen_t sz = sizeof(sock_addr);
 
-	auto sock = setSock(check([&] { return ::accept(listeningSocket.getSock(), &sock_addr.sa, &sz); }), sock_addr.sa.sa_family);
+	auto sock = setSock(check([&] {
+		return ::accept(readable(listeningSocket.sock4, listeningSocket.sock6), &sock_addr.sa, &sz);
+	}), sock_addr.sa.sa_family);
 
 #ifdef _WIN32
 	// Make sure we disable any inherited windows message things for this socket.
@@ -253,21 +270,54 @@
 	setIp(resolveName(&sock_addr.sa, sz));
 }
 
-uint16_t Socket::listen(const string& port, int af) {
+uint16_t Socket::listen(const string& port) {
 	disconnect();
 
-	auto &localIp = af == AF_INET ? getLocalIp4() : getLocalIp6();
-
-	auto ai = resolveAddr(localIp, port, af, AI_PASSIVE | AI_ADDRCONFIG);
-
-	create(*ai); // TODO What if more than one is returned?
-	check([&] { return ::bind(getSock(), ai->ai_addr, ai->ai_addrlen); });
-
-	if(type == TYPE_TCP) {
-		check([&] { return ::listen(getSock(), 20); });
-	}
-
-	return getLocalPort();
+	//auto &localIp = af == AF_INET ? getLocalIp4() : getLocalIp6();
+
+	auto ai = resolveAddr(/*localIp*/ "", port, AF_UNSPEC, AI_PASSIVE | AI_ADDRCONFIG);
+
+	uint16_t p = 0;
+
+	// For server sockets we create both ipv4 and ipv6 if possible
+	// We use the same port for both sockets to deal with the fact that
+	// there's no way in ADC to have different ports for v4 and v6 TCP sockets
+	for(auto a = ai.get(); a; a = a->ai_next) {
+		if(!sock4.valid() && a->ai_family == AF_INET) {
+			create(*a);
+			if(p != 0) {
+				((sockaddr_in*)a->ai_addr)->sin_port = p;
+			}
+
+			check([&] { return ::bind(sock4, a->ai_addr, a->ai_addrlen); });
+			check([&] { return ::getsockname(sock4, a->ai_addr, (socklen_t*)&a->ai_addrlen); });
+			p = ((sockaddr_in*)a->ai_addr)->sin_port;
+
+			if(type == TYPE_TCP) {
+				check([&] { return ::listen(sock4, 20); });
+			}
+		}
+
+		if(!sock6.valid() && a->ai_family == AF_INET6) {
+			create(*a);
+			if(p != 0) {
+				((sockaddr_in6*)a->ai_addr)->sin6_port = p;
+			}
+
+			check([&] { return ::bind(sock6, a->ai_addr, a->ai_addrlen); });
+			check([&] { return ::getsockname(sock6, a->ai_addr, (socklen_t*)&a->ai_addrlen); });
+			p = ((sockaddr_in6*)a->ai_addr)->sin6_port;
+
+			if(type == TYPE_TCP) {
+				check([&] { return ::listen(sock6, 20); });
+			}
+		}
+	}
+
+	if(p == 0) {
+		throw SocketException(_("Could not open port for listening"));
+	}
+	return ntohs(p);
 }
 
 void Socket::connect(const string& aAddr, const string& aPort, const string& localPort) {
@@ -456,7 +506,7 @@
 	socklen_t addr_length = sizeof(remote_addr);
 
 	auto len = check([&] {
-		return ::recvfrom(getSock(), (char*)aBuffer, aBufLen, 0, &remote_addr.sa, &addr_length);
+		return ::recvfrom(readable(sock4, sock6), (char*)aBuffer, aBufLen, 0, &remote_addr.sa, &addr_length);
 	}, true);
 
 	if(len > 0) {
@@ -527,6 +577,9 @@
 		throw SocketException(EADDRNOTAVAIL);
 	}
 
+	if(!sock4.valid() || !sock6.valid()) {
+
+	}
 	auto buf = (const uint8_t*)aBuffer;
 
 	int sent;
@@ -563,10 +616,15 @@
 
 		connStr.insert(connStr.end(), buf, buf + aLen);
 
-		sent = check([&] { return ::sendto(getSock(), (const char*)&connStr[0], (int)connStr.size(), 0, &udpAddr.sa, udpAddrLen); });
+		sent = check([&] { return ::sendto(udpAddr.sa.sa_family == AF_INET ? sock4 : sock6,
+			(const char*)&connStr[0], (int)connStr.size(), 0, &udpAddr.sa, udpAddrLen); });
 	} else {
 		auto ai = resolveAddr(aAddr, aPort);
-		sent = check([&] { return ::sendto(getSock(), (const char*)aBuffer, (int)aLen, 0, ai->ai_addr, ai->ai_addrlen); });
+		if((ai->ai_family == AF_INET && !sock4.valid()) || (ai->ai_family == AF_INET6 && !sock6.valid())) {
+			create(*ai);
+		}
+		sent = check([&] { return ::sendto(ai->ai_family == AF_INET ? sock4 : sock6,
+			(const char*)aBuffer, (int)aLen, 0, ai->ai_addr, ai->ai_addrlen); });
 	}
 
 	stats.totalUp += sent;
@@ -639,31 +697,49 @@
 		return 0;
 	}
 
-	auto sock = getSock();
 	check([&] () -> int {
+		int nfds = -1;
+
 		if(waitFor & WAIT_READ) {
 			dcassert(!(waitFor & WAIT_CONNECT));
 			rfdp = &rfd;
 			FD_ZERO(rfdp);
-			FD_SET(sock, rfdp);
+			if(sock4.valid()) {
+				FD_SET(sock4, &rfd);
+				nfds = std::max((int)sock4, nfds);
+			}
+
+			if(sock6.valid()) {
+				FD_SET(sock6, &rfd);
+				nfds = std::max((int)sock6, nfds);
+			}
 		}
 
 		if(waitFor & WAIT_WRITE) {
 			dcassert(!(waitFor & WAIT_CONNECT));
 			wfdp = &wfd;
 			FD_ZERO(wfdp);
-			FD_SET(sock, wfdp);
+			if(sock4.valid()) {
+				FD_SET(sock4, &wfd);
+				nfds = std::max((int)sock4, nfds);
+			}
+
+			if(sock6.valid()) {
+				FD_SET(sock6, &wfd);
+				nfds = std::max((int)sock6, nfds);
+			}
 		}
 
-		return ::select((int)(sock+1), rfdp, wfdp, NULL, &tv);
+		return ::select(nfds + 1, rfdp, wfdp, NULL, &tv);
 	});
 
 	waitFor = WAIT_NONE;
 
-	if(rfdp && FD_ISSET(sock, rfdp)) {
+	if(rfdp && ((sock4.valid() && FD_ISSET(sock4, rfdp)) || (sock6.valid() && FD_ISSET(sock6, rfdp)))) {
 		waitFor |= WAIT_READ;
 	}
-	if(wfdp && FD_ISSET(sock, wfdp)) {
+
+	if(wfdp && ((sock4.valid() && FD_ISSET(sock4, wfdp)) || (sock6.valid() && FD_ISSET(sock6, wfdp)))) {
 		waitFor |= WAIT_WRITE;
 	}
 

=== modified file 'dcpp/Socket.h'
--- dcpp/Socket.h	2011-08-11 13:02:19 +0000
+++ dcpp/Socket.h	2011-08-19 18:07:56 +0000
@@ -172,7 +172,7 @@
 	uint16_t getLocalPort() noexcept;
 
 	/** Binds a socket to a certain local port and possibly IP. */
-	virtual uint16_t listen(const string& port, int af);
+	virtual uint16_t listen(const string& port);
 	virtual void accept(const Socket& listeningSocket);
 
 	int getSocketOptInt(int option);