proxygen
Acceptor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 
30 
31 #include <fstream>
32 
33 using folly::AsyncSocket;
38 using folly::EventBase;
40 using folly::StringPiece;
41 using std::chrono::microseconds;
42 using std::chrono::milliseconds;
43 using std::filebuf;
44 using std::ifstream;
45 using std::ios;
46 using std::shared_ptr;
47 using std::string;
48 
49 namespace wangle {
50 
52 std::atomic<uint64_t> Acceptor::totalNumPendingSSLConns_{0};
53 
55  accConfig_(accConfig),
56  socketOptions_(accConfig.getSocketOptions()) {
57 }
58 
59 void
61  EventBase* eventBase,
62  SSLStats* stats) {
63  if (accConfig_.isSSL()) {
64 
67  }
68 
70  auto fizzCtx = createFizzContext();
71  auto* peeker = getFizzPeeker();
72  peeker->setContext(std::move(fizzCtx));
78  } else {
80  }
81 
82  if (!sslCtxManager_) {
83  sslCtxManager_ = std::make_unique<SSLContextManager>(
84  eventBase,
85  "vip_" + getName(),
86  accConfig_.strictSSL, stats);
87  }
88  try {
89  for (const auto& sslCtxConfig : accConfig_.sslContextConfigs) {
90  sslCtxManager_->addSSLContextConfig(
91  sslCtxConfig,
96  }
97 
98  CHECK(sslCtxManager_->getDefaultSSLCtx());
99  } catch (const std::runtime_error& ex) {
100  if (accConfig_.strictSSL) {
101  throw;
102  } else {
103  sslCtxManager_->clear();
104  // This is not a Not a fatal error, but useful to know.
105  LOG(INFO) << "Failed to configure TLS. This is not a fatal error. "
106  << ex.what();
107  }
108  }
109  }
110 
112  if (serverSocket) {
113  serverSocket->addAcceptCallback(this, eventBase);
114 
115  for (auto& fd : serverSocket->getSockets()) {
116  if (fd < 0) {
117  continue;
118  }
119  for (const auto& opt: socketOptions_) {
120  opt.first.apply(fd, opt.second);
121  }
122  }
123  }
124 }
125 
127  CHECK(nullptr == this->base_ || eventBase == this->base_);
128  base_ = eventBase;
131  eventBase, accConfig_.connectionIdleTimeout, this);
132 }
133 
134 
135 std::shared_ptr<fizz::server::FizzServerContext> Acceptor::createFizzContext() {
137 }
138 
139 std::shared_ptr<fizz::server::TicketCipher>
141  return FizzConfigUtil::createTicketCipher<fizz::server::AES128TicketCipher>(
146  std::move(pskContext));
147 }
148 
150  if (ctx) {
151  std::string pskContext;
152  if (!accConfig_.sslContextConfigs.empty()) {
153  pskContext = accConfig_.sslContextConfigs.front().sessionContext.value_or(
154  "");
155  }
159  }
160 }
161 
164  auto ctx = createFizzContext();
165  if (ctx) {
166  updateFizzContext(ctx.get());
168  }
169  }
170  try {
171  sslCtxManager_->resetSSLContextConfigs(accConfig_.sslContextConfigs,
173  nullptr,
176  } catch (const std::runtime_error& ex) {
177  LOG(ERROR) << "Failed to re-configure TLS: "
178  << ex.what()
179  << "will keep old config";
180  }
181 
182 }
183 
185 }
186 
188  sslCtxManager_->addSSLContextConfig(sslCtxConfig,
193 }
194 
196  const std::vector<std::string>& oldSecrets,
197  const std::vector<std::string>& currentSecrets,
198  const std::vector<std::string>& newSecrets) {
199  currentSecrets_.oldSeeds = oldSecrets;
200  currentSecrets_.currentSeeds = currentSecrets;
201  currentSecrets_.newSeeds = newSecrets;
202 
204  updateFizzContext(getFizzPeeker()->getContext().get());
205  }
206 
207  if (sslCtxManager_) {
208  sslCtxManager_->reloadTLSTicketKeys(
209  oldSecrets, currentSecrets, newSecrets);
210  }
211 }
212 
213 void
216  downstreamConnectionManager_->initiateGracefulShutdown(
218  }
219 }
220 
222  std::shared_ptr<const LoadShedConfiguration> loadShedConfig,
223  const IConnectionCounter* counter) {
224  loadShedConfig_ = loadShedConfig;
226 }
227 
228 bool Acceptor::canAccept(const SocketAddress& address) {
229  if (!connectionCounter_) {
230  return true;
231  }
232 
233  const auto totalConnLimit =
234  loadShedConfig_ ? loadShedConfig_->getMaxConnections() : 0;
235  if (totalConnLimit == 0) {
236  return true;
237  }
238 
239  uint64_t currentConnections = connectionCounter_->getNumConnections();
240  uint64_t maxConnections = getWorkerMaxConnections();
241  if (currentConnections < maxConnections) {
242  return true;
243  }
244 
245  if (loadShedConfig_ && loadShedConfig_->isWhitelisted(address)) {
246  return true;
247  }
248 
249  // Take care of the connection counts across all acceptors.
250  // Expensive since a lock must be taken to get the counter.
251 
252  // getConnectionCountForLoadShedding() call can be very expensive,
253  // don't call it if you are not going to use the results.
254  const auto totalConnExceeded =
255  totalConnLimit > 0 && getConnectionCountForLoadShedding() >= totalConnLimit;
256 
257  const auto activeConnLimit =
258  loadShedConfig_ ? loadShedConfig_->getMaxActiveConnections() : 0;
259  // getActiveConnectionCountForLoadShedding() call can be very expensive,
260  // don't call it if you are not going to use the results.
261  const auto activeConnExceeded =
262  !totalConnExceeded &&
263  activeConnLimit > 0 &&
264  getActiveConnectionCountForLoadShedding() >= activeConnLimit;
265 
266  if (!activeConnExceeded && !totalConnExceeded) {
267  return true;
268  }
269  LOG_EVERY_N(ERROR, 1000) << "shedding connection because activeConnExceeded="
270  << activeConnExceeded << "totalConnExceeded="
271  << totalConnExceeded;
272  VLOG(4) << address.describe() << " not whitelisted";
273  return false;
274 }
275 
276 void
278  int fd, const SocketAddress& clientAddr) noexcept {
279  namespace fsp = folly::portability::sockets;
280  if (!canAccept(clientAddr)) {
281  // Send a RST to free kernel memory faster
282  struct linger optLinger = {1, 0};
283  fsp::setsockopt(fd, SOL_SOCKET, SO_LINGER, &optLinger, sizeof(optLinger));
284  close(fd);
285  return;
286  }
287  auto acceptTime = std::chrono::steady_clock::now();
288  for (const auto& opt: socketOptions_) {
289  opt.first.apply(fd, opt.second);
290  }
291 
292  onDoneAcceptingConnection(fd, clientAddr, acceptTime);
293 }
294 
296  int fd,
297  const SocketAddress& clientAddr,
298  std::chrono::steady_clock::time_point acceptTime) noexcept {
299  TransportInfo tinfo;
300  processEstablishedConnection(fd, clientAddr, acceptTime, tinfo);
301 }
302 
303 void
305  int fd,
306  const SocketAddress& clientAddr,
307  std::chrono::steady_clock::time_point acceptTime,
308  TransportInfo& tinfo) noexcept {
309  bool shouldDoSSL = false;
310  if (accConfig_.isSSL()) {
311  CHECK(sslCtxManager_);
312  shouldDoSSL = sslCtxManager_->getDefaultSSLCtx() != nullptr;
313  }
314  if (shouldDoSSL) {
317  sslCtxManager_->getDefaultSSLCtx(), base_, fd));
321  VLOG(2) << "dropped SSL handshake on " << accConfig_.name <<
322  " too many handshakes in progress";
324  auto latency = std::chrono::milliseconds(0);
325  updateSSLStats(sslSock.get(), latency, error);
326  auto ex = folly::make_exception_wrapper<SSLException>(
327  error, latency, sslSock->getRawBytesReceived());
328  sslConnectionError(ex);
329  return;
330  }
331 
332  tinfo.tfoSucceded = sslSock->getTFOSucceded();
334  std::move(sslSock),
335  this,
336  clientAddr,
337  acceptTime,
338  tinfo);
339  } else {
340  tinfo.secure = false;
341  tinfo.acceptTime = acceptTime;
343  tinfo.tfoSucceded = sock->getTFOSucceded();
345  std::move(sock),
346  clientAddr,
347  empty_string,
349  tinfo);
350  }
351 }
352 
355  Acceptor*,
356  const SocketAddress& clientAddr,
357  std::chrono::steady_clock::time_point acceptTime,
358  TransportInfo& tinfo) noexcept {
360  this, clientAddr, acceptTime, tinfo);
361  manager->start(std::move(sslSock));
362 }
363 
364 void
367  const SocketAddress& clientAddr,
368  const string& nextProtocolName,
369  SecureTransportType secureTransportType,
370  TransportInfo& tinfo) {
371  // Limit the number of reads from the socket per poll loop iteration,
372  // both to keep memory usage under control and to prevent one fast-
373  // writing client from starving other connections.
374  auto asyncSocket = sock->getUnderlyingTransport<AsyncSocket>();
375  asyncSocket->setMaxReadsPerEvent(16);
376  tinfo.initWithSocket(asyncSocket);
377  tinfo.appProtocol = std::make_shared<std::string>(nextProtocolName);
378  if (state_ < State::kDraining) {
380  std::move(sock),
381  &clientAddr,
382  nextProtocolName,
383  secureTransportType,
384  tinfo);
385  }
386 }
387 
390  const SocketAddress& clientAddr,
391  const string& nextProtocolName,
392  SecureTransportType secureTransportType,
393  TransportInfo& tinfo) {
395  std::move(sock),
396  clientAddr,
397  nextProtocolName,
398  secureTransportType,
399  tinfo);
400 }
401 
402 void
404  const SocketAddress& clientAddr,
405  const string& nextProtocol,
406  SecureTransportType secureTransportType,
407  TransportInfo& tinfo) {
408  CHECK(numPendingSSLConns_ > 0);
412  std::move(sock),
413  clientAddr,
414  nextProtocol,
415  secureTransportType,
416  tinfo);
417  if (state_ == State::kDraining) {
418  checkDrained();
419  }
420 }
421 
423  CHECK(numPendingSSLConns_ > 0);
426  if (state_ == State::kDraining) {
427  checkDrained();
428  }
429 }
430 
431 void
432 Acceptor::acceptError(const std::exception& ex) noexcept {
433  // An error occurred.
434  // The most likely error is out of FDs. AsyncServerSocket will back off
435  // briefly if we are out of FDs, then continue accepting later.
436  // Just log a message here.
437  LOG(ERROR) << "error accepting on acceptor socket: " << ex.what();
438 }
439 
440 void
442  VLOG(3) << "Acceptor " << this << " acceptStopped()";
443  // Drain the open client connections
445 
446  // If we haven't yet finished draining, begin doing so by marking ourselves
447  // as in the draining state. We must be sure to hit checkDrained() here, as
448  // if we're completely idle, we can should consider ourself drained
449  // immediately (as there is no outstanding work to complete to cause us to
450  // re-evaluate this).
451  if (state_ != State::kDone) {
453  checkDrained();
454  }
455 }
456 
457 void
459  VLOG(3) << "Acceptor=" << this << " onEmpty()";
460  if (state_ == State::kDraining) {
461  checkDrained();
462  }
463 }
464 
465 void
467  CHECK(state_ == State::kDraining);
469  (downstreamConnectionManager_->getNumConnections() != 0) ||
470  (numPendingSSLConns_ != 0)) {
471  return;
472  }
473 
474  VLOG(2) << "All connections drained from Acceptor=" << this << " in thread "
475  << base_;
476 
478 
480 
482 }
483 
484 void
485 Acceptor::drainConnections(double pctToDrain) {
487  LOG(INFO) << "Draining " << pctToDrain * 100 << "% of "
488  << getNumConnections() << " connections from Acceptor=" << this
489  << " in thread " << base_;
490  assert(base_->isInEventBaseThread());
493  }
494 }
495 
496 milliseconds
499 }
500 
502  // Add the socket to the timeout manager so that it can be cleaned
503  // up after being left idle for a long time.
504  downstreamConnectionManager_->addConnection(conn, true);
505 }
506 
507 void
510 }
511 
512 void
515  LOG(INFO) << "Dropping all connections from Acceptor=" << this
516  << " in thread " << base_;
517  assert(base_->isInEventBaseThread());
519  downstreamConnectionManager_->dropAllConnections();
520  CHECK(downstreamConnectionManager_->getNumConnections() == 0);
522  }
523  CHECK(numPendingSSLConns_ == 0);
524 
527 }
528 
529 void
530 Acceptor::dropConnections(double pctToDrop) {
531  base_->runInEventBaseThread([&, pctToDrop] {
533  LOG(INFO) << "Dropping " << pctToDrop * 100 << "% of "
534  << getNumConnections() << " connections from Acceptor=" << this
535  << " in thread " << base_;
536  assert(base_->isInEventBaseThread());
538  downstreamConnectionManager_->dropConnections(pctToDrop);
539  }
540  });
541 }
542 
543 } // namespace wangle
std::chrono::milliseconds getConnTimeout() const
Definition: Acceptor.cpp:497
void onEmpty(const wangle::ConnectionManager &cm) override
Definition: Acceptor.cpp:458
std::vector< std::string > newSeeds
virtual void start(folly::AsyncSSLSocket::UniquePtr sock) noexcept
std::vector< std::string > currentSeeds
static const std::string empty_string
Definition: Acceptor.cpp:51
virtual uint64_t getWorkerMaxConnections() const
Definition: Acceptor.h:323
virtual folly::AsyncSocket::UniquePtr makeNewAsyncSocket(folly::EventBase *base, int fd)
Definition: Acceptor.h:365
void connectionReady(folly::AsyncTransportWrapper::UniquePtr sock, const folly::SocketAddress &clientAddr, const std::string &nextProtocolName, SecureTransportType secureTransportType, TransportInfo &tinfo)
Definition: Acceptor.cpp:365
void setLoadShedConfig(std::shared_ptr< const LoadShedConfiguration > loadShedConfig, const IConnectionCounter *counter)
Definition: Acceptor.cpp:221
uint32_t getNumConnections() const
Definition: Acceptor.h:119
void addSSLContextConfig(const SSLContextConfig &sslCtxConfig)
Definition: Acceptor.cpp:187
~Acceptor() override
Definition: Acceptor.cpp:184
std::vector< int > getSockets() const
virtual void setTLSTicketSecrets(const std::vector< std::string > &oldSecrets, const std::vector< std::string > &currentSecrets, const std::vector< std::string > &newSecrets)
Definition: Acceptor.cpp:195
int setsockopt(NetworkSocket s, int level, int optname, const void *optval, socklen_t optlen)
Definition: NetOps.cpp:384
std::chrono::milliseconds connectionIdleTimeout
wangle::TLSTicketKeySeeds currentSecrets_
Definition: Acceptor.h:441
uint64_t numPendingSSLConns_
Definition: Acceptor.h:452
void processEstablishedConnection(int fd, const folly::SocketAddress &clientAddr, std::chrono::steady_clock::time_point acceptTime, TransportInfo &tinfo) noexcept
Definition: Acceptor.cpp:304
std::chrono::steady_clock::time_point now()
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const IConnectionCounter * connectionCounter_
Definition: Acceptor.h:458
std::shared_ptr< SSLCacheProvider > cacheProvider_
Definition: Acceptor.h:440
static std::shared_ptr< fizz::server::FizzServerContext > createFizzContext(const wangle::ServerSocketConfig &config, std::unique_ptr< fizz::server::CertManager > certMgr=nullptr)
void checkDrained()
Definition: Acceptor.cpp:466
virtual void initDownstreamConnectionManager(folly::EventBase *eventBase)
Definition: Acceptor.cpp:126
wangle::ConnectionManager::UniquePtr downstreamConnectionManager_
Definition: Acceptor.h:438
bool forceShutdownInProgress_
Definition: Acceptor.h:456
void addPeeker(PeekingCallbackPtr peekingCallback)
std::shared_ptr< const LoadShedConfiguration > loadShedConfig_
Definition: Acceptor.h:457
virtual void onDoneAcceptingConnection(int fd, const folly::SocketAddress &clientAddr, std::chrono::steady_clock::time_point acceptTime) noexcept
Definition: Acceptor.cpp:295
std::string describe() const
virtual void dropConnections(double pctToDrop)
Definition: Acceptor.cpp:530
requires E e noexcept(noexcept(s.error(std::move(e))))
static std::atomic< uint64_t > totalNumPendingSSLConns_
Definition: Acceptor.h:454
virtual void drainConnections(double pctToDrain)
Definition: Acceptor.cpp:485
virtual void updateSSLStats(const folly::AsyncTransportWrapper *, std::chrono::milliseconds, SSLErrorEnum) noexcept
Definition: Acceptor.h:305
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
virtual std::shared_ptr< fizz::server::TicketCipher > createFizzTicketCipher(folly::Optional< std::string >=folly::none)
Definition: Acceptor.cpp:140
void acceptStopped() noexceptoverride
Definition: Acceptor.cpp:441
CipherSuite cipher
virtual void startHandshakeManager(folly::AsyncSSLSocket::UniquePtr sslSock, Acceptor *acceptor, const folly::SocketAddress &clientAddr, std::chrono::steady_clock::time_point acceptTime, TransportInfo &tinfo) noexcept
Definition: Acceptor.cpp:353
void acceptError(const std::exception &ex) noexceptoverride
Definition: Acceptor.cpp:432
folly::AsyncSocket::OptionMap socketOptions_
Definition: Acceptor.h:425
const std::string & getName() const
Definition: Acceptor.h:162
std::unique_ptr< AsyncSSLSocket, Destructor > UniquePtr
void setMaxReadsPerEvent(uint16_t maxReads)
Definition: AsyncSocket.h:451
bool initWithSocket(const folly::AsyncSocket *sock)
bool isInEventBaseThread() const
Definition: EventBase.h:504
folly::SocketAddress bindAddress
std::unique_ptr< AsyncTransportWrapper, Destructor > UniquePtr
virtual void onConnectionsDrained()
Definition: Acceptor.h:392
static UniquePtr makeUnique(Args &&...args)
void updateFizzContext(fizz::server::FizzServerContext *)
Definition: Acceptor.cpp:149
Acceptor(const ServerSocketConfig &accConfig)
Definition: Acceptor.cpp:54
virtual void forceStop()
Definition: Acceptor.cpp:508
bool runInEventBaseThread(void(*fn)(T *), T *arg)
Definition: EventBase.h:794
void setTicketCipher(std::shared_ptr< TicketCipher > ticketCipher)
virtual DefaultToFizzPeekingCallback * getFizzPeeker()
Definition: Acceptor.h:414
const ServerSocketConfig accConfig_
Definition: Acceptor.h:407
void addConnection(wangle::ManagedConnection *connection)
Definition: Acceptor.cpp:501
virtual uint64_t getActiveConnectionCountForLoadShedding() const
Definition: Acceptor.h:322
virtual void plaintextConnectionReady(folly::AsyncTransportWrapper::UniquePtr sock, const folly::SocketAddress &clientAddr, const std::string &nextProtocolName, SecureTransportType secureTransportType, TransportInfo &tinfo)
Definition: Acceptor.cpp:388
virtual uint64_t getConnectionCountForLoadShedding(void) const
Definition: Acceptor.h:321
void setContext(std::shared_ptr< fizz::server::FizzServerContext > context)
DefaultToSSLPeekingCallback defaultPeekingCallback_
Definition: Acceptor.h:435
SecurityProtocolContextManager securityProtocolCtxManager_
Definition: Acceptor.h:432
virtual void sslConnectionReady(folly::AsyncTransportWrapper::UniquePtr sock, const folly::SocketAddress &clientAddr, const std::string &nextProtocol, SecureTransportType secureTransportType, TransportInfo &tinfo)
Definition: Acceptor.cpp:403
std::chrono::seconds sslCacheTimeout
AcceptorHandshakeManager * getHandshakeManager(Acceptor *acceptor, const folly::SocketAddress &clientAddr, std::chrono::steady_clock::time_point acceptTime, TransportInfo &tinfo) noexcept
virtual std::shared_ptr< fizz::server::FizzServerContext > createFizzContext()
Definition: Acceptor.cpp:135
std::atomic< int > counter
TLSTicketKeySeeds initialTicketSeeds
const char * string
Definition: Conv.cpp:212
std::chrono::milliseconds gracefulShutdownTimeout_
Definition: Acceptor.h:459
virtual uint64_t getNumConnections() const =0
virtual bool canAccept(const folly::SocketAddress &)
Definition: Acceptor.cpp:228
virtual void sslConnectionError(const folly::exception_wrapper &ex)
Definition: Acceptor.cpp:422
std::shared_ptr< std::string > appProtocol
std::vector< std::string > oldSeeds
void connectionAccepted(int fd, const folly::SocketAddress &clientAddr) noexceptoverride
Definition: Acceptor.cpp:277
Range< const char * > StringPiece
TLSPlaintextPeekingCallback tlsPlaintextPeekingCallback_
Definition: Acceptor.h:434
int close(NetworkSocket s)
Definition: NetOps.cpp:90
virtual void resetSSLContextConfigs()
Definition: Acceptor.cpp:162
std::vector< SSLContextConfig > sslContextConfigs
std::unique_ptr< AsyncSocket, Destructor > UniquePtr
Definition: AsyncSocket.h:83
std::unique_ptr< SSLContextManager > sslCtxManager_
Definition: Acceptor.h:427
virtual folly::AsyncSSLSocket::UniquePtr makeNewAsyncSSLSocket(const std::shared_ptr< folly::SSLContext > &ctx, folly::EventBase *base, int fd)
Definition: Acceptor.h:372
folly::EventBase * base_
Definition: Acceptor.h:319
virtual void init(folly::AsyncServerSocket *serverSocket, folly::EventBase *eventBase, SSLStats *stats=nullptr)
Definition: Acceptor.cpp:60
virtual void onNewConnection(folly::AsyncTransportWrapper::UniquePtr, const folly::SocketAddress *, const std::string &, SecureTransportType, const TransportInfo &)
Definition: Acceptor.h:350
void drainAllConnections()
Definition: Acceptor.cpp:214
void dropAllConnections()
Definition: Acceptor.cpp:513
virtual void addAcceptCallback(AcceptCallback *callback, EventBase *eventBase, uint32_t maxAtOnce=kDefaultCallbackAcceptAtOnce)