1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 
17 #ifndef THRIFT_SERVER_H_
18 #define THRIFT_SERVER_H_ 1
19 
20 #include <array>
21 #include <atomic>
22 #include <chrono>
23 #include <cstdlib>
24 #include <map>
25 #include <mutex>
26 #include <optional>
27 #include <unordered_map>
28 #include <utility>
29 #include <vector>
30 
31 #include <folly/Memory.h>
32 #include <folly/Singleton.h>
33 #include <folly/SocketAddress.h>
34 #include <folly/executors/IOThreadPoolExecutor.h>
35 #include <folly/experimental/PrimaryPtr.h>
36 #include <folly/experimental/coro/AsyncScope.h>
37 #include <folly/experimental/observer/Observer.h>
38 #include <folly/io/ShutdownSocketSet.h>
39 #include <folly/io/async/AsyncServerSocket.h>
40 #include <folly/io/async/EventBase.h>
41 #include <folly/io/async/EventBaseManager.h>
42 #include <folly/lang/Badge.h>
43 #include <folly/synchronization/CallOnce.h>
44 #include <thrift/lib/cpp/concurrency/PosixThreadFactory.h>
45 #include <thrift/lib/cpp/concurrency/ThreadManager.h>
46 #include <thrift/lib/cpp/server/TServerObserver.h>
47 #include <thrift/lib/cpp/transport/THeader.h>
48 #include <thrift/lib/cpp2/PluggableFunction.h>
49 #include <thrift/lib/cpp2/Thrift.h>
50 #include <thrift/lib/cpp2/async/AsyncProcessor.h>
51 #include <thrift/lib/cpp2/async/HeaderServerChannel.h>
52 #include <thrift/lib/cpp2/server/BaseThriftServer.h>
53 #include <thrift/lib/cpp2/server/PolledServiceHealth.h>
54 #include <thrift/lib/cpp2/server/PreprocessParams.h>
55 #include <thrift/lib/cpp2/server/RequestDebugLog.h>
56 #include <thrift/lib/cpp2/server/RequestsRegistry.h>
57 #include <thrift/lib/cpp2/server/ServerInstrumentation.h>
58 #include <thrift/lib/cpp2/server/ServiceHealthPoller.h>
59 #include <thrift/lib/cpp2/server/TransportRoutingHandler.h>
60 #include <thrift/lib/cpp2/transport/rocket/PayloadUtils.h>
61 #include <thrift/lib/cpp2/transport/rocket/Types.h>
62 #include <thrift/lib/thrift/gen-cpp2/RpcMetadata_constants.h>
63 #include <wangle/acceptor/ServerSocketConfig.h>
64 #include <wangle/acceptor/SharedSSLContextManager.h>
65 #include <wangle/bootstrap/ServerBootstrap.h>
66 #include <wangle/ssl/SSLContextConfig.h>
67 #include <wangle/ssl/TLSCredProcessor.h>
68 
69 DECLARE_bool(thrift_abort_if_exceeds_shutdown_deadline);
70 DECLARE_string(service_identity);
71 
72 THRIFT_FLAG_DECLARE_bool(dump_snapshot_on_long_shutdown);
73 THRIFT_FLAG_DECLARE_bool(alpn_allow_mismatch);
74 THRIFT_FLAG_DECLARE_bool(server_check_unimplemented_extra_interfaces);
75 
76 namespace apache {
77 namespace thrift {
78 
79 // Forward declaration of classes
80 class Cpp2Connection;
81 class Cpp2Worker;
82 class ThriftServer;
83 class ThriftProcessor;
84 namespace rocket {
85 class ThriftRocketServerHandler;
86 }
87 
88 enum class SSLPolicy { DISABLED, PERMITTED, REQUIRED };
89 
90 typedef wangle::Pipeline<folly::IOBufQueue&, std::unique_ptr<folly::IOBuf>>
91     Pipeline;
92 
93 class ThriftTlsConfig : public wangle::CustomConfig {
94  public:
95   bool enableThriftParamsNegotiation{true};
96   bool enableStopTLS{false};
97 };
98 
99 class TLSCredentialWatcher {
100  public:
101   explicit TLSCredentialWatcher(ThriftServer* server);
102 
setCertPathsToWatch(std::set<std::string> paths)103   void setCertPathsToWatch(std::set<std::string> paths) {
104     credProcessor_.setCertPathsToWatch(std::move(paths));
105   }
106 
setTicketPathToWatch(const std::string & path)107   void setTicketPathToWatch(const std::string& path) {
108     credProcessor_.setTicketPathToWatch(path);
109   }
110 
111  private:
112   wangle::TLSCredProcessor credProcessor_;
113 };
114 
115 /**
116  * State pertaining to stopping a running Thrift server. It is safe to call
117  * stop() on this even after the relevant ThriftServer has been destroyed as
118  * long as the server's event base is not re-used for something else. This is
119  * useful to prevent racing between requests to stop (such as from signal
120  * handlers) and ThriftServer's destructor.
121  *
122  * This class cannot be directly constructed by user code. Instead every
123  * ThriftServer owns a stop controller (using folly::PrimaryPtr) and hands out
124  * non-owning references to use (folly::PrimaryPtrRef). ThriftServer's
125  * destructor will block until all locked references have been released.
126  *
127  * The user-facing API that makes use of this is ServiceHandler::shutdownServer.
128  */
129 class ThriftServerStopController final {
130  public:
ThriftServerStopController(folly::badge<ThriftServer>,folly::EventBase & eventBase)131   explicit ThriftServerStopController(
132       folly::badge<ThriftServer>, folly::EventBase& eventBase)
133       : serveEventBase_(eventBase) {}
134 
135   void stop();
136 
137  private:
138   folly::EventBase& serveEventBase_;
139   folly::once_flag stopped_;
140 };
141 
142 /**
143  *   This is yet another thrift server.
144  *   Uses cpp2 style generated code.
145  */
146 
147 class ThriftServer : public apache::thrift::BaseThriftServer,
148                      public wangle::ServerBootstrap<Pipeline> {
149  private:
150   //! SSL context
151   std::optional<folly::observer::Observer<wangle::SSLContextConfig>>
152       sslContextObserver_;
153   std::optional<wangle::TLSTicketKeySeeds> ticketSeeds_;
154   folly::observer::CallbackHandle getSSLCallbackHandle();
155 
156   std::optional<bool> reusePort_;
157   std::optional<bool> enableTFO_;
158   uint32_t fastOpenQueueSize_{10000};
159 
160   std::optional<wangle::SSLCacheOptions> sslCacheOptions_;
161   wangle::FizzConfig fizzConfig_;
162   ThriftTlsConfig thriftConfig_;
163 
164   // Security negotiation settings
165   std::optional<SSLPolicy> sslPolicy_;
166   bool strictSSL_ = false;
167   // whether we allow plaintext connections from loopback in REQUIRED mode
168   bool allowPlaintextOnLoopback_ = false;
169 
170   // If true, then falls back to the corresponding THRIFT_FLAG.
171   // If false, then the check is bypassed even if the THRIFT_FLAG is set.
172   // This allows a hard-coded opt-out of the check for services where it would
173   // not be useful, e.g. non-C++ languages.
174   bool allowCheckUnimplementedExtraInterfaces_ = true;
175 
176   std::weak_ptr<folly::ShutdownSocketSet> wShutdownSocketSet_;
177 
178   //! Listen socket
179   folly::AsyncServerSocket::UniquePtr socket_;
180 
181   struct IdleServerAction : public folly::HHWheelTimer::Callback {
182     IdleServerAction(
183         ThriftServer& server,
184         folly::HHWheelTimer& timer,
185         std::chrono::milliseconds timeout);
186 
187     void timeoutExpired() noexcept override;
188 
189     ThriftServer& server_;
190     folly::HHWheelTimer& timer_;
191     std::chrono::milliseconds timeout_;
192   };
193 
194   //! The folly::EventBase currently driving serve().  NULL when not serving.
195   std::atomic<folly::EventBase*> serveEventBase_{nullptr};
196   std::optional<IdleServerAction> idleServer_;
197   std::chrono::milliseconds idleServerTimeout_ = std::chrono::milliseconds(0);
198   std::optional<std::chrono::milliseconds> sslHandshakeTimeout_;
199   std::atomic<std::chrono::steady_clock::duration::rep> lastRequestTime_;
200 
201   // Includes non-request events in Rocket. Only bumped if idleTimeout set.
202   std::chrono::steady_clock::time_point lastRequestTime() const noexcept;
203   void touchRequestTimestamp() noexcept;
204 
205   //! Manager of per-thread EventBase objects.
206   folly::EventBaseManager* eventBaseManager_ = folly::EventBaseManager::get();
207 
208   //! IO thread pool. Drives Cpp2Workers.
209   std::shared_ptr<folly::IOThreadPoolExecutor> ioThreadPool_ =
210       std::make_shared<folly::IOThreadPoolExecutor>(
211           0, std::make_shared<folly::NamedThreadFactory>("ThriftIO"));
212 
213   /**
214    * The speed for adjusting connection accept rate.
215    * 0 for disabling auto adjusting connection accept rate.
216    */
217   double acceptRateAdjustSpeed_ = 0.0;
218 
219   /**
220    * Acceptors accept and process incoming connections.  The acceptor factory
221    * helps create acceptors.
222    */
223   std::shared_ptr<wangle::AcceptorFactory> acceptorFactory_;
224   std::shared_ptr<wangle::SharedSSLContextManager> sharedSSLContextManager_;
225 
226   void handleSetupFailure(void);
227 
228   void updateCertsToWatch();
229 
230   bool stopWorkersOnStopListening_ = true;
231   bool joinRequestsWhenServerStops_{true};
232 
233   folly::AsyncWriter::ZeroCopyEnableFunc zeroCopyEnableFunc_;
234 
235   std::shared_ptr<folly::IOThreadPoolExecutor> acceptPool_;
236   int nAcceptors_ = 1;
237   uint16_t socketMaxReadsPerEvent_{16};
238 
239   // HeaderServerChannel and Cpp2Worker to use for a duplex server
240   // (used by client). Both are nullptr for a regular server.
241   std::shared_ptr<HeaderServerChannel> serverChannel_;
242   std::shared_ptr<Cpp2Worker> duplexWorker_;
243 
244   bool isDuplex_ = false; // is server in duplex mode? (used by server)
245 
246   mutable std::mutex ioGroupMutex_;
247 
getIOGroupSafe()248   std::shared_ptr<folly::IOThreadPoolExecutor> getIOGroupSafe() const {
249     std::lock_guard<std::mutex> lock(ioGroupMutex_);
250     return getIOGroup();
251   }
252 
253   void stopWorkers();
254   void stopCPUWorkers();
255   void stopAcceptingAndJoinOutstandingRequests();
256 
257   void callOnStartServing();
258   void callOnStopServing();
259 
260   void ensureDecoratedProcessorFactoryInitialized();
261 
262 #if FOLLY_HAS_COROUTINES
263   std::unique_ptr<folly::coro::CancellableAsyncScope> asyncScope_;
264 #endif
265 
266   folly::Synchronized<std::optional<TLSCredentialWatcher>> tlsCredWatcher_{};
267 
268   std::unique_ptr<ThriftProcessor> thriftProcessor_;
269   std::vector<std::unique_ptr<TransportRoutingHandler>> routingHandlers_;
270 
271   friend class Cpp2Connection;
272   friend class Cpp2Worker;
273   friend class rocket::ThriftRocketServerHandler;
274 
275   bool tosReflect_{false};
276   uint32_t listenerTos_{0};
277 
278   std::optional<instrumentation::ServerTracker> tracker_;
279 
280   bool quickExitOnShutdownTimeout_ = false;
281 
282  public:
283   /**
284    * The goal of this enum is to capture every state the server goes through in
285    * its lifecycle. Notice how the lifecycle is actually a cycle - after the
286    * server stops, it returns to its initial state of NOT_RUNNING.
287    *
288    * NOTE: For the restrictions regarding only allowing internal methods - these
289    * do not apply if getRejectRequestsUntilStarted() is false.
290    */
291   enum class ServerStatus {
292     /**
293      * The server is not running. Either:
294      *   1. The server was never started. Or,
295      *   2. The server was stopped and there are outstanding requests
296      *      were drained.
297      */
298     NOT_RUNNING = 0,
299     /**
300      * The server is about to start and is executing
301      * TServerEventHandler::preStart hooks. If getRejectRequestsUntilStarted()
302      * is true, the server only responds to internal methods. See
303      * ServerConfigs::getInternalMethods.
304      */
305     PRE_STARTING,
306     /**
307      * The preStart hooks are done executing and
308      * ServiceHandler::semifuture_onStartServing hooks are executing. If
309      * getRejectRequestsUntilStarted() is true, the server only responds to
310      * internal methods.
311      */
312     STARTING,
313     /**
314      * The service is healthy and ready to handle traffic.
315      */
316     RUNNING,
317     /**
318      * The server is preparing to stop. No new connections are accepted.
319      * Existing connections are unaffected.
320      */
321     PRE_STOPPING,
322     /**
323      * The server is about to stop and ServiceHandler::semifuture_onStopServing
324      * hooks are still executing.
325      */
326     STOPPING,
327     /**
328      * ServiceHandler::semifuture_onStopServing hooks have finished executing.
329      * Outstanding requests are being joined. New requests are rejected.
330      */
331     DRAINING_UNTIL_STOPPED,
332   };
333 
getServerStatus()334   ServerStatus getServerStatus() const {
335     auto status = internalStatus_.load(std::memory_order_acquire);
336     if (status == ServerStatus::RUNNING && !getEnabled()) {
337       // Even if the server is capable of serving, the user might have
338       // explicitly disabled the service at startup, in which case the server
339       // only responds to internal methods.
340       return ServerStatus::STARTING;
341     }
342     return status;
343   }
344 
345 #if FOLLY_HAS_COROUTINES
346   using ServiceHealth = PolledServiceHealth::ServiceHealth;
347 
getServiceHealth()348   std::optional<ServiceHealth> getServiceHealth() const {
349     auto health = cachedServiceHealth_.load(std::memory_order_relaxed);
350     return health == ServiceHealth{} ? std::nullopt
351                                      : std::make_optional(health);
352   }
353 #endif
354 
shouldHandleRequests()355   RequestHandlingCapability shouldHandleRequests() const override {
356     auto status = getServerStatus();
357     switch (status) {
358       case ServerStatus::RUNNING:
359         return RequestHandlingCapability::ALL;
360       case ServerStatus::NOT_RUNNING:
361         // The server can be in the NOT_RUNNING state and still have open
362         // connections, for example, if useExistingSocket is called with a
363         // socket that is already listening.
364         [[fallthrough]];
365       case ServerStatus::PRE_STARTING:
366       case ServerStatus::STARTING:
367         return getRejectRequestsUntilStarted()
368             ? RequestHandlingCapability::INTERNAL_METHODS_ONLY
369             : RequestHandlingCapability::ALL;
370       case ServerStatus::PRE_STOPPING:
371       case ServerStatus::STOPPING:
372         // When the server is stopping, we close the sockets for new
373         // connections. However, existing connections should be unaffected.
374         return RequestHandlingCapability::ALL;
375       case ServerStatus::DRAINING_UNTIL_STOPPED:
376       default:
377         return RequestHandlingCapability::NONE;
378     }
379   }
380 
381  private:
382   /**
383    * Thrift server's view of the currently running service. This status
384    * represents the source of truth for the status reported by the server.
385    */
386   std::atomic<ServerStatus> internalStatus_{ServerStatus::NOT_RUNNING};
387 #if FOLLY_HAS_COROUTINES
388   /**
389    * Thrift server's latest view of the running service's reported health.
390    */
391   std::atomic<ServiceHealth> cachedServiceHealth_{};
392 #endif
393 
394   std::unique_ptr<AsyncProcessorFactory> decoratedProcessorFactory_;
395 
396   /**
397    * Collects service handlers of the current service of a specific type.
398    */
399   template <
400       typename TServiceHandler = ServiceHandler,
401       typename =
402           std::enable_if_t<std::is_base_of_v<ServiceHandler, TServiceHandler>>>
collectServiceHandlers()403   std::vector<TServiceHandler*> collectServiceHandlers() const {
404     if constexpr (std::is_same_v<TServiceHandler, ServiceHandler>) {
405       return getDecoratedProcessorFactory().getServiceHandlers();
406     }
407     std::vector<TServiceHandler*> matchedServiceHandlers;
408     for (auto* serviceHandler :
409          getDecoratedProcessorFactory().getServiceHandlers()) {
410       if (auto matched = dynamic_cast<TServiceHandler*>(serviceHandler)) {
411         matchedServiceHandlers.push_back(matched);
412       }
413     }
414     return matchedServiceHandlers;
415   }
416 
417  public:
418   ThriftServer();
419 
420   // NOTE: Don't use this constructor to create a regular Thrift server. This
421   // constructor is used by the client to create a duplex server on an existing
422   // connection.
423   // Don't create a listening server. Instead use the channel to run incoming
424   // requests.
425   explicit ThriftServer(
426       const std::shared_ptr<HeaderServerChannel>& serverChannel);
427 
428   ~ThriftServer() override;
429 
430   /**
431    * Set the thread pool used to drive the server's IO threads. Note that the
432    * pool's thread factory will be overridden - if you'd like to use your own,
433    * set it afterwards via ThriftServer::setIOThreadFactory(). If the given
434    * thread pool has one or more allocated threads, the number of workers will
435    * be set to this number. Use ThreadServer::setNumIOWorkerThreads() to set
436    * it afterwards if you want to change the number of works.
437    *
438    * @param the new thread pool
439    */
setIOThreadPool(std::shared_ptr<folly::IOThreadPoolExecutor> ioThreadPool)440   void setIOThreadPool(
441       std::shared_ptr<folly::IOThreadPoolExecutor> ioThreadPool) {
442     CHECK(configMutable());
443     ioThreadPool_ = ioThreadPool;
444 
445     if (ioThreadPool_->numThreads() > 0) {
446       setNumIOWorkerThreads(ioThreadPool_->numThreads());
447     }
448   }
449 
450   /**
451    * Doing any blocking work on this executor will cause the server to
452    * stall servicing requests. Be careful about using this executor for anything
453    * other than its main purpose.
454    */
getIOThreadPool()455   std::shared_ptr<folly::IOThreadPoolExecutor> getIOThreadPool() {
456     return ioThreadPool_;
457   }
458 
459   /**
460    * Set the thread factory that will be used to create the server's IO
461    * threads.
462    *
463    * @param the new thread factory
464    */
setIOThreadFactory(std::shared_ptr<folly::NamedThreadFactory> threadFactory)465   void setIOThreadFactory(
466       std::shared_ptr<folly::NamedThreadFactory> threadFactory) {
467     CHECK(configMutable());
468     ioThreadPool_->setThreadFactory(threadFactory);
469   }
470 
471   /**
472    * Set the prefix for naming the worker threads. "Cpp2Worker" by default.
473    * must be called before serve() for it to take effect
474    *
475    * @param cpp2WorkerThreadName net thread name prefix
476    */
setCpp2WorkerThreadName(const std::string & cpp2WorkerThreadName)477   void setCpp2WorkerThreadName(const std::string& cpp2WorkerThreadName) {
478     CHECK(configMutable());
479     auto factory = ioThreadPool_->getThreadFactory();
480     CHECK(factory);
481     auto namedFactory =
482         std::dynamic_pointer_cast<folly::NamedThreadFactory>(factory);
483     CHECK(namedFactory);
484     namedFactory->setNamePrefix(cpp2WorkerThreadName);
485   }
486 
487   // if overloaded, returns applicable overloaded exception code.
488   folly::Optional<std::string> checkOverload(
489       const transport::THeader::StringToStringMap* readHeaders = nullptr,
490       const std::string* = nullptr) const final;
491 
492   // returns descriptive error if application is unable to process request
493   PreprocessResult preprocess(
494       const server::PreprocessParams& params) const final;
495 
496   std::string getLoadInfo(int64_t load) const override;
497 
498   /*
499    * Use a ZeroCopyEnableFunc to decide when to use zerocopy mode
500    * Ex: use zerocopy when the IOBuf chain exceeds a certain thresold
501    * setZeroCopyEnableFunc([threshold](const std::unique_ptr<folly::IOBuf>& buf)
502    * { return (buf->computeChainDataLength() > threshold);});
503    */
setZeroCopyEnableFunc(folly::AsyncWriter::ZeroCopyEnableFunc func)504   void setZeroCopyEnableFunc(folly::AsyncWriter::ZeroCopyEnableFunc func) {
505     zeroCopyEnableFunc_ = std::move(func);
506   }
507 
getZeroCopyEnableFunc()508   const folly::AsyncWriter::ZeroCopyEnableFunc& getZeroCopyEnableFunc() const {
509     return zeroCopyEnableFunc_;
510   }
511 
setAcceptExecutor(std::shared_ptr<folly::IOThreadPoolExecutor> pool)512   void setAcceptExecutor(std::shared_ptr<folly::IOThreadPoolExecutor> pool) {
513     acceptPool_ = pool;
514   }
515 
516   /**
517    * Generally the acceptor should not do any work other than
518    * accepting connections, so use this with care.
519    */
getAcceptExecutor()520   std::shared_ptr<folly::IOThreadPoolExecutor> getAcceptExecutor() {
521     return acceptPool_;
522   }
523 
setNumAcceptThreads(int numAcceptThreads)524   void setNumAcceptThreads(int numAcceptThreads) {
525     CHECK(!acceptPool_);
526     nAcceptors_ = numAcceptThreads;
527   }
528 
529   /**
530    * Set the SSLContextConfig on the thrift server.
531    */
setSSLConfig(std::shared_ptr<wangle::SSLContextConfig> context)532   void setSSLConfig(std::shared_ptr<wangle::SSLContextConfig> context) {
533     CHECK(configMutable());
534     if (context) {
535       setSSLConfig(folly::observer::makeObserver(
536           [context = std::move(context)]() { return *context; }));
537     }
538     updateCertsToWatch();
539   }
540 
541   /**
542    * Set the SSLContextConfig on the thrift server. Note that the thrift server
543    * keeps an observer on the SSLContextConfig. Whenever the SSLContextConfig
544    * has an update, the observer callback would reset SSLContextConfig on all
545    * acceptors.
546    */
setSSLConfig(folly::observer::Observer<wangle::SSLContextConfig> contextObserver)547   void setSSLConfig(
548       folly::observer::Observer<wangle::SSLContextConfig> contextObserver) {
549     sslContextObserver_ = folly::observer::makeObserver(
550         [observer = std::move(contextObserver),
551          alpnObserver = ThriftServer::alpnAllowMismatch()]() {
552           auto context = **observer;
553           context.isDefault = true;
554           context.alpnAllowMismatch = **alpnObserver;
555           return context;
556         });
557   }
558 
setFizzConfig(wangle::FizzConfig config)559   void setFizzConfig(wangle::FizzConfig config) { fizzConfig_ = config; }
560 
setThriftConfig(ThriftTlsConfig thriftConfig)561   void setThriftConfig(ThriftTlsConfig thriftConfig) {
562     thriftConfig_ = thriftConfig;
563   }
564 
setSSLCacheOptions(wangle::SSLCacheOptions options)565   void setSSLCacheOptions(wangle::SSLCacheOptions options) {
566     sslCacheOptions_ = std::move(options);
567   }
568 
setTicketSeeds(wangle::TLSTicketKeySeeds seeds)569   void setTicketSeeds(wangle::TLSTicketKeySeeds seeds) { ticketSeeds_ = seeds; }
570 
571   /**
572    * Set the ssl handshake timeout.
573    */
setSSLHandshakeTimeout(std::optional<std::chrono::milliseconds> timeout)574   void setSSLHandshakeTimeout(
575       std::optional<std::chrono::milliseconds> timeout) {
576     sslHandshakeTimeout_ = timeout;
577   }
578 
getSSLHandshakeTimeout()579   const std::optional<std::chrono::milliseconds>& getSSLHandshakeTimeout()
580       const {
581     return sslHandshakeTimeout_;
582   }
583 
584   /**
585    * Stops the Thrift server if it's idle for the given time.
586    */
setIdleServerTimeout(std::chrono::milliseconds timeout)587   void setIdleServerTimeout(std::chrono::milliseconds timeout) {
588     idleServerTimeout_ = timeout;
589   }
590 
591   /**
592    * Configures maxReadsPerEvent for accepted connections, see
593    * `folly::AsyncSocket::setMaxReadsPerEvent` for more details.
594    */
setSocketMaxReadsPerEvent(uint16_t socketMaxReadsPerEvent)595   void setSocketMaxReadsPerEvent(uint16_t socketMaxReadsPerEvent) {
596     socketMaxReadsPerEvent_ = socketMaxReadsPerEvent;
597   }
598 
599   void updateTicketSeeds(wangle::TLSTicketKeySeeds seeds);
600 
601   void updateTLSCert();
602 
603   /**
604    * Tells the thrift server to update ticket seeds with the contents of the
605    * file ticketPath when modified and initialized the seeds with the contents
606    * of the file ticketPath. The seed file previously being watched will no
607    * longer be watched.  This is not thread safe.
608    */
609   void watchTicketPathForChanges(const std::string& ticketPath);
610 
setFastOpenOptions(bool enableTFO,uint32_t fastOpenQueueSize)611   void setFastOpenOptions(bool enableTFO, uint32_t fastOpenQueueSize) {
612     enableTFO_ = enableTFO;
613     fastOpenQueueSize_ = fastOpenQueueSize;
614   }
615 
getTFOEnabled()616   std::optional<bool> getTFOEnabled() { return enableTFO_; }
617 
setReusePort(bool reusePort)618   void setReusePort(bool reusePort) { reusePort_ = reusePort; }
619 
getReusePort()620   std::optional<bool> getReusePort() { return reusePort_; }
621 
622   const std::optional<folly::observer::Observer<wangle::SSLContextConfig>>&
getSSLConfig()623   getSSLConfig() const {
624     return sslContextObserver_;
625   }
626 
getTicketSeeds()627   const std::optional<wangle::TLSTicketKeySeeds>& getTicketSeeds() const {
628     return ticketSeeds_;
629   }
630 
getSSLCacheOptions()631   const std::optional<wangle::SSLCacheOptions>& getSSLCacheOptions() const {
632     return sslCacheOptions_;
633   }
634 
getServerSocketConfig()635   wangle::ServerSocketConfig getServerSocketConfig() {
636     wangle::ServerSocketConfig config;
637     if (sslContextObserver_.has_value()) {
638       config.sslContextConfigs.push_back(*sslContextObserver_->getSnapshot());
639     }
640     if (sslCacheOptions_) {
641       config.sslCacheOptions = *sslCacheOptions_;
642     }
643     config.connectionIdleTimeout = getIdleTimeout();
644     config.acceptBacklog = getListenBacklog();
645     if (ticketSeeds_) {
646       config.initialTicketSeeds = *ticketSeeds_;
647     }
648     if (enableTFO_) {
649       config.enableTCPFastOpen = *enableTFO_;
650       config.fastOpenQueueSize = fastOpenQueueSize_;
651     }
652     if (sslHandshakeTimeout_) {
653       config.sslHandshakeTimeout = *sslHandshakeTimeout_;
654     } else if (getIdleTimeout() == std::chrono::milliseconds::zero()) {
655       // make sure a handshake that takes too long doesn't kill the connection
656       config.sslHandshakeTimeout = std::chrono::milliseconds::zero();
657     }
658     // By default, we set strictSSL to false. This means the server will start
659     // even if cert/key is missing as it may become available later
660     config.strictSSL = getStrictSSL() || getSSLPolicy() == SSLPolicy::REQUIRED;
661     config.fizzConfig = fizzConfig_;
662     config.customConfigMap["thrift_tls_config"] =
663         std::make_shared<ThriftTlsConfig>(thriftConfig_);
664     config.socketMaxReadsPerEvent = socketMaxReadsPerEvent_;
665 
666     config.useZeroCopy = !!zeroCopyEnableFunc_;
667     return config;
668   }
669 
670   /**
671    * Use the provided socket rather than binding to address_.  The caller must
672    * call ::bind on this socket, but should not call ::listen.
673    *
674    * NOTE: ThriftServer takes ownership of this 'socket' so if binding fails
675    *       we destroy this socket, while cleaning itself up. So, 'accept' better
676    *       work the first time :)
677    */
678   void useExistingSocket(int socket);
679   void useExistingSockets(const std::vector<int>& sockets);
680   void useExistingSocket(folly::AsyncServerSocket::UniquePtr socket);
681 
682   /**
683    * Return the file descriptor(s) associated with the listening socket
684    */
685   int getListenSocket() const;
686   std::vector<int> getListenSockets() const;
687 
688   /**
689    * Get the ThriftServer's main event base.
690    *
691    * @return a pointer to the EventBase.
692    */
getServeEventBase()693   folly::EventBase* getServeEventBase() const { return serveEventBase_; }
694 
695   /**
696    * Get the EventBaseManager used by this server.  This can be used to find
697    * or create the EventBase associated with any given thread, including any
698    * new threads created by clients.  This may be called from any thread.
699    *
700    * @return a pointer to the EventBaseManager.
701    */
702   folly::EventBaseManager* getEventBaseManager();
getEventBaseManager()703   const folly::EventBaseManager* getEventBaseManager() const {
704     return const_cast<ThriftServer*>(this)->getEventBaseManager();
705   }
706 
707   SSLPolicy getSSLPolicy() const;
708 
709   // Convenience method to check if SSLPolicy is explicitly set
isSSLPolicySet()710   bool isSSLPolicySet() const { return sslPolicy_.has_value(); }
711 
setSSLPolicy(SSLPolicy policy)712   void setSSLPolicy(SSLPolicy policy) { sslPolicy_ = policy; }
713 
setStrictSSL(bool strictSSL)714   void setStrictSSL(bool strictSSL) { strictSSL_ = strictSSL; }
715 
getStrictSSL()716   bool getStrictSSL() { return strictSSL_; }
717 
setAllowPlaintextOnLoopback(bool allow)718   void setAllowPlaintextOnLoopback(bool allow) {
719     allowPlaintextOnLoopback_ = allow;
720   }
721 
isPlaintextAllowedOnLoopback()722   bool isPlaintextAllowedOnLoopback() const {
723     return allowPlaintextOnLoopback_;
724   }
725 
setAllowCheckUnimplementedExtraInterfaces(bool allow)726   void setAllowCheckUnimplementedExtraInterfaces(bool allow) {
727     allowCheckUnimplementedExtraInterfaces_ = allow;
728   }
729 
isCheckUnimplementedExtraInterfacesAllowed()730   bool isCheckUnimplementedExtraInterfacesAllowed() const {
731     return allowCheckUnimplementedExtraInterfaces_;
732   }
733 
734   static folly::observer::Observer<bool> enableStopTLS();
735 
736 #if FOLLY_HAS_COROUTINES
737   /**
738    * Get CancellableAsyncScope that will be maintained by the Thrift Server.
739    * Cancellation is requested when the server is stopping.
740    * Returns nullptr, before server setup and after server stops.
741    */
getAsyncScope()742   folly::coro::CancellableAsyncScope* getAsyncScope() {
743     return asyncScope_.get();
744   }
745 
746   /**
747    * Get the global CancellableAsyncScope, it is usally the AsyncScope
748    * associated with the global server Cancellation is requested when the
749    * global server is stopping.
750    */
751   static folly::coro::CancellableAsyncScope& getGlobalAsyncScope();
752 #endif
753 
754   static void setGlobalServer(ThriftServer* server);
755 
setAcceptorFactory(const std::shared_ptr<wangle::AcceptorFactory> & acceptorFactory)756   void setAcceptorFactory(
757       const std::shared_ptr<wangle::AcceptorFactory>& acceptorFactory) {
758     acceptorFactory_ = acceptorFactory;
759   }
760 
761   /**
762    * Get the speed of adjusting connection accept rate.
763    */
getAcceptRateAdjustSpeed()764   double getAcceptRateAdjustSpeed() const { return acceptRateAdjustSpeed_; }
765 
766   /**
767    * Set the speed of adjusting connection accept rate.
768    */
setAcceptRateAdjustSpeed(double speed)769   void setAcceptRateAdjustSpeed(double speed) {
770     CHECK(configMutable());
771     acceptRateAdjustSpeed_ = speed;
772   }
773 
774   /**
775    * Enable/Disable TOS reflection on the server socket
776    */
setTosReflect(bool enable)777   void setTosReflect(bool enable) { tosReflect_ = enable; }
778 
779   /**
780    * Get TOS reflection setting for the server socket
781    */
getTosReflect()782   bool getTosReflect() const override { return tosReflect_; }
783 
784   /**
785    * Set default TOS for listener/accepted connections
786    */
setListenerTos(uint32_t tos)787   void setListenerTos(uint32_t tos) { listenerTos_ = tos; }
788 
789   /**
790    * Get default TOS for listener socket
791    */
getListenerTos()792   uint32_t getListenerTos() const override { return listenerTos_; }
793 
794   /**
795    * Get the number of connections dropped by the AsyncServerSocket
796    */
797   uint64_t getNumDroppedConnections() const override;
798 
799   /**
800    * Clear all the workers.
801    */
clearWorkers()802   void clearWorkers() { ioThreadPool_->join(); }
803 
804   /**
805    * Set whether to stop io workers when stopListening() is called (we do stop
806    * them by default).
807    */
setStopWorkersOnStopListening(bool stopWorkers)808   void setStopWorkersOnStopListening(bool stopWorkers) {
809     CHECK(configMutable());
810     stopWorkersOnStopListening_ = stopWorkers;
811   }
812 
813   /**
814    * Get whether to stop io workers when stopListening() is called.
815    */
getStopWorkersOnStopListening()816   bool getStopWorkersOnStopListening() const {
817     return stopWorkersOnStopListening_;
818   }
819 
820   /**
821    * If stopWorkersOnStopListening is disabled, then enabling
822    * leakOutstandingRequestsWhenServerStops permits thriftServer->serve() to
823    * return before all outstanding requests are joined.
824    */
leakOutstandingRequestsWhenServerStops(bool leak)825   void leakOutstandingRequestsWhenServerStops(bool leak) {
826     CHECK(configMutable());
827     joinRequestsWhenServerStops_ = !leak;
828   }
829 
830   /**
831    * Call this to complete initialization
832    */
833   void setup();
834 
835   /**
836    * Create and start the default thread manager unless it already exists.
837    */
838   void setupThreadManager();
839 
840   /**
841    * Kill the workers and wait for listeners to quit
842    */
843   void cleanUp();
844 
845   /**
846    * Preferably use this method in order to start ThriftServer created for
847    * DuplexChannel instead of the serve() method.
848    */
849   void startDuplex();
850 
851   /**
852    * This method should be used to cleanly stop a ThriftServer created for
853    * DuplexChannel before disposing the ThriftServer. The caller should pass in
854    * a shared_ptr to this ThriftServer since the ThriftServer does not have a
855    * way of getting that (does not inherit from enable_shared_from_this)
856    */
857   void stopDuplex(std::shared_ptr<ThriftServer> thisServer);
858 
859   /**
860    * One stop solution:
861    *
862    * starts worker threads, enters accept loop; when
863    * the accept loop exits, shuts down and joins workers.
864    */
865   void serve() override;
866 
867   /**
868    * Call this to stop the server, if started by serve()
869    *
870    * This (asynchronously) causes the main serve() function to stop listening
871    * for new connections, close existing connections, shut down the worker
872    * threads, and then return.
873    *
874    * NOTE: that this function may not be safe to call multiple times (such as
875    * from a signal handler) because a previous call may initiate a sequence of
876    * events leading to the destruction of this object.
877    * Instead you should use StopController (see getStopController()) which lets
878    * you guard against destruction (by way of folly::PrimaryPtr).
879    */
880   void stop() override;
881 
882   using StopController = ThriftServerStopController;
883 
884  private:
885   folly::PrimaryPtr<StopController> stopController_{
886       std::unique_ptr<StopController>{}};
887 
888  public:
getStopController()889   folly::PrimaryPtrRef<StopController> getStopController() {
890     return stopController_.ref();
891   }
892 
893   /**
894    * Call this to stop listening on the server port.
895    *
896    * This causes the main serve() function to stop listening for new
897    * connections while still allows the worker threads to process
898    * existing connections. stop() still needs to be called to clear
899    * up the worker threads.
900    */
901   void stopListening() override;
902 
903   // client side duplex
getDuplexServerChannel()904   std::shared_ptr<HeaderServerChannel> getDuplexServerChannel() {
905     return serverChannel_;
906   }
907 
908   // server side duplex
isDuplex()909   bool isDuplex() { return isDuplex_; }
910 
911   std::vector<std::unique_ptr<TransportRoutingHandler>> const*
getRoutingHandlers()912   getRoutingHandlers() const {
913     return &routingHandlers_;
914   }
915 
addRoutingHandler(std::unique_ptr<TransportRoutingHandler> routingHandler)916   void addRoutingHandler(
917       std::unique_ptr<TransportRoutingHandler> routingHandler) {
918     routingHandlers_.push_back(std::move(routingHandler));
919   }
920 
clearRoutingHandlers()921   void clearRoutingHandlers() { routingHandlers_.clear(); }
922 
setDuplex(bool duplex)923   void setDuplex(bool duplex) {
924     // setDuplex may only be called on the server side.
925     // serverChannel_ must be nullptr in this case
926     CHECK(serverChannel_ == nullptr);
927     CHECK(configMutable());
928     isDuplex_ = duplex;
929   }
930 
931   /**
932    * Returns a reference to the processor that is used by custom transports
933    */
getThriftProcessor()934   apache::thrift::ThriftProcessor* getThriftProcessor() {
935     return thriftProcessor_.get();
936   }
937 
getSockets()938   const std::vector<std::shared_ptr<folly::AsyncServerSocket>> getSockets()
939       const {
940     std::vector<std::shared_ptr<folly::AsyncServerSocket>> serverSockets;
941     for (auto& socket : ServerBootstrap::getSockets()) {
942       serverSockets.push_back(
943           std::dynamic_pointer_cast<folly::AsyncServerSocket>(socket));
944     }
945     return serverSockets;
946   }
947 
948   /**
949    * Sets an explicit AsyncProcessorFactory and sets the ThriftProcessor
950    * to use for custom transports
951    */
952   virtual void setProcessorFactory(
953       std::shared_ptr<AsyncProcessorFactory> pFac) override;
954 
955   /**
956    * Returns an AsyncProcessorFactory that wraps the user-provided service and
957    * additionally handles Thrift-internal methods as well (such as the
958    * monitoring interface).
959    *
960    * This is the factory that all transports should use to handle requests.
961    *
962    * Logically, this is an apache::thrift::MultiplexAsyncProcessorFactory with
963    * the following composition:
964    *
965    *    ┌────────────────────────┐
966    *    │      User Service      │
967    *    │ (setProcessorFactory)  │  │
968    *    └────────────────────────┘  │
969    *                                │
970    *    ┌────────────────────────┐  │
971    *    │    Status Interface    │  │
972    *    │  (setStatusInterface)  │  │
973    *    └────────────────────────┘  │
974    *                                │   Method
975    *    ┌────────────────────────┐  │ precedence
976    *    │  Monitoring Interface  │  │
977    *    │(setMonitoringInterface)│  │
978    *    └────────────────────────┘  │
979    *                                │
980    *    ┌────────────────────────┐  │
981    *    │   Control Interface    │  ▼
982    *    │ (setControlInterface)  │
983    *    └────────────────────────┘
984    */
getDecoratedProcessorFactory()985   AsyncProcessorFactory& getDecoratedProcessorFactory() const {
986     CHECK(decoratedProcessorFactory_)
987         << "Server must be set up before calling this method";
988     return *decoratedProcessorFactory_;
989   }
990 
991   /**
992    * Returns an AsyncProcessor from getDecoratedProcessorFactory() without any
993    * application-specific event handlers installed on the underlying processors.
994    * This is useful, for example, in InterfaceKind::MONITORING where
995    * application-specific checks (such as ACL checks) should be bypassed.
996    */
997   std::unique_ptr<AsyncProcessor> getDecoratedProcessorWithoutEventHandlers()
998       const;
999 
1000   /**
1001    * A struct containing all "extra" internal interfaces that the service
1002    * multiplexes behind the main user-defined interface.
1003    *
1004    * See ThriftServer::getDecoratedProcessorFactory.
1005    */
1006   struct ExtraInterfaces {
1007     // See ThriftServer::setMonitoringInterface.
1008     std::shared_ptr<MonitoringServerInterface> monitoring;
1009     // See ThriftServer::setStatusInterface.
1010     std::shared_ptr<StatusServerInterface> status;
1011     // See ThriftServer::setControlInterface
1012     std::shared_ptr<ControlServerInterface> control;
1013   };
1014 
1015   // ThriftServer by defaults uses a global ShutdownSocketSet, so all socket's
1016   // FDs are registered there. But in some tests you might want to simulate 2
1017   // ThriftServer running in different processes, so their ShutdownSocketSet are
1018   // different. In that case server should have their own SSS each so shutting
1019   // down FD from one doesn't interfere with shutting down sockets for the
1020   // other.
1021   void replaceShutdownSocketSet(
1022       const std::shared_ptr<folly::ShutdownSocketSet>& newSSS);
1023 
1024   static folly::observer::Observer<std::list<std::string>>
1025   defaultNextProtocols();
1026 
getQuickExitOnShutdownTimeout()1027   bool getQuickExitOnShutdownTimeout() const {
1028     return quickExitOnShutdownTimeout_;
1029   }
1030 
setQuickExitOnShutdownTimeout(bool quickExitOnShutdownTimeout)1031   void setQuickExitOnShutdownTimeout(bool quickExitOnShutdownTimeout) {
1032     quickExitOnShutdownTimeout_ = quickExitOnShutdownTimeout;
1033   }
1034 
1035   static folly::observer::Observer<bool> alpnAllowMismatch();
1036 
1037   /**
1038    * For each request debug stub, a snapshot information can be constructed to
1039    * persist some transitent states about the corresponding request.
1040    */
1041   class RequestSnapshot {
1042    public:
RequestSnapshot(const RequestsRegistry::DebugStub & stub)1043     explicit RequestSnapshot(const RequestsRegistry::DebugStub& stub)
1044         : methodName_(stub.getMethodName()),
1045           creationTimestamp_(stub.getTimestamp()),
1046           finishedTimestamp_(stub.getFinished()),
1047           protoId_(stub.getProtoId()),
1048           peerAddress_(*stub.getPeerAddress()),
1049           localAddress_(*stub.getLocalAddress()),
1050           rootRequestContextId_(stub.getRootRequestContextId()),
1051           reqId_(RequestsRegistry::getRequestId(rootRequestContextId_)),
1052           reqDebugLog_(collectRequestDebugLog(stub)) {
1053       auto requestPayload = rocket::unpack<RequestPayload>(stub.clonePayload());
1054       payload_ = std::move(*requestPayload->payload);
1055       auto& metadata = requestPayload->metadata;
1056       if (metadata.otherMetadata_ref()) {
1057         headers_ = std::move(*requestPayload->metadata.otherMetadata_ref());
1058       }
1059       clientId_ = metadata.clientId_ref().to_optional();
1060       serviceTraceMeta_ = metadata.serviceTraceMeta_ref().to_optional();
1061       auto req = stub.getRequest();
1062       DCHECK(
1063           req != nullptr || finishedTimestamp_.time_since_epoch().count() != 0);
1064       startedProcessing_ = req == nullptr ? true : stub.getStartedProcessing();
1065     }
1066 
getMethodName()1067     const std::string& getMethodName() const { return methodName_; }
1068 
getCreationTimestamp()1069     std::chrono::steady_clock::time_point getCreationTimestamp() const {
1070       return creationTimestamp_;
1071     }
1072 
getFinishedTimestamp()1073     std::chrono::steady_clock::time_point getFinishedTimestamp() const {
1074       return finishedTimestamp_;
1075     }
1076 
getRootRequestContextId()1077     intptr_t getRootRequestContextId() const { return rootRequestContextId_; }
1078 
getRequestId()1079     const std::string& getRequestId() const { return reqId_; }
1080 
getStartedProcessing()1081     bool getStartedProcessing() const { return startedProcessing_; }
1082 
1083     /**
1084      * Returns empty IOBuff if payload is not present.
1085      */
getPayload()1086     const folly::IOBuf& getPayload() const { return payload_; }
1087 
getHeaders()1088     const transport::THeader::StringToStringMap& getHeaders() const {
1089       return headers_;
1090     }
1091 
getProtoId()1092     protocol::PROTOCOL_TYPES getProtoId() const { return protoId_; }
1093 
getLocalAddress()1094     const folly::SocketAddress& getLocalAddress() const {
1095       return localAddress_;
1096     }
getPeerAddress()1097     const folly::SocketAddress& getPeerAddress() const { return peerAddress_; }
1098 
getDebugLog()1099     const std::vector<std::string>& getDebugLog() const { return reqDebugLog_; }
1100 
clientId()1101     const auto& clientId() const { return clientId_; }
clientId()1102     auto& clientId() { return clientId_; }
1103 
serviceTraceMeta()1104     const auto& serviceTraceMeta() const { return serviceTraceMeta_; }
serviceTraceMeta()1105     auto& serviceTraceMeta() { return serviceTraceMeta_; }
1106 
1107    private:
1108     const std::string methodName_;
1109     const std::chrono::steady_clock::time_point creationTimestamp_;
1110     const std::chrono::steady_clock::time_point finishedTimestamp_;
1111     const protocol::PROTOCOL_TYPES protoId_;
1112     folly::IOBuf payload_;
1113     transport::THeader::StringToStringMap headers_;
1114     std::optional<std::string> clientId_;
1115     std::optional<std::string> serviceTraceMeta_;
1116     folly::SocketAddress peerAddress_;
1117     folly::SocketAddress localAddress_;
1118     intptr_t rootRequestContextId_;
1119     const std::string reqId_;
1120     const std::vector<std::string> reqDebugLog_;
1121     bool startedProcessing_;
1122   };
1123 
1124   struct ConnectionSnapshot {
1125     size_t numActiveRequests{0};
1126     size_t numPendingWrites{0};
1127     std::chrono::steady_clock::time_point creationTime;
1128   };
1129   using RequestSnapshots = std::vector<RequestSnapshot>;
1130   using ConnectionSnapshots =
1131       std::unordered_map<folly::SocketAddress, ConnectionSnapshot>;
1132   struct ServerSnapshot {
1133     RecentRequestCounter::Values recentCounters;
1134     RequestSnapshots requests;
1135     ConnectionSnapshots connections;
1136   };
1137   struct SnapshotOptions {
1138     std::chrono::microseconds connectionsAgeMax;
1139   };
getServerSnapshot()1140   folly::SemiFuture<ServerSnapshot> getServerSnapshot() {
1141     return getServerSnapshot(SnapshotOptions{});
1142   }
1143   folly::SemiFuture<ServerSnapshot> getServerSnapshot(
1144       const SnapshotOptions& options);
1145 
1146   /**
1147    * If shutdown does not complete within the configured worker join timeout,
1148    * then we schedule a task to dump the server's state to disk for
1149    * investigation.
1150    *
1151    * The implementor of the dumping logic should provide the the task as well
1152    * as an appropriate timeout -- we do not want to indefinitely block shutdown
1153    * in case the task deadlocks.
1154    */
1155   struct DumpSnapshotOnLongShutdownResult {
1156     folly::SemiFuture<folly::Unit> task;
1157     std::chrono::milliseconds timeout;
1158   };
1159 
1160   enum class UnimplementedExtraInterfacesResult {
1161     /**
1162      * The method is completely unrecognized by the service.
1163      */
1164     UNRECOGNIZED,
1165     /**
1166      * Extra interfaces are implemented directly by the service.
1167      */
1168     IMPLEMENTED,
1169     /**
1170      * Extra interfaces are left unimplemented but recognized by the service.
1171      */
1172     UNIMPLEMENTED,
1173   };
1174 };
1175 
1176 template <typename AcceptorClass, typename SharedSSLContextManagerClass>
1177 class ThriftAcceptorFactory : public wangle::AcceptorFactorySharedSSLContext {
1178  public:
ThriftAcceptorFactory(ThriftServer * server)1179   ThriftAcceptorFactory(ThriftServer* server) : server_(server) {}
1180 
1181   std::shared_ptr<wangle::SharedSSLContextManager>
initSharedSSLContextManager()1182   initSharedSSLContextManager() {
1183     if constexpr (!std::is_same<SharedSSLContextManagerClass, void>::value) {
1184       sharedSSLContextManager_ = std::make_shared<SharedSSLContextManagerClass>(
1185           server_->getServerSocketConfig());
1186     }
1187     return sharedSSLContextManager_;
1188   }
1189 
newAcceptor(folly::EventBase * eventBase)1190   std::shared_ptr<wangle::Acceptor> newAcceptor(folly::EventBase* eventBase) {
1191     if (!sharedSSLContextManager_) {
1192       return AcceptorClass::create(server_, nullptr, eventBase);
1193     }
1194     auto acceptor = AcceptorClass::create(
1195         server_,
1196         nullptr,
1197         eventBase,
1198         sharedSSLContextManager_->getCertManager(),
1199         sharedSSLContextManager_->getContextManager(),
1200         sharedSSLContextManager_->getFizzContext());
1201     sharedSSLContextManager_->addAcceptor(acceptor);
1202     return acceptor;
1203   }
1204 
1205  protected:
1206   ThriftServer* server_;
1207 };
1208 using DefaultThriftAcceptorFactory = ThriftAcceptorFactory<Cpp2Worker, void>;
1209 
1210 using DefaultThriftAcceptorFactorySharedSSLContext = ThriftAcceptorFactory<
1211     Cpp2Worker,
1212     wangle::SharedSSLContextManagerImpl<wangle::FizzConfigUtil>>;
1213 
1214 namespace detail {
1215 
1216 THRIFT_PLUGGABLE_FUNC_DECLARE(
1217     apache::thrift::ThriftServer::DumpSnapshotOnLongShutdownResult,
1218     dumpSnapshotOnLongShutdown);
1219 
1220 THRIFT_PLUGGABLE_FUNC_DECLARE(
1221     apache::thrift::ThriftServer::ExtraInterfaces,
1222     createDefaultExtraInterfaces);
1223 
1224 THRIFT_PLUGGABLE_FUNC_DECLARE(
1225     ThriftServer::UnimplementedExtraInterfacesResult,
1226     serviceHasUnimplementedExtraInterfaces,
1227     AsyncProcessorFactory& service);
1228 
1229 } // namespace detail
1230 
1231 } // namespace thrift
1232 } // namespace apache
1233 
1234 #endif // #ifndef THRIFT_SERVER_H_
1235