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
53#endif /* DOXYGEN_SHOULD_SKIP_THIS */
54
55namespace net::in6 {
56
57 SocketAddress::SocketAddress()
58 : Super(AF_INET6)
60 }
61
62 SocketAddress::SocketAddress(const std::string& ipOrHostname)
63 : SocketAddress() {
64 setHost(ipOrHostname);
65 }
66
67 SocketAddress::SocketAddress(uint16_t port)
68 : SocketAddress() {
69 setPort(port);
70 }
71
72 SocketAddress::SocketAddress(const std::string& ipOrHostname, uint16_t port)
73 : SocketAddress() {
74 setHost(ipOrHostname);
75 setPort(port);
76 }
77
78 SocketAddress::SocketAddress(const SockAddr& sockAddr, SockLen sockAddrLen, bool numeric)
81 char hostC[NI_MAXHOST];
82 char servC[NI_MAXSERV];
83 std::memset(hostC, 0, NI_MAXHOST);
84 std::memset(servC, 0, NI_MAXSERV);
85
86 const int aiErrCode = core::system::getnameinfo(reinterpret_cast<const sockaddr*>(&sockAddr),
87 sizeof(sockAddr),
88 hostC,
89 NI_MAXHOST,
90 servC,
91 NI_MAXSERV,
92 NI_NUMERICSERV | (numeric ? NI_NUMERICHOST : NI_NAMEREQD));
93 if (aiErrCode == 0) {
94 if (servC[0] != '\0') {
95 this->port = static_cast<uint16_t>(std::stoul(servC));
96 }
97
98 this->host = hostC;
99 this->canonName = hostC;
100 } else {
101 core::socket::State state = core::socket::STATE_OK;
102 switch (aiErrCode) {
103 case EAI_AGAIN:
104 case EAI_MEMORY:
105 state = core::socket::STATE_ERROR;
106 break;
107 default:
108 state = core::socket::STATE_FATAL;
109 break;
110 }
111
112 throw core::socket::SocketAddress::BadSocketAddress(
113 state, aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode), aiErrCode == EAI_SYSTEM ? errno : aiErrCode);
114 }
115 }
116
117 void SocketAddress::init(const Hints& hints) {
118 addrinfo addrInfoHints{};
119
120 addrInfoHints.ai_family = Super::getAddressFamily();
121 addrInfoHints.ai_flags = hints.aiFlags | AI_ADDRCONFIG |
122 AI_CANONNAME /*| AI_CANONIDN*/ /*| AI_ALL*/; // AI_CANONIDN produces a still reachable memory leak
123 addrInfoHints.ai_socktype = hints.aiSockType;
124 addrInfoHints.ai_protocol = hints.aiProtocol;
125
126 const int aiErrCode = socketAddrInfo->resolve(host, std::to_string(port), addrInfoHints);
127 if (aiErrCode == 0) {
128 sockAddr = socketAddrInfo->getSockAddr();
129 canonName = socketAddrInfo->getCanonName();
130 } else {
131 core::socket::State state = core::socket::STATE_OK;
132
133 switch (aiErrCode) {
134 case EAI_AGAIN:
135 case EAI_MEMORY:
136 state = core::socket::STATE_ERROR;
137 break;
138 default:
139 state = core::socket::STATE_FATAL;
140 break;
141 }
142
143 throw core::socket::SocketAddress::BadSocketAddress(state,
144 host + ":" + std::to_string(port) + " - " +
145 (aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode)),
146 (aiErrCode == EAI_SYSTEM ? errno : aiErrCode));
147 }
148 }
149
150 SocketAddress& SocketAddress::setHost(const std::string& ipOrHostname) {
151 this->host = ipOrHostname;
152
153 return *this;
154 }
155
156 std::string SocketAddress::getHost() const {
157 return host;
158 }
159
160 SocketAddress& SocketAddress::setPort(uint16_t port) {
161 this->port = port;
162
163 return *this;
164 }
165
166 uint16_t SocketAddress::getPort() const {
167 return port;
168 }
169
170 std::string SocketAddress::getCanonName() const {
171 return canonName;
172 }
173
174 std::string SocketAddress::toString(bool expanded) const {
175 return std::string(host).append(expanded ? std::string(":").append(std::to_string(port)).append(" (").append(canonName).append(")")
176 : "");
177 }
178
179 bool SocketAddress::useNext() {
180 const bool useNext = socketAddrInfo->useNext();
181
182 if (useNext) {
183 sockAddr = socketAddrInfo->getSockAddr();
184 }
185
186 return useNext;
187 }
188
189} // namespace net::in6
190
191template class net::SocketAddress<sockaddr_in6>;
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 getCanonName() const
SocketAddress(const std::string &ipOrHostname)
std::string getHost() const
std::string toString(bool expanded=true) const override
SocketAddress(const std::string &ipOrHostname, uint16_t port)
SocketAddress(const SockAddr &sockAddr, SockLen sockAddrLen, bool numeric=true)