network.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "network.h"
  2. #include <util/generic/maybe.h>
  3. #include <util/generic/ptr.h>
  4. #include <util/network/init.h>
  5. #include <util/network/socket.h>
  6. #include <util/system/platform.h>
  7. using namespace NBus;
  8. using namespace NBus::NPrivate;
  9. namespace {
  10. TBindResult BindOnPortProto(int port, int af, bool reusePort) {
  11. Y_ABORT_UNLESS(af == AF_INET || af == AF_INET6, "wrong af");
  12. SOCKET fd = ::socket(af, SOCK_STREAM, 0);
  13. if (fd == INVALID_SOCKET) {
  14. ythrow TSystemError() << "failed to create a socket";
  15. }
  16. int one = 1;
  17. int r1 = SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, one);
  18. if (r1 < 0) {
  19. ythrow TSystemError() << "failed to setsockopt SO_REUSEADDR";
  20. }
  21. #ifdef SO_REUSEPORT
  22. if (reusePort) {
  23. int r = SetSockOpt(fd, SOL_SOCKET, SO_REUSEPORT, one);
  24. if (r < 0) {
  25. ythrow TSystemError() << "failed to setsockopt SO_REUSEPORT";
  26. }
  27. }
  28. #else
  29. Y_UNUSED(reusePort);
  30. #endif
  31. THolder<TOpaqueAddr> addr(new TOpaqueAddr);
  32. sockaddr* sa = addr->MutableAddr();
  33. sa->sa_family = af;
  34. socklen_t len;
  35. if (af == AF_INET) {
  36. len = sizeof(sockaddr_in);
  37. ((sockaddr_in*)sa)->sin_port = HostToInet((ui16)port);
  38. ((sockaddr_in*)sa)->sin_addr.s_addr = INADDR_ANY;
  39. } else {
  40. len = sizeof(sockaddr_in6);
  41. ((sockaddr_in6*)sa)->sin6_port = HostToInet((ui16)port);
  42. }
  43. if (af == AF_INET6) {
  44. FixIPv6ListenSocket(fd);
  45. }
  46. int r2 = ::bind(fd, sa, len);
  47. if (r2 < 0) {
  48. ythrow TSystemError() << "failed to bind on port " << port;
  49. }
  50. int rsn = ::getsockname(fd, addr->MutableAddr(), addr->LenPtr());
  51. if (rsn < 0) {
  52. ythrow TSystemError() << "failed to getsockname";
  53. }
  54. int r3 = ::listen(fd, 50);
  55. if (r3 < 0) {
  56. ythrow TSystemError() << "listen failed";
  57. }
  58. TBindResult r;
  59. r.Socket.Reset(new TSocketHolder(fd));
  60. r.Addr = TNetAddr(addr.Release());
  61. return r;
  62. }
  63. TMaybe<TBindResult> TryBindOnPortProto(int port, int af, bool reusePort) {
  64. try {
  65. return {BindOnPortProto(port, af, reusePort)};
  66. } catch (const TSystemError&) {
  67. return {};
  68. }
  69. }
  70. std::pair<unsigned, TVector<TBindResult>> AggregateBindResults(TBindResult&& r1, TBindResult&& r2) {
  71. Y_ABORT_UNLESS(r1.Addr.GetPort() == r2.Addr.GetPort(), "internal");
  72. std::pair<unsigned, TVector<TBindResult>> r;
  73. r.second.reserve(2);
  74. r.first = r1.Addr.GetPort();
  75. r.second.emplace_back(std::move(r1));
  76. r.second.emplace_back(std::move(r2));
  77. return r;
  78. }
  79. }
  80. std::pair<unsigned, TVector<TBindResult>> NBus::BindOnPort(int port, bool reusePort) {
  81. std::pair<unsigned, TVector<TBindResult>> r;
  82. r.second.reserve(2);
  83. if (port != 0) {
  84. return AggregateBindResults(BindOnPortProto(port, AF_INET, reusePort),
  85. BindOnPortProto(port, AF_INET6, reusePort));
  86. }
  87. // use nothrow versions in cycle
  88. for (int i = 0; i < 1000; ++i) {
  89. TMaybe<TBindResult> in4 = TryBindOnPortProto(0, AF_INET, reusePort);
  90. if (!in4) {
  91. continue;
  92. }
  93. TMaybe<TBindResult> in6 = TryBindOnPortProto(in4->Addr.GetPort(), AF_INET6, reusePort);
  94. if (!in6) {
  95. continue;
  96. }
  97. return AggregateBindResults(std::move(*in4), std::move(*in6));
  98. }
  99. TBindResult in4 = BindOnPortProto(0, AF_INET, reusePort);
  100. TBindResult in6 = BindOnPortProto(in4.Addr.GetPort(), AF_INET6, reusePort);
  101. return AggregateBindResults(std::move(in4), std::move(in6));
  102. }
  103. void NBus::NPrivate::SetSockOptTcpCork(SOCKET s, bool value) {
  104. #ifdef _linux_
  105. CheckedSetSockOpt(s, IPPROTO_TCP, TCP_CORK, (int)value, "TCP_CORK");
  106. #else
  107. Y_UNUSED(s);
  108. Y_UNUSED(value);
  109. #endif
  110. }
  111. ssize_t NBus::NPrivate::SocketSend(SOCKET s, TArrayRef<const char> data) {
  112. int flags = 0;
  113. #if defined(_linux_) || defined(_freebsd_)
  114. flags |= MSG_NOSIGNAL;
  115. #endif
  116. ssize_t r = ::send(s, data.data(), data.size(), flags);
  117. if (r < 0) {
  118. Y_ABORT_UNLESS(LastSystemError() != EBADF, "bad fd");
  119. }
  120. return r;
  121. }
  122. ssize_t NBus::NPrivate::SocketRecv(SOCKET s, TArrayRef<char> buffer) {
  123. int flags = 0;
  124. #if defined(_linux_) || defined(_freebsd_)
  125. flags |= MSG_NOSIGNAL;
  126. #endif
  127. ssize_t r = ::recv(s, buffer.data(), buffer.size(), flags);
  128. if (r < 0) {
  129. Y_ABORT_UNLESS(LastSystemError() != EBADF, "bad fd");
  130. }
  131. return r;
  132. }