Commit 5727f72b authored by Alan Campbell's avatar Alan Campbell

This allows libcppa to compile and run on windows using g++ and MingW.

The examples and tests run. Remaining problems:
1. middleman_event_handler::update runs into "cannot erase " << ptr << " (no such element)" on disconnect of a remote actor.
2. chat example client crashes in windows on connect
backtrace just prints addresses.
added execinfo_windows.h for missing execinfo.h in mingw
uuid from disk partition now implemented.
parent a4f60453
......@@ -39,6 +39,10 @@ if (CMAKE_CXX_FLAGS)
else (CMAKE_CXX_FLAGS)
set(CXXFLAGS_PROVIDED false)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic")
if (MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32")
include (GenerateExportHeader)
endif(MINGW)
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
......@@ -57,7 +61,7 @@ endif (HAVE_VALGRIND_H)
# check for g++ >= 4.7 or clang++ > = 3.2
try_run(ProgramResult
CompilationSucceeded
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/get_compiler_version.cpp
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/get_compiler_version.cpp
RUN_OUTPUT_VARIABLE CompilerVersion)
if (NOT CompilationSucceeded OR NOT ProgramResult EQUAL 0)
message(FATAL_ERROR "Cannot determine compiler version")
......@@ -111,6 +115,8 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(LIBCPPA_PLATFORM_SRC src/middleman_event_handler_epoll.cpp)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBCPPA_PLATFORM_SRC src/middleman_event_handler_poll.cpp)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Window")
set(LIBCPPA_PLATFORM_SRC src/middleman_event_handler_poll.cpp src/backtrace.cpp)
else ()
message(FATAL_ERROR "This platform is not supported by libcppa")
endif()
......@@ -123,7 +129,8 @@ file(GLOB LIBCPPA_HDRS "cppa/*.hpp"
"cppa/io/*.hpp"
"cppa/opencl/*.hpp"
"cppa/qtsupport/*.hpp"
"cppa/util/*.hpp")
"cppa/util/*.hpp"
"cppa/windows/*.hpp")
# list cpp files including platform-dependent files
set(LIBCPPA_SRC
......@@ -199,6 +206,7 @@ set(LIBCPPA_SRC
src/serializer.cpp
src/shared_spinlock.cpp
src/singleton_manager.cpp
src/socketpair.cpp
src/string_serialization.cpp
src/sync_request_bouncer.cpp
src/thread_pool_scheduler.cpp
......@@ -223,6 +231,9 @@ if (APPLE)
# -pthread is ignored on MacOSX
elseif (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
elseif (MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
set(LD_FLAGS "ws2_32 -liphlpapi")
endif ()
if (ENABLE_OPENCL)
......@@ -237,6 +248,13 @@ if (ENABLE_OPENCL)
add_definitions(-DCPPA_OPENCL)
endif (ENABLE_OPENCL)
if (MINGW)
set(LIBCPPA_SRC
${LIBCPPA_SRC}
src/windows/windows_tcp.cpp)
endif (MINGW)
if (DISABLE_MEM_MANAGEMENT)
add_definitions(-DCPPA_DISABLE_MEM_MANAGEMENT)
endif (DISABLE_MEM_MANAGEMENT)
......@@ -285,7 +303,7 @@ if (DISABLE_CONTEXT_SWITCHING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCPPA_DISABLE_CONTEXT_SWITCHING")
endif ()
# bulid shared library if not comiling static only
# build shared library if not compiling static only
if (NOT "${CPPA_BUILD_STATIC_ONLY}" STREQUAL "yes")
add_library(libcppa SHARED ${LIBCPPA_SRC} ${LIBCPPA_HDRS})
target_link_libraries(libcppa ${LD_FLAGS})
......@@ -296,7 +314,9 @@ if (NOT "${CPPA_BUILD_STATIC_ONLY}" STREQUAL "yes")
SOVERSION ${LIBRARY_SOVERSION}
VERSION ${LIBRARY_VERSION}
OUTPUT_NAME cppa)
install(TARGETS libcppa LIBRARY DESTINATION lib)
if(NOT MINGW)
install(TARGETS libcppa LIBRARY DESTINATION lib)
endif()
endif ()
# build static library only if --build-static or --build-static-only was set
......@@ -338,6 +358,8 @@ else ()
#set (CPPA_LIBRARY -L${LIBRARY_OUTPUT_PATH} -lcppa)
elseif (UNIX)
set (CPPA_LIBRARY ${LIBRARY_OUTPUT_PATH}/libcppa.so)
elseif (MINGW)
set (CPPA_LIBRARY ${LIBRARY_OUTPUT_PATH}/libcppa.dll)
else ()
message (SEND_FATAL "Host platform not supported ...")
endif ()
......
This diff is collapsed.
......@@ -66,6 +66,32 @@ void handle_read_result(ssize_t result, bool is_nonblocking_io);
#else
// throws ios_base::failure and adds errno failure if @p add_errno_failure
void throw_io_failure(const char* what, bool add_errno_failure = true);
// returns true if fd is nonblocking
// throws @p ios_base::failure on error
bool nonblocking(native_socket_type fd);
// sets fd to nonblocking if <tt>set_nonblocking == true</tt>
// or to blocking if <tt>set_nonblocking == false</tt>
// throws @p ios_base::failure on error
void nonblocking(native_socket_type fd, bool new_value);
// returns true if fd is nodelay socket
// throws @p ios_base::failure on error
bool tcp_nodelay(native_socket_type fd);
// returns true if fd is nodelay socket
// throws @p ios_base::failure on error
void tcp_nodelay(native_socket_type fd, bool new_value);
// reads @p result and @p errno and throws @p ios_base::failure on error
void handle_write_result(ssize_t result, bool is_nonblocking_io);
// reads @p result and @p errno and throws @p ios_base::failure on error
void handle_read_result(ssize_t result, bool is_nonblocking_io);
#endif
} } } // namespace cppa::detail::fd_util
......
......@@ -44,6 +44,8 @@ namespace cppa { namespace io { class middleman; } }
namespace cppa { namespace opencl { class opencl_metainfo; } }
namespace cppa { namespace windows { class windows_tcp; } }
namespace cppa { namespace detail {
class empty_tuple;
......@@ -80,6 +82,8 @@ class singleton_manager {
static opencl::opencl_metainfo* get_opencl_metainfo();
static windows::windows_tcp* get_windows_tcp();
private:
/*
......
/*
Copyright (c) 2012 mingw-w64 project
Contributing author: Kai Tietz
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
int backtrace (void **buffer, int size);
char ** backtrace_symbols (void *const *buffer, int size);
void backtrace_symbols_fd (void *const *buffer, int size, int fd);
......@@ -197,6 +197,8 @@ class middleman {
};
int dumb_socketpair(native_socket_type socks[2], int make_overlapped);
inline actor_namespace& middleman::get_namespace() {
return m_namespace;
}
......
......@@ -34,7 +34,12 @@
#include <cstring>
#include <sstream>
#include <iostream>
#include <cppa/config.hpp>
#ifdef CPPA_WINDOWS
#include <cppa/execinfo_windows.h>
#else
#include <execinfo.h>
#endif
#include <type_traits>
#include "cppa/singletons.hpp"
......
......@@ -67,9 +67,11 @@ inline detail::empty_tuple* get_empty_tuple() {
return detail::singleton_manager::get_empty_tuple();
}
inline opencl::opencl_metainfo* get_opencl_metainfo() {
return detail::singleton_manager::get_opencl_metainfo();
#ifdef CPPA_WINDOWS
inline windows::windows_tcp* get_windows_tcp() {
return detail::singleton_manager::get_windows_tcp();
}
#endif
} // namespace cppa
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef WINDOWS_TCP_HPP
#define WINDOWS_TCP_HPP
#include <atomic>
#include <vector>
#include <algorithm>
#include <functional>
#include "cppa/cppa.hpp"
#include <winsock2.h>
#include <ws2tcpip.h>
#include "cppa/windows/windows_tcp.hpp"
#include "cppa/detail/singleton_mixin.hpp"
#include "cppa/detail/singleton_manager.hpp"
namespace cppa { namespace windows {
class windows_tcp {
friend class detail::singleton_manager;
private:
static inline windows_tcp* create_singleton() {
return new windows_tcp;
}
void initialize();
void dispose();
void destroy();
};
windows_tcp* get_windows_tcp();
} } // namespace cppa::windows
#endif // WINDOWS_TCP_HPP
......@@ -127,7 +127,11 @@ int main(int argc, char** argv) {
}
},
on("/quit") >> [&] {
#ifndef CPPA_WINDOWS
close(STDIN_FILENO); // close STDIN; causes this match loop to quit
#else
cin.setstate(ios_base::eofbit); // close STDIN; causes this match loop to quit
#endif
},
on<string, anything>().when(_x1.starts_with("/")) >> [&] {
cout << "*** available commands:\n"
......
/*
Copyright (c) 2012 mingw-w64 project
Contributing author: Kai Tietz
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <windows.h>
/*
#include <dbghelp.h>
*/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
int backtrace (void **buffer, int size);
char ** backtrace_symbols (void *const *buffer, int size);
void backtrace_symbols_fd (void *const *buffer, int size, int fd);
int
backtrace (void **buffer, int size)
{
USHORT frames;
HANDLE hProcess;
if (size <= 0)
return 0;
hProcess = GetCurrentProcess ();
frames = CaptureStackBackTrace (0, (DWORD) size, buffer, NULL);
return (int) frames;
}
char **
backtrace_symbols (void *const *buffer, int size)
{
size_t t = 0;
char **r, *cur;
int i;
t = ((size_t) size) * ((sizeof (void *) * 2) + 6 + sizeof (char *));
r = (char **) malloc (t);
if (!r)
return r;
cur = (char *) &r[size];
for (i = 0; i < size; i++)
{
r[i] = cur;
sprintf (cur, "[+0x%Ix]", (size_t) buffer[i]);
cur += strlen (cur) + 1;
}
return r;
}
void
backtrace_symbols_fd (void *const *buffer, int size, int fd)
{
char s[128];
int i;
for (i = 0; i < size; i++)
{
sprintf (s, "[+0x%Ix]\n", (size_t) buffer[i]);
write (fd, s, strlen (s));
}
_commit (fd);
}
/*
void printStack (void);
void printStack (void)
{
unsigned int i;
void *stack[100];
unsigned short frames;
SYMBOL_INFO *symbol;
HANDLE hProcess;
hProcess = GetCurrentProcess ();
SymInitialize (hProcess, NULL, TRUE);
frames = CaptureStackBackTrace( 0, 100, stack, NULL );
symbol = (SYMBOL_INFO *) calloc (sizeof (SYMBOL_INFO) + 256 * sizeof (char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
for (i = 0;i < frames; i++)
{
SymFromAddr (hProcess, (DWORD_PTR) (stack[i]), 0, symbol);
printf ("%u: %p %s = 0x%Ix\n", frames - i - 1, stack[i], symbol->Name, symbol->Address);
}
free (symbol);
}
int main ()
{
printStack ();
return 0;
}
*/
......@@ -29,10 +29,16 @@
#include <sstream>
#include "cppa/config.hpp"
#include "cppa/exception.hpp"
#ifndef CPPA_WINDOWS
#include <sys/socket.h>
#include <sys/un.h>
#else
#include <winerror.h>
#endif
#include <stdlib.h>
#include <errno.h>
......@@ -46,11 +52,19 @@ std::string ae_what(std::uint32_t reason) {
std::string be_what(int err_code) {
switch (err_code) {
#ifndef CPPA_WINDOWS
case EACCES: return "EACCES: address is protected; root access needed";
case EADDRINUSE: return "EADDRINUSE: address is already in use";
case EBADF: return "EBADF: no valid socket descriptor";
case EINVAL: return "EINVAL: socket already bound to an address";
case ENOTSOCK: return "ENOTSOCK: file descriptor given";
#else
case WSAEACCES: return "EACCES: address is protected; root access needed";
case WSAEADDRINUSE: return "EADDRINUSE: address is already in use";
case WSAEBADF: return "EBADF: no valid socket descriptor";
case WSAEINVAL: return "EINVAL: socket already bound to an address";
case WSAENOTSOCK: return "ENOTSOCK: file descriptor given";
#endif
default: break;
}
std::stringstream oss;
......
......@@ -112,5 +112,74 @@ void handle_read_result(ssize_t res, bool is_nonblock) {
} } } // namespace cppa::detail::fd_util
#else
// windows
#include <winsock2.h>
namespace cppa { namespace detail { namespace fd_util {
void throw_io_failure(const char* what, bool add_errno_failure) {
if (add_errno_failure) {
std::ostringstream oss;
oss << what << ": " << strerror(errno)
<< " [errno: " << errno << "]";
throw std::ios_base::failure(oss.str());
}
throw std::ios_base::failure(what);
}
// int rd_flags(native_socket_type fd) {
// auto flags = ioctlsocket(fd, F_GETFL, 0);
// if (flags == -1) throw_io_failure("unable to read socket flags");
// return flags;
// }
// bool nonblocking(native_socket_type fd) {
// return (rd_flags(fd) & O_NONBLOCK) != 0;
// }
void nonblocking(native_socket_type fd, bool new_value) {
u_long iMode = new_value ? 1 : 0;
// If iMode = 0, blocking is enabled;
// If iMode != 0, non-blocking mode is enabled.
if (ioctlsocket(fd, FIONBIO, &iMode) < 0) {
throw_io_failure("unable to set FIONBIO");
}
}
bool tcp_nodelay(native_socket_type fd) {
int flag;
auto len = static_cast<int>(sizeof(flag));
if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *> (&flag), &len) < 0) {
throw_io_failure("unable to read TCP_NODELAY socket option");
}
return flag != 0;
}
void tcp_nodelay(native_socket_type fd, bool new_value) {
int flag = new_value ? 1 : 0;
auto len = static_cast<int>(sizeof(flag));
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *> (&flag), len) < 0) {
throw_io_failure("unable to set TCP_NODELAY");
}
}
void handle_io_result(ssize_t res, bool is_nonblock, const char* msg) {
if (res < 0) {
// don't throw for 'failed' non-blocking IO
if (is_nonblock && ( WSAGetLastError() == WSAEWOULDBLOCK)) { }
else throw_io_failure(msg);
}
}
void handle_write_result(ssize_t res, bool is_nonblock) {
handle_io_result(res, is_nonblock, "cannot write to file descriptor");
}
void handle_read_result(ssize_t res, bool is_nonblock) {
handle_io_result(res, is_nonblock, "cannot read from file descriptor");
if (res == 0) throw_io_failure("cannot read from closed file descriptor");
}
} } } // namespace cppa::detail::fd_util
#endif
......@@ -158,5 +158,140 @@ std::vector<std::string> get_mac_addresses() {
} } // namespace cppa::util
#else
// windows
#include <winsock2.h>
#include <vector>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdio.h>
#include <cstring>
//#include <unistd.h>
#include <iostream>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#include "cppa/singletons.hpp"
#include "cppa/windows/windows_tcp.hpp"
// Link with Iphlpapi.lib
// #pragma comment(lib, "IPHLPAPI.lib") -liphlpapi
#define WORKING_BUFFER_SIZE 15000
#define MAX_TRIES 3
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
/* Note: could also use malloc() and free() */
using namespace std;
namespace cppa { namespace util {
std::vector<std::string> get_mac_addresses() {
/* Declare and initialize variables */
DWORD dwRetVal = 0;
unsigned int i = 0;
// Set the flags to pass to GetAdaptersAddresses
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
// default to unspecified address family (both)
ULONG family = AF_UNSPEC;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 0;
ULONG Iterations = 0;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
vector<string> hw_addresses;
// Allocate a 15 KB buffer to start with.
outBufLen = WORKING_BUFFER_SIZE;
cppa::windows::get_windows_tcp();
do {
pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
if (pAddresses == NULL) {
perror("Memory allocation failed for IP_ADAPTER_ADDRESSES struct");
exit(1);
}
dwRetVal =
GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = NULL;
} else {
break;
}
Iterations++;
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
if (dwRetVal == NO_ERROR) {
// If successful, output some information from the data we received
pCurrAddresses = pAddresses;
while (pCurrAddresses) {
if (pCurrAddresses->PhysicalAddressLength != 0) {
std::ostringstream oss;
oss << hex;
for (i = 0; i < (unsigned int) pCurrAddresses->PhysicalAddressLength; i++) {
if (i == (pCurrAddresses->PhysicalAddressLength - 1)) {
oss.width(2);
oss << ((int) pCurrAddresses->PhysicalAddress[i]);
} else {
oss.width(2);
oss << ((int) pCurrAddresses->PhysicalAddress[i]) << ":";
}
}
auto addr = oss.str();
if (addr != "00:00:00:00:00:00") {
hw_addresses.push_back(std::move(addr));
}
}
pCurrAddresses = pCurrAddresses->Next;
}
} else {
if (dwRetVal == ERROR_NO_DATA) {
perror("No addresses were found for the requested parameters");
} else {
perror("Call to GetAdaptersAddresses failed with error");
}
}
if (pAddresses) {
FREE(pAddresses);
}
return hw_addresses;
}
} } // namespace cppa::util
#endif
This diff is collapsed.
......@@ -26,7 +26,11 @@
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/config.hpp"
#ifdef CPPA_WINDOWS
# include <ws2tcpip.h>
# include <winsock2.h>
#endif
#include <ios>
#include <cstring>
......@@ -43,6 +47,10 @@
#include "cppa/detail/fd_util.hpp"
#ifdef CPPA_WINDOWS
# include <winsock2.h>
# include <ws2tcpip.h>
# include "cppa/singletons.hpp"
# include "cppa/windows/windows_tcp.hpp"
#else
# include <netdb.h>
# include <unistd.h>
......@@ -82,8 +90,24 @@ bool accept_impl(stream_ptr_pair& result,
native_socket_type fd,
bool nonblocking) {
sockaddr addr;
#ifdef CPPA_WINDOWS
int addrlen;
#else
socklen_t addrlen;
#endif
memset(&addr, 0, sizeof(addr));
#ifdef CPPA_WINDOWS
addrlen=sizeof(addr); // check this
auto sfd = ::WSAAccept(fd, &addr, &addrlen, 0, 0); // size too small
if (sfd == INVALID_SOCKET) {
if (nonblocking && (WSAGetLastError() == WSATRY_AGAIN || WSAGetLastError() == WSAEWOULDBLOCK)) {
// ok, try again
return false;
}
throw_io_failure("accept failed");
}
#else
memset(&addrlen, 0, sizeof(addrlen));
auto sfd = ::accept(fd, &addr, &addrlen);
if (sfd < 0) {
......@@ -93,6 +117,7 @@ bool accept_impl(stream_ptr_pair& result,
}
throw_io_failure("accept failed");
}
#endif
stream_ptr ptr(ipv4_io_stream::from_native_socket(sfd));
result.first = ptr;
result.second = ptr;
......@@ -109,25 +134,51 @@ std::unique_ptr<acceptor> ipv4_acceptor::create(std::uint16_t port,
CPPA_LOGM_TRACE("ipv4_acceptor", CPPA_ARG(port) << ", addr = "
<< (addr ? addr : "nullptr"));
native_socket_type sockfd;
#ifdef CPPA_WINDOWS
// ensure tcp has been initialized
cppa::windows::get_windows_tcp();
sockfd = INVALID_SOCKET;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == INVALID_SOCKET) {
throw network_error("could not create server socket");
}
#else
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == invalid_socket) {
throw network_error("could not create server socket");
}
#endif
// sguard closes the socket in case of exception
socket_guard sguard(sockfd);
#ifdef CPPA_WINDOWS
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on,sizeof(on)) < 0) {
throw_io_failure("unable to set SO_REUSEADDR");
}
#else
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
throw_io_failure("unable to set SO_REUSEADDR");
}
#endif
struct sockaddr_in serv_addr;
memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
if (! addr) {
serv_addr.sin_addr.s_addr = INADDR_ANY;
}
#ifdef CPPA_WINDOWS
else if (::inet_pton(AF_INET, addr, &serv_addr.sin_addr) <= 0) {
throw network_error("invalid IPv4 address");
}
#else
else if (inet_pton(AF_INET, addr, &serv_addr.sin_addr) <= 0) {
throw network_error("invalid IPv4 address");
}
#endif
serv_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
......
......@@ -33,12 +33,20 @@
#include <errno.h>
#include <iostream>
#include "cppa/config.hpp"
#ifdef CPPA_WINDOWS
# include <ws2tcpip.h>
# include <winsock2.h>
#endif
#include "cppa/logging.hpp"
#include "cppa/exception.hpp"
#include "cppa/detail/fd_util.hpp"
#include "cppa/io/ipv4_io_stream.hpp"
#ifdef CPPA_WINDOWS
# include "cppa/singletons.hpp"
# include "cppa/windows/windows_tcp.hpp"
#else
# include <netdb.h>
# include <unistd.h>
......@@ -48,6 +56,9 @@
# include <netinet/tcp.h>
#endif
namespace cppa { namespace io {
using namespace ::cppa::detail::fd_util;
......@@ -87,7 +98,7 @@ void ipv4_io_stream::read(void* vbuf, size_t len) {
}
size_t ipv4_io_stream::read_some(void* buf, size_t len) {
auto recv_result = ::recv(m_fd, buf, len, 0);
auto recv_result = ::recv(m_fd, reinterpret_cast<char*>(buf), len, 0);
handle_read_result(recv_result, true);
return (recv_result > 0) ? static_cast<size_t>(recv_result) : 0;
}
......@@ -114,7 +125,7 @@ void ipv4_io_stream::write(const void* vbuf, size_t len) {
}
size_t ipv4_io_stream::write_some(const void* buf, size_t len) {
auto send_result = ::send(m_fd, buf, len, 0);
auto send_result = ::send(m_fd, reinterpret_cast<const char*>(buf), len, 0);
handle_write_result(send_result, true);
return static_cast<size_t>(send_result);
}
......@@ -131,6 +142,12 @@ io::stream_ptr ipv4_io_stream::connect_to(const char* host,
CPPA_LOGF_INFO("try to connect to " << host << " on port " << port);
struct sockaddr_in serv_addr;
struct hostent* server;
#ifdef CPPA_WINDOWS
// ensure tcp has been initialized
cppa::get_windows_tcp();
#endif
native_socket_type fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == invalid_socket) {
throw network_error("socket creation failed");
......
......@@ -65,6 +65,11 @@
#include "cppa/intrusive/single_reader_queue.hpp"
#ifdef CPPA_WINDOWS
#include "io.h"
#include "fcntl.h"
#endif
using namespace std;
namespace cppa { namespace io {
......@@ -145,8 +150,12 @@ class middleman_impl : public middleman {
m_queue.enqueue(new middleman_event(move(fun)));
atomic_thread_fence(memory_order_seq_cst);
uint8_t dummy = 0;
auto res = ::write(m_pipe_write, &dummy, sizeof(dummy));
// ignore result; write error only means middleman already exited
#ifdef CPPA_WINDOWS
auto res = ::send(m_pipe_write, (char *)&dummy, sizeof(dummy), 0);
#else
auto res = write(m_pipe_write, &dummy, sizeof(dummy));
#endif
static_cast<void>(res);
}
......@@ -256,8 +265,16 @@ class middleman_impl : public middleman {
protected:
void initialize() override {
#ifdef CPPA_WINDOWS
// if ( CreatePipe(&m_pipe_read,&m_pipe_write,0,4096) ) { CPPA_CRITICAL("cannot create pipe"); }
// DWORD dwMode = PIPE_NOWAIT;
// if ( !SetNamedPipeHandleState(&m_pipe_read,&dwMode,NULL,NULL) ) { CPPA_CRITICAL("cannot set PIPE_NOWAIT"); }
native_socket_type pipefds[2];
if ( cppa::io::dumb_socketpair(pipefds, 0) != 0) { CPPA_CRITICAL("cannot create pipe"); }
#else
int pipefds[2];
if (pipe(pipefds) != 0) { CPPA_CRITICAL("cannot create pipe"); }
#endif
m_pipe_read = pipefds[0];
m_pipe_write = pipefds[1];
detail::fd_util::nonblocking(m_pipe_read, true);
......@@ -271,8 +288,10 @@ class middleman_impl : public middleman {
this->m_done = true;
});
m_thread.join();
close(m_pipe_read);
close(m_pipe_write);
closesocket(m_pipe_read);
closesocket(m_pipe_write);
#
}
private:
......@@ -286,6 +305,7 @@ class middleman_impl : public middleman {
middleman_event_handler& handler();
thread m_thread;
native_socket_type m_pipe_read;
native_socket_type m_pipe_write;
middleman_queue m_queue;
......@@ -306,7 +326,7 @@ class middleman_overseer : public continuable {
public:
middleman_overseer(int pipe_fd, middleman_queue& q)
middleman_overseer(native_socket_type pipe_fd, middleman_queue& q)
: super(pipe_fd), m_queue(q) { }
void dispose() override {
......@@ -317,8 +337,25 @@ class middleman_overseer : public continuable {
CPPA_LOG_TRACE("");
static constexpr size_t num_dummies = 64;
uint8_t dummies[num_dummies];
#ifdef CPPA_WINDOWS
auto read_result = ::recv(read_handle(), (char *)dummies, num_dummies, 0);
#else
auto read_result = ::read(read_handle(), dummies, num_dummies);
#endif
CPPA_LOG_DEBUG("read " << read_result << " messages from queue");
#ifdef CPPA_WINDOWS
if (read_result == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK) {
// try again later
return read_continue_later;
}
else {
CPPA_LOG_ERROR("cannot read from pipe");
CPPA_CRITICAL("cannot read from pipe");
}
}
#else
if (read_result < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// try again later
......@@ -329,6 +366,7 @@ class middleman_overseer : public continuable {
CPPA_CRITICAL("cannot read from pipe");
}
}
#endif
for (int i = 0; i < read_result; ++i) {
unique_ptr<middleman_event> msg(m_queue.try_pop());
if (!msg) {
......
......@@ -32,7 +32,21 @@
#if !defined(CPPA_LINUX) || defined(CPPA_POLL_IMPL)
#ifndef CPPA_WINDOWS
#include <poll.h>
#define SOCKERR errno
#else
# include <ws2tcpip.h>
# include <ws2ipdef.h>
# include <winsock2.h>
#define SOCKERR GetLastError()
#undef EINTR
#undef ENOMEM
#define EINTR WSAEINTR
#define ENOMEM WSAENOBUFS
#endif
#include "cppa/io/middleman_event_handler.hpp"
#ifndef POLLRDHUP
......@@ -73,11 +87,15 @@ class middleman_event_handler_impl : public middleman_event_handler {
CPPA_REQUIRE(m_pollset.size() == m_meta.size());
int presult = -1;
while (presult < 0) {
#ifdef CPPA_WINDOWS
presult = ::WSAPoll(m_pollset.data(), m_pollset.size(), -1);
#else
presult = ::poll(m_pollset.data(), m_pollset.size(), -1);
#endif
CPPA_LOG_DEBUG("poll() on " << num_sockets()
<< " sockets returned " << presult);
if (presult < 0) {
switch (errno) {
switch (SOCKERR) {
case EINTR: {
// a signal was caught
// just try again
......
......@@ -56,6 +56,18 @@ class opencl_metainfo : public detail::singleton_mixin<opencl_metainfo> { };
} } // namespace cppa::opencl
#endif
#ifdef CPPA_WINDOWS
# include "cppa/windows/windows_tcp.hpp"
#else
namespace cppa { namespace windows {
class windows_tcp : public detail::singleton_mixin<windows_tcp> { };
} } // namespace cppa::windows
#endif
namespace cppa { void shutdown() { detail::singleton_manager::shutdown(); } }
namespace cppa { namespace detail {
......@@ -70,6 +82,7 @@ std::atomic<group_manager*> s_group_manager;
std::atomic<empty_tuple*> s_empty_tuple;
std::atomic<scheduler*> s_scheduler;
std::atomic<logging*> s_logger;
std::atomic<windows::windows_tcp*> s_windows_tcp;
} // namespace <anonymous>
......@@ -91,6 +104,11 @@ void singleton_manager::shutdown() {
CPPA_LOGF_DEBUG("clear type info map");
destroy(s_uniform_type_info_map);
destroy(s_logger);
#ifdef CPPA_WINDOWS
CPPA_LOGF_DEBUG("WSACleanup");
destroy(s_windows_tcp);
#endif
}
opencl::opencl_metainfo* singleton_manager::get_opencl_metainfo() {
......@@ -102,7 +120,17 @@ opencl::opencl_metainfo* singleton_manager::get_opencl_metainfo() {
# endif
}
windows::windows_tcp* singleton_manager::get_windows_tcp() {
#ifdef CPPA_WINDOWS
return lazy_get(s_windows_tcp);
# else
CPPA_LOGF_ERROR("libcppa was compiled without windows support");
throw std::logic_error("libcppa was compiled without windows support");
# endif
}
actor_registry* singleton_manager::get_actor_registry() {
return lazy_get(s_actor_registry);
}
......
/* socketpair.c
Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
The name of the author must not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Changes:
* 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements
* git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54
* github.com/GerHobbelt/selectable-socketpair
* always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64
* and UNIX/other platforms
* 2013-07-18: Change to BSD 3-clause license
* 2010-03-31:
* set addr to 127.0.0.1 because win32 getsockname does not always set it.
* 2010-02-25:
* set SO_REUSEADDR option to avoid leaking some windows resource.
* Windows System Error 10049, "Event ID 4226 TCP/IP has reached
* the security limit imposed on the number of concurrent TCP connect
* attempts." Bleah.
* 2007-04-25:
* preserve value of WSAGetLastError() on all error returns.
* 2007-04-22: (Thanks to Matthew Gregan <kinetik@flim.org>)
* s/EINVAL/WSAEINVAL/ fix trivial compile failure
* s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout
* of a child process.
* add argument make_overlapped
*/
#include <string.h>
#ifdef WIN32
# include <ws2tcpip.h> /* socklen_t, et al (MSVC20xx) */
# include <windows.h>
# include <io.h>
# include "cppa/singletons.hpp"
# include "cppa/windows/windows_tcp.hpp"
#else
# include <sys/types.h>
# include <sys/socket.h>
# include <errno.h>
#endif
namespace cppa { namespace io {
#ifdef WIN32
/* dumb_socketpair:
* If make_overlapped is nonzero, both sockets created will be usable for
* "overlapped" operations via WSASend etc. If make_overlapped is zero,
* socks[0] (only) will be usable with regular ReadFile etc., and thus
* suitable for use as stdin or stdout of a child process. Note that the
* sockets must be closed with closesocket() regardless.
*/
int dumb_socketpair(SOCKET socks[2], int make_overlapped)
{
union {
struct sockaddr_in inaddr;
struct sockaddr addr;
} a;
cppa::windows::get_windows_tcp();
SOCKET listener = INVALID_SOCKET;
int e;
socklen_t addrlen = sizeof(a.inaddr);
DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0);
int reuse = 1;
if (socks == 0) {
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
socks[0] = socks[1] = -1;
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listener == INVALID_SOCKET) // -1
return SOCKET_ERROR;
memset(&a, 0, sizeof(a));
a.inaddr.sin_family = AF_INET;
a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
a.inaddr.sin_port = 0;
for (;;) {
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,
(char*) &reuse, (socklen_t) sizeof(reuse)) == -1)
break;
if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
break;
memset(&a, 0, sizeof(a));
if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
break;
// win32 getsockname may only set the port number, p=0.0005.
// ( http://msdn.microsoft.com/library/ms738543.aspx ):
a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
a.inaddr.sin_family = AF_INET;
if (listen(listener, 1) == SOCKET_ERROR)
break;
socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
if (socks[0] == INVALID_SOCKET)
break;
if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
break;
socks[1] = accept(listener, NULL, NULL);
if (socks[1] == INVALID_SOCKET)
break;
closesocket(listener);
return 0;
}
e = WSAGetLastError();
closesocket(listener);
closesocket(socks[0]);
closesocket(socks[1]);
WSASetLastError(e);
socks[0] = socks[1] = -1;
return SOCKET_ERROR;
}
#else
int dumb_socketpair(int socks[2], int dummy)
{
if (socks == 0) {
errno = EINVAL;
return -1;
}
dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, socks);
if (dummy)
socks[0] = socks[1] = -1;
return dummy;
}
#endif
}}
\ No newline at end of file
......@@ -37,7 +37,9 @@
#include <iostream>
#include <stdexcept>
#ifndef CPPA_WINDOWS
#include <netinet/tcp.h>
#endif
#include "cppa/cppa.hpp"
#include "cppa/atom.hpp"
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include <atomic>
#include <iostream>
#include "cppa/logging.hpp"
#include "cppa/exception.hpp"
#include "cppa/windows/windows_tcp.hpp"
using namespace std;
namespace cppa { namespace windows {
void windows_tcp::initialize()
{
WSADATA WinsockData;
if (WSAStartup(MAKEWORD(2, 2), &WinsockData) != 0) {
ostringstream oss;
oss << "libcppa WSAStartup failed. ";
CPPA_LOGMF(CPPA_ERROR, oss.str());
throw runtime_error(oss.str());
}
}
void windows_tcp::destroy() {
WSACleanup();
delete this;
}
void windows_tcp::dispose() {
WSACleanup();
delete this;
}
windows_tcp* get_windows_tcp() {
return detail::singleton_manager::get_windows_tcp();
}
} } // namespace cppa::windows
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