socket_ut.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #include "socket.h"
  2. #include "pair.h"
  3. #include <library/cpp/testing/unittest/registar.h>
  4. #include <util/string/builder.h>
  5. #include <util/generic/vector.h>
  6. #include <ctime>
  7. #ifdef _linux_
  8. #include <linux/version.h>
  9. #include <sys/utsname.h>
  10. #endif
  11. class TSockTest: public TTestBase {
  12. UNIT_TEST_SUITE(TSockTest);
  13. UNIT_TEST(TestSock);
  14. UNIT_TEST(TestTimeout);
  15. #ifndef _win_ // Test hangs on Windows
  16. UNIT_TEST_EXCEPTION(TestConnectionRefused, yexception);
  17. #endif
  18. UNIT_TEST(TestNetworkResolutionError);
  19. UNIT_TEST(TestNetworkResolutionErrorMessage);
  20. UNIT_TEST(TestBrokenPipe);
  21. UNIT_TEST(TestClose);
  22. UNIT_TEST(TestReusePortAvailCheck);
  23. UNIT_TEST_SUITE_END();
  24. public:
  25. void TestSock();
  26. void TestTimeout();
  27. void TestConnectionRefused();
  28. void TestNetworkResolutionError();
  29. void TestNetworkResolutionErrorMessage();
  30. void TestBrokenPipe();
  31. void TestClose();
  32. void TestReusePortAvailCheck();
  33. };
  34. UNIT_TEST_SUITE_REGISTRATION(TSockTest);
  35. void TSockTest::TestSock() {
  36. TNetworkAddress addr("yandex.ru", 80);
  37. TSocket s(addr);
  38. TSocketOutput so(s);
  39. TSocketInput si(s);
  40. const TStringBuf req = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n";
  41. so.Write(req.data(), req.size());
  42. UNIT_ASSERT(!si.ReadLine().empty());
  43. }
  44. void TSockTest::TestTimeout() {
  45. static const int timeout = 1000;
  46. i64 startTime = millisec();
  47. try {
  48. TNetworkAddress addr("localhost", 1313);
  49. TSocket s(addr, TDuration::MilliSeconds(timeout));
  50. } catch (const yexception&) {
  51. }
  52. int realTimeout = (int)(millisec() - startTime);
  53. if (realTimeout > timeout + 2000) {
  54. TString err = TStringBuilder() << "Timeout exceeded: " << realTimeout << " ms (expected " << timeout << " ms)";
  55. UNIT_FAIL(err);
  56. }
  57. }
  58. void TSockTest::TestConnectionRefused() {
  59. TNetworkAddress addr("localhost", 1313);
  60. TSocket s(addr);
  61. }
  62. void TSockTest::TestNetworkResolutionError() {
  63. TString errMsg;
  64. try {
  65. TNetworkAddress addr("", 0);
  66. } catch (const TNetworkResolutionError& e) {
  67. errMsg = e.what();
  68. }
  69. if (errMsg.empty()) {
  70. return; // on Windows getaddrinfo("", 0, ...) returns "OK"
  71. }
  72. int expectedErr = EAI_NONAME;
  73. TString expectedErrMsg = gai_strerror(expectedErr);
  74. if (errMsg.find(expectedErrMsg) == TString::npos) {
  75. UNIT_FAIL("TNetworkResolutionError contains\nInvalid msg: " + errMsg + "\nExpected msg: " + expectedErrMsg + "\n");
  76. }
  77. }
  78. void TSockTest::TestNetworkResolutionErrorMessage() {
  79. #ifdef _unix_
  80. auto str = [](int code) -> TString {
  81. return TNetworkResolutionError(code).what();
  82. };
  83. auto expected = [](int code) -> TString {
  84. return gai_strerror(code);
  85. };
  86. struct TErrnoGuard {
  87. TErrnoGuard()
  88. : PrevValue_(errno)
  89. {
  90. }
  91. ~TErrnoGuard() {
  92. errno = PrevValue_;
  93. }
  94. private:
  95. int PrevValue_;
  96. } g;
  97. UNIT_ASSERT_VALUES_EQUAL(expected(0) + "(0): ", str(0));
  98. UNIT_ASSERT_VALUES_EQUAL(expected(-9) + "(-9): ", str(-9));
  99. errno = 0;
  100. UNIT_ASSERT_VALUES_EQUAL(expected(EAI_SYSTEM) + "(" + IntToString<10>(EAI_SYSTEM) + "; errno=0): ",
  101. str(EAI_SYSTEM));
  102. errno = 110;
  103. UNIT_ASSERT_VALUES_EQUAL(expected(EAI_SYSTEM) + "(" + IntToString<10>(EAI_SYSTEM) + "; errno=110): ",
  104. str(EAI_SYSTEM));
  105. #endif
  106. }
  107. class TTempEnableSigPipe {
  108. public:
  109. TTempEnableSigPipe() {
  110. OriginalSigHandler_ = signal(SIGPIPE, SIG_DFL);
  111. Y_VERIFY(OriginalSigHandler_ != SIG_ERR);
  112. }
  113. ~TTempEnableSigPipe() {
  114. auto ret = signal(SIGPIPE, OriginalSigHandler_);
  115. Y_VERIFY(ret != SIG_ERR);
  116. }
  117. private:
  118. void (*OriginalSigHandler_)(int);
  119. };
  120. void TSockTest::TestBrokenPipe() {
  121. TTempEnableSigPipe guard;
  122. SOCKET socks[2];
  123. int ret = SocketPair(socks);
  124. UNIT_ASSERT_VALUES_EQUAL(ret, 0);
  125. TSocket sender(socks[0]);
  126. TSocket receiver(socks[1]);
  127. receiver.ShutDown(SHUT_RDWR);
  128. int sent = sender.Send("FOO", 3);
  129. UNIT_ASSERT(sent < 0);
  130. IOutputStream::TPart parts[] = {
  131. {"foo", 3},
  132. {"bar", 3},
  133. };
  134. sent = sender.SendV(parts, 2);
  135. UNIT_ASSERT(sent < 0);
  136. }
  137. void TSockTest::TestClose() {
  138. SOCKET socks[2];
  139. UNIT_ASSERT_EQUAL(SocketPair(socks), 0);
  140. TSocket receiver(socks[1]);
  141. UNIT_ASSERT_EQUAL(static_cast<SOCKET>(receiver), socks[1]);
  142. #if defined _linux_
  143. UNIT_ASSERT_GE(fcntl(socks[1], F_GETFD), 0);
  144. receiver.Close();
  145. UNIT_ASSERT_EQUAL(fcntl(socks[1], F_GETFD), -1);
  146. #else
  147. receiver.Close();
  148. #endif
  149. UNIT_ASSERT_EQUAL(static_cast<SOCKET>(receiver), INVALID_SOCKET);
  150. }
  151. void TSockTest::TestReusePortAvailCheck() {
  152. #if defined _linux_
  153. utsname sysInfo;
  154. Y_VERIFY(!uname(&sysInfo), "Error while call uname: %s", LastSystemErrorText());
  155. TStringBuf release(sysInfo.release);
  156. release = release.substr(0, release.find_first_not_of(".0123456789"));
  157. int v1 = FromString<int>(release.NextTok('.'));
  158. int v2 = FromString<int>(release.NextTok('.'));
  159. int v3 = FromString<int>(release.NextTok('.'));
  160. int linuxVersionCode = KERNEL_VERSION(v1, v2, v3);
  161. if (linuxVersionCode >= KERNEL_VERSION(3, 9, 1)) {
  162. // new kernels support SO_REUSEPORT
  163. UNIT_ASSERT(true == IsReusePortAvailable());
  164. UNIT_ASSERT(true == IsReusePortAvailable());
  165. } else {
  166. // older kernels may or may not support SO_REUSEPORT
  167. // just check that it doesn't crash or throw
  168. (void)IsReusePortAvailable();
  169. (void)IsReusePortAvailable();
  170. }
  171. #else
  172. // check that it doesn't crash or throw
  173. (void)IsReusePortAvailable();
  174. (void)IsReusePortAvailable();
  175. #endif
  176. }
  177. class TPollTest: public TTestBase {
  178. UNIT_TEST_SUITE(TPollTest);
  179. UNIT_TEST(TestPollInOut);
  180. UNIT_TEST_SUITE_END();
  181. public:
  182. inline TPollTest() {
  183. srand(static_cast<unsigned int>(time(nullptr)));
  184. }
  185. void TestPollInOut();
  186. private:
  187. sockaddr_in GetAddress(ui32 ip, ui16 port);
  188. SOCKET CreateSocket();
  189. SOCKET StartServerSocket(ui16 port, int backlog);
  190. SOCKET StartClientSocket(ui32 ip, ui16 port);
  191. SOCKET AcceptConnection(SOCKET serverSocket);
  192. };
  193. UNIT_TEST_SUITE_REGISTRATION(TPollTest);
  194. sockaddr_in TPollTest::GetAddress(ui32 ip, ui16 port) {
  195. struct sockaddr_in addr;
  196. memset(&addr, 0, sizeof(addr));
  197. addr.sin_family = AF_INET;
  198. addr.sin_port = htons(port);
  199. addr.sin_addr.s_addr = htonl(ip);
  200. return addr;
  201. }
  202. SOCKET TPollTest::CreateSocket() {
  203. SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
  204. if (s == INVALID_SOCKET) {
  205. ythrow yexception() << "Can not create socket (" << LastSystemErrorText() << ")";
  206. }
  207. return s;
  208. }
  209. SOCKET TPollTest::StartServerSocket(ui16 port, int backlog) {
  210. TSocketHolder s(CreateSocket());
  211. sockaddr_in addr = GetAddress(ntohl(INADDR_ANY), port);
  212. if (bind(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
  213. ythrow yexception() << "Can not bind server socket (" << LastSystemErrorText() << ")";
  214. }
  215. if (listen(s, backlog) == SOCKET_ERROR) {
  216. ythrow yexception() << "Can not listen on server socket (" << LastSystemErrorText() << ")";
  217. }
  218. return s.Release();
  219. }
  220. SOCKET TPollTest::StartClientSocket(ui32 ip, ui16 port) {
  221. TSocketHolder s(CreateSocket());
  222. sockaddr_in addr = GetAddress(ip, port);
  223. if (connect(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
  224. ythrow yexception() << "Can not connect client socket (" << LastSystemErrorText() << ")";
  225. }
  226. return s.Release();
  227. }
  228. SOCKET TPollTest::AcceptConnection(SOCKET serverSocket) {
  229. SOCKET connectedSocket = accept(serverSocket, nullptr, nullptr);
  230. if (connectedSocket == INVALID_SOCKET) {
  231. ythrow yexception() << "Can not accept connection on server socket (" << LastSystemErrorText() << ")";
  232. }
  233. return connectedSocket;
  234. }
  235. void TPollTest::TestPollInOut() {
  236. #ifdef _win_
  237. const size_t socketCount = 1000;
  238. ui16 port = static_cast<ui16>(1300 + rand() % 97);
  239. TSocketHolder serverSocket = StartServerSocket(port, socketCount);
  240. ui32 localIp = ntohl(inet_addr("127.0.0.1"));
  241. TVector<TSimpleSharedPtr<TSocketHolder>> clientSockets;
  242. TVector<TSimpleSharedPtr<TSocketHolder>> connectedSockets;
  243. TVector<pollfd> fds;
  244. for (size_t i = 0; i < socketCount; ++i) {
  245. TSimpleSharedPtr<TSocketHolder> clientSocket(new TSocketHolder(StartClientSocket(localIp, port)));
  246. clientSockets.push_back(clientSocket);
  247. if (i % 5 == 0 || i % 5 == 2) {
  248. char buffer = 'c';
  249. if (send(*clientSocket, &buffer, 1, 0) == -1)
  250. ythrow yexception() << "Can not send (" << LastSystemErrorText() << ")";
  251. }
  252. TSimpleSharedPtr<TSocketHolder> connectedSocket(new TSocketHolder(AcceptConnection(serverSocket)));
  253. connectedSockets.push_back(connectedSocket);
  254. if (i % 5 == 2 || i % 5 == 3) {
  255. closesocket(*clientSocket);
  256. shutdown(*clientSocket, SD_BOTH);
  257. }
  258. }
  259. int expectedCount = 0;
  260. for (size_t i = 0; i < connectedSockets.size(); ++i) {
  261. pollfd fd = {(i % 5 == 4) ? INVALID_SOCKET : static_cast<SOCKET>(*connectedSockets[i]), POLLIN | POLLOUT, 0};
  262. fds.push_back(fd);
  263. if (i % 5 != 4)
  264. ++expectedCount;
  265. }
  266. int polledCount = poll(&fds[0], fds.size(), INFTIM);
  267. UNIT_ASSERT_EQUAL(expectedCount, polledCount);
  268. for (size_t i = 0; i < connectedSockets.size(); ++i) {
  269. short revents = fds[i].revents;
  270. if (i % 5 == 0) {
  271. UNIT_ASSERT_EQUAL(static_cast<short>(POLLRDNORM | POLLWRNORM), revents);
  272. } else if (i % 5 == 1) {
  273. UNIT_ASSERT_EQUAL(static_cast<short>(POLLOUT | POLLWRNORM), revents);
  274. } else if (i % 5 == 2) {
  275. UNIT_ASSERT_EQUAL(static_cast<short>(POLLHUP | POLLRDNORM | POLLWRNORM), revents);
  276. } else if (i % 5 == 3) {
  277. UNIT_ASSERT_EQUAL(static_cast<short>(POLLHUP | POLLWRNORM), revents);
  278. } else if (i % 5 == 4) {
  279. UNIT_ASSERT_EQUAL(static_cast<short>(POLLNVAL), revents);
  280. }
  281. }
  282. #endif
  283. }