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"; |