VC++ under Windows uses boost::asio + WSAEventSelect + WSACreateEvent to implement async-listen-accept socket-fd

What requirements would lead to giving up using boost::asio::ip::tcp::acceptor directly? to listen and accept socket instances from clients?

Hypothetical scenario:

We need to make the sockets that already know the IPEndPoint address endpoint work under the same context, because this group of sockets will copy data across each other. If we have multiple contexts, it means that there will be thread safety issues. If we frequently Cross-thread post (delivered to the event queue), the additional cost is not low.

If we can put these sockets on the same thread, we don’t need to consider thread safety issues, and can directly avoid lock synchronization and mutual exclusion.

We know that boost:asio::ip::tcp::socket provides a release function to release the attached socket-fd, but there is a problem. In operating systems below Windows 8.1 release version, this function cannot be executed correctly (platform Incompatible), then when considering compatibility, you need to adopt the above solution.

Note: This is just an alternative solution chosen to resolve the differences in platform details. It does not represent much practical significance. It is only for reference for children’s boots in similar scenarios.

head File:

#pragma once

#include <ppp/net/SocketAcceptor.h>

namespace ppp
{
    namespace net
    {
        class Win32SocketAcceptor final : public ppp::net::SocketAcceptor
        {
        public:
            Win32SocketAcceptor() noexcept;
            Win32SocketAcceptor(const std::shared_ptr<boost::asio::io_context> & amp; context) noexcept;
            virtual ~Win32SocketAcceptor() noexcept;

        public:
            virtual bool IsOpen() noexcept;
            virtual bool Open(const char* localIP, int localPort, int backlog) noexcept;
            virtual void Close() noexcept;
            virtual int GetHandle() noexcept;

        private:
            bool Next() noexcept;
            void Finalize() noexcept;

        private:
            int listenfd_;
            void* hEvent_;
            std::shared_ptr<void*> afo_;
            std::shared_ptr<boost::asio::io_context> context_;
        };
    }
}

Source File:

#include <ppp/net/SocketAcceptor.h>
#include <ppp/net/IPEndPoint.h>
#include <ppp/net/Socket.h>
#include <ppp/threading/Executors.h>

#include <windows/ppp/win32/Win32Native.h>
#include <windows/ppp/net/Win32SocketAcceptor.h>

#include <Windows.h>
#include <Iphlpapi.h>

typedef ppp::net::IPEndPoint IPEndPoint;

static struct WINDOWS_SOCKET_INITIALIZATION
{
public:
    WINDOWS_SOCKET_INITIALIZATION() noexcept
    {
        int err = WSAStartup(MAKEWORD(2, 2), & amp;wsadata_);
        assert(err == ERROR_SUCCESS);
    }
    ~WINDOWS_SOCKET_INITIALIZATION() noexcept
    {
        WSACleanup();
    }

private:
    WSADATA wsadata_;
} __WINDOWS_SOCKET_INITIALIZATION__;
/*
 * Exhaust the true love of three lives and three lives in exchange for the beauty of one life
 * Spend three lifetimes of sincerity in exchange for memories of one lifetime
 */
namespace ppp
{
    namespace net
    {
        // Love floats and falls in the world of mortals, but I stay where I am
        Win32SocketAcceptor::Win32SocketAcceptor(const std::shared_ptr<boost::asio::io_context> & amp; context) noexcept
            : listenfd_(INVALID_SOCKET)
            , hEvent_(NULL)
            , afo_(NULL)
            , context_(context)
        {

        }

        Win32SocketAcceptor::Win32SocketAcceptor() noexcept
            : Win32SocketAcceptor(ppp::threading::Executors::GetDefault()) {

        }

        Win32SocketAcceptor::~Win32SocketAcceptor() noexcept
        {
            Finalize();
        }

        bool Win32SocketAcceptor::IsOpen() noexcept
        {
            bool b = NULL != hEvent_ & amp; & amp; NULL != afo_ & amp; & amp; NULL != context_;
            if(b)
            {
                b = listenfd_ != INVALID_SOCKET;
            }
            return b;
        }

        bool Win32SocketAcceptor::Open(const char* localIP, int localPort, int backlog) noexcept
        {
            if (localPort < IPEndPoint::MinPort || localPort > IPEndPoint::MaxPort)
            {
                return false;
            }

            if (NULL == localIP || *localIP == '\x0')
            {
                return false;
            }

            if (listenfd_ != INVALID_SOCKET)
            {
                return false;
            }

            if (NULL != hEvent_)
            {
                return false;
            }

            if (NULL != afo_)
            {
                return false;
            }

            if (NULL == context_)
            {
                return false;
            }

            boost::system::error_code ec;
            boost::asio::ip::address bindIP = boost::asio::ip::address::from_string(localIP, ec);
            if(ec)
            {
                return false;
            }

            if (backlog < 1)
            {
                backlog = PPP_LISTEN_BACKLOG;
            }

            if (bindIP.is_v6())
            {
                struct sockaddr_in6 in6;
                memset( & amp;in6, 0, sizeof(in6));

                in6.sin6_family = AF_INET6;
                in6.sin6_port = htons(localPort);
                if (inet_pton(AF_INET6, localIP, & amp;in6.sin6_addr) < 1)
                {
                    return false;
                }

                listenfd_ = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
                if (listenfd_ == INVALID_SOCKET)
                {
                    return false;
                }

                if (!ppp::net::Socket::ReuseSocketAddress(listenfd_, true))
                {
                    return false;
                }

                BOOL bEnable = FALSE;
                if (setsockopt(listenfd_, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>( & amp;bEnable), sizeof(bEnable)) < 0)
                {
                    return false;
                }

                if (bind(listenfd_, reinterpret_cast<sockaddr*>( & amp;in6), sizeof(in6)) < 0)
                {
                    return false;
                }
            }
            elif(bindIP.is_v4())
            {
                struct sockaddr_in in4;
                memset( & amp;in4, 0, sizeof(in4));

                in4.sin_family = AF_INET;
                in4.sin_port = htons(localPort);
                if (inet_pton(AF_INET, localIP, & amp;in4.sin_addr) < 1)
                {
                    return false;
                }

                listenfd_ = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
                if (listenfd_ == INVALID_SOCKET)
                {
                    return false;
                }

                if (!ppp::net::Socket::ReuseSocketAddress(listenfd_, true))
                {
                    return false;
                }

                if (bind(listenfd_, reinterpret_cast<sockaddr*>( & amp;in4), sizeof(in4)) < 0)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }

            if (listen(listenfd_, backlog) < 0)
            {
                return false;
            }

            hEvent_ = WSACreateEvent();
            if (hEvent_ == WSA_INVALID_EVENT)
            {
                return false;
            }

            if (WSAEventSelect(listenfd_, hEvent_, FD_ACCEPT | FD_CLOSE) != NOERROR)
            {
                return false;
            }

            afo_ = make_shared_void_pointer<boost::asio::windows::object_handle>(*context_, hEvent_);
            return Next();
        }

        void Win32SocketAcceptor::Close() noexcept
        {
            std::shared_ptr<boost::asio::io_context> context = context_;
            if (NULL != context)
            {
                auto self = shared_from_this();
                context->post(
                    [self, this]() noexcept
                    {
                        Finalize();
                    });
            }
        }

        bool Win32SocketAcceptor::Next() noexcept
        {
            boost::asio::windows::object_handle* afo = reinterpret_cast<boost::asio::windows::object_handle*>(afo_.get());
            if (NULL == afo)
            {
                return false;
            }

            int listenfd = listenfd_;
            if (listenfd == INVALID_SOCKET)
            {
                return false;
            }

            void* hEvent = hEvent_;
            if (NULL == hEvent)
            {
                return false;
            }

            std::shared_ptr<SocketAcceptor> self = shared_from_this();
            afo->async_wait(
                [self, this, hEvent, listenfd](const boost::system::error_code & amp; ec) noexcept
                {
                    if (ec == boost::system::errc::operation_canceled) /* WSAWaitForMultipleEvents */
                    {
                        return;
                    }

                    WSANETWORKEVENTS events;
                    if (WSAEnumNetworkEvents(listenfd, hEvent, & amp;events) == NOERROR)
                    {
                        if (events.lNetworkEvents & FD_ACCEPT)
                        {
                            if (events.iErrorCode[FD_ACCEPT_BIT] == 0)
                            {
                                struct sockaddr address = { 0 };
                                int address_size = sizeof(address);
                                int sockfd = accept(listenfd_, & amp;address, & amp;address_size);
                                if (sockfd != INVALID_SOCKET)
                                {
                                    AcceptSocketEventArgs e = { sockfd };
                                    OnAcceptSocket(e);
                                }
                            }
                        }
                        elif(events.lNetworkEvents & FD_CLOSE)
                        {
                            if (events.iErrorCode[FD_ACCEPT_BIT] == 0) /* event is operation_canceled. */
                            {
                                return;
                            }
                        }
                    }

                    Next();
                });
            return true;
        }

        int Win32SocketAcceptor::GetHandle() noexcept
        {
            return listenfd_;
        }

        void Win32SocketAcceptor::Finalize() noexcept
        {
            boost::asio::windows::object_handle* afo = reinterpret_cast<boost::asio::windows::object_handle*>(afo_.get());
            if (NULL != afo)
            {
                boost::system::error_code ec;
                try
                {
                    afo->cancel(ec);
                }
                catch (std::exception & amp;) {}

                try
                {
                    afo->close(ec);
                }
                catch (std::exception & amp;) {}

                afo_ = NULL;
                hEvent_ = NULL;
            }

            void* hEvent = hEvent_;
            if (NULL != hEvent)
            {
                ppp::win32::Win32Native::WSACloseEvent(hEvent);
            }

            int listenfd = listenfd_;
            if (listenfd != INVALID_SOCKET)
            {
                closesocket(listenfd);
            }

            AcceptSocket.reset();
            afo_ = NULL;
            hEvent_ = NULL;
            context_ = NULL;
            listenfd_ = INVALID_SOCKET;
        }
    }
}