userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
sockaddr.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/engine/io/sockaddr.hpp
4
/// @brief @copybrief engine::io::Sockaddr
5
6
#
include
<
netinet
/
in
.
h
>
7
#
include
<
sys
/
socket
.
h
>
8
#
include
<
sys
/
types
.
h
>
9
#
include
<
sys
/
un
.
h
>
10
11
#
include
<
cstring
>
12
#
include
<
string
>
13
14
#
include
<
fmt
/
format
.
h
>
15
#
include
<
userver
/
utils
/
fmt_compat
.
hpp
>
16
#
include
<
userver
/
utils
/
zstring_view
.
hpp
>
17
18
#
include
<
userver
/
logging
/
log_helper_fwd
.
hpp
>
19
20
USERVER_NAMESPACE_BEGIN
21
22
namespace
engine::
io
{
23
24
/// Socket address-related exceptions
25
class
AddrException
:
public
std::runtime_error {
26
public
:
27
using
std::runtime_error::runtime_error;
28
};
29
30
/// Communication domain
31
enum
class
AddrDomain
{
32
kUnspecified
= AF_UNSPEC,
///< Unspecified
33
kInet
= AF_INET,
///< IPv4
34
kInet6
= AF_INET6,
///< IPv6
35
kUnix
= AF_UNIX,
///< Unix socket
36
};
37
38
static_assert
(
39
AF_UNSPEC == 0,
// NOLINT(misc-redundant-expression)
40
"Your socket subsystem looks broken, please contact support chat."
41
);
42
43
/// Native socket address wrapper
44
class
Sockaddr
final
{
45
public
:
46
/// Constructs an unspecified native socket address.
47
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
48
Sockaddr
()
noexcept
{ ::memset(&data_, 0,
sizeof
(data_)); }
49
50
/// @brief Wraps a native socket address structure.
51
/// @warning sa_family must contain a correct address family.
52
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
53
explicit
Sockaddr
(
const
void
* data) {
54
const
auto
* sockaddr =
reinterpret_cast
<
const
struct
sockaddr*>(data);
55
const
auto
domain =
static_cast
<
AddrDomain
>(sockaddr->sa_family);
56
::memcpy(&data_, data, Sockaddr
::
Addrlen
(
domain
)
);
57
}
58
59
/// @brief Creates address of an IP socket with passed address.
60
/// @note use @ref Socket::ConnectTcpByName in case you need DNS resolving.
61
static
Sockaddr
MakeIPSocketAddress
(
utils
::
zstring_view
ip_address);
62
63
/// @brief Creates address of a Unix socket located at the specified path.
64
static
Sockaddr
MakeUnixSocketAddress
(std::string_view path);
65
66
/// @brief Creates the IPv6 wildcard address `[::]:0` that also handles IPv4
67
/// connections.
68
///
69
/// A program needs to support only this API type to support IPv4 and IPv6.
70
static
Sockaddr
MakeInaddrAny
()
noexcept
;
71
72
/// @brief Creates the IPv4 only wildcard address `0.0.0.0:0`.
73
///
74
/// Prefer a more generic MakeInaddrAny() function if not sure.
75
static
Sockaddr
MakeIPv4InaddrAny
()
noexcept
;
76
77
/// @brief Creates the IPv6 loopback address `[::1]:0` that also handles IPv4
78
/// connections.
79
///
80
/// A program needs to support only this API type to support IPv4 and IPv6.
81
static
Sockaddr
MakeLoopbackAddress
()
noexcept
;
82
83
/// @brief Creates the IPv4 only loopback address `127.0.0.1:0`.
84
///
85
/// Prefer a more generic MakeLoopbackAddress() function if not sure.
86
static
Sockaddr
MakeIPv4LoopbackAddress
()
noexcept
;
87
88
/// @brief Domain-specific native socket address structure pointer.
89
/// @warning No type checking is performed, user must ensure that only the
90
/// correct domain is accessed.
91
template
<
typename
T>
92
T*
As
() {
93
static_assert
(
sizeof
(T) <=
sizeof
(data_),
"Invalid socket address type"
);
94
return
reinterpret_cast
<T*>(&data_);
95
}
96
97
/// @brief Domain-specific native socket address structure pointer.
98
/// @warning No type checking is performed, user must ensure that only the
99
/// correct domain is accessed.
100
template
<
typename
T>
101
const
T*
As
()
const
{
102
static_assert
(
sizeof
(T) <=
sizeof
(data_),
"Invalid socket address type"
);
103
return
reinterpret_cast
<
const
T*>(&data_);
104
}
105
106
/// Native socket address structure pointer.
107
struct
sockaddr*
Data
() {
return
As
<
struct
sockaddr
>
(
)
; }
108
109
/// Native socket address structure pointer.
110
const
struct
sockaddr*
Data
()
const
{
return
As
<
struct
sockaddr
>
(
)
; }
111
112
/// Maximum supported native socket address structure size.
113
socklen_t
Size
()
const
{
return
Addrlen
(
Domain
(
)
)
; }
114
115
/// Maximum supported native socket address structure size.
116
socklen_t
Capacity
()
const
{
return
sizeof
(data_); }
117
118
/// Protocol family.
119
sa_family_t
Family
()
const
{
return
Data
(
)
->sa_family; }
120
121
/// Communication domain.
122
AddrDomain
Domain
()
const
{
return
static_cast
<
AddrDomain
>(
Family
(
)
); }
123
124
/// Whether the stored socket address family expects a port.
125
bool
HasPort
()
const
;
126
127
/// Returns the stored port number if available, otherwise throws.
128
std::
uint16_t
Port
()
const
;
129
130
/// Sets a port for address families that allow for one, otherwise throws.
131
void
SetPort
(std::uint16_t port);
132
133
/// @brief Human-readable address representation.
134
/// @note Does not include port number.
135
std::string
PrimaryAddressString
()
const
;
136
137
/// Domain-specific native socket address structure size.
138
static
constexpr
socklen_t
Addrlen
(
AddrDomain
domain) {
139
const
auto
res = AddrlenImpl(domain);
140
141
if
(res == 0) {
142
throw
AddrException
(fmt::format(
"Unexpected address family {}"
,
static_cast
<
int
>(domain)));
143
}
144
145
return
res;
146
}
147
148
private
:
149
static
constexpr
socklen_t AddrlenImpl(
AddrDomain
domain)
noexcept
{
150
switch
(domain) {
151
case
AddrDomain
::
kUnspecified
:
152
return
sizeof
(
struct
sockaddr);
153
case
AddrDomain
::
kInet
:
154
return
sizeof
(
struct
sockaddr_in);
155
case
AddrDomain
::
kInet6
:
156
return
sizeof
(
struct
sockaddr_in6);
157
case
AddrDomain
::
kUnix
:
158
return
sizeof
(
struct
sockaddr_un);
159
}
160
161
return
0;
162
}
163
164
union
Storage {
165
struct
sockaddr sa_any;
166
struct
sockaddr_in sa_inet;
167
struct
sockaddr_in6 sa_inet6;
168
struct
sockaddr_un sa_unix;
169
} data_;
170
};
171
172
/// Outputs human-readable address representation, including port number.
173
logging::LogHelper& operator<<(logging::LogHelper&,
const
Sockaddr&);
174
175
}
// namespace engine::io
176
177
USERVER_NAMESPACE_END
178
179
/// Socket address fmt formatter.
180
template
<>
181
struct
fmt
::
formatter
<USERVER_NAMESPACE::engine::
io
::Sockaddr> {
182
static
constexpr
auto
parse(format_parse_context&);
183
184
template
<
typename
FormatContext>
185
auto
format(
const
USERVER_NAMESPACE::engine::
io
::Sockaddr& sa, FormatContext& ctx)
USERVER_FMT_CONST
;
186
};
187
188
inline
constexpr
auto
fmt::formatter<USERVER_NAMESPACE::engine::
io
::Sockaddr>::parse(format_parse_context& ctx) {
189
const
auto
* it = ctx.begin();
190
if
(it != ctx.end() && *it !=
'}'
) {
191
throw
format_error(
"invalid Sockaddr format"
);
192
}
193
return
it;
194
}
195
196
template
<
typename
FormatContext>
197
inline
auto
fmt::formatter<USERVER_NAMESPACE::engine::
io
::Sockaddr>::format(
198
const
USERVER_NAMESPACE::engine::
io
::Sockaddr& sa,
199
FormatContext& ctx
200
)
USERVER_FMT_CONST
{
201
switch
(sa
.
Domain
(
)
) {
202
case
USERVER_NAMESPACE
::
engine
::
io
::
AddrDomain
::
kInet
:
203
return
fmt::format_to(ctx.out(),
"{}:{}"
, sa
.
PrimaryAddressString
(
)
, sa
.
Port
(
)
);
204
205
case
USERVER_NAMESPACE
::
engine
::
io
::
AddrDomain
::
kInet6
:
206
return
fmt::format_to(ctx.out(),
"[{}]:{}"
, sa
.
PrimaryAddressString
(
)
, sa
.
Port
(
)
);
207
208
default
:
209
return
fmt::format_to(ctx.out(),
"{}"
, sa
.
PrimaryAddressString
(
)
);
210
}
211
}
userver
engine
io
sockaddr.hpp
Generated on
for userver by
Doxygen
1.17.0