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
27using Poco::RefCountedObject;
28using Poco::NumberParser;
29using Poco::UInt16;
30using Poco::InvalidArgumentException;
31using Poco::Net::Impl::SocketAddressImpl;
32using Poco::Net::Impl::IPv4SocketAddressImpl;
33#ifdef POCO_HAVE_IPv6
34using Poco::Net::Impl::IPv6SocketAddressImpl;
35#endif
36#ifdef POCO_OS_FAMILY_UNIX
37using Poco::Net::Impl::LocalSocketAddressImpl;
38#endif
39
40
41namespace Poco {
42namespace Net {
43
44
45struct 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
62const SocketAddress::Family SocketAddress::IPv4;
63#if defined(POCO_HAVE_IPv6)
64const SocketAddress::Family SocketAddress::IPv6;
65#endif
66#if defined(POCO_OS_FAMILY_UNIX)
67const SocketAddress::Family SocketAddress::UNIX_LOCAL;
68#endif
69#endif
70
71
72SocketAddress::SocketAddress()
73{
74 newIPv4();
75}
76
77
78SocketAddress::SocketAddress(Family fam)
79{
80 init(IPAddress(fam), 0);
81}
82
83
84SocketAddress::SocketAddress(const IPAddress& hostAddress, Poco::UInt16 portNumber)
85{
86 init(hostAddress, portNumber);
87}
88
89
90SocketAddress::SocketAddress(Poco::UInt16 portNumber)
91{
92 init(IPAddress(), portNumber);
93}
94
95
96SocketAddress::SocketAddress(Family fam, Poco::UInt16 portNumber)
97{
98 init(IPAddress(fam), portNumber);
99}
100
101
102SocketAddress::SocketAddress(const std::string& hostAddress, Poco::UInt16 portNumber)
103{
104 init(hostAddress, portNumber);
105}
106
107
108SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber)
109{
110 init(fam, hostAddress, portNumber);
111}
112
113
114SocketAddress::SocketAddress(const std::string& hostAddress, const std::string& portNumber)
115{
116 init(hostAddress, resolveService(portNumber));
117}
118
119
120SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, const std::string& portNumber)
121{
122 init(fam, hostAddress, resolveService(portNumber));
123}
124
125
126SocketAddress::SocketAddress(Family fam, const std::string& addr)
127{
128 init(fam, addr);
129}
130
131
132SocketAddress::SocketAddress(const std::string& hostAndPort)
133{
134 init(hostAndPort);
135}
136
137
138SocketAddress::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()));
149#endif
150}
151
152
153SocketAddress::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));
164#endif
165 else throw Poco::InvalidArgumentException("Invalid address length or family passed to SocketAddress()");
166}
167
168
169SocketAddress::~SocketAddress()
170{
171 destruct();
172}
173
174
175bool 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
188SocketAddress& 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()));
202#endif
203 }
204 return *this;
205}
206
207
208IPAddress SocketAddress::host() const
209{
210 return pImpl()->host();
211}
212
213
214Poco::UInt16 SocketAddress::port() const
215{
216 return ntohs(pImpl()->port());
217}
218
219
220poco_socklen_t SocketAddress::length() const
221{
222 return pImpl()->length();
223}
224
225
226const struct sockaddr* SocketAddress::addr() const
227{
228 return pImpl()->addr();
229}
230
231
232int SocketAddress::af() const
233{
234 return pImpl()->af();
235}
236
237
238SocketAddress::Family SocketAddress::family() const
239{
240 return static_cast<Family>(pImpl()->family());
241}
242
243
244std::string SocketAddress::toString() const
245{
246 return pImpl()->toString();
247}
248
249
250void 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
262void 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
286void 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
315void 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
352void 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 == '/')
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
389Poco::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
411void SocketAddress::destruct()
412{
413 pImpl()->~SocketAddressImpl();
414}
415
416
417SocketAddress::Ptr SocketAddress::pImpl() const
418{
419 return reinterpret_cast<Ptr>(const_cast<char *>(_memory.buffer));
420}
421
422
423void SocketAddress::newIPv4()
424{
425 new (storage()) Poco::Net::Impl::IPv4SocketAddressImpl;
426}
427
428
429void SocketAddress::newIPv4(const sockaddr_in* sockAddr)
430{
431 new (storage()) Poco::Net::Impl::IPv4SocketAddressImpl(sockAddr);
432}
433
434
435void 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)
442void SocketAddress::newIPv6(const sockaddr_in6* sockAddr)
443{
444 new (storage()) Poco::Net::Impl::IPv6SocketAddressImpl(sockAddr);
445}
446
447
448void 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)
456void SocketAddress::newLocal(const sockaddr_un* sockAddr)
457{
458 new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(sockAddr);
459}
460
461
462void SocketAddress::newLocal(const std::string& path)
463{
464 new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(path.c_str());
465}
466#endif // POCO_OS_FAMILY_UNIX
467
468
469char* SocketAddress::storage()
470{
471 return _memory.buffer;
472}
473
474
475bool 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
486bool SocketAddress::operator != (const SocketAddress& socketAddress) const
487{
488 return !(operator == (socketAddress));
489}
490
491
492} } // namespace Poco::Net
493
494
495Poco::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
503Poco::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
514std::ostream& operator << (std::ostream& ostr, const Poco::Net::SocketAddress& address)
515{
516 ostr << address.toString();
517 return ostr;
518}
519