AddressInfos [] = AddressInfo; UDP v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 06 Aug 2022 00:27:22 +0200
branchv_0
changeset 13 c29b13a659a7
parent 12 fcc5ed0fab9f
child 14 86feef4b6ee6
AddressInfos [] = AddressInfo; UDP
src/Socket.cpp
--- a/src/Socket.cpp	Fri Aug 05 23:45:48 2022 +0200
+++ b/src/Socket.cpp	Sat Aug 06 00:27:22 2022 +0200
@@ -69,44 +69,41 @@
 	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));
-}
-
 class AddressInfos {
 private:
-	struct addrinfo* addrInfo;
+	std::shared_ptr<addrinfo> addrInfo;
 
-	AddressInfos(addrinfo* addrInfo) : addrInfo(addrInfo) {
-		std::cerr << "  AddressInfo()" << std::endl;
+	AddressInfos(addrinfo* addrInfo) : addrInfo(std::shared_ptr<addrinfo>(addrInfo, freeaddrinfo)) {
 	}
 
 public:
 
 	virtual ~AddressInfos() {
-		std::cerr << " ~AddressInfo()" << std::endl;
-		freeaddrinfo(addrInfo);
 	}
-	
+
 	class AddressInfo {
+	private:
+		std::shared_ptr<addrinfo> parent; // to avoid premature deletion of the whole structure
 	public:
-		const addrinfo* const ai;
-		
-		AddressInfo(const addrinfo* const ai) : ai(ai) {}
+		const addrinfo * const ai;
+
+		AddressInfo(const addrinfo * const ai, std::shared_ptr<addrinfo> parent) : ai(ai), parent(parent) {
+		}
+
+		const std::string toString() const {
+			char buffer[INET6_ADDRSTRLEN] = {0};
+			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 return "unknown address family: " + std::to_string(ai->ai_family);
+		}
 	};
 
-	static AddressInfos getAddressInfo(const std::string& host, const std::string& port) {
+	static AddressInfos getAddressInfos(const std::string& host, const std::string& port, int socketType = SOCK_STREAM, int protocol = IPPROTO_TCP) {
 		struct addrinfo query;
 		memset(&query, sizeof (query), 0);
 		query.ai_family = AF_UNSPEC;
-		query.ai_socktype = SOCK_STREAM;
-		query.ai_protocol = IPPROTO_TCP;
+		query.ai_socktype = socketType;
+		query.ai_protocol = protocol;
 		query.ai_flags = AI_ALL;
 
 		struct addrinfo* addrInfo;
@@ -121,34 +118,24 @@
 
 	const std::size_t size() const {
 		std::size_t size = 0;
-		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) size++;
+		for (addrinfo* ai = addrInfo.get(); ai; ai = ai->ai_next) size++;
 		return size;
 	}
 
-	const addrinfo& operator[](std::size_t index) const {
-		for (addrinfo* ai = addrInfo; ai; index--) {
-			if (index == 0) return *ai;
+	const AddressInfo operator[](std::size_t index) const {
+		for (addrinfo* ai = addrInfo.get(); ai; index--) {
+			if (index == 0) return AddressInfo(ai, addrInfo);
 			else ai = ai->ai_next;
 		}
-		
+
 		throw std::out_of_range("invalid index for AddressInfo: " + std::to_string(index));
 	}
-	
+
 };
 
+// TODO: delete getAddress()
+
 static in_addr_t getAddress(const std::string& host) {
-
-	{
-		AddressInfos ai = AddressInfos::getAddressInfo("::0ff2", "smtp");
-		std::cerr << "AddressInfo size = " << ai.size() << std::endl;
-		for (size_t i = 0, limit = ai.size(); i < limit; i++) {
-			std::cerr << "AddressInfo: " << ip2string(&ai[i]) << std::endl;
-		}
-	}
-
-
-
-
 	struct addrinfo query;
 	memset(&query, sizeof (query), 0);
 	query.ai_family = AF_UNSPEC;
@@ -159,16 +146,6 @@
 	struct addrinfo* addrInfo;
 	check(getaddrinfo(host.c_str(), "", &query, &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) << " socktype=" << std::to_string(ai->ai_socktype) << " protocol=" << std::to_string(ai->ai_protocol);
-			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)) {
@@ -188,30 +165,29 @@
 
 class UDPClientSocket : public Socket {
 private:
-	struct sockaddr_in remoteAddress;
-	int protocol = IPPROTO_UDP;
-	int type = SOCK_DGRAM;
+	AddressInfos remoteAddresses;
+
+	UDPClientSocket(AddressInfos remoteAddresses) : remoteAddresses(remoteAddresses) {
+	}
+
 public:
 
 	static std::shared_ptr<Socket> open(const SocketOptions& options) {
-		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 = 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);
 
-		auto protocol = findOption(options, OPTION_PROTOCOL);
-		if (protocol == PROTOCOL_SCTP) {
-			s->protocol = IPPROTO_SCTP;
-			s->type = SOCK_SEQPACKET;
-		}
+		AddressInfos remoteAddresses = AddressInfos::getAddressInfos(
+				findOption(options, OPTION_HOST, true),
+				findOption(options, OPTION_PORT, true),
+				protocol == PROTOCOL_SCTP ? SOCK_SEQPACKET : SOCK_DGRAM,
+				protocol == PROTOCOL_SCTP ? IPPROTO_SCTP : IPPROTO_UDP);
 
-		return s;
+		return std::shared_ptr<UDPClientSocket>(new UDPClientSocket(remoteAddresses));
 	}
 
 	void send(const std::string& message) override {
-		FD s(::socket(AF_INET, type, protocol));
-		sendto(s.getFD(), message.c_str(), message.size(), 0, (sockaddr*) & remoteAddress, sizeof (remoteAddress));
+		auto ai = remoteAddresses[0].ai;
+		FD s(::socket(AF_INET, ai->ai_socktype, ai->ai_protocol));
+		sendto(s.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen);
 	}
 
 	const std::string receive() override {