src/Socket.cpp
branchv_0
changeset 13 c29b13a659a7
parent 12 fcc5ed0fab9f
child 14 86feef4b6ee6
equal deleted inserted replaced
12:fcc5ed0fab9f 13:c29b13a659a7
    67 template <typename T> static T* castAddress(addrinfo* ai, sa_family_t family) {
    67 template <typename T> static T* castAddress(addrinfo* ai, sa_family_t family) {
    68 	if (ai && ai->ai_family == family && sizeof (T) == ai->ai_addrlen) return (T*) ai->ai_addr;
    68 	if (ai && ai->ai_family == family && sizeof (T) == ai->ai_addrlen) return (T*) ai->ai_addr;
    69 	else return nullptr;
    69 	else return nullptr;
    70 }
    70 }
    71 
    71 
    72 static std::string ip2string(const addrinfo* ai) {
       
    73 	//char buffer[INET_ADDRSTRLEN] = {0};
       
    74 	char buffer[INET6_ADDRSTRLEN] = {0};
       
    75 	//return inet_ntop(ai->ai_family, &ai->ai_addr, buffer, sizeof (buffer));
       
    76 	//return inet_ntop(ai->ai_family, &ai->ai_addr->sa_data, buffer, sizeof (buffer));
       
    77 	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
       
    78 	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
       
    79 	else throw std::logic_error("Invalid address family: " + std::to_string(ai->ai_family));
       
    80 }
       
    81 
       
    82 class AddressInfos {
    72 class AddressInfos {
    83 private:
    73 private:
    84 	struct addrinfo* addrInfo;
    74 	std::shared_ptr<addrinfo> addrInfo;
    85 
    75 
    86 	AddressInfos(addrinfo* addrInfo) : addrInfo(addrInfo) {
    76 	AddressInfos(addrinfo* addrInfo) : addrInfo(std::shared_ptr<addrinfo>(addrInfo, freeaddrinfo)) {
    87 		std::cerr << "  AddressInfo()" << std::endl;
       
    88 	}
    77 	}
    89 
    78 
    90 public:
    79 public:
    91 
    80 
    92 	virtual ~AddressInfos() {
    81 	virtual ~AddressInfos() {
    93 		std::cerr << " ~AddressInfo()" << std::endl;
    82 	}
    94 		freeaddrinfo(addrInfo);
    83 
    95 	}
       
    96 	
       
    97 	class AddressInfo {
    84 	class AddressInfo {
       
    85 	private:
       
    86 		std::shared_ptr<addrinfo> parent; // to avoid premature deletion of the whole structure
    98 	public:
    87 	public:
    99 		const addrinfo* const ai;
    88 		const addrinfo * const ai;
   100 		
    89 
   101 		AddressInfo(const addrinfo* const ai) : ai(ai) {}
    90 		AddressInfo(const addrinfo * const ai, std::shared_ptr<addrinfo> parent) : ai(ai), parent(parent) {
       
    91 		}
       
    92 
       
    93 		const std::string toString() const {
       
    94 			char buffer[INET6_ADDRSTRLEN] = {0};
       
    95 			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
       
    96 			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
       
    97 			else return "unknown address family: " + std::to_string(ai->ai_family);
       
    98 		}
   102 	};
    99 	};
   103 
   100 
   104 	static AddressInfos getAddressInfo(const std::string& host, const std::string& port) {
   101 	static AddressInfos getAddressInfos(const std::string& host, const std::string& port, int socketType = SOCK_STREAM, int protocol = IPPROTO_TCP) {
   105 		struct addrinfo query;
   102 		struct addrinfo query;
   106 		memset(&query, sizeof (query), 0);
   103 		memset(&query, sizeof (query), 0);
   107 		query.ai_family = AF_UNSPEC;
   104 		query.ai_family = AF_UNSPEC;
   108 		query.ai_socktype = SOCK_STREAM;
   105 		query.ai_socktype = socketType;
   109 		query.ai_protocol = IPPROTO_TCP;
   106 		query.ai_protocol = protocol;
   110 		query.ai_flags = AI_ALL;
   107 		query.ai_flags = AI_ALL;
   111 
   108 
   112 		struct addrinfo* addrInfo;
   109 		struct addrinfo* addrInfo;
   113 		check(getaddrinfo(host.c_str(), port.c_str(), &query, &addrInfo), "getaddrinfo");
   110 		check(getaddrinfo(host.c_str(), port.c_str(), &query, &addrInfo), "getaddrinfo");
   114 
   111 
   119 		return addrInfo->ai_addr;
   116 		return addrInfo->ai_addr;
   120 	}
   117 	}
   121 
   118 
   122 	const std::size_t size() const {
   119 	const std::size_t size() const {
   123 		std::size_t size = 0;
   120 		std::size_t size = 0;
   124 		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) size++;
   121 		for (addrinfo* ai = addrInfo.get(); ai; ai = ai->ai_next) size++;
   125 		return size;
   122 		return size;
   126 	}
   123 	}
   127 
   124 
   128 	const addrinfo& operator[](std::size_t index) const {
   125 	const AddressInfo operator[](std::size_t index) const {
   129 		for (addrinfo* ai = addrInfo; ai; index--) {
   126 		for (addrinfo* ai = addrInfo.get(); ai; index--) {
   130 			if (index == 0) return *ai;
   127 			if (index == 0) return AddressInfo(ai, addrInfo);
   131 			else ai = ai->ai_next;
   128 			else ai = ai->ai_next;
   132 		}
   129 		}
   133 		
   130 
   134 		throw std::out_of_range("invalid index for AddressInfo: " + std::to_string(index));
   131 		throw std::out_of_range("invalid index for AddressInfo: " + std::to_string(index));
   135 	}
   132 	}
   136 	
   133 
   137 };
   134 };
       
   135 
       
   136 // TODO: delete getAddress()
   138 
   137 
   139 static in_addr_t getAddress(const std::string& host) {
   138 static in_addr_t getAddress(const std::string& host) {
   140 
       
   141 	{
       
   142 		AddressInfos ai = AddressInfos::getAddressInfo("::0ff2", "smtp");
       
   143 		std::cerr << "AddressInfo size = " << ai.size() << std::endl;
       
   144 		for (size_t i = 0, limit = ai.size(); i < limit; i++) {
       
   145 			std::cerr << "AddressInfo: " << ip2string(&ai[i]) << std::endl;
       
   146 		}
       
   147 	}
       
   148 
       
   149 
       
   150 
       
   151 
       
   152 	struct addrinfo query;
   139 	struct addrinfo query;
   153 	memset(&query, sizeof (query), 0);
   140 	memset(&query, sizeof (query), 0);
   154 	query.ai_family = AF_UNSPEC;
   141 	query.ai_family = AF_UNSPEC;
   155 	query.ai_socktype = SOCK_STREAM;
   142 	query.ai_socktype = SOCK_STREAM;
   156 	query.ai_protocol = IPPROTO_TCP;
   143 	query.ai_protocol = IPPROTO_TCP;
   157 	query.ai_flags = AI_ALL;
   144 	query.ai_flags = AI_ALL;
   158 
   145 
   159 	struct addrinfo* addrInfo;
   146 	struct addrinfo* addrInfo;
   160 	check(getaddrinfo(host.c_str(), "", &query, &addrInfo), "getaddrinfo");
   147 	check(getaddrinfo(host.c_str(), "", &query, &addrInfo), "getaddrinfo");
   161 
   148 
   162 	std::cerr << "found: " << addrInfo << std::endl;
       
   163 	if (addrInfo) {
       
   164 		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
       
   165 			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);
       
   166 			if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) std::cerr << " IPv4=" << ip2string(ai);
       
   167 			else if (sockaddr_in6 * sa = castAddress<sockaddr_in6>(ai, AF_INET6)) std::cerr << " IPv6=" << ip2string(ai);
       
   168 			std::cerr << std::endl;
       
   169 		}
       
   170 	}
       
   171 
       
   172 	if (addrInfo) {
   149 	if (addrInfo) {
   173 		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
   150 		for (addrinfo* ai = addrInfo; ai; ai = ai->ai_next) {
   174 			if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) {
   151 			if (sockaddr_in * sa = castAddress<sockaddr_in>(ai, AF_INET)) {
   175 				in_addr_t address = sa->sin_addr.s_addr;
   152 				in_addr_t address = sa->sin_addr.s_addr;
   176 				freeaddrinfo(addrInfo);
   153 				freeaddrinfo(addrInfo);
   186 	return inet_addr(host.c_str());
   163 	return inet_addr(host.c_str());
   187 }
   164 }
   188 
   165 
   189 class UDPClientSocket : public Socket {
   166 class UDPClientSocket : public Socket {
   190 private:
   167 private:
   191 	struct sockaddr_in remoteAddress;
   168 	AddressInfos remoteAddresses;
   192 	int protocol = IPPROTO_UDP;
   169 
   193 	int type = SOCK_DGRAM;
   170 	UDPClientSocket(AddressInfos remoteAddresses) : remoteAddresses(remoteAddresses) {
       
   171 	}
       
   172 
   194 public:
   173 public:
   195 
   174 
   196 	static std::shared_ptr<Socket> open(const SocketOptions& options) {
   175 	static std::shared_ptr<Socket> open(const SocketOptions& options) {
   197 		std::shared_ptr<UDPClientSocket> s = std::make_shared<UDPClientSocket>();
       
   198 		memset((char *) &s->remoteAddress, 0, sizeof (s->remoteAddress));
       
   199 		s->remoteAddress.sin_family = AF_INET;
       
   200 		s->remoteAddress.sin_addr.s_addr = getAddress(findOption(options, OPTION_HOST, true)); // TODO: use getaddrinfo() instead (because of error -1 = 255.255.255.255)
       
   201 		s->remoteAddress.sin_port = htons(std::stoi(findOption(options, OPTION_PORT, true)));
       
   202 
       
   203 		auto protocol = findOption(options, OPTION_PROTOCOL);
   176 		auto protocol = findOption(options, OPTION_PROTOCOL);
   204 		if (protocol == PROTOCOL_SCTP) {
   177 
   205 			s->protocol = IPPROTO_SCTP;
   178 		AddressInfos remoteAddresses = AddressInfos::getAddressInfos(
   206 			s->type = SOCK_SEQPACKET;
   179 				findOption(options, OPTION_HOST, true),
   207 		}
   180 				findOption(options, OPTION_PORT, true),
   208 
   181 				protocol == PROTOCOL_SCTP ? SOCK_SEQPACKET : SOCK_DGRAM,
   209 		return s;
   182 				protocol == PROTOCOL_SCTP ? IPPROTO_SCTP : IPPROTO_UDP);
       
   183 
       
   184 		return std::shared_ptr<UDPClientSocket>(new UDPClientSocket(remoteAddresses));
   210 	}
   185 	}
   211 
   186 
   212 	void send(const std::string& message) override {
   187 	void send(const std::string& message) override {
   213 		FD s(::socket(AF_INET, type, protocol));
   188 		auto ai = remoteAddresses[0].ai;
   214 		sendto(s.getFD(), message.c_str(), message.size(), 0, (sockaddr*) & remoteAddress, sizeof (remoteAddress));
   189 		FD s(::socket(AF_INET, ai->ai_socktype, ai->ai_protocol));
       
   190 		sendto(s.getFD(), message.c_str(), message.size(), 0, ai->ai_addr, ai->ai_addrlen);
   215 	}
   191 	}
   216 
   192 
   217 	const std::string receive() override {
   193 	const std::string receive() override {
   218 		// TODO: TCP receive()
   194 		// TODO: TCP receive()
   219 		return "TODO: receive() a message";
   195 		return "TODO: receive() a message";