proxygen
ShutdownSocketSetTest.cpp
Go to the documentation of this file.
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  */
17 
18 #include <atomic>
19 #include <chrono>
20 #include <thread>
21 
22 #include <glog/logging.h>
23 
26 
28 
30 
31 namespace folly {
32 namespace test {
33 
35 
36 class Server {
37  public:
38  Server();
39 
40  void stop(bool abortive);
41  void join();
42  int port() const {
43  return port_;
44  }
45  int closeClients(bool abortive);
46 
47  private:
49  int port_;
51  std::atomic<StopMode> stop_;
52  std::thread serverThread_;
53  std::vector<int> fds_;
54 };
55 
57  acceptSocket_ = fsp::socket(PF_INET, SOCK_STREAM, 0);
58  CHECK_ERR(acceptSocket_);
59  shutdownSocketSet.add(acceptSocket_);
60 
61  sockaddr_in addr;
62  addr.sin_family = AF_INET;
63  addr.sin_port = 0;
64  addr.sin_addr.s_addr = INADDR_ANY;
65  CHECK_ERR(bind(
66  acceptSocket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)));
67 
68  CHECK_ERR(listen(acceptSocket_, 10));
69 
70  socklen_t addrLen = sizeof(addr);
71  CHECK_ERR(
72  getsockname(acceptSocket_, reinterpret_cast<sockaddr*>(&addr), &addrLen));
73 
74  port_ = ntohs(addr.sin_port);
75 
76  serverThread_ = std::thread([this] {
77  while (stop_ == NO_STOP) {
78  sockaddr_in peer;
79  socklen_t peerLen = sizeof(peer);
80  int fd =
81  accept(acceptSocket_, reinterpret_cast<sockaddr*>(&peer), &peerLen);
82  if (fd == -1) {
83  if (errno == EINTR) {
84  continue;
85  }
86  if (errno == EINVAL || errno == ENOTSOCK) { // socket broken
87  break;
88  }
89  }
90  CHECK_ERR(fd);
91  shutdownSocketSet.add(fd);
92  fds_.push_back(fd);
93  }
94 
95  if (stop_ != NO_STOP) {
97  }
98 
99  shutdownSocketSet.close(acceptSocket_);
100  acceptSocket_ = -1;
101  port_ = 0;
102  });
103 }
104 
105 int Server::closeClients(bool abortive) {
106  for (int fd : fds_) {
107  if (abortive) {
108  struct linger l = {1, 0};
109  CHECK_ERR(setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)));
110  }
111  shutdownSocketSet.close(fd);
112  }
113  int n = fds_.size();
114  fds_.clear();
115  return n;
116 }
117 
118 void Server::stop(bool abortive) {
119  stop_ = abortive ? ABORTIVE : ORDERLY;
120  shutdown(acceptSocket_, SHUT_RDWR);
121 }
122 
123 void Server::join() {
124  serverThread_.join();
125 }
126 
128  int sock = fsp::socket(PF_INET, SOCK_STREAM, 0);
129  CHECK_ERR(sock);
130  sockaddr_in addr;
131  addr.sin_family = AF_INET;
132  addr.sin_port = htons(port);
133  addr.sin_addr.s_addr = htonl((127 << 24) | 1); // XXX
134  CHECK_ERR(
135  connect(sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)));
136  return sock;
137 }
138 
139 void runCloseTest(bool abortive) {
140  Server server;
141 
142  int sock = createConnectedSocket(server.port());
143 
144  std::thread stopper([&server, abortive] {
145  std::this_thread::sleep_for(std::chrono::milliseconds(200));
146  server.stop(abortive);
147  server.join();
148  });
149 
150  char c;
151  int r = read(sock, &c, 1);
152  if (abortive) {
153  int e = errno;
154  EXPECT_EQ(-1, r);
155  EXPECT_EQ(ECONNRESET, e);
156  } else {
157  EXPECT_EQ(0, r);
158  }
159 
160  close(sock);
161 
162  stopper.join();
163 
164  EXPECT_EQ(0, server.closeClients(false)); // closed by server when it exited
165 }
166 
167 TEST(ShutdownSocketSetTest, OrderlyClose) {
168  runCloseTest(false);
169 }
170 
171 TEST(ShutdownSocketSetTest, AbortiveClose) {
172  runCloseTest(true);
173 }
174 
175 void runKillTest(bool abortive) {
176  Server server;
177 
178  int sock = createConnectedSocket(server.port());
179 
180  std::thread killer([&server, abortive] {
181  std::this_thread::sleep_for(std::chrono::milliseconds(200));
182  shutdownSocketSet.shutdownAll(abortive);
183  server.join();
184  });
185 
186  char c;
187  int r = read(sock, &c, 1);
188 
189  // "abortive" is just a hint for ShutdownSocketSet, so accept both
190  // behaviors
191  if (abortive) {
192  if (r == -1) {
193  EXPECT_EQ(ECONNRESET, errno);
194  } else {
195  EXPECT_EQ(r, 0);
196  }
197  } else {
198  EXPECT_EQ(0, r);
199  }
200 
201  close(sock);
202 
203  killer.join();
204 
205  // NOT closed by server when it exited
206  EXPECT_EQ(1, server.closeClients(false));
207 }
208 
209 TEST(ShutdownSocketSetTest, OrderlyKill) {
210  runKillTest(false);
211 }
212 
213 TEST(ShutdownSocketSetTest, AbortiveKill) {
214  runKillTest(true);
215 }
216 } // namespace test
217 } // namespace folly
int connect(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:94
int setsockopt(NetworkSocket s, int level, int optname, const void *optval, socklen_t optlen)
Definition: NetOps.cpp:384
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::atomic< StopMode > stop_
int createConnectedSocket(int port)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
int closeClients(bool abortive)
void runKillTest(bool abortive)
int getsockname(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:108
size_t read(T &out, folly::io::Cursor &cursor)
Definition: Types-inl.h:258
void shutdown(Counter &)
ShutdownSocketSet shutdownSocketSet
NetworkSocket socket(int af, int type, int protocol)
Definition: NetOps.cpp:412
int listen(NetworkSocket s, int backlog)
Definition: NetOps.cpp:137
TEST(ProgramOptionsTest, Errors)
void shutdownAll(bool abortive=false)
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:76
void stop(bool abortive)
char c
int close(NetworkSocket s)
Definition: NetOps.cpp:90
ThreadPoolListHook * addr
void runCloseTest(bool abortive)
NetworkSocket accept(NetworkSocket s, sockaddr *addr, socklen_t *addrlen)
Definition: NetOps.cpp:71