63 lines
2.4 KiB
C++
63 lines
2.4 KiB
C++
|
#include "SocketService.h"
|
||
|
#include "ErrorCode.h"
|
||
|
#include <boost/assert.hpp>
|
||
|
#include <zmq.h>
|
||
|
|
||
|
#include "BoostLog.h"
|
||
|
|
||
|
namespace ZeroMQ {
|
||
|
SocketService::SocketService(boost::asio::io_context &context) : boost::asio::io_context::service(context) {
|
||
|
m_context = zmq_ctx_new();
|
||
|
}
|
||
|
|
||
|
SocketService::~SocketService() { zmq_ctx_term(m_context); }
|
||
|
|
||
|
void SocketService::construct(ImplementationType &impl, SocketType type) {
|
||
|
impl = std::make_shared<Implementation>(m_context, type, get_io_context());
|
||
|
}
|
||
|
|
||
|
void SocketService::destroy(ImplementationType &impl) { impl.reset(); }
|
||
|
|
||
|
void SocketService::connect(ImplementationType &impl, std::string_view endpoint, boost::system::error_code &error) {
|
||
|
std::lock_guard lock_guard(impl->mutex);
|
||
|
BOOST_ASSERT_MSG(impl->socket, "invalid socket");
|
||
|
auto status = zmq_connect(impl->socket, endpoint.data());
|
||
|
if (status < 0) error = makeErrorCode();
|
||
|
}
|
||
|
|
||
|
void SocketService::setOption(SocketService::ImplementationType &impl, int option, const void *optval, size_t optvallen,
|
||
|
boost::system::error_code &error) {
|
||
|
int status = zmq_setsockopt(impl->socket, option, optval, optvallen);
|
||
|
if (status < 0) error = makeErrorCode();
|
||
|
}
|
||
|
|
||
|
void SocketService::option(const ImplementationType &impl, int option, void *optval, size_t *optvallen,
|
||
|
boost::system::error_code &error) {
|
||
|
int rc = zmq_getsockopt(impl->socket, option, optval, optvallen);
|
||
|
if (rc != 0) error = makeErrorCode();
|
||
|
}
|
||
|
|
||
|
SocketService::Implementation::Implementation(void *context, SocketType type, boost::asio::io_context &ioContext) {
|
||
|
socket = zmq_socket(context, static_cast<int>(type));
|
||
|
NativeHandleType handle = 0;
|
||
|
auto size = sizeof(handle);
|
||
|
auto rc = zmq_getsockopt(socket, ZMQ_FD, &handle, &size);
|
||
|
if (rc < 0) {
|
||
|
throw makeErrorCode();
|
||
|
}
|
||
|
#if !defined BOOST_ASIO_WINDOWS
|
||
|
descriptor.reset(new StreamType(ioContext, handle));
|
||
|
#else
|
||
|
// Use duplicated SOCKET, because ASIO socket takes ownership over it so destroys one in dtor.
|
||
|
::WSAPROTOCOL_INFOW pi;
|
||
|
::WSADuplicateSocketW(handle, ::GetCurrentProcessId(), &pi);
|
||
|
handle = ::WSASocketW(pi.iAddressFamily /*AF_INET*/, pi.iSocketType /*SOCK_STREAM*/, pi.iProtocol /*IPPROTO_TCP*/,
|
||
|
&pi, 0, 0);
|
||
|
descriptor.reset(new boost::asio::ip::tcp::socket(ioContext, boost::asio::ip::tcp::v4(), handle));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
SocketService::Implementation::~Implementation() { zmq_close(socket); }
|
||
|
|
||
|
} // namespace ZeroMQ
|