Commit 068470bb authored by Dominik Charousset's avatar Dominik Charousset

Fix MinGW build

Fix some issues with CAF on MinGW:
- Correctly initialize networking on Windows using WSAStartup()
- Rename `interface` member function to `message_types` because `interface` is
  a define on Windows (srsly Microsoft?)
- Cast to correct pointer type when using `send` or `recv`
- Fix some warnings caused by using `int` instead of `native_socket_t`

  The issues have been reported by GitHub user xmt.
parent e1643bbb
......@@ -7,6 +7,13 @@
* - ./build/bin/broker -c localhost 4242 *
\ ******************************************************************************/
#ifdef WIN32
# define _WIN32_WINNT 0x0600
# include <Winsock2.h>
#else
# include <arpa/inet.h> // htonl
#endif
#include <vector>
#include <string>
#include <limits>
......@@ -15,12 +22,6 @@
#include <cassert>
#include <iostream>
#ifdef WIN32
#include <Winsock2.h>
#else
#include <arpa/inet.h> // htonl
#endif
#include "caf/all.hpp"
#include "caf/io/all.hpp"
......
......@@ -168,10 +168,10 @@ class abstract_actor : public abstract_channel {
}
/**
* Returns the type interface as set of strings or an empty set
* if this actor is untyped.
* Returns the set of accepted messages types as strings or
* an empty set if this actor is untyped.
*/
virtual std::set<std::string> interface() const;
virtual std::set<std::string> message_types() const;
protected:
/**
......
......@@ -95,7 +95,11 @@ class actor_addr : detail::comparable<actor_addr>,
*/
bool is_remote() const;
std::set<std::string> interface() const;
/**
* Returns the set of accepted messages types as strings or
* an empty set if this actor is untyped.
*/
std::set<std::string> message_types() const;
private:
......
......@@ -130,7 +130,7 @@ class typed_actor
return m_ptr ? 1 : 0;
}
static std::set<std::string> get_interface() {
static std::set<std::string> get_message_types() {
return {detail::to_uniform_name<Rs>()...};
}
......
......@@ -38,9 +38,9 @@ namespace caf {
* @extends local_actor
*/
template <class... Rs>
class typed_event_based_actor
: public extend<local_actor, typed_event_based_actor<Rs...>>::template with<
mixin::mailbox_based,
class typed_event_based_actor : public
extend<local_actor, typed_event_based_actor<Rs...>>::template
with<mixin::mailbox_based,
mixin::behavior_stack_based<typed_behavior<Rs...>>::template impl,
mixin::sync_sender<nonblocking_response_handle_tag>::template impl> {
public:
......@@ -52,7 +52,7 @@ class typed_event_based_actor
using behavior_type = typed_behavior<Rs...>;
std::set<std::string> interface() const override {
std::set<std::string> message_types() const override {
return {detail::to_uniform_name<Rs>()...};
}
......
......@@ -217,7 +217,7 @@ void abstract_actor::cleanup(uint32_t reason) {
}
}
std::set<std::string> abstract_actor::interface() const {
std::set<std::string> abstract_actor::message_types() const {
// defaults to untyped
return std::set<std::string>{};
}
......
......@@ -66,8 +66,8 @@ bool actor_addr::is_remote() const {
return m_ptr ? m_ptr->is_remote() : false;
}
std::set<std::string> actor_addr::interface() const {
return !m_ptr ? std::set<std::string>{} : m_ptr->interface();
std::set<std::string> actor_addr::message_types() const {
return !m_ptr ? std::set<std::string>{} : m_ptr->message_types();
}
} // namespace caf
......@@ -172,7 +172,7 @@ std::vector<std::string> get_mac_addresses() {
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#include "caf/singletons.hpp"
#include "caf/detail/singletons.hpp"
namespace {
......
......@@ -63,39 +63,16 @@
# ifndef POLLRDHUP
# define POLLRDHUP POLLHUP
# endif
namespace caf {
namespace io {
namespace network {
constexpr short input_mask = POLLIN | POLLPRI;
constexpr short error_mask = POLLRDHUP | POLLERR | POLLHUP | POLLNVAL;
constexpr short output_mask = POLLOUT;
class event_handler;
using multiplexer_data = pollfd;
using multiplexer_poll_shadow_data = std::vector<event_handler*>;
} // namespace network
} // namespace io
} // namespace caf
#else
# define CAF_EPOLL_MULTIPLEXER
# include <sys/epoll.h>
namespace caf {
namespace io {
namespace network {
constexpr int input_mask = EPOLLIN;
constexpr int error_mask = EPOLLRDHUP | EPOLLERR | EPOLLHUP;
constexpr int output_mask = EPOLLOUT;
using multiplexer_data = epoll_event;
using multiplexer_poll_shadow_data = int;
} // namespace network
} // namespace io
} // namespace caf
#endif
namespace caf {
namespace io {
namespace network {
// some more annoying platform-dependent bootstrapping
// annoying platform-dependent bootstrapping
#ifdef CAF_WINDOWS
using native_socket_t = SOCKET;
using setsockopt_ptr = const char*;
......@@ -124,6 +101,23 @@ namespace network {
constexpr int ec_interrupted_syscall = EINTR;
#endif
// poll vs epoll backend
#if !defined(CAF_LINUX) || defined(CAF_POLL_IMPL) // poll() multiplexer
constexpr short input_mask = POLLIN | POLLPRI;
constexpr short error_mask = POLLRDHUP | POLLERR | POLLHUP | POLLNVAL;
constexpr short output_mask = POLLOUT;
class event_handler;
using multiplexer_data = pollfd;
using multiplexer_poll_shadow_data = std::vector<event_handler*>;
#else
# define CAF_EPOLL_MULTIPLEXER
constexpr int input_mask = EPOLLIN;
constexpr int error_mask = EPOLLRDHUP | EPOLLERR | EPOLLHUP;
constexpr int output_mask = EPOLLOUT;
using multiplexer_data = epoll_event;
using multiplexer_poll_shadow_data = native_socket_t;
#endif
/**
* Platform-specific native socket type.
*/
......@@ -315,6 +309,9 @@ class multiplexer {
private:
// platform-dependent additional initialization code
void init();
template <class F>
void new_event(F fun, operation op, native_socket fd, event_handler* ptr) {
CAF_REQUIRE(fd != invalid_socket);
......
......@@ -40,7 +40,7 @@ struct typed_remote_actor_helper<detail::type_list<Ts...>> {
using return_type = typed_actor<Ts...>;
template <class... Vs>
return_type operator()(Vs&&... vs) {
auto iface = return_type::get_interface();
auto iface = return_type::get_message_types();
auto tmp = remote_actor_impl(std::forward<Vs>(vs)..., std::move(iface));
return actor_cast<return_type>(tmp);
}
......
......@@ -552,7 +552,7 @@ void basp_broker::init_handshake_as_sever(connection_context& ctx,
{ // lifetime scope of first serializer
binary_serializer bs1(std::back_inserter(buf), &m_namespace);
bs1 << addr.id();
auto sigs = addr.interface();
auto sigs = addr.message_types();
bs1 << static_cast<uint32_t>(sigs.size());
for (auto& sig : sigs)
bs1 << sig;
......
......@@ -166,7 +166,7 @@ namespace network {
a.inaddr.sin_port = 0;
bool success = false;
// makes sure all sockets are closed in case of an error
auto guard = util::make_scope_guard([&] {
auto guard = detail::make_scope_guard([&] {
if (success) {
return; // everyhting's fine
}
......@@ -219,6 +219,7 @@ namespace network {
// registered to epoll.
multiplexer::multiplexer() : m_epollfd(invalid_socket), m_shadow(1) {
init();
m_epollfd = epoll_create1(EPOLL_CLOEXEC);
if (m_epollfd == -1) {
CAF_LOG_ERROR("epoll_create1: " << strerror(errno));
......@@ -333,6 +334,7 @@ namespace network {
// i.e., O(1), access the actual object when handling socket events.
multiplexer::multiplexer() : m_epollfd(-1) {
init();
// initial setup
m_pipe = create_pipe();
pollfd pipefd;
......@@ -351,7 +353,7 @@ namespace network {
// altering the pollset while traversing it is not exactly a
// bright idea ...
struct fd_event {
int fd; // our file descriptor
native_socket_t fd; // our file descriptor
short mask; // the event mask returned by poll()
short fd_mask; // the mask associated with fd
event_handler* ptr; // nullptr in case of a pipe event
......@@ -394,8 +396,7 @@ namespace network {
if (pfd.revents != 0) {
CAF_LOG_DEBUG("event on socket " << pfd.fd
<< ", revents = " << pfd.revents);
poll_res.push_back({pfd.fd, pfd.revents,
pfd.events, m_shadow[i]});
poll_res.push_back({pfd.fd, pfd.revents, pfd.events, m_shadow[i]});
pfd.revents = 0;
--presult; // stop as early as possible
}
......@@ -534,7 +535,8 @@ void multiplexer::wr_dispatch_request(runnable* ptr) {
intptr_t ptrval = reinterpret_cast<intptr_t>(ptr);
// on windows, we actually have sockets, otherwise we have file handles
# ifdef CAF_WINDOWS
::send(m_pipe.second, &ptrval, sizeof(ptrval), 0);
::send(m_pipe.second, reinterpret_cast<socket_send_ptr>(&ptrval),
sizeof(ptrval), 0);
# else
::write(m_pipe.second, &ptrval, sizeof(ptrval));
# endif
......@@ -544,7 +546,8 @@ multiplexer::runnable* multiplexer::rd_dispatch_request() {
intptr_t ptrval;
// on windows, we actually have sockets, otherwise we have file handles
# ifdef CAF_WINDOWS
::recv(m_pipe.first, &ptrval, sizeof(ptrval), 0);
::recv(m_pipe.first, reinterpret_cast<socket_recv_ptr>(&ptrval),
sizeof(ptrval), 0);
# else
::read(m_pipe.first, &ptrval, sizeof(ptrval));
# endif
......@@ -604,8 +607,20 @@ void multiplexer::handle_socket_event(native_socket fd, int mask,
}
}
void multiplexer::init() {
# ifdef CAF_WINDOWS
WSADATA WinsockData;
if (WSAStartup(MAKEWORD(2, 2), &WinsockData) != 0) {
CAF_CRITICAL("WSAStartup failed");
}
# endif
}
multiplexer::~multiplexer() {
if (m_epollfd != -1) {
# ifdef CAF_WINDOWS
WSACleanup();
# endif
if (m_epollfd != invalid_socket) {
closesocket(m_epollfd);
}
closesocket(m_pipe.first);
......
......@@ -178,7 +178,7 @@ void test_event_testee() {
"caf::replies_to<@str>::with<void>",
"caf::replies_to<float>::with<void>",
"caf::replies_to<@i32>::with<@i32>"};
CAF_CHECK_EQUAL(join(sub_et->interface(), ","), join(iface, ","));
CAF_CHECK_EQUAL(join(sub_et->message_types(), ","), join(iface, ","));
self->send(sub_et, get_state_msg{});
// we expect three 42s
int i = 0;
......@@ -224,10 +224,11 @@ string_actor::behavior_type simple_string_reverter() {
void test_simple_string_reverter() {
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(
simple_relay, spawn_typed(simple_string_reverter), true);
auto aut = self->spawn_typed<monitored>(simple_relay,
spawn_typed(simple_string_reverter),
true);
set<string> iface{"caf::replies_to<@str>::with<@str>"};
CAF_CHECK(aut->interface() == iface);
CAF_CHECK(aut->message_types() == iface);
self->sync_send(aut, "Hello World!").await([](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
});
......
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