Commit 69756788 authored by Jon Siwek's avatar Jon Siwek

Set CLOEXEC flag on socket/accept/pipe calls

parent 5b0e9dd5
...@@ -101,7 +101,11 @@ namespace detail { ...@@ -101,7 +101,11 @@ namespace detail {
std::vector<iface_info> get_mac_addresses() { std::vector<iface_info> get_mac_addresses() {
// get a socket handle // get a socket handle
int sck = socket(AF_INET, SOCK_DGRAM, 0); int socktype = SOCK_DGRAM;
#ifdef SOCK_CLOEXEC
socktype |= SOCK_CLOEXEC;
#endif
int sck = socket(AF_INET, socktype, 0);
if (sck < 0) { if (sck < 0) {
perror("socket"); perror("socket");
return {}; return {};
......
...@@ -83,6 +83,11 @@ std::string last_socket_error_as_string(); ...@@ -83,6 +83,11 @@ std::string last_socket_error_as_string();
/// and the latter is the write handle. /// and the latter is the write handle.
std::pair<native_socket, native_socket> create_pipe(); std::pair<native_socket, native_socket> create_pipe();
/// Sets fd to be inherited by child processes if `new_value == true`
/// or not if `new_value == false`. Not implemented on Windows.
/// throws `network_error` on error
expected<void> child_process_inherit(native_socket fd, bool new_value);
/// Sets fd to nonblocking if `set_nonblocking == true` /// Sets fd to nonblocking if `set_nonblocking == true`
/// or to blocking if `set_nonblocking == false` /// or to blocking if `set_nonblocking == false`
/// throws `network_error` on error /// throws `network_error` on error
......
...@@ -776,8 +776,12 @@ new_tcp_connection(const std::string& host, uint16_t port, ...@@ -776,8 +776,12 @@ new_tcp_connection(const std::string& host, uint16_t port,
} }
auto proto = res->second; auto proto = res->second;
CAF_ASSERT(proto == ipv4 || proto == ipv6); CAF_ASSERT(proto == ipv4 || proto == ipv6);
int socktype = SOCK_STREAM;
#ifdef SOCK_CLOEXEC
socktype |= SOCK_CLOEXEC;
#endif
CALL_CFUN(fd, detail::cc_valid_socket, "socket", CALL_CFUN(fd, detail::cc_valid_socket, "socket",
socket(proto == ipv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0)); socket(proto == ipv4 ? AF_INET : AF_INET6, socktype, 0));
detail::socket_guard sguard(fd); detail::socket_guard sguard(fd);
if (proto == ipv6) { if (proto == ipv6) {
if (ip_connect<AF_INET6>(fd, res->first, port)) { if (ip_connect<AF_INET6>(fd, res->first, port)) {
...@@ -828,7 +832,11 @@ expected<native_socket> new_ip_acceptor_impl(uint16_t port, const char* addr, ...@@ -828,7 +832,11 @@ expected<native_socket> new_ip_acceptor_impl(uint16_t port, const char* addr,
bool reuse_addr, bool any) { bool reuse_addr, bool any) {
static_assert(Family == AF_INET || Family == AF_INET6, "invalid family"); static_assert(Family == AF_INET || Family == AF_INET6, "invalid family");
CAF_LOG_TRACE(CAF_ARG(port) << ", addr = " << (addr ? addr : "nullptr")); CAF_LOG_TRACE(CAF_ARG(port) << ", addr = " << (addr ? addr : "nullptr"));
CALL_CFUN(fd, detail::cc_valid_socket, "socket", socket(Family, SockType, 0)); int socktype = SockType;
#ifdef SOCK_CLOEXEC
socktype |= SOCK_CLOEXEC;
#endif
CALL_CFUN(fd, detail::cc_valid_socket, "socket", socket(Family, socktype, 0));
// sguard closes the socket in case of exception // sguard closes the socket in case of exception
detail::socket_guard sguard{fd}; detail::socket_guard sguard{fd};
if (reuse_addr) { if (reuse_addr) {
......
...@@ -125,6 +125,16 @@ namespace network { ...@@ -125,6 +125,16 @@ namespace network {
return strerror(errno); return strerror(errno);
} }
expected<void> child_process_inherit(native_socket fd, bool new_value) {
CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(new_value));
// read flags for fd
CALL_CFUN(rf, detail::cc_not_minus1, "fcntl", fcntl(fd, F_GETFD));
// calculate and set new flags
auto wf = (! new_value) ? (rf | FD_CLOEXEC) : (rf & (~(FD_CLOEXEC)));
CALL_CFUN(set_res, detail::cc_not_minus1, "fcntl", fcntl(fd, F_SETFD, wf));
return unit;
}
expected<void> nonblocking(native_socket fd, bool new_value) { expected<void> nonblocking(native_socket fd, bool new_value) {
CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(new_value)); CAF_LOG_TRACE(CAF_ARG(fd) << CAF_ARG(new_value));
// read flags for fd // read flags for fd
...@@ -156,6 +166,9 @@ namespace network { ...@@ -156,6 +166,9 @@ namespace network {
perror("pipe"); perror("pipe");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// note pipe2 is better to avoid races in setting CLOEXEC (but not posix)
child_process_inherit(pipefds[0], false);
child_process_inherit(pipefds[1], false);
return {pipefds[0], pipefds[1]}; return {pipefds[0], pipefds[1]};
} }
...@@ -197,6 +210,11 @@ namespace network { ...@@ -197,6 +210,11 @@ namespace network {
return result; return result;
} }
expected<void> child_process_inherit(native_socket fd, bool new_value) {
// nop; FIXME: possible to implement via SetHandleInformation ?
return unit;
}
expected<void> nonblocking(native_socket fd, bool new_value) { expected<void> nonblocking(native_socket fd, bool new_value) {
u_long mode = new_value ? 1 : 0; u_long mode = new_value ? 1 : 0;
CALL_CFUN(res, detail::cc_zero, "ioctlsocket", CALL_CFUN(res, detail::cc_zero, "ioctlsocket",
......
...@@ -71,6 +71,8 @@ bool tcp::try_accept(native_socket& result, native_socket fd) { ...@@ -71,6 +71,8 @@ bool tcp::try_accept(native_socket& result, native_socket fd) {
std::memset(&addr, 0, sizeof(addr)); std::memset(&addr, 0, sizeof(addr));
socket_size_type addrlen = sizeof(addr); socket_size_type addrlen = sizeof(addr);
result = ::accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen); result = ::accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
// note accept4 is better to avoid races in setting CLOEXEC (but not posix)
child_process_inherit(result, false);
CAF_LOG_DEBUG(CAF_ARG(fd) << CAF_ARG(result)); CAF_LOG_DEBUG(CAF_ARG(fd) << CAF_ARG(result));
if (result == invalid_native_socket) { if (result == invalid_native_socket) {
auto err = last_socket_error(); auto err = last_socket_error();
......
...@@ -80,6 +80,8 @@ struct ssl_policy { ...@@ -80,6 +80,8 @@ struct ssl_policy {
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
caf::io::network::socket_size_type addrlen = sizeof(addr); caf::io::network::socket_size_type addrlen = sizeof(addr);
result = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen); result = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
// note accept4 is better to avoid races in setting CLOEXEC (but not posix)
io::network::child_process_inherit(result, false);
CAF_LOG_DEBUG(CAF_ARG(fd) << CAF_ARG(result)); CAF_LOG_DEBUG(CAF_ARG(fd) << CAF_ARG(result));
if (result == io::network::invalid_native_socket) { if (result == io::network::invalid_native_socket) {
auto err = io::network::last_socket_error(); auto err = io::network::last_socket_error();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment