nonblock.cpp 2.6 KB

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