ShutdownSocketSetTest.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright 2013-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/io/ShutdownSocketSet.h>
  17. #include <atomic>
  18. #include <chrono>
  19. #include <thread>
  20. #include <glog/logging.h>
  21. #include <folly/portability/GTest.h>
  22. #include <folly/portability/Sockets.h>
  23. using folly::ShutdownSocketSet;
  24. namespace fsp = folly::portability::sockets;
  25. namespace folly {
  26. namespace test {
  27. ShutdownSocketSet shutdownSocketSet;
  28. class Server {
  29. public:
  30. Server();
  31. void stop(bool abortive);
  32. void join();
  33. int port() const {
  34. return port_;
  35. }
  36. int closeClients(bool abortive);
  37. private:
  38. int acceptSocket_;
  39. int port_;
  40. enum StopMode { NO_STOP, ORDERLY, ABORTIVE };
  41. std::atomic<StopMode> stop_;
  42. std::thread serverThread_;
  43. std::vector<int> fds_;
  44. };
  45. Server::Server() : acceptSocket_(-1), port_(0), stop_(NO_STOP) {
  46. acceptSocket_ = fsp::socket(PF_INET, SOCK_STREAM, 0);
  47. CHECK_ERR(acceptSocket_);
  48. shutdownSocketSet.add(acceptSocket_);
  49. sockaddr_in addr;
  50. addr.sin_family = AF_INET;
  51. addr.sin_port = 0;
  52. addr.sin_addr.s_addr = INADDR_ANY;
  53. CHECK_ERR(bind(
  54. acceptSocket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)));
  55. CHECK_ERR(listen(acceptSocket_, 10));
  56. socklen_t addrLen = sizeof(addr);
  57. CHECK_ERR(
  58. getsockname(acceptSocket_, reinterpret_cast<sockaddr*>(&addr), &addrLen));
  59. port_ = ntohs(addr.sin_port);
  60. serverThread_ = std::thread([this] {
  61. while (stop_ == NO_STOP) {
  62. sockaddr_in peer;
  63. socklen_t peerLen = sizeof(peer);
  64. int fd =
  65. accept(acceptSocket_, reinterpret_cast<sockaddr*>(&peer), &peerLen);
  66. if (fd == -1) {
  67. if (errno == EINTR) {
  68. continue;
  69. }
  70. if (errno == EINVAL || errno == ENOTSOCK) { // socket broken
  71. break;
  72. }
  73. }
  74. CHECK_ERR(fd);
  75. shutdownSocketSet.add(fd);
  76. fds_.push_back(fd);
  77. }
  78. if (stop_ != NO_STOP) {
  79. closeClients(stop_ == ABORTIVE);
  80. }
  81. shutdownSocketSet.close(acceptSocket_);
  82. acceptSocket_ = -1;
  83. port_ = 0;
  84. });
  85. }
  86. int Server::closeClients(bool abortive) {
  87. for (int fd : fds_) {
  88. if (abortive) {
  89. struct linger l = {1, 0};
  90. CHECK_ERR(setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)));
  91. }
  92. shutdownSocketSet.close(fd);
  93. }
  94. int n = fds_.size();
  95. fds_.clear();
  96. return n;
  97. }
  98. void Server::stop(bool abortive) {
  99. stop_ = abortive ? ABORTIVE : ORDERLY;
  100. shutdown(acceptSocket_, SHUT_RDWR);
  101. }
  102. void Server::join() {
  103. serverThread_.join();
  104. }
  105. int createConnectedSocket(int port) {
  106. int sock = fsp::socket(PF_INET, SOCK_STREAM, 0);
  107. CHECK_ERR(sock);
  108. sockaddr_in addr;
  109. addr.sin_family = AF_INET;
  110. addr.sin_port = htons(port);
  111. addr.sin_addr.s_addr = htonl((127 << 24) | 1); // XXX
  112. CHECK_ERR(
  113. connect(sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)));
  114. return sock;
  115. }
  116. void runCloseTest(bool abortive) {
  117. Server server;
  118. int sock = createConnectedSocket(server.port());
  119. std::thread stopper([&server, abortive] {
  120. std::this_thread::sleep_for(std::chrono::milliseconds(200));
  121. server.stop(abortive);
  122. server.join();
  123. });
  124. char c;
  125. int r = read(sock, &c, 1);
  126. if (abortive) {
  127. int e = errno;
  128. EXPECT_EQ(-1, r);
  129. EXPECT_EQ(ECONNRESET, e);
  130. } else {
  131. EXPECT_EQ(0, r);
  132. }
  133. close(sock);
  134. stopper.join();
  135. EXPECT_EQ(0, server.closeClients(false)); // closed by server when it exited
  136. }
  137. TEST(ShutdownSocketSetTest, OrderlyClose) {
  138. runCloseTest(false);
  139. }
  140. TEST(ShutdownSocketSetTest, AbortiveClose) {
  141. runCloseTest(true);
  142. }
  143. void runKillTest(bool abortive) {
  144. Server server;
  145. int sock = createConnectedSocket(server.port());
  146. std::thread killer([&server, abortive] {
  147. std::this_thread::sleep_for(std::chrono::milliseconds(200));
  148. shutdownSocketSet.shutdownAll(abortive);
  149. server.join();
  150. });
  151. char c;
  152. int r = read(sock, &c, 1);
  153. // "abortive" is just a hint for ShutdownSocketSet, so accept both
  154. // behaviors
  155. if (abortive) {
  156. if (r == -1) {
  157. EXPECT_EQ(ECONNRESET, errno);
  158. } else {
  159. EXPECT_EQ(r, 0);
  160. }
  161. } else {
  162. EXPECT_EQ(0, r);
  163. }
  164. close(sock);
  165. killer.join();
  166. // NOT closed by server when it exited
  167. EXPECT_EQ(1, server.closeClients(false));
  168. }
  169. TEST(ShutdownSocketSetTest, OrderlyKill) {
  170. runKillTest(false);
  171. }
  172. TEST(ShutdownSocketSetTest, AbortiveKill) {
  173. runKillTest(true);
  174. }
  175. } // namespace test
  176. } // namespace folly