Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Endpoint.cpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2021 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#include "Endpoint.hpp"
18
20
21using namespace std;
22
23namespace toolbox {
24inline namespace net {
25namespace {
26
28{
29 // Reverse find for compatibility with ipv6 address notation.
30 const auto pos = addr.find_last_of(delim);
31 string node, service;
32 if (pos == string::npos) {
33 node = addr;
34 } else {
35 node = addr.substr(0, pos);
36 service = addr.substr(pos + 1);
37 }
38 // Remove square braces around ipv6 address.
39 if (node.size() >= 2 && node.front() == '[' && node.back() == ']') {
40 node = node.substr(1, node.size() - 2);
41 }
42 return {node, service};
43}
44
46{
47 const auto pos = uri.find("://");
48 string scheme, addr;
49 if (pos == string::npos) {
50 addr = uri;
51 } else {
52 scheme = uri.substr(0, pos);
53 addr = uri.substr(pos + 3);
54 }
55 return {scheme, addr};
56}
57} // namespace
58
59AddrInfoPtr parse_endpoint(string_view uri, int type)
60{
61 int family{-1}, protocol{0};
62 const auto [scheme, addr] = split_uri(uri);
63 if (scheme.empty()) {
64 family = AF_UNSPEC;
65 } else if (scheme == "ip4") {
66 family = AF_INET;
67 } else if (scheme == "ip6") {
68 family = AF_INET6;
69 } else if (scheme == "tcp4") {
70 if (type == SOCK_STREAM) {
71 family = AF_INET;
72 protocol = IPPROTO_TCP;
73 }
74 } else if (scheme == "tcp6") {
75 if (type == SOCK_STREAM) {
76 family = AF_INET6;
77 protocol = IPPROTO_TCP;
78 }
79 } else if (scheme == "udp4") {
80 if (type == SOCK_DGRAM) {
81 family = AF_INET;
82 protocol = IPPROTO_UDP;
83 }
84 } else if (scheme == "udp6") {
85 if (type == SOCK_DGRAM) {
86 family = AF_INET6;
87 protocol = IPPROTO_UDP;
88 }
89 } else if (scheme == "unix") {
90 return get_unix_addrinfo(addr, type);
91 }
92 if (family < 0) {
93 throw invalid_argument{make_string("invalid uri: ", uri)};
94 }
95 auto [node, service] = split_ip_addr(addr, ':');
96 return os::getaddrinfo(!node.empty() ? node.c_str() : nullptr,
97 !service.empty() ? service.c_str() : nullptr, family, type, protocol);
98}
99
100istream& operator>>(istream& is, DgramEndpoint& ep)
101{
102 string uri;
103 if (is >> uri) {
105 }
106 return is;
107}
108
109istream& operator>>(istream& is, StreamEndpoint& ep)
110{
111 string uri;
112 if (is >> uri) {
114 }
115 return is;
116}
117
118namespace {
119template <typename T>
120ostream& print_unix_endpoint(ostream& os, const T& ep)
121{
122 constexpr const char* scheme = "unix://";
123 // abstract unix socket's path starts with '\0' and not null-terminated
124 const auto* path = reinterpret_cast<const sockaddr_un*>(ep.data())->sun_path;
125 if (path[0] == '\0') {
126 size_t size = ep.size() - sizeof(std::declval<sockaddr_un>().sun_family) - 1;
127 return os << scheme << '|' << std::string_view{path + 1, size};
128 }
129 return os << scheme << *ep.data();
130}
131} // namespace
132
133ostream& operator<<(ostream& os, const DgramEndpoint& ep)
134{
135 const char* scheme = "";
136 const auto p = ep.protocol();
137 if (p.family() == AF_INET) {
138 if (p.protocol() == IPPROTO_UDP) {
139 scheme = "udp4://";
140 } else {
141 scheme = "ip4://";
142 }
143 } else if (p.family() == AF_INET6) {
144 if (p.protocol() == IPPROTO_UDP) {
145 scheme = "udp6://";
146 } else {
147 scheme = "ip6://";
148 }
149 } else if (p.family() == AF_UNIX) {
150 return print_unix_endpoint(os, ep);
151 }
152 return os << scheme << *ep.data();
153}
154
155ostream& operator<<(ostream& os, const StreamEndpoint& ep)
156{
157 const char* scheme = "";
158 const auto p = ep.protocol();
159 if (p.family() == AF_INET) {
160 if (p.protocol() == IPPROTO_TCP) {
161 scheme = "tcp4://";
162 } else {
163 scheme = "ip4://";
164 }
165 } else if (p.family() == AF_INET6) {
166 if (p.protocol() == IPPROTO_TCP) {
167 scheme = "tcp6://";
168 } else {
169 scheme = "ip6://";
170 }
171 } else if (p.family() == AF_UNIX) {
172 return print_unix_endpoint(os, ep);
173 }
174 return os << scheme << *ep.data();
175}
176
177} // namespace net
178} // namespace toolbox
179
180ostream& operator<<(ostream& os, const sockaddr_in& sa)
181{
182 char buf[INET_ADDRSTRLEN];
183 inet_ntop(AF_INET, &toolbox::remove_const(sa).sin_addr, buf, sizeof(buf));
184 return os << buf << ':' << ntohs(sa.sin_port);
185}
186
187ostream& operator<<(ostream& os, const sockaddr_in6& sa)
188{
189 char buf[INET6_ADDRSTRLEN];
190 inet_ntop(AF_INET6, &toolbox::remove_const(sa).sin6_addr, buf, sizeof(buf));
191 return os << '[' << buf << "]:" << ntohs(sa.sin6_port);
192}
193
194ostream& operator<<(ostream& os, const sockaddr_un& sa)
195{
196 return os << sa.sun_path;
197}
198
199ostream& operator<<(ostream& os, const sockaddr& sa)
200{
201 if (sa.sa_family == AF_INET) {
202 os << reinterpret_cast<const sockaddr_in&>(sa);
203 } else if (sa.sa_family == AF_INET6) {
204 os << reinterpret_cast<const sockaddr_in6&>(sa);
205 } else if (sa.sa_family == AF_UNIX) {
206 os << reinterpret_cast<const sockaddr_un&>(sa);
207 } else {
208 os << "<sockaddr>";
209 }
210 return os;
211}
212
213ostream& operator<<(ostream& os, const addrinfo& ai)
214{
215 const char* scheme = "";
216 if (ai.ai_family == AF_INET) {
217 if (ai.ai_protocol == IPPROTO_TCP) {
218 scheme = "tcp4://";
219 } else if (ai.ai_protocol == IPPROTO_UDP) {
220 scheme = "udp4://";
221 } else {
222 scheme = "ip4://";
223 }
224 } else if (ai.ai_family == AF_INET6) {
225 if (ai.ai_protocol == IPPROTO_TCP) {
226 scheme = "tcp6://";
227 } else if (ai.ai_protocol == IPPROTO_UDP) {
228 scheme = "udp6://";
229 } else {
230 scheme = "ip6://";
231 }
232 } else if (ai.ai_family == AF_UNIX) {
233 scheme = "unix://";
234 }
235 return os << scheme << *ai.ai_addr;
236}
STL namespace.
ostream & operator<<(ostream &os, const pair< T, U > &p)
Definition Parser.ut.cpp:29
BasicEndpoint< DgramProtocol > DgramEndpoint
Definition Endpoint.hpp:34
istream & operator>>(istream &is, DgramEndpoint &ep)
Definition Endpoint.cpp:100
AddrInfoPtr parse_endpoint(string_view uri, int type)
Definition Endpoint.cpp:59
std::unique_ptr< addrinfo, void(*)(addrinfo *)> AddrInfoPtr
Definition Socket.hpp:30
BasicEndpoint< StreamProtocol > StreamEndpoint
Definition Endpoint.hpp:35
AddrInfoPtr get_unix_addrinfo(string_view path, int type)
Create an addrinfo structure for a Unix domain address.
Definition Socket.cpp:35
DgramEndpoint parse_dgram_endpoint(std::string_view uri)
Definition Endpoint.hpp:51
StreamEndpoint parse_stream_endpoint(std::string_view uri)
Definition Endpoint.hpp:57
AddrInfoPtr getaddrinfo(const char *node, const char *service, const addrinfo &hints, std::error_code &ec) noexcept
Get network address from Internet host and service.
Definition Socket.hpp:35
std::string make_string(ArgsT &&... args)
Definition String.hpp:351
auto & remove_const(const ValueT &ref)
Definition Utility.hpp:33
constexpr std::size_t size(const detail::Struct< detail::Member< TagsT, ValuesT >... > &s)
Definition Struct.hpp:98
constexpr auto bind() noexcept
Definition Slot.hpp:92