1 | // |
2 | // SocketAddress.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: NetCore |
6 | // Module: SocketAddress |
7 | // |
8 | // Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/SocketAddress.h" |
16 | #include "Poco/Net/IPAddress.h" |
17 | #include "Poco/Net/NetException.h" |
18 | #include "Poco/Net/DNS.h" |
19 | #include "Poco/RefCountedObject.h" |
20 | #include "Poco/NumberParser.h" |
21 | #include "Poco/BinaryReader.h" |
22 | #include "Poco/BinaryWriter.h" |
23 | #include <algorithm> |
24 | #include <cstring> |
25 | |
26 | |
27 | using Poco::RefCountedObject; |
28 | using Poco::NumberParser; |
29 | using Poco::UInt16; |
30 | using Poco::InvalidArgumentException; |
31 | using Poco::Net::Impl::SocketAddressImpl; |
32 | using Poco::Net::Impl::IPv4SocketAddressImpl; |
33 | #ifdef POCO_HAVE_IPv6 |
34 | using Poco::Net::Impl::IPv6SocketAddressImpl; |
35 | #endif |
36 | #ifdef POCO_OS_FAMILY_UNIX |
37 | using Poco::Net::Impl::LocalSocketAddressImpl; |
38 | #endif |
39 | |
40 | |
41 | namespace Poco { |
42 | namespace Net { |
43 | |
44 | |
45 | struct AFLT |
46 | { |
47 | bool operator () (const IPAddress& a1, const IPAddress& a2) |
48 | { |
49 | return a1.af() < a2.af(); |
50 | } |
51 | }; |
52 | |
53 | |
54 | // |
55 | // SocketAddress |
56 | // |
57 | |
58 | |
59 | #if !defined(_MSC_VER) || defined(__STDC__) |
60 | // Go home MSVC, you're drunk... |
61 | // See http://stackoverflow.com/questions/5899857/multiple-definition-error-for-static-const-class-members |
62 | const SocketAddress::Family SocketAddress::IPv4; |
63 | #if defined(POCO_HAVE_IPv6) |
64 | const SocketAddress::Family SocketAddress::IPv6; |
65 | #endif |
66 | #if defined(POCO_OS_FAMILY_UNIX) |
67 | const SocketAddress::Family SocketAddress::UNIX_LOCAL; |
68 | #endif |
69 | #endif |
70 | |
71 | |
72 | SocketAddress::SocketAddress() |
73 | { |
74 | newIPv4(); |
75 | } |
76 | |
77 | |
78 | SocketAddress::SocketAddress(Family fam) |
79 | { |
80 | init(IPAddress(fam), 0); |
81 | } |
82 | |
83 | |
84 | SocketAddress::SocketAddress(const IPAddress& hostAddress, Poco::UInt16 portNumber) |
85 | { |
86 | init(hostAddress, portNumber); |
87 | } |
88 | |
89 | |
90 | SocketAddress::SocketAddress(Poco::UInt16 portNumber) |
91 | { |
92 | init(IPAddress(), portNumber); |
93 | } |
94 | |
95 | |
96 | SocketAddress::SocketAddress(Family fam, Poco::UInt16 portNumber) |
97 | { |
98 | init(IPAddress(fam), portNumber); |
99 | } |
100 | |
101 | |
102 | SocketAddress::SocketAddress(const std::string& hostAddress, Poco::UInt16 portNumber) |
103 | { |
104 | init(hostAddress, portNumber); |
105 | } |
106 | |
107 | |
108 | SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber) |
109 | { |
110 | init(fam, hostAddress, portNumber); |
111 | } |
112 | |
113 | |
114 | SocketAddress::SocketAddress(const std::string& hostAddress, const std::string& portNumber) |
115 | { |
116 | init(hostAddress, resolveService(portNumber)); |
117 | } |
118 | |
119 | |
120 | SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, const std::string& portNumber) |
121 | { |
122 | init(fam, hostAddress, resolveService(portNumber)); |
123 | } |
124 | |
125 | |
126 | SocketAddress::SocketAddress(Family fam, const std::string& addr) |
127 | { |
128 | init(fam, addr); |
129 | } |
130 | |
131 | |
132 | SocketAddress::SocketAddress(const std::string& hostAndPort) |
133 | { |
134 | init(hostAndPort); |
135 | } |
136 | |
137 | |
138 | SocketAddress::SocketAddress(const SocketAddress& socketAddress) |
139 | { |
140 | if (socketAddress.family() == IPv4) |
141 | newIPv4(reinterpret_cast<const sockaddr_in*>(socketAddress.addr())); |
142 | #if defined(POCO_HAVE_IPv6) |
143 | else if (socketAddress.family() == IPv6) |
144 | newIPv6(reinterpret_cast<const sockaddr_in6*>(socketAddress.addr())); |
145 | #endif |
146 | #if defined(POCO_OS_FAMILY_UNIX) |
147 | else if (socketAddress.family() == UNIX_LOCAL) |
148 | newLocal(reinterpret_cast<const sockaddr_un*>(socketAddress.addr()), socketAddress.length()); |
149 | #endif |
150 | } |
151 | |
152 | |
153 | SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length) |
154 | { |
155 | if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET) |
156 | newIPv4(reinterpret_cast<const struct sockaddr_in*>(sockAddr)); |
157 | #if defined(POCO_HAVE_IPv6) |
158 | else if (length == sizeof(struct sockaddr_in6) && sockAddr->sa_family == AF_INET6) |
159 | newIPv6(reinterpret_cast<const struct sockaddr_in6*>(sockAddr)); |
160 | #endif |
161 | #if defined(POCO_OS_FAMILY_UNIX) |
162 | else if (length > 0 && length <= sizeof(struct sockaddr_un) && sockAddr->sa_family == AF_UNIX) |
163 | newLocal(reinterpret_cast<const sockaddr_un*>(sockAddr), length); |
164 | #endif |
165 | else throw Poco::InvalidArgumentException("Invalid address length or family passed to SocketAddress()" ); |
166 | } |
167 | |
168 | |
169 | SocketAddress::~SocketAddress() |
170 | { |
171 | destruct(); |
172 | } |
173 | |
174 | |
175 | bool SocketAddress::operator < (const SocketAddress& socketAddress) const |
176 | { |
177 | if (family() < socketAddress.family()) return true; |
178 | if (family() > socketAddress.family()) return false; |
179 | #if defined(POCO_OS_FAMILY_UNIX) |
180 | if (family() == UNIX_LOCAL) return toString() < socketAddress.toString(); |
181 | #endif |
182 | if (host() < socketAddress.host()) return true; |
183 | if (host() > socketAddress.host()) return false; |
184 | return (port() < socketAddress.port()); |
185 | } |
186 | |
187 | |
188 | SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress) |
189 | { |
190 | if (&socketAddress != this) |
191 | { |
192 | destruct(); |
193 | if (socketAddress.family() == IPv4) |
194 | newIPv4(reinterpret_cast<const sockaddr_in*>(socketAddress.addr())); |
195 | #if defined(POCO_HAVE_IPv6) |
196 | else if (socketAddress.family() == IPv6) |
197 | newIPv6(reinterpret_cast<const sockaddr_in6*>(socketAddress.addr())); |
198 | #endif |
199 | #if defined(POCO_OS_FAMILY_UNIX) |
200 | else if (socketAddress.family() == UNIX_LOCAL) |
201 | newLocal(reinterpret_cast<const sockaddr_un*>(socketAddress.addr()), socketAddress.length()); |
202 | #endif |
203 | } |
204 | return *this; |
205 | } |
206 | |
207 | |
208 | IPAddress SocketAddress::host() const |
209 | { |
210 | return pImpl()->host(); |
211 | } |
212 | |
213 | |
214 | Poco::UInt16 SocketAddress::port() const |
215 | { |
216 | return ntohs(pImpl()->port()); |
217 | } |
218 | |
219 | |
220 | poco_socklen_t SocketAddress::length() const |
221 | { |
222 | return pImpl()->length(); |
223 | } |
224 | |
225 | |
226 | const struct sockaddr* SocketAddress::addr() const |
227 | { |
228 | return pImpl()->addr(); |
229 | } |
230 | |
231 | |
232 | int SocketAddress::af() const |
233 | { |
234 | return pImpl()->af(); |
235 | } |
236 | |
237 | |
238 | SocketAddress::Family SocketAddress::family() const |
239 | { |
240 | return static_cast<Family>(pImpl()->family()); |
241 | } |
242 | |
243 | |
244 | std::string SocketAddress::toString() const |
245 | { |
246 | return pImpl()->toString(); |
247 | } |
248 | |
249 | |
250 | void SocketAddress::init(const IPAddress& hostAddress, Poco::UInt16 portNumber) |
251 | { |
252 | if (hostAddress.family() == IPAddress::IPv4) |
253 | newIPv4(hostAddress, portNumber); |
254 | #if defined(POCO_HAVE_IPv6) |
255 | else if (hostAddress.family() == IPAddress::IPv6) |
256 | newIPv6(hostAddress, portNumber); |
257 | #endif |
258 | else throw Poco::NotImplementedException("unsupported IP address family" ); |
259 | } |
260 | |
261 | |
262 | void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber) |
263 | { |
264 | IPAddress ip; |
265 | if (IPAddress::tryParse(hostAddress, ip)) |
266 | { |
267 | init(ip, portNumber); |
268 | } |
269 | else |
270 | { |
271 | HostEntry he = DNS::hostByName(hostAddress); |
272 | HostEntry::AddressList addresses = he.addresses(); |
273 | if (addresses.size() > 0) |
274 | { |
275 | #if defined(POCO_HAVE_IPv6) && defined(POCO_SOCKETADDRESS_PREFER_IPv4) |
276 | // if we get both IPv4 and IPv6 addresses, prefer IPv4 |
277 | std::stable_sort(addresses.begin(), addresses.end(), AFLT()); |
278 | #endif |
279 | init(addresses[0], portNumber); |
280 | } |
281 | else throw HostNotFoundException("No address found for host" , hostAddress); |
282 | } |
283 | } |
284 | |
285 | |
286 | void SocketAddress::init(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber) |
287 | { |
288 | IPAddress ip; |
289 | if (IPAddress::tryParse(hostAddress, ip)) |
290 | { |
291 | if (ip.family() != fam) throw AddressFamilyMismatchException(hostAddress); |
292 | init(ip, portNumber); |
293 | } |
294 | else |
295 | { |
296 | HostEntry he = DNS::hostByName(hostAddress); |
297 | HostEntry::AddressList addresses = he.addresses(); |
298 | if (addresses.size() > 0) |
299 | { |
300 | for (HostEntry::AddressList::const_iterator it = addresses.begin(); it != addresses.end(); ++it) |
301 | { |
302 | if (it->family() == fam) |
303 | { |
304 | init(*it, portNumber); |
305 | return; |
306 | } |
307 | } |
308 | throw AddressFamilyMismatchException(hostAddress); |
309 | } |
310 | else throw HostNotFoundException("No address found for host" , hostAddress); |
311 | } |
312 | } |
313 | |
314 | |
315 | void SocketAddress::init(Family fam, const std::string& address) |
316 | { |
317 | #if defined(POCO_OS_FAMILY_UNIX) |
318 | if (fam == UNIX_LOCAL) |
319 | { |
320 | newLocal(address); |
321 | } |
322 | else |
323 | #endif |
324 | { |
325 | std::string host; |
326 | std::string port; |
327 | std::string::const_iterator it = address.begin(); |
328 | std::string::const_iterator end = address.end(); |
329 | |
330 | if (*it == '[') |
331 | { |
332 | ++it; |
333 | while (it != end && *it != ']') host += *it++; |
334 | if (it == end) throw InvalidArgumentException("Malformed IPv6 address" ); |
335 | ++it; |
336 | } |
337 | else |
338 | { |
339 | while (it != end && *it != ':') host += *it++; |
340 | } |
341 | if (it != end && *it == ':') |
342 | { |
343 | ++it; |
344 | while (it != end) port += *it++; |
345 | } |
346 | else throw InvalidArgumentException("Missing port number" ); |
347 | init(fam, host, resolveService(port)); |
348 | } |
349 | } |
350 | |
351 | |
352 | void SocketAddress::init(const std::string& hostAndPort) |
353 | { |
354 | poco_assert (!hostAndPort.empty()); |
355 | |
356 | std::string host; |
357 | std::string port; |
358 | std::string::const_iterator it = hostAndPort.begin(); |
359 | std::string::const_iterator end = hostAndPort.end(); |
360 | |
361 | #if defined(POCO_OS_FAMILY_UNIX) |
362 | if (*it == '/' || *it == '\0') |
363 | { |
364 | newLocal(hostAndPort); |
365 | return; |
366 | } |
367 | #endif |
368 | if (*it == '[') |
369 | { |
370 | ++it; |
371 | while (it != end && *it != ']') host += *it++; |
372 | if (it == end) throw InvalidArgumentException("Malformed IPv6 address" ); |
373 | ++it; |
374 | } |
375 | else |
376 | { |
377 | while (it != end && *it != ':') host += *it++; |
378 | } |
379 | if (it != end && *it == ':') |
380 | { |
381 | ++it; |
382 | while (it != end) port += *it++; |
383 | } |
384 | else throw InvalidArgumentException("Missing port number" ); |
385 | init(host, resolveService(port)); |
386 | } |
387 | |
388 | |
389 | Poco::UInt16 SocketAddress::resolveService(const std::string& service) |
390 | { |
391 | unsigned port; |
392 | if (NumberParser::tryParseUnsigned(service, port) && port <= 0xFFFF) |
393 | { |
394 | return (UInt16) port; |
395 | } |
396 | else |
397 | { |
398 | #if defined(POCO_VXWORKS) |
399 | throw ServiceNotFoundException(service); |
400 | #else |
401 | struct servent* se = getservbyname(service.c_str(), NULL); |
402 | if (se) |
403 | return ntohs(se->s_port); |
404 | else |
405 | throw ServiceNotFoundException(service); |
406 | #endif |
407 | } |
408 | } |
409 | |
410 | |
411 | void SocketAddress::destruct() |
412 | { |
413 | pImpl()->~SocketAddressImpl(); |
414 | } |
415 | |
416 | |
417 | SocketAddress::Ptr SocketAddress::pImpl() const |
418 | { |
419 | return reinterpret_cast<Ptr>(const_cast<char *>(_memory.buffer)); |
420 | } |
421 | |
422 | |
423 | void SocketAddress::newIPv4() |
424 | { |
425 | new (storage()) Poco::Net::Impl::IPv4SocketAddressImpl; |
426 | } |
427 | |
428 | |
429 | void SocketAddress::newIPv4(const sockaddr_in* sockAddr) |
430 | { |
431 | new (storage()) Poco::Net::Impl::IPv4SocketAddressImpl(sockAddr); |
432 | } |
433 | |
434 | |
435 | void SocketAddress::newIPv4(const IPAddress& hostAddress, Poco::UInt16 portNumber) |
436 | { |
437 | new (storage()) Poco::Net::Impl::IPv4SocketAddressImpl(hostAddress.addr(), htons(portNumber)); |
438 | } |
439 | |
440 | |
441 | #if defined(POCO_HAVE_IPv6) |
442 | void SocketAddress::newIPv6(const sockaddr_in6* sockAddr) |
443 | { |
444 | new (storage()) Poco::Net::Impl::IPv6SocketAddressImpl(sockAddr); |
445 | } |
446 | |
447 | |
448 | void SocketAddress::newIPv6(const IPAddress& hostAddress, Poco::UInt16 portNumber) |
449 | { |
450 | new (storage()) Poco::Net::Impl::IPv6SocketAddressImpl(hostAddress.addr(), htons(portNumber), hostAddress.scope()); |
451 | } |
452 | #endif // POCO_HAVE_IPv6 |
453 | |
454 | |
455 | #if defined(POCO_OS_FAMILY_UNIX) |
456 | void SocketAddress::newLocal(const sockaddr_un* sockAddr, poco_socklen_t length) |
457 | { |
458 | new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(sockAddr, length); |
459 | } |
460 | |
461 | |
462 | void SocketAddress::newLocal(const std::string& path) |
463 | { |
464 | new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(path); |
465 | } |
466 | #endif // POCO_OS_FAMILY_UNIX |
467 | |
468 | |
469 | char* SocketAddress::storage() |
470 | { |
471 | return _memory.buffer; |
472 | } |
473 | |
474 | |
475 | bool SocketAddress::operator == (const SocketAddress& socketAddress) const |
476 | { |
477 | #if defined(POCO_OS_FAMILY_UNIX) |
478 | if (family() == UNIX_LOCAL) |
479 | return toString() == socketAddress.toString(); |
480 | else |
481 | #endif |
482 | return host() == socketAddress.host() && port() == socketAddress.port(); |
483 | } |
484 | |
485 | |
486 | bool SocketAddress::operator != (const SocketAddress& socketAddress) const |
487 | { |
488 | return !(operator == (socketAddress)); |
489 | } |
490 | |
491 | |
492 | } } // namespace Poco::Net |
493 | |
494 | |
495 | Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::SocketAddress& value) |
496 | { |
497 | writer << value.host(); |
498 | writer << value.port(); |
499 | return writer; |
500 | } |
501 | |
502 | |
503 | Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::SocketAddress& value) |
504 | { |
505 | Poco::Net::IPAddress host; |
506 | reader >> host; |
507 | Poco::UInt16 port; |
508 | reader >> port; |
509 | value = Poco::Net::SocketAddress(host, port); |
510 | return reader; |
511 | } |
512 | |
513 | |
514 | std::ostream& operator << (std::ostream& ostr, const Poco::Net::SocketAddress& address) |
515 | { |
516 | ostr << address.toString(); |
517 | return ostr; |
518 | } |
519 | |