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#include "net/in6/SocketAddress.h"
21
22#include "core/socket/State.h"
23#include "net/SocketAddress.hpp"
24#include "net/in6/SocketAddrInfo.h"
25
26#ifndef DOXYGEN_SHOULD_SKIP_THIS
27
28#include <cerrno>
29#include <cstring>
30
31#endif /* DOXYGEN_SHOULD_SKIP_THIS */
32
33namespace net::in6 {
34
35 SocketAddress::SocketAddress()
36 : Super(AF_INET6)
38 }
39
40 SocketAddress::SocketAddress(const std::string& ipOrHostname)
41 : SocketAddress() {
42 setHost(ipOrHostname);
43 }
44
45 SocketAddress::SocketAddress(uint16_t port)
46 : SocketAddress() {
47 setPort(port);
48 }
49
50 SocketAddress::SocketAddress(const std::string& ipOrHostname, uint16_t port)
51 : SocketAddress() {
52 setHost(ipOrHostname);
53 setPort(port);
54 }
55
56 SocketAddress::SocketAddress(const SockAddr& sockAddr, SockLen sockAddrLen, bool numeric)
59 char hostC[NI_MAXHOST];
60 char servC[NI_MAXSERV];
61 std::memset(hostC, 0, NI_MAXHOST);
62 std::memset(servC, 0, NI_MAXSERV);
63
64 const int aiErrCode = core::system::getnameinfo(reinterpret_cast<const sockaddr*>(&sockAddr),
65 sizeof(sockAddr),
66 hostC,
67 NI_MAXHOST,
68 servC,
69 NI_MAXSERV,
70 NI_NUMERICSERV | (numeric ? NI_NUMERICHOST : NI_NAMEREQD));
71 if (aiErrCode == 0) {
72 if (servC[0] != '\0') {
73 this->port = static_cast<uint16_t>(std::stoul(servC));
74 }
75
76 this->host = hostC;
77 this->canonName = hostC;
78 } else {
79 core::socket::State state = core::socket::STATE_OK;
80 switch (aiErrCode) {
81 case EAI_AGAIN:
82 case EAI_MEMORY:
83 state = core::socket::STATE_ERROR;
84 break;
85 default:
86 state = core::socket::STATE_FATAL;
87 break;
88 }
89
90 throw core::socket::SocketAddress::BadSocketAddress(
91 state, aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode), aiErrCode == EAI_SYSTEM ? errno : aiErrCode);
92 }
93 }
94
95 void SocketAddress::init(const Hints& hints) {
96 addrinfo addrInfoHints{};
97
98 addrInfoHints.ai_family = Super::getAddressFamily();
99 addrInfoHints.ai_flags =
100 hints.aiFlags | AI_ADDRCONFIG | AI_CANONNAME /*| AI_CANONIDN*/ | AI_ALL; // AI_CANONIDN produces a still reachable memory leak
101 addrInfoHints.ai_socktype = hints.aiSockType;
102 addrInfoHints.ai_protocol = hints.aiProtocol;
103
104 const int aiErrCode = socketAddrInfo->resolve(host, std::to_string(port), addrInfoHints);
105 if (aiErrCode == 0) {
106 sockAddr = socketAddrInfo->getSockAddr();
107 canonName = socketAddrInfo->getCanonName();
108 } else {
109 core::socket::State state = core::socket::STATE_OK;
110
111 switch (aiErrCode) {
112 case EAI_AGAIN:
113 case EAI_MEMORY:
114 state = core::socket::STATE_ERROR;
115 break;
116 default:
117 state = core::socket::STATE_FATAL;
118 break;
119 }
120
121 throw core::socket::SocketAddress::BadSocketAddress(state,
122 host + ":" + std::to_string(port) + " - " +
123 (aiErrCode == EAI_SYSTEM ? strerror(errno) : gai_strerror(aiErrCode)),
124 (aiErrCode == EAI_SYSTEM ? errno : aiErrCode));
125 }
126 }
127
128 SocketAddress& SocketAddress::setHost(const std::string& ipOrHostname) {
129 this->host = ipOrHostname;
130
131 return *this;
132 }
133
134 std::string SocketAddress::getHost() const {
135 return host;
136 }
137
138 SocketAddress& SocketAddress::setPort(uint16_t port) {
139 this->port = port;
140
141 return *this;
142 }
143
144 uint16_t SocketAddress::getPort() const {
145 return port;
146 }
147
148 std::string SocketAddress::getCanonName() const {
149 return canonName;
150 }
151
152 std::string SocketAddress::toString(bool expanded) const {
153 return std::string(host).append(expanded ? std::string(":").append(std::to_string(port)).append(" (").append(canonName).append(")")
154 : "");
155 }
156
157 bool SocketAddress::useNext() {
158 const bool useNext = socketAddrInfo->useNext();
159
160 sockAddr = socketAddrInfo->getSockAddr();
161
162 return useNext;
163 }
164
165} // namespace net::in6
166
167template 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)