SNode.C
Loading...
Searching...
No Matches
SocketAddress.cpp
Go to the documentation of this file.
1/*
2 * SNode.C - A Slim Toolkit for Network Communication
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2020, 2021, 2022, 2023, 2024, 2025
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * MIT License
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42#include "net/in6/SocketAddress.h"
43
44#include "core/socket/State.h"
45#include "net/SocketAddress.hpp"
46#include "net/in6/SocketAddrInfo.h"
47
48#ifndef DOXYGEN_SHOULD_SKIP_THIS
49
50#include <cerrno>
51#include <cstring>
52#include <format>
53
54#endif /* DOXYGEN_SHOULD_SKIP_THIS */
55
56namespace net::in6 {
57
58 SocketAddress::SocketAddress()
59 : Super(AF_INET6)
60 , socketAddrInfo(std::make_shared<SocketAddrInfo>()) {
61 }
62
63 SocketAddress::SocketAddress(const std::string& ipOrHostname)
64 : SocketAddress() {
65 setHost(ipOrHostname);
66 }
67
68 SocketAddress::SocketAddress(uint16_t port)
69 : SocketAddress() {
70 setPort(port);
71 }
72
73 SocketAddress::SocketAddress(const std::string& ipOrHostname, uint16_t port)
74 : SocketAddress() {
75 setHost(ipOrHostname);
76 setPort(port);
77 }
78
79 SocketAddress::SocketAddress(const SockAddr& sockAddr, SockLen sockAddrLen, bool numeric)
80 : net::SocketAddress<SockAddr>(sockAddr, sockAddrLen)
81 , socketAddrInfo(std::make_shared<SocketAddrInfo>()) {
82 char hostC[NI_MAXHOST];
83 char servC[NI_MAXSERV];
84 std::memset(hostC, 0, NI_MAXHOST);
85 std::memset(servC, 0, NI_MAXSERV);
86
87 const int aiErrCode = core::system::getnameinfo(reinterpret_cast<const sockaddr*>(&sockAddr),
88 sizeof(sockAddr),
89 hostC,
90 NI_MAXHOST,
91 servC,
92 NI_MAXSERV,
93 NI_NUMERICSERV | (numeric ? NI_NUMERICHOST : NI_NAMEREQD));
94 if (aiErrCode == 0) {
95 this->host = hostC;
96 this->port = (servC[0] != '\0') ? static_cast<uint16_t>(std::stoul(servC)) : 0;
97 } else {
98 core::socket::State state = core::socket::STATE_OK;
99 switch (aiErrCode) {
100 case EAI_AGAIN:
101 case EAI_MEMORY:
102 state = core::socket::STATE_ERROR;
103 break;
104 default:
105 state = core::socket::STATE_FATAL;
106 break;
107 }
108
109 throw core::socket::SocketAddress::BadSocketAddress(
110 state, aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode), aiErrCode == EAI_SYSTEM ? errno : aiErrCode);
111 }
112 }
113
114 void SocketAddress::init(const Hints& hints) {
115 addrinfo addrInfoHints{};
116
117 addrInfoHints.ai_family = Super::getAddressFamily();
118 addrInfoHints.ai_flags = hints.aiFlags | AI_ADDRCONFIG |
119 AI_CANONNAME /*| AI_CANONIDN*/ /*| AI_ALL*/; // AI_CANONIDN produces a still reachable memory leak
120 addrInfoHints.ai_socktype = hints.aiSockType;
121 addrInfoHints.ai_protocol = hints.aiProtocol;
122
123 const int aiErrCode = socketAddrInfo->resolve(host, std::to_string(port), addrInfoHints);
124 if (aiErrCode == 0) {
125 sockAddr = socketAddrInfo->getSockAddr();
127 } else {
128 core::socket::State state = core::socket::STATE_OK;
129
130 switch (aiErrCode) {
131 case EAI_AGAIN:
132 case EAI_MEMORY:
133 state = core::socket::STATE_ERROR;
134 break;
135 default:
136 state = core::socket::STATE_FATAL;
137 break;
138 }
139
140 throw core::socket::SocketAddress::BadSocketAddress(state,
141 host + ":" + std::to_string(port) + ": " +
142 (aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode)),
143 (aiErrCode == EAI_SYSTEM ? errno : aiErrCode));
144 }
145 }
146
147 SocketAddress& SocketAddress::setHost(const std::string& ipOrHostname) {
148 this->host = ipOrHostname;
149
150 return *this;
151 }
152
153 std::string SocketAddress::getHost() const {
154 return host;
155 }
156
157 SocketAddress& SocketAddress::setPort(uint16_t port) {
158 this->port = port;
159
160 return *this;
161 }
162
163 uint16_t SocketAddress::getPort() const {
164 return port;
165 }
166
167 std::string SocketAddress::getCanonName() const {
168 return canonName;
169 }
170
171 std::string SocketAddress::toString(bool expanded) const {
172 return std::string(host).append(std::string(":")
173 .append(std::to_string(port))
174 .append(expanded && !canonName.empty() ? std::string(" (").append(canonName).append(")") : ""));
175 }
176
177 std::string SocketAddress::getEndpoint(const std::string_view& format) const {
178 return std::vformat(format, std::make_format_args((port)));
179 }
180
181 bool SocketAddress::useNext() {
182 const bool useNext = socketAddrInfo->useNext();
183
184 if (useNext) {
185 sockAddr = socketAddrInfo->getSockAddr();
186 }
187
188 return useNext;
189 }
190
191} // namespace net::in6
192
193template class net::SocketAddress<sockaddr_in6>;
SocketAddress(const SockAddr &sockAddr, SockLen sockAddrLen)
SocketAddress(sa_family_t af, SockLen sockAddrLen=sizeof(SockAddr))
sa_family_t getAddressFamily() const
SocketAddress(uint16_t port)
SocketAddress & setHost(const std::string &ipOrHostname)
SocketAddress & setPort(uint16_t port)
void init(const Hints &hints={.aiFlags=0,.aiSockType=0,.aiProtocol=0})
std::string getEndpoint(const std::string_view &format={}) const override
std::string getCanonName() const
SocketAddress(const std::string &ipOrHostname)
std::string getHost() const
std::string toString(bool expanded=true) const override
std::shared_ptr< SocketAddrInfo > socketAddrInfo
SocketAddress(const std::string &ipOrHostname, uint16_t port)
SocketAddress(const SockAddr &sockAddr, SockLen sockAddrLen, bool numeric=true)