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 #include <signal.h>
18 
19 #include <iostream>
20 
21 #include <folly/Random.h>
22 #include <folly/String.h>
23 #include <folly/init/Init.h>
24 #include <folly/ssl/Init.h>
25 
26 #include <thrift/lib/cpp2/server/ThriftServer.h>
27 #include <thrift/perf/cpp/AsyncLoadHandler2.h>
28 
29 using std::cout;
30 using namespace apache::thrift;
31 
32 DEFINE_int32(port, 1234, "server port");
33 DEFINE_int64(num_threads, 4, "number of worker threads");
34 DEFINE_int64(num_queue_threads, 4, "number of task queue threads");
35 DEFINE_int32(max_conn_pool_size, 0, "maximum size of idle connection pool");
36 DEFINE_int32(idle_timeout, 0, "idle timeout (in milliseconds)");
37 DEFINE_int32(task_timeout, 0, "task timeout (in milliseconds)");
38 DEFINE_int32(
39     handshake_timeout,
40     0,
41     "SSL handshake timeout (in milliseconds). "
42     "Default is 0, which is to not set a granular timeout for SSL handshakes. "
43     "Connections that stall during handshakes may still be timed out "
44     "with --idle_timeout");
45 DEFINE_int32(max_connections, 0, "DEPRECATED (REMOVE ME)");
46 DEFINE_int32(max_requests, 0, "max active requests");
47 DEFINE_string(cert, "", "server SSL certificate file");
48 DEFINE_string(key, "", "server SSL private key file");
49 DEFINE_string(client_ca_list, "", "file pointing to a client CA or list");
50 DEFINE_string(ticket_seeds, "", "server Ticket seeds file");
51 DEFINE_string(
52     ecc_curve, "prime256v1", "The ECC curve to use for EC handshakes");
53 DEFINE_bool(enable_tfo, true, "Enable TFO");
54 DEFINE_int32(tfo_queue_size, 1000, "TFO queue size");
55 
setTunables(ThriftServer * server)56 void setTunables(ThriftServer* server) {
57   if (FLAGS_idle_timeout > 0) {
58     server->setIdleTimeout(std::chrono::milliseconds(FLAGS_idle_timeout));
59   }
60   if (FLAGS_task_timeout > 0) {
61     server->setTaskExpireTime(std::chrono::milliseconds(FLAGS_task_timeout));
62   }
63   if (FLAGS_handshake_timeout > 0) {
64     server->setSSLHandshakeTimeout(
65         std::chrono::milliseconds(FLAGS_handshake_timeout));
66   }
67 }
68 
69 ThriftServer* g_server = nullptr;
70 
sigHandler(int)71 [[noreturn]] void sigHandler(int /* signo */) {
72   g_server->stop();
73   exit(0);
74 }
75 
main(int argc,char * argv[])76 int main(int argc, char* argv[]) {
77   folly::init(&argc, &argv);
78 
79   if (argc != 1) {
80     fprintf(stderr, "error: unhandled arguments:");
81     for (int n = 1; n < argc; ++n) {
82       fprintf(stderr, " %s", argv[n]);
83     }
84     fprintf(stderr, "\n");
85     return 1;
86   }
87 
88   auto handler = std::make_shared<AsyncLoadHandler2>();
89 
90   std::shared_ptr<ThriftServer> server;
91   server.reset(new ThriftServer());
92   server->setInterface(handler);
93   server->setPort(FLAGS_port);
94   server->setNumIOWorkerThreads(FLAGS_num_threads);
95   server->setNumCPUWorkerThreads(FLAGS_num_queue_threads);
96   server->setMaxRequests(FLAGS_max_requests);
97   server->setFastOpenOptions(FLAGS_enable_tfo, FLAGS_tfo_queue_size);
98 
99   if (FLAGS_cert.length() > 0 && FLAGS_key.length() > 0) {
100     auto sslContext = std::make_shared<wangle::SSLContextConfig>();
101     sslContext->setCertificate(FLAGS_cert, FLAGS_key, "");
102     sslContext->clientCAFile = FLAGS_client_ca_list;
103     sslContext->eccCurveName = FLAGS_ecc_curve;
104     server->setSSLConfig(sslContext);
105   }
106   if (!FLAGS_ticket_seeds.empty()) {
107     server->watchTicketPathForChanges(FLAGS_ticket_seeds);
108   } else {
109     // Generate random seeds to use for all workers.  If no seeds are set, then
110     // each worker gets its own random seeds, so session resumptions fail across
111     // workers.
112     wangle::TLSTicketKeySeeds seeds;
113     for (auto* seed : {&seeds.oldSeeds, &seeds.currentSeeds, &seeds.newSeeds}) {
114       auto randomData = folly::Random::secureRandom<uint64_t>();
115       auto asHex = folly::hexlify(folly::ByteRange(
116           (const unsigned char*)&randomData, sizeof(uint64_t)));
117       seed->push_back(std::move(asHex));
118     }
119     server->setTicketSeeds(std::move(seeds));
120   }
121 
122   // Set tunable server parameters
123   setTunables(server.get());
124 
125   g_server = server.get();
126   signal(SIGINT, sigHandler);
127 
128   cout << "Serving requests on port " << FLAGS_port << "...\n";
129   server->serve();
130 
131   cout << "Exiting normally" << std::endl;
132 
133   return 0;
134 }
135