#include "SocketService.h" #include "ErrorCode.h" #include #include #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(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(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