use getaddrinfo(), inet_ntop(), some DNS and IPv4 support v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu, 04 Aug 2022 02:13:22 +0200
branchv_0
changeset 10 6a6b93507856
parent 9 de48b9278211
child 11 a910051cd975
use getaddrinfo(), inet_ntop(), some DNS and IPv4 support
src/Socket.cpp
--- a/src/Socket.cpp	Sat Jul 30 23:25:23 2022 +0200
+++ b/src/Socket.cpp	Thu Aug 04 02:13:22 2022 +0200
@@ -25,6 +25,8 @@
 #include <vector>
 #include <memory>
 #include <regex>
+#include <iostream>
+#include <netdb.h>
 
 #include "Socket.h"
 
@@ -62,6 +64,53 @@
 	else throw std::logic_error("Got error result: " + std::to_string(result) + " - " + message);
 }
 
+template <typename T> static T* castAddress(addrinfo* ai, sa_family_t family) {
+	if (ai && ai->ai_family == family && sizeof (T) == ai->ai_addrlen) return (T*) ai->ai_addr;
+	else return nullptr;
+}
+
+static std::string ip2string(const addrinfo* ai) {
+	//char buffer[INET_ADDRSTRLEN] = {0};
+	char buffer[INET6_ADDRSTRLEN] = {0};
+	//return inet_ntop(ai->ai_family, &ai->ai_addr, buffer, sizeof (buffer));
+	//return inet_ntop(ai->ai_family, &ai->ai_addr->sa_data, buffer, sizeof (buffer));
+	if (ai->ai_family == AF_INET) return inet_ntop(ai->ai_family, &((sockaddr_in const *) ai->ai_addr)->sin_addr, buffer, sizeof (buffer)); // TODO: check 0 result
+	else if (ai->ai_family == AF_INET6) return inet_ntop(ai->ai_family, &((sockaddr_in6 const *) ai->ai_addr)->sin6_addr, buffer, sizeof (buffer)); // TODO: check 0 result
+	else throw std::logic_error("Invalid address family: " + std::to_string(ai->ai_family));
+}
+
+static in_addr_t getAddress(const std::string& host) {
+
+	struct addrinfo* addrInfo;
+	check(getaddrinfo(host.c_str(), "", nullptr, &addrInfo), "getaddrinfo");
+
+	std::cerr << "found: " << addrInfo << std::endl;
+	if (addrInfo) {
+		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
+			std::cerr << "address info: family=" << std::to_string(ai->ai_addr->sa_family);
+			if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) std::cerr << " IPv4=" << ip2string(ai);
+			else if (sockaddr_in6 * sa = castAddress<sockaddr_in6>(ai, AF_INET6)) std::cerr << " IPv6=" << ip2string(ai);
+			std::cerr << std::endl;
+		}
+	}
+
+	if (addrInfo) {
+		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
+			if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) {
+				in_addr_t address = sa->sin_addr.s_addr;
+				freeaddrinfo(addrInfo);
+				return address;
+
+			}
+		}
+	}
+
+	freeaddrinfo(addrInfo);
+
+	// TODO: rather throw exception – requires IP address in the host string:
+	return inet_addr(host.c_str());
+}
+
 class UDPClientSocket : public Socket {
 private:
 	struct sockaddr_in remoteAddress;
@@ -73,7 +122,7 @@
 		std::shared_ptr<UDPClientSocket> s = std::make_shared<UDPClientSocket>();
 		memset((char *) &s->remoteAddress, 0, sizeof (s->remoteAddress));
 		s->remoteAddress.sin_family = AF_INET;
-		s->remoteAddress.sin_addr.s_addr = inet_addr(findOption(options, OPTION_HOST, true).c_str()); // TODO: use getaddrinfo() instead (because of error -1 = 255.255.255.255)
+		s->remoteAddress.sin_addr.s_addr = getAddress(findOption(options, OPTION_HOST, true)); // TODO: use getaddrinfo() instead (because of error -1 = 255.255.255.255)
 		s->remoteAddress.sin_port = htons(std::stoi(findOption(options, OPTION_PORT, true)));
 
 		auto protocol = findOption(options, OPTION_PROTOCOL);
@@ -106,7 +155,7 @@
 		std::shared_ptr<TCPClientSocket> s = std::make_shared<TCPClientSocket>();
 		memset((char *) &s->remoteAddress, 0, sizeof (s->remoteAddress));
 		s->remoteAddress.sin_family = AF_INET;
-		s->remoteAddress.sin_addr.s_addr = inet_addr(findOption(options, OPTION_HOST, true).c_str()); // TODO: use getaddrinfo() instead (because of error -1 = 255.255.255.255)
+		s->remoteAddress.sin_addr.s_addr = getAddress(findOption(options, OPTION_HOST, true).c_str()); // TODO: use getaddrinfo() instead (because of error -1 = 255.255.255.255)
 		s->remoteAddress.sin_port = htons(std::stoi(findOption(options, OPTION_PORT, true)));
 		return s;
 	}
@@ -144,17 +193,17 @@
 static std::vector<std::shared_ptr<SocketFactory>> factories
 {
 	std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_CLIENT, MODE_STREAM, TCPClientSocket >> (),
-	std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_SERVER, MODE_STREAM, TCPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (),
-	std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
-	std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_TCP, ROLE_SERVER, MODE_STREAM, TCPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (),
+			std::make_shared<TemplateSocketFactory<PROTOCOL_UDP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_SCTP, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_CLIENT, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_STREAM, UDPClientSocket >> (), // TODO: correct class
+			std::make_shared<TemplateSocketFactory<PROTOCOL_UDS, ROLE_SERVER, MODE_DATAGRAM, UDPClientSocket >> (), // TODO: correct class
 };
 
 std::shared_ptr<SocketFactory> SocketFactory::find(const SocketOptions& options) {