Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
actor-incubator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
actor-incubator
Commits
d17f4394
Commit
d17f4394
authored
Aug 24, 2019
by
Joseph Noir
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rework TCP sockets and ip address lookup
parent
1616d88e
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
647 additions
and
87 deletions
+647
-87
libcaf_net/CMakeLists.txt
libcaf_net/CMakeLists.txt
+3
-3
libcaf_net/caf/detail/sockaddr_members.hpp
libcaf_net/caf/detail/sockaddr_members.hpp
+28
-21
libcaf_net/caf/net/ip.hpp
libcaf_net/caf/net/ip.hpp
+12
-7
libcaf_net/caf/net/socket_guard.hpp
libcaf_net/caf/net/socket_guard.hpp
+28
-8
libcaf_net/caf/net/stream_socket.hpp
libcaf_net/caf/net/stream_socket.hpp
+0
-3
libcaf_net/caf/net/tcp_accept_socket.hpp
libcaf_net/caf/net/tcp_accept_socket.hpp
+75
-0
libcaf_net/caf/net/tcp_stream_socket.hpp
libcaf_net/caf/net/tcp_stream_socket.hpp
+40
-29
libcaf_net/caf/policy/doorman.hpp
libcaf_net/caf/policy/doorman.hpp
+7
-10
libcaf_net/src/ip.cpp
libcaf_net/src/ip.cpp
+190
-0
libcaf_net/src/stream_socket.cpp
libcaf_net/src/stream_socket.cpp
+2
-0
libcaf_net/src/tcp_accept_socket.cpp
libcaf_net/src/tcp_accept_socket.cpp
+145
-0
libcaf_net/src/tcp_stream_socket.cpp
libcaf_net/src/tcp_stream_socket.cpp
+99
-0
libcaf_net/test/doorman.cpp
libcaf_net/test/doorman.cpp
+18
-6
No files found.
libcaf_net/CMakeLists.txt
View file @
d17f4394
...
...
@@ -11,17 +11,17 @@ set(LIBCAF_NET_SRCS
src/datagram_socket.cpp
src/endpoint_manager.cpp
src/host.cpp
src/i
nterfaces
.cpp
src/i
p
.cpp
src/multiplexer.cpp
src/network_socket.cpp
src/pipe_socket.cpp
src/pollset_updater.cpp
src/socket.cpp
src/socket_guard.cpp
src/socket_manager.cpp
src/stream_socket.cpp
src/scribe.cpp
src/tcp.cpp
src/tcp_accept_socket.cpp
src/tcp_stream_socket.cpp
)
add_custom_target
(
libcaf_net
)
...
...
libcaf_net/caf/
net/interface
s.hpp
→
libcaf_net/caf/
detail/sockaddr_member
s.hpp
View file @
d17f4394
...
...
@@ -18,27 +18,34 @@
#pragma once
#include <cstdint>
#include <vector>
#include "caf/net/ip.hpp"
#include "caf/optional.hpp"
#include "caf/detail/socket_sys_includes.hpp"
namespace
caf
{
namespace
net
{
/// Utility class bundling access to network interface names and addresses.
class
interfaces
{
public:
/// Returns a native IPv4 or IPv6 translation of `host`.
static
optional
<
std
::
pair
<
std
::
string
,
ip
>>
native_address
(
const
std
::
string
&
host
,
optional
<
ip
>
preferred
=
none
);
/// Returns the host and protocol available for a local server socket
static
std
::
vector
<
std
::
pair
<
std
::
string
,
ip
>>
server_address
(
uint16_t
port
,
const
char
*
host
,
optional
<
ip
>
preferred
=
none
);
};
}
// namespace net
namespace
detail
{
inline
auto
addr_of
(
sockaddr_in
&
what
)
->
decltype
(
what
.
sin_addr
)
&
{
return
what
.
sin_addr
;
}
inline
auto
family_of
(
sockaddr_in
&
what
)
->
decltype
(
what
.
sin_family
)
&
{
return
what
.
sin_family
;
}
inline
auto
port_of
(
sockaddr_in
&
what
)
->
decltype
(
what
.
sin_port
)
&
{
return
what
.
sin_port
;
}
inline
auto
addr_of
(
sockaddr_in6
&
what
)
->
decltype
(
what
.
sin6_addr
)
&
{
return
what
.
sin6_addr
;
}
inline
auto
family_of
(
sockaddr_in6
&
what
)
->
decltype
(
what
.
sin6_family
)
&
{
return
what
.
sin6_family
;
}
inline
auto
port_of
(
sockaddr_in6
&
what
)
->
decltype
(
what
.
sin6_port
)
&
{
return
what
.
sin6_port
;
}
}
// namespace detail
}
// namespace caf
libcaf_net/caf/net/ip.hpp
View file @
d17f4394
...
...
@@ -18,19 +18,24 @@
#pragma once
#include <cstddef>
#include <string>
#include <vector>
#include "caf/fwd.hpp"
namespace
caf
{
namespace
net
{
namespace
ip
{
/// Returns the ip addresses assigned to `host`.
std
::
vector
<
ip_address
>
resolve
(
const
std
::
string
&
host
);
//
IP version tag
.
enum
class
ip
{
v4
,
v6
}
;
//
/ Returns the ip addresses for the local hostname
.
std
::
vector
<
ip_address
>
local_addrs
(
const
std
::
string
&
host
)
;
/// @relates ip
inline
std
::
string
to_string
(
ip
x
)
{
return
x
==
ip
::
v4
?
"IPv4"
:
"IPv6"
;
}
/// Returns the hostname of this device.
std
::
string
hostname
();
}
// namespace ip
}
// namespace net
}
// namespace caf
libcaf_net/caf/net/socket_guard.hpp
View file @
d17f4394
...
...
@@ -24,19 +24,39 @@ namespace caf {
namespace
net
{
/// Closes the guarded socket when destroyed.
template
<
class
Socket
>
class
socket_guard
{
public:
explicit
socket_guard
(
net
::
socket
fd
);
~
socket_guard
();
net
::
socket
release
();
void
close
();
explicit
socket_guard
(
Socket
fd
)
:
fd_
(
fd
)
{
// nop
}
~
socket_guard
()
{
close
();
}
Socket
release
()
{
auto
fd
=
fd_
;
fd_
=
Socket
{};
return
fd
;
}
void
close
()
{
if
(
fd_
.
id
!=
net
::
invalid_socket
)
{
CAF_LOG_DEBUG
(
"close socket"
<<
CAF_ARG
(
fd_
));
net
::
close
(
fd_
);
fd_
=
Socket
{};
}
}
private:
net
::
s
ocket
fd_
;
S
ocket
fd_
;
};
template
<
class
Socket
>
socket_guard
<
Socket
>
make_socket_guard
(
Socket
sock
)
{
return
socket_guard
<
Socket
>
{
sock
};
}
}
// namespace net
}
// namespace caf
libcaf_net/caf/net/stream_socket.hpp
View file @
d17f4394
...
...
@@ -18,11 +18,8 @@
#pragma once
#include "caf/expected.hpp"
#include "caf/fwd.hpp"
#include "caf/net/network_socket.hpp"
#include "caf/sec.hpp"
#include "caf/variant.hpp"
namespace
caf
{
namespace
net
{
...
...
libcaf_net/
src/socket_guard.c
pp
→
libcaf_net/
caf/net/tcp_accept_socket.h
pp
View file @
d17f4394
...
...
@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-201
8
Dominik Charousset *
* Copyright 2011-201
9
Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
...
...
@@ -16,34 +16,60 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#
include "caf/net/socket_guard.hpp"
#
pragma once
#include "caf/logger.hpp"
#include "caf/net/abstract_socket.hpp"
#include "caf/net/network_socket.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/stream_socket.hpp"
#include "caf/net/tcp_stream_socket.hpp"
#include "caf/uri.hpp"
namespace
caf
{
namespace
net
{
socket_guard
::
socket_guard
(
net
::
socket
fd
)
:
fd_
(
fd
)
{
// nop
}
socket_guard
::~
socket_guard
()
{
close
();
}
net
::
socket
socket_guard
::
release
()
{
auto
fd
=
fd_
;
fd_
=
net
::
invalid_socket
;
return
fd
;
}
void
socket_guard
::
close
()
{
if
(
fd_
!=
net
::
invalid_socket
)
{
CAF_LOG_DEBUG
(
"close socket"
<<
CAF_ARG
(
fd_
));
net
::
close
(
fd_
);
fd_
=
net
::
invalid_socket
;
/// Represents an open TCP endpoint. Can be implicitly converted to a
/// `stream_socket` for sending and receiving, or `network_socket`
/// for inspection.
struct
tcp_accept_socket
:
abstract_socket
<
tcp_accept_socket
>
{
using
super
=
abstract_socket
<
tcp_accept_socket
>
;
using
super
::
super
;
constexpr
operator
socket
()
const
noexcept
{
return
socket
{
id
};
}
}
constexpr
operator
network_socket
()
const
noexcept
{
return
network_socket
{
id
};
}
constexpr
operator
stream_socket
()
const
noexcept
{
return
stream_socket
{
id
};
}
};
/// Creates a new TCP socket to accept connections on a given port.
/// @param port The port to listen on.
/// @param addr Only accepts connections originating from this address.
/// @param reuse_addr Optionally sets the SO_REUSEADDR option on the socket.
/// @relates stream_socket
expected
<
tcp_accept_socket
>
make_accept_socket
(
ip_address
host
,
uint16_t
port
,
bool
reuse_addr
);
/// Creates a new TCP socket to accept connections on a given port.
/// @param port The port to listen on.
/// @param addr Only accepts connections originating from this address.
/// @param reuse_addr Optionally sets the SO_REUSEADDR option on the socket.
/// @relates stream_socket
expected
<
tcp_accept_socket
>
make_accept_socket
(
const
uri
::
authority_type
&
auth
,
bool
reuse_addr
=
false
);
/// Accept a connection on `x`.
/// @param x Listening endpoint.
/// @returns The socket that handles the accepted connection.
/// @relates stream_socket
expected
<
tcp_stream_socket
>
accept
(
tcp_accept_socket
x
);
}
// namespace net
}
// namespace caf
libcaf_net/caf/net/tcp.hpp
→
libcaf_net/caf/net/tcp
_stream_socket
.hpp
View file @
d17f4394
...
...
@@ -18,41 +18,52 @@
#pragma once
#include <cstdint>
#include "caf/expected.hpp"
#include "caf/net/ip.hpp"
#include "caf/net/abstract_socket.hpp"
#include "caf/net/network_socket.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/stream_socket.hpp"
#include "caf/uri.hpp"
namespace
caf
{
namespace
net
{
struct
tcp
{
/// Creates a new TCP socket to accept connections on a given port.
/// @param port The port to listen on.
/// @param addr Only accepts connections originating from this address.
/// @param reuse_addr Optionally sets the SO_REUSEADDR option on the socket.
/// @relates stream_socket
static
expected
<
stream_socket
>
make_accept_socket
(
uint16_t
port
,
const
char
*
addr
=
nullptr
,
bool
reuse_addr
=
false
);
/// Create a `stream_socket` connected to `host`:`port` via the
/// `preferred` IP version.
/// @param host The remote host to connecto to.
/// @param port The port on the remote host to connect to.
/// @preferred Preferred IP version.
/// @returns The connected socket or an error.
/// @relates stream_socket
static
expected
<
stream_socket
>
make_connected_socket
(
std
::
string
host
,
uint16_t
port
,
optional
<
ip
>
preferred
=
none
);
/// Accept a connection on `x`.
/// @param x Listening endpoint.
/// @returns The socket that handles the accepted connection.
/// @relates stream_socket
static
expected
<
stream_socket
>
accept
(
stream_socket
x
);
/// Represents a TCP connection. Can be implicitly converted to a
/// `stream_socket` for sending and receiving, or `network_socket`
/// for inspection.
struct
tcp_stream_socket
:
abstract_socket
<
tcp_stream_socket
>
{
using
super
=
abstract_socket
<
tcp_stream_socket
>
;
using
super
::
super
;
constexpr
operator
socket
()
const
noexcept
{
return
socket
{
id
};
}
constexpr
operator
network_socket
()
const
noexcept
{
return
network_socket
{
id
};
}
constexpr
operator
stream_socket
()
const
noexcept
{
return
stream_socket
{
id
};
}
};
/// Create a `stream_socket` connected to `host`:`port`.
/// @param host The remote host to connecto to.
/// @param port The port on the remote host to connect to.
/// @preferred Preferred IP version.
/// @returns The connected socket or an error.
/// @relates stream_socket
expected
<
stream_socket
>
make_connected_socket
(
ip_address
host
,
uint16_t
port
);
/// Create a `stream_socket` connected to `auth`.
/// @param authority The remote host to connecto to.
/// @preferred Preferred IP version.
/// @returns The connected socket or an error.
/// @relates stream_socket
expected
<
stream_socket
>
make_connected_socket
(
const
uri
::
authority_type
&
auth
);
}
// namespace net
}
// namespace caf
libcaf_net/caf/policy/doorman.hpp
View file @
d17f4394
...
...
@@ -20,11 +20,11 @@
#include <vector>
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/logger.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/stream_socket.hpp"
#include "caf/net/tcp.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/tcp_stream_socket.hpp"
#include "caf/policy/scribe.hpp"
#include "caf/send.hpp"
...
...
@@ -34,11 +34,11 @@ namespace policy {
/// A doorman accepts TCP connections and creates scribes to handle them.
class
doorman
{
public:
doorman
(
net
::
stream
_socket
acceptor
)
:
acceptor_
(
acceptor
)
{
doorman
(
net
::
tcp_accept
_socket
acceptor
)
:
acceptor_
(
acceptor
)
{
// nop
}
net
::
socket
acceptor_
;
net
::
tcp_accept_
socket
acceptor_
;
net
::
socket
handle
()
{
return
acceptor_
;
...
...
@@ -54,23 +54,20 @@ public:
template
<
class
Parent
>
bool
handle_read_event
(
Parent
&
parent
)
{
auto
sck
=
net
::
tcp
::
accept
(
net
::
socket_cast
<
net
::
stream_socket
>
(
acceptor_
));
auto
sck
=
net
::
accept
(
acceptor_
);
if
(
!
sck
)
{
CAF_LOG_ERROR
(
"accept failed:"
<<
sck
.
error
());
return
false
;
}
auto
mpx
=
parent
.
multiplexer
();
if
(
!
mpx
)
{
CAF_LOG_DEBUG
(
"could not acquire multiplexer to create a new endpoint manager"
);
CAF_LOG_DEBUG
(
"unable to get multiplexer from parent"
);
return
false
;
}
auto
child
=
make_endpoint_manager
(
mpx
,
parent
.
system
(),
scribe
{
*
sck
},
parent
.
application
().
make
());
if
(
auto
err
=
child
->
init
())
{
if
(
auto
err
=
child
->
init
())
return
false
;
}
return
true
;
}
...
...
libcaf_net/src/i
nterfaces
.cpp
→
libcaf_net/src/i
p
.cpp
View file @
d17f4394
...
...
@@ -16,12 +16,10 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/net/interfaces.hpp"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
// clang-format off
#ifdef CAF_WINDOWS
...
...
@@ -29,36 +27,41 @@
# define _WIN32_WINNT 0x0600
# endif
# include <iostream>
# include <winsock2.h>
# include <ws2tcpip.h>
# include <iphlpapi.h>
#else
# include <sys/socket.h>
# include <netinet/in.h>
# include <net/if.h>
# include <unistd.h>
# include <netdb.h>
# include <ifaddrs.h>
# include <sys/ioctl.h>
# include <
arpa/inet
.h>
# include <
sys/types
.h>
#endif
// clang-format on
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/error.hpp"
#include "caf/ip_address.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/logger.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/string_view.hpp"
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif
using
std
::
string
;
using
std
::
vector
;
using
std
::
pair
;
namespace
caf
{
namespace
net
{
namespace
ip
{
namespace
{
// {interface_name => {protocol => address}}
using
interfaces_map
=
std
::
map
<
std
::
string
,
std
::
map
<
ip
,
std
::
vector
<
std
::
string
>>>
;
constexpr
auto
v4_any_addr
=
"0.0.0.0"
;
constexpr
auto
v6_any_addr
=
"::"
;
constexpr
auto
localhost
=
"localhost"
;
template
<
class
T
>
void
*
vptr
(
T
*
ptr
)
{
...
...
@@ -71,6 +74,7 @@ void* fetch_in_addr(int family, sockaddr* addr) {
return
vptr
(
&
reinterpret_cast
<
sockaddr_in6
*>
(
addr
)
->
sin6_addr
);
}
// TODO: Use getnameinfo instead?
int
fetch_addr_str
(
bool
get_ipv4
,
bool
get_ipv6
,
char
(
&
buf
)[
INET6_ADDRSTRLEN
],
sockaddr
*
addr
)
{
if
(
addr
==
nullptr
)
...
...
@@ -83,62 +87,104 @@ int fetch_addr_str(bool get_ipv4, bool get_ipv6, char (&buf)[INET6_ADDRSTRLEN],
:
AF_UNSPEC
;
}
void
find_by_name
(
const
vector
<
pair
<
string
,
ip_address
>>&
interfaces
,
const
string
&
name
,
vector
<
ip_address
>&
results
)
{
for
(
auto
&
p
:
interfaces
)
if
(
p
.
first
==
name
)
results
.
push_back
(
p
.
second
);
}
void
find_by_addr
(
const
vector
<
pair
<
string
,
ip_address
>>&
interfaces
,
ip_address
addr
,
vector
<
ip_address
>&
results
)
{
for
(
auto
&
p
:
interfaces
)
if
(
p
.
second
==
addr
)
results
.
push_back
(
p
.
second
);
}
}
// namespace
optional
<
std
::
pair
<
std
::
string
,
ip
>>
interfaces
::
native_address
(
const
std
::
string
&
host
,
optional
<
ip
>
preferred
)
{
std
::
vector
<
ip_address
>
resolve
(
const
std
::
string
&
host
)
{
addrinfo
hint
;
memset
(
&
hint
,
0
,
sizeof
(
hint
));
hint
.
ai_socktype
=
SOCK_STREAM
;
if
(
preferred
)
hint
.
ai_family
=
*
preferred
==
ip
::
v4
?
AF_INET
:
AF_INET6
;
hint
.
ai_family
=
AF_UNSPEC
;
if
(
host
.
empty
())
hint
.
ai_flags
=
AI_PASSIVE
;
addrinfo
*
tmp
=
nullptr
;
if
(
getaddrinfo
(
host
.
c_str
(),
nullptr
,
&
hint
,
&
tmp
)
!=
0
)
return
none
;
return
{}
;
std
::
unique_ptr
<
addrinfo
,
decltype
(
freeaddrinfo
)
*>
addrs
{
tmp
,
freeaddrinfo
};
char
buffer
[
INET6_ADDRSTRLEN
];
std
::
vector
<
ip_address
>
results
;
for
(
auto
i
=
addrs
.
get
();
i
!=
nullptr
;
i
=
i
->
ai_next
)
{
auto
family
=
fetch_addr_str
(
true
,
true
,
buffer
,
i
->
ai_addr
);
if
(
family
!=
AF_UNSPEC
)
return
std
::
make_pair
(
buffer
,
family
==
AF_INET
?
ip
::
v4
:
ip
::
v6
);
if
(
family
!=
AF_UNSPEC
)
{
ip_address
ip
;
if
(
auto
err
=
parse
(
buffer
,
ip
))
{
CAF_LOG_ERROR
(
"could not parse into ip address "
<<
buffer
);
continue
;
}
results
.
emplace_back
(
ip
);
}
}
return
none
;
// TODO: Should we just prefer ipv6 or use a config option?
//std::stable_sort(std::begin(results), std::end(results),
// [](const ip_address& lhs, const ip_address& rhs) {
// return !lhs.embeds_v4() && rhs.embeds_v4();
// });
return
results
;
}
std
::
vector
<
std
::
pair
<
std
::
string
,
ip
>>
interfaces
::
server_address
(
uint16_t
port
,
const
char
*
host
,
optional
<
ip
>
preferred
)
{
using
addr_pair
=
std
::
pair
<
std
::
string
,
ip
>
;
addrinfo
hint
;
memset
(
&
hint
,
0
,
sizeof
(
hint
));
hint
.
ai_socktype
=
SOCK_STREAM
;
if
(
preferred
)
hint
.
ai_family
=
*
preferred
==
ip
::
v4
?
AF_INET
:
AF_INET6
;
else
hint
.
ai_family
=
AF_UNSPEC
;
if
(
host
==
nullptr
)
hint
.
ai_flags
=
AI_PASSIVE
;
auto
port_str
=
std
::
to_string
(
port
);
addrinfo
*
tmp
=
nullptr
;
if
(
getaddrinfo
(
host
,
port_str
.
c_str
(),
&
hint
,
&
tmp
)
!=
0
)
std
::
vector
<
ip_address
>
local_addrs
(
const
std
::
string
&
host
)
{
std
::
vector
<
ip_address
>
results
;
// The string is not returned by getifaddrs, let's just do that ourselves.
if
(
host
==
localhost
)
return
{
ip_address
{{
0
},
{
0x1
}},
ipv6_address
{
make_ipv4_address
(
127
,
0
,
0
,
1
)}};
if
(
host
==
v4_any_addr
||
host
==
v6_any_addr
)
return
{
ip_address
{}};
ifaddrs
*
tmp
=
nullptr
;
if
(
getifaddrs
(
&
tmp
)
!=
0
)
return
{};
std
::
unique_ptr
<
addrinfo
,
decltype
(
freeaddrinfo
)
*>
addrs
{
tmp
,
freeaddrinfo
};
std
::
unique_ptr
<
ifaddrs
,
decltype
(
freeifaddrs
)
*>
addrs
{
tmp
,
freeifaddrs
};
char
buffer
[
INET6_ADDRSTRLEN
];
// Take the first ipv6 address or the first available address otherwise
std
::
vector
<
addr_pair
>
results
;
for
(
auto
i
=
addrs
.
get
();
i
!=
nullptr
;
i
=
i
->
ai_next
)
{
auto
family
=
fetch_addr_str
(
true
,
true
,
buffer
,
i
->
ai_addr
);
// Unless explicitly specified we are going to skip link-local addresses.
auto
is_link_local
=
starts_with
(
host
,
"fe80:"
);
std
::
vector
<
std
::
pair
<
std
::
string
,
ip_address
>>
interfaces
;
for
(
auto
i
=
addrs
.
get
();
i
!=
nullptr
;
i
=
i
->
ifa_next
)
{
auto
family
=
fetch_addr_str
(
true
,
true
,
buffer
,
i
->
ifa_addr
);
if
(
family
!=
AF_UNSPEC
)
{
results
.
emplace_back
(
std
::
string
{
buffer
},
family
==
AF_INET
?
ip
::
v4
:
ip
::
v6
);
ip_address
ip
;
if
(
!
is_link_local
&&
starts_with
(
buffer
,
"fe80:"
))
{
CAF_LOG_DEBUG
(
"skipping link-local address: "
<<
buffer
);
continue
;
}
else
if
(
auto
err
=
parse
(
buffer
,
ip
))
{
CAF_LOG_ERROR
(
"could not parse into ip address "
<<
buffer
);
continue
;
}
interfaces
.
emplace_back
(
std
::
string
{
i
->
ifa_name
},
ip
);
}
}
std
::
stable_sort
(
std
::
begin
(
results
),
std
::
end
(
results
),
[](
const
addr_pair
&
lhs
,
const
addr_pair
&
rhs
)
{
return
lhs
.
second
>
rhs
.
second
;
});
ip_address
host_addr
;
if
(
host
.
empty
()
||
host
==
v4_any_addr
||
host
==
v6_any_addr
)
for
(
auto
&
p
:
interfaces
)
results
.
push_back
(
std
::
move
(
p
.
second
));
else
if
(
auto
err
=
parse
(
host
,
host_addr
))
find_by_name
(
interfaces
,
host
,
results
);
else
find_by_addr
(
interfaces
,
host_addr
,
results
);
return
results
;
}
std
::
string
hostname
()
{
char
buf
[
HOST_NAME_MAX
+
1
];
buf
[
HOST_NAME_MAX
]
=
'\0'
;
gethostname
(
buf
,
HOST_NAME_MAX
);
struct
hostent
*
h
;
h
=
gethostbyname
(
buf
);
return
std
::
string
{
buf
};
}
}
// namespace ip
}
// namespace net
}
// namespace caf
libcaf_net/src/stream_socket.cpp
View file @
d17f4394
...
...
@@ -10,6 +10,7 @@
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
...
...
@@ -21,6 +22,7 @@
#include "caf/detail/net_syscall.hpp"
#include "caf/detail/socket_sys_aliases.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/expected.hpp"
#include "caf/logger.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/socket_guard.hpp"
...
...
libcaf_net/src/tcp.cpp
→
libcaf_net/src/tcp
_accept_socket
.cpp
View file @
d17f4394
...
...
@@ -16,44 +16,26 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/net/tcp.hpp"
#include "caf/net/tcp
_accept_socket
.hpp"
#include "caf/detail/net_syscall.hpp"
#include "caf/detail/sockaddr_members.hpp"
#include "caf/detail/socket_sys_aliases.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/expected.hpp"
#include "caf/ip_address.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/logger.hpp"
#include "caf/net/i
nterfaces
.hpp"
#include "caf/net/i
p
.hpp"
#include "caf/net/socket_guard.hpp"
#include "caf/net/tcp_stream_socket.hpp"
#include "caf/sec.hpp"
namespace
caf
{
namespace
net
{
namespace
{
auto
addr_of
(
sockaddr_in
&
what
)
->
decltype
(
what
.
sin_addr
)
&
{
return
what
.
sin_addr
;
}
auto
family_of
(
sockaddr_in
&
what
)
->
decltype
(
what
.
sin_family
)
&
{
return
what
.
sin_family
;
}
auto
port_of
(
sockaddr_in
&
what
)
->
decltype
(
what
.
sin_port
)
&
{
return
what
.
sin_port
;
}
auto
addr_of
(
sockaddr_in6
&
what
)
->
decltype
(
what
.
sin6_addr
)
&
{
return
what
.
sin6_addr
;
}
auto
family_of
(
sockaddr_in6
&
what
)
->
decltype
(
what
.
sin6_family
)
&
{
return
what
.
sin6_family
;
}
auto
port_of
(
sockaddr_in6
&
what
)
->
decltype
(
what
.
sin6_port
)
&
{
return
what
.
sin6_port
;
}
expected
<
void
>
set_inaddr_any
(
socket
,
sockaddr_in
&
sa
)
{
sa
.
sin_addr
.
s_addr
=
INADDR_ANY
;
return
unit
;
...
...
@@ -82,7 +64,7 @@ caf::expected<socket> new_ip_acceptor_impl(uint16_t port, const char* addr,
CAF_NET_SYSCALL
(
"socket"
,
fd
,
==
,
-
1
,
::
socket
(
Family
,
socktype
,
0
));
child_process_inherit
(
fd
,
false
);
// sguard closes the socket in case of exception
socket_guard
sguard
{
fd
}
;
auto
sguard
=
make_socket_guard
(
socket
{
fd
})
;
if
(
reuse_addr
)
{
int
on
=
1
;
CAF_NET_SYSCALL
(
"setsockopt"
,
tmp1
,
!=
,
0
,
...
...
@@ -94,113 +76,59 @@ caf::expected<socket> new_ip_acceptor_impl(uint16_t port, const char* addr,
Family
==
AF_INET
,
sockaddr_in
,
sockaddr_in6
>::
type
;
sockaddr_type
sa
;
memset
(
&
sa
,
0
,
sizeof
(
sockaddr_type
));
family_of
(
sa
)
=
Family
;
detail
::
family_of
(
sa
)
=
Family
;
if
(
any
)
set_inaddr_any
(
fd
,
sa
);
CAF_NET_SYSCALL
(
"inet_pton"
,
tmp
,
!=
,
1
,
inet_pton
(
Family
,
addr
,
&
addr_of
(
sa
)));
port_of
(
sa
)
=
htons
(
port
);
inet_pton
(
Family
,
addr
,
&
detail
::
addr_of
(
sa
)));
detail
::
port_of
(
sa
)
=
htons
(
port
);
CAF_NET_SYSCALL
(
"bind"
,
res
,
!=
,
0
,
bind
(
fd
,
reinterpret_cast
<
sockaddr
*>
(
&
sa
),
static_cast
<
socket_size_type
>
(
sizeof
(
sa
))));
return
sguard
.
release
();
}
template
<
int
Family
>
bool
ip_connect
(
socket
fd
,
const
std
::
string
&
host
,
uint16_t
port
)
{
CAF_LOG_TRACE
(
"Family ="
<<
(
Family
==
AF_INET
?
"AF_INET"
:
"AF_INET6"
)
<<
CAF_ARG
(
fd
.
id
)
<<
CAF_ARG
(
host
));
static_assert
(
Family
==
AF_INET
||
Family
==
AF_INET6
,
"invalid family"
);
using
sockaddr_type
=
typename
std
::
conditional
<
Family
==
AF_INET
,
sockaddr_in
,
sockaddr_in6
>::
type
;
sockaddr_type
sa
;
memset
(
&
sa
,
0
,
sizeof
(
sockaddr_type
));
inet_pton
(
Family
,
host
.
c_str
(),
&
addr_of
(
sa
));
family_of
(
sa
)
=
Family
;
port_of
(
sa
)
=
htons
(
port
);
using
sa_ptr
=
const
sockaddr
*
;
return
::
connect
(
fd
.
id
,
reinterpret_cast
<
sa_ptr
>
(
&
sa
),
sizeof
(
sa
))
==
0
;
}
}
// namespace
expected
<
stream_socket
>
tcp
::
make_accept_socket
(
uint16_t
port
,
const
char
*
addr
,
bool
reuse_addr
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
port
)
<<
", addr = "
<<
(
addr
?
addr
:
"nullptr"
));
auto
addrs
=
interfaces
::
server_address
(
port
,
addr
);
auto
addr_str
=
std
::
string
{
addr
==
nullptr
?
""
:
addr
};
if
(
addrs
.
empty
())
return
make_error
(
sec
::
cannot_open_port
,
"No local interface available"
,
addr_str
);
bool
any
=
addr_str
.
empty
()
||
addr_str
==
"::"
||
addr_str
==
"0.0.0.0"
;
socket
fd
=
invalid_socket
;
for
(
auto
&
elem
:
addrs
)
{
auto
hostname
=
elem
.
first
.
c_str
();
auto
p
=
elem
.
second
==
ip
::
v4
?
new_ip_acceptor_impl
<
AF_INET
>
(
port
,
hostname
,
reuse_addr
,
any
)
:
new_ip_acceptor_impl
<
AF_INET6
>
(
port
,
hostname
,
reuse_addr
,
any
);
if
(
!
p
)
{
CAF_LOG_DEBUG
(
p
.
error
());
continue
;
}
fd
=
*
p
;
break
;
}
if
(
fd
==
invalid_socket_id
)
{
expected
<
tcp_accept_socket
>
make_accept_socket
(
ip_address
addr
,
uint16_t
port
,
bool
reuse_addr
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
port
)
<<
", addr = "
<<
to_string
(
addr
));
auto
h
=
addr
.
embeds_v4
()
?
to_string
(
addr
.
embedded_v4
())
:
to_string
(
addr
);
bool
any
=
addr
.
zero
();
auto
p
=
addr
.
embeds_v4
()
?
new_ip_acceptor_impl
<
AF_INET
>
(
port
,
h
.
c_str
(),
reuse_addr
,
any
)
:
new_ip_acceptor_impl
<
AF_INET6
>
(
port
,
h
.
c_str
(),
reuse_addr
,
any
);
if
(
!
p
)
{
CAF_LOG_WARNING
(
"could not open tcp socket on:"
<<
CAF_ARG
(
port
)
<<
CAF_ARG
(
addr_str
));
<<
CAF_ARG
(
h
));
return
make_error
(
sec
::
cannot_open_port
,
"tcp socket creation failed"
,
port
,
addr_str
);
h
);
}
socket_guard
sguard
{
fd
};
auto
fd
=
socket_cast
<
tcp_accept_socket
>
(
*
p
);
auto
sguard
=
make_socket_guard
(
fd
);
CAF_NET_SYSCALL
(
"listen"
,
tmp
,
!=
,
0
,
listen
(
fd
.
id
,
SOMAXCONN
));
// ok, no errors so far
CAF_LOG_DEBUG
(
CAF_ARG
(
fd
.
id
));
return
s
ocket_cast
<
stream_socket
>
(
sguard
.
release
()
);
return
s
guard
.
release
(
);
}
expected
<
stream_socket
>
tcp
::
make_connected_socket
(
std
::
string
host
,
uint16_t
port
,
optional
<
ip
>
preferred
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
)
<<
CAF_ARG
(
preferred
));
CAF_LOG_DEBUG
(
"try to connect to:"
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
auto
res
=
interfaces
::
native_address
(
host
,
std
::
move
(
preferred
));
if
(
!
res
)
{
CAF_LOG_DEBUG
(
"no such host"
);
return
make_error
(
sec
::
cannot_connect_to_node
,
"no such host"
,
host
,
port
);
}
auto
proto
=
res
->
second
;
CAF_ASSERT
(
proto
==
ip
::
v4
||
proto
==
ip
::
v6
);
int
socktype
=
SOCK_STREAM
;
#ifdef SOCK_CLOEXEC
socktype
|=
SOCK_CLOEXEC
;
#endif
CAF_NET_SYSCALL
(
"socket"
,
fd
,
==
,
-
1
,
::
socket
(
proto
==
ip
::
v4
?
AF_INET
:
AF_INET6
,
socktype
,
0
));
child_process_inherit
(
fd
,
false
);
socket_guard
sguard
(
fd
);
if
(
proto
==
ip
::
v6
)
{
if
(
ip_connect
<
AF_INET6
>
(
fd
,
res
->
first
,
port
))
{
CAF_LOG_INFO
(
"successfully connected to (IPv6):"
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
return
socket_cast
<
stream_socket
>
(
sguard
.
release
());
}
sguard
.
close
();
// IPv4 fallback
return
make_connected_socket
(
host
,
port
,
ip
::
v4
);
}
if
(
!
ip_connect
<
AF_INET
>
(
fd
,
res
->
first
,
port
))
{
CAF_LOG_WARNING
(
"could not connect to:"
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
return
make_error
(
sec
::
cannot_connect_to_node
,
"ip_connect failed"
,
host
,
port
);
expected
<
tcp_accept_socket
>
make_accept_socket
(
const
uri
::
authority_type
&
auth
,
bool
reuse_addr
)
{
if
(
auto
ip
=
get_if
<
ip_address
>
(
&
auth
.
host
))
return
make_accept_socket
(
*
ip
,
auth
.
port
,
reuse_addr
);
auto
host
=
get
<
std
::
string
>
(
auth
.
host
);
auto
addrs
=
ip
::
local_addrs
(
host
);
if
(
addrs
.
empty
())
return
make_error
(
sec
::
cannot_open_port
,
"No local interface available"
,
to_string
(
auth
));
for
(
auto
&
addr
:
addrs
)
{
if
(
auto
sock
=
make_accept_socket
(
addr
,
auth
.
port
,
reuse_addr
))
return
*
sock
;
}
CAF_LOG_INFO
(
"successfully connected to (IPv4):"
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
return
socket_cast
<
stream_socket
>
(
sguard
.
release
());
return
make_error
(
sec
::
cannot_open_port
,
"tcp socket creation failed"
,
to_string
(
auth
));
}
expected
<
stream_socket
>
tcp
::
accept
(
stream
_socket
x
)
{
expected
<
tcp_stream_socket
>
accept
(
tcp_accept
_socket
x
)
{
auto
sck
=
::
accept
(
x
.
id
,
nullptr
,
nullptr
);
if
(
sck
==
net
::
invalid_socket_id
)
{
auto
err
=
net
::
last_socket_error
();
...
...
@@ -210,7 +138,7 @@ expected<stream_socket> tcp::accept(stream_socket x) {
}
return
caf
::
make_error
(
sec
::
socket_operation_failed
);
}
return
stream_socket
{
sck
};
return
tcp_
stream_socket
{
sck
};
}
}
// namespace net
...
...
libcaf_net/src/tcp_stream_socket.cpp
0 → 100644
View file @
d17f4394
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/net/tcp_stream_socket.hpp"
#include "caf/detail/net_syscall.hpp"
#include "caf/detail/sockaddr_members.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/expected.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/logger.hpp"
#include "caf/net/ip.hpp"
#include "caf/net/socket_guard.hpp"
#include "caf/sec.hpp"
#include "caf/variant.hpp"
namespace
caf
{
namespace
net
{
namespace
{
template
<
int
Family
>
bool
ip_connect
(
stream_socket
fd
,
std
::
string
host
,
uint16_t
port
)
{
CAF_LOG_TRACE
(
"Family ="
<<
(
Family
==
AF_INET
?
"AF_INET"
:
"AF_INET6"
)
<<
CAF_ARG
(
fd
.
id
)
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
static_assert
(
Family
==
AF_INET
||
Family
==
AF_INET6
,
"invalid family"
);
using
sockaddr_type
=
typename
std
::
conditional
<
Family
==
AF_INET
,
sockaddr_in
,
sockaddr_in6
>::
type
;
sockaddr_type
sa
;
memset
(
&
sa
,
0
,
sizeof
(
sockaddr_type
));
inet_pton
(
Family
,
host
.
c_str
(),
&
detail
::
addr_of
(
sa
));
detail
::
family_of
(
sa
)
=
Family
;
detail
::
port_of
(
sa
)
=
htons
(
port
);
using
sa_ptr
=
const
sockaddr
*
;
return
::
connect
(
fd
.
id
,
reinterpret_cast
<
sa_ptr
>
(
&
sa
),
sizeof
(
sa
))
==
0
;
}
}
// namespace
expected
<
stream_socket
>
make_connected_socket
(
ip_address
host
,
uint16_t
port
)
{
CAF_LOG_DEBUG
(
"try to connect to:"
<<
CAF_ARG
(
to_string
(
host
))
<<
CAF_ARG
(
port
));
auto
proto
=
host
.
embeds_v4
()
?
AF_INET
:
AF_INET6
;
auto
socktype
=
SOCK_STREAM
;
#ifdef SOCK_CLOEXEC
socktype
|=
SOCK_CLOEXEC
;
#endif
CAF_NET_SYSCALL
(
"socket"
,
fd
,
==
,
-
1
,
::
socket
(
proto
,
socktype
,
0
));
child_process_inherit
(
fd
,
false
);
auto
sguard
=
make_socket_guard
(
stream_socket
{
fd
});
if
(
proto
==
AF_INET6
)
{
if
(
ip_connect
<
AF_INET6
>
(
fd
,
to_string
(
host
),
port
))
{
CAF_LOG_INFO
(
"successfully connected to (IPv6):"
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
return
sguard
.
release
();
}
}
else
if
(
ip_connect
<
AF_INET
>
(
fd
,
to_string
(
host
.
embedded_v4
()),
port
))
{
return
sguard
.
release
();
}
CAF_LOG_WARNING
(
"could not connect to:"
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
sguard
.
close
();
return
make_error
(
sec
::
cannot_connect_to_node
);
}
expected
<
stream_socket
>
make_connected_socket
(
const
uri
::
authority_type
&
auth
)
{
auto
port
=
auth
.
port
;
if
(
port
==
0
)
return
make_error
(
sec
::
cannot_connect_to_node
,
"port is zero"
);
std
::
vector
<
ip_address
>
addrs
;
if
(
auto
str
=
get_if
<
std
::
string
>
(
&
auth
.
host
))
addrs
=
ip
::
resolve
(
std
::
move
(
*
str
));
else
if
(
auto
addr
=
get_if
<
ip_address
>
(
&
auth
.
host
))
addrs
.
push_back
(
*
addr
);
if
(
addrs
.
empty
())
return
make_error
(
sec
::
cannot_connect_to_node
,
"empty authority"
);
for
(
auto
&
addr
:
addrs
)
{
if
(
auto
sock
=
make_connected_socket
(
addr
,
port
))
return
*
sock
;
}
return
make_error
(
sec
::
cannot_connect_to_node
,
to_string
(
auth
));
}
}
// namespace net
}
// namespace caf
libcaf_net/test/doorman.cpp
View file @
d17f4394
...
...
@@ -19,10 +19,13 @@
#define CAF_SUITE doorman
#include "caf/policy/doorman.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/make_endpoint_manager.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/tcp.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/uri.hpp"
#include "caf/net/ip.hpp"
#include "caf/test/dsl.hpp"
...
...
@@ -38,6 +41,8 @@ struct fixture : test_coordinator_fixture<>, host_fixture {
mpx
=
std
::
make_shared
<
multiplexer
>
();
if
(
auto
err
=
mpx
->
init
())
CAF_FAIL
(
"mpx->init failed: "
<<
sys
.
render
(
err
));
auth
.
port
=
0
;
auth
.
host
=
std
::
string
{
"0.0.0.0"
};
}
bool
handle_io_event
()
override
{
...
...
@@ -46,6 +51,7 @@ struct fixture : test_coordinator_fixture<>, host_fixture {
}
multiplexer_ptr
mpx
;
uri
::
authority_type
auth
;
};
class
dummy_application
{
...
...
@@ -113,11 +119,14 @@ public:
CAF_TEST_FIXTURE_SCOPE
(
doorman_tests
,
fixture
)
CAF_TEST
(
tcp
connect
)
{
auto
acceptor
=
unbox
(
tcp
::
make_accept_socket
(
0
,
nullptr
,
false
));
auto
acceptor
=
unbox
(
make_accept_socket
(
auth
,
false
));
auto
port
=
unbox
(
local_port
(
socket_cast
<
network_socket
>
(
acceptor
)));
CAF_MESSAGE
(
"opened acceptor on port "
<<
port
);
auto
con_fd
=
unbox
(
tcp
::
make_connected_socket
(
"localhost"
,
port
));
auto
acc_fd
=
unbox
(
tcp
::
accept
(
acceptor
));
uri
::
authority_type
dst
;
dst
.
port
=
port
;
dst
.
host
=
std
::
string
{
"localhost"
};
auto
con_fd
=
unbox
(
make_connected_socket
(
dst
));
auto
acc_fd
=
unbox
(
accept
(
acceptor
));
CAF_MESSAGE
(
"accepted connection"
);
close
(
con_fd
);
close
(
acc_fd
);
...
...
@@ -125,7 +134,7 @@ CAF_TEST(tcp connect) {
}
CAF_TEST
(
doorman
accept
)
{
auto
acceptor
=
unbox
(
tcp
::
make_accept_socket
(
0
,
nullptr
,
false
));
auto
acceptor
=
unbox
(
make_accept_socket
(
auth
,
false
));
auto
port
=
unbox
(
local_port
(
socket_cast
<
network_socket
>
(
acceptor
)));
CAF_MESSAGE
(
"opened acceptor on port "
<<
port
);
auto
mgr
=
make_endpoint_manager
(
mpx
,
sys
,
policy
::
doorman
{
acceptor
},
...
...
@@ -134,7 +143,10 @@ CAF_TEST(doorman accept) {
handle_io_event
();
auto
before
=
mpx
->
num_socket_managers
();
CAF_MESSAGE
(
"connecting to doorman"
);
auto
fd
=
unbox
(
tcp
::
make_connected_socket
(
"localhost"
,
port
));
uri
::
authority_type
dst
;
dst
.
port
=
port
;
dst
.
host
=
std
::
string
{
"localhost"
};
auto
fd
=
unbox
(
make_connected_socket
(
dst
));
CAF_MESSAGE
(
"waiting for connection"
);
while
(
mpx
->
num_socket_managers
()
!=
before
+
1
)
handle_io_event
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment