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 if (servC[0] != '\0') {
96 this->port = static_cast<uint16_t>(std::stoul(servC));
97 }
98
99 this->host = hostC;
100 this->canonName = hostC;
101 } else {
102 core::socket::State state = core::socket::STATE_OK;
103 switch (aiErrCode) {
104 case EAI_AGAIN:
105 case EAI_MEMORY:
106 state = core::socket::STATE_ERROR;
107 break;
108 default:
109 state = core::socket::STATE_FATAL;
110 break;
111 }
112
113 throw core::socket::SocketAddress::BadSocketAddress(
114 state, aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode), aiErrCode == EAI_SYSTEM ? errno : aiErrCode);
115 }
116 }
117
118 void SocketAddress::init(const Hints& hints) {
119 addrinfo addrInfoHints{};
120
121 addrInfoHints.ai_family = Super::getAddressFamily();
122 addrInfoHints.ai_flags = hints.aiFlags | AI_ADDRCONFIG |
123 AI_CANONNAME /*| AI_CANONIDN*/ /*| AI_ALL*/; // AI_CANONIDN produces a still reachable memory leak
124 addrInfoHints.ai_socktype = hints.aiSockType;
125 addrInfoHints.ai_protocol = hints.aiProtocol;
126
127 const int aiErrCode = socketAddrInfo->resolve(host, std::to_string(port), addrInfoHints);
128 if (aiErrCode == 0) {
129 sockAddr = socketAddrInfo->getSockAddr();
131 } else {
132 core::socket::State state = core::socket::STATE_OK;
133
134 switch (aiErrCode) {
135 case EAI_AGAIN:
136 case EAI_MEMORY:
137 state = core::socket::STATE_ERROR;
138 break;
139 default:
140 state = core::socket::STATE_FATAL;
141 break;
142 }
143
144 throw core::socket::SocketAddress::BadSocketAddress(state,
145 host + ":" + std::to_string(port) + " - " +
146 (aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode)),
147 (aiErrCode == EAI_SYSTEM ? errno : aiErrCode));
148 }
149 }
150
151 SocketAddress& SocketAddress::setHost(const std::string& ipOrHostname) {
152 this->host = ipOrHostname;
153
154 return *this;
155 }
156
157 std::string SocketAddress::getHost() const {
158 return host;
159 }
160
161 SocketAddress& SocketAddress::setPort(uint16_t port) {
162 this->port = port;
163
164 return *this;
165 }
166
167 uint16_t SocketAddress::getPort() const {
168 return port;
169 }
170
171 std::string SocketAddress::getCanonName() const {
172 return canonName;
173 }
174
175 std::string SocketAddress::toString(bool expanded) const {
176 return std::string(host).append(expanded ? std::string(":").append(std::to_string(port)).append(" (").append(canonName).append(")")
177 : "");
178 }
179
180 std::string SocketAddress::getEndpoint(const std::string_view& format) const {
181 return std::vformat(format, std::make_format_args((port)));
182 }
183
184 bool SocketAddress::useNext() {
185 const bool useNext = socketAddrInfo->useNext();
186
187 if (useNext) {
188 sockAddr = socketAddrInfo->getSockAddr();
189 }
190
191 return useNext;
192 }
193
194} // namespace net::in6
195
196template 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)