Kylin/AsioZeroMQ/SocketService.cpp
2023-07-21 14:07:27 +08:00

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