aboutsummaryrefslogtreecommitdiffstats
path: root/util/network/nonblock.cpp
blob: ad00becbce78a9f667cef97e4ae255004a96072a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "nonblock.h" 
 
#include <util/system/platform.h> 
 
#include <util/generic/singleton.h> 
 
#if defined(_unix_) 
    #include <dlfcn.h> 
#endif 
 
#if defined(_linux_) 
    #if !defined(SOCK_NONBLOCK) 
        #define SOCK_NONBLOCK 04000 
    #endif 
#endif 
 
namespace { 
    struct TFeatureCheck { 
        inline TFeatureCheck() 
            : Accept4(nullptr)
            , HaveSockNonBlock(false) 
        { 
#if defined(_unix_) && defined(SOCK_NONBLOCK) 
            { 
                Accept4 = reinterpret_cast<TAccept4>(dlsym(RTLD_DEFAULT, "accept4"));
 
    #if defined(_musl_) 
                //musl always statically linked 
                if (!Accept4) { 
                    Accept4 = accept4; 
                } 
    #endif 
 
                if (Accept4) { 
                    Accept4(-1, nullptr, nullptr, SOCK_NONBLOCK);
 
                    if (errno == ENOSYS) { 
                        Accept4 = nullptr;
                    } 
                } 
            } 
#endif 
 
#if defined(SOCK_NONBLOCK) 
            { 
                TSocketHolder tmp(socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)); 
 
                HaveSockNonBlock = !tmp.Closed(); 
            } 
#endif 
        } 
 
        inline SOCKET FastAccept(SOCKET s, struct sockaddr* addr, socklen_t* addrlen) const { 
#if defined(SOCK_NONBLOCK) 
            if (Accept4) { 
                return Accept4(s, addr, addrlen, SOCK_NONBLOCK); 
            } 
#endif 
 
            const SOCKET ret = accept(s, addr, addrlen); 
 
#if !defined(_freebsd_) 
            //freebsd inherit O_NONBLOCK flag 
            if (ret != INVALID_SOCKET) { 
                SetNonBlock(ret); 
            } 
#endif 
 
            return ret; 
        } 
 
        inline SOCKET FastSocket(int domain, int type, int protocol) const { 
#if defined(SOCK_NONBLOCK) 
            if (HaveSockNonBlock) { 
                return socket(domain, type | SOCK_NONBLOCK, protocol); 
            } 
#endif 
 
            const SOCKET ret = socket(domain, type, protocol); 
 
            if (ret != INVALID_SOCKET) { 
                SetNonBlock(ret); 
            } 
 
            return ret; 
        } 
 
        static inline const TFeatureCheck* Instance() noexcept {
            return Singleton<TFeatureCheck>(); 
        } 
 
        using TAccept4 = int (*)(int sockfd, struct sockaddr* addr, socklen_t* addrlen, int flags);
        TAccept4 Accept4; 
        bool HaveSockNonBlock; 
    }; 
} 
 
SOCKET Accept4(SOCKET s, struct sockaddr* addr, socklen_t* addrlen) { 
    return TFeatureCheck::Instance()->FastAccept(s, addr, addrlen); 
} 
 
SOCKET Socket4(int domain, int type, int protocol) { 
    return TFeatureCheck::Instance()->FastSocket(domain, type, protocol); 
}