proxygen
Server.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018-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 
17 #include <folly/init/Init.h>
20 #include <folly/ssl/Init.h>
27 
28 DEFINE_string(cert_path, "", "Path to cert pem");
29 DEFINE_string(key_path, "", "Path to cert key");
30 DEFINE_string(ca_path, "", "Path to trusted CA file");
31 DEFINE_int32(port, 8080, "Listen port");
32 DEFINE_string(tickets_path, "", "Path for ticket seeds");
33 DEFINE_uint32(num_workers, 2, "Number of worker threads");
34 
43 using namespace wangle;
44 using namespace folly;
45 
47 
48 namespace {
49 // the main logic of our echo server; receives a string and writes it straight
50 // back
51 class EchoHandler : public HandlerAdapter<std::string> {
52  public:
53  void read(Context* ctx, std::string msg) override {
54  std::cout << "handling " << msg << std::endl;
55  write(ctx, msg + "\r\n");
56  }
57 };
58 
59 // where we define the chain of handlers for each messeage received
60 class EchoPipelineFactory : public PipelineFactory<EchoPipeline> {
61  public:
62  EchoPipeline::Ptr newPipeline(
63  std::shared_ptr<AsyncTransportWrapper> sock) override {
64  auto pipeline = EchoPipeline::create();
65  pipeline->addBack(AsyncSocketHandler(sock));
66  pipeline->addBack(LineBasedFrameDecoder(8192));
67  pipeline->addBack(StringCodec());
68  pipeline->addBack(EchoHandler());
69  pipeline->finalize();
70  return pipeline;
71  }
72 };
73 
74 // Init the processor callbacks. It's fine to do this
75 // even if nothing is being watched
76 void initCredProcessorCallbacks(
78  TLSCredProcessor& processor) {
79  // set up ticket seed callback
80  processor.addTicketCallback([&](TLSTicketKeySeeds seeds) {
81  // update
82  sb.forEachWorker([&](Acceptor* acceptor) {
83  if (!acceptor) {
84  // this condition can happen if the processor triggers before the
85  // server is ready / listening
86  return;
87  }
88  auto evb = acceptor->getEventBase();
89  if (!evb) {
90  return;
91  }
92  evb->runInEventBaseThread([acceptor, seeds] {
93  acceptor->setTLSTicketSecrets(
94  seeds.oldSeeds, seeds.currentSeeds, seeds.newSeeds);
95  });
96  });
97  });
98 
99  // Reconfigure SSL when we detect cert or CA changes.
100  processor.addCertCallback([&] {
101  sb.forEachWorker([&](Acceptor* acceptor) {
102  if (!acceptor) {
103  return;
104  }
105  auto evb = acceptor->getEventBase();
106  if (!evb) {
107  return;
108  }
109  evb->runInEventBaseThread([acceptor] {
110  acceptor->resetSSLContextConfigs();
111  });
112  });
113  });
114 }
115 } // namespace
116 
117 int main(int argc, char** argv) {
118  folly::Init init(&argc, &argv);
120 
121  ServerSocketConfig cfg;
123 
125  TLSCredProcessor processor;
126 
127  if (!FLAGS_tickets_path.empty()) {
128  seeds = TLSCredProcessor::processTLSTickets(FLAGS_tickets_path);
129  if (seeds) {
130  cfg.initialTicketSeeds = *seeds;
131  // watch for changes
132  processor.setTicketPathToWatch(FLAGS_tickets_path);
133  }
134  }
135 
136  if (!FLAGS_cert_path.empty() && !FLAGS_key_path.empty()) {
137  VLOG(0) << "Configuring SSL";
138  SSLContextConfig sslCfg;
139  sslCfg.addCertificate(FLAGS_cert_path, FLAGS_key_path, "");
140  sslCfg.clientCAFile = FLAGS_ca_path;
141  sslCfg.isDefault = true;
142  cfg.sslContextConfigs.push_back(sslCfg);
143  // IMPORTANT: when allowing both plaintext and ssl on the same port,
144  // the acceptor requires 9 bytes of data to determine what kind of
145  // connection is coming in. If the client does not send 9 bytes the
146  // connection will idle out before the EchoCallback receives data.
148 
149  // reload ssl contexts when certs change
150  std::set<std::string> pathsToWatch { FLAGS_cert_path, FLAGS_key_path };
151  if (!FLAGS_ca_path.empty()) {
152  pathsToWatch.insert(FLAGS_ca_path);
153  }
154  processor.setCertPathsToWatch(std::move(pathsToWatch));
155  }
156 
157  initCredProcessorCallbacks(sb, processor);
158 
159  // workers
160  auto workers =
161  std::make_shared<folly::IOThreadPoolExecutor>(FLAGS_num_workers);
162 
163  // create a server
164  sb.acceptorConfig(cfg);
165  sb.childPipeline(std::make_shared<EchoPipelineFactory>());
166  sb.group(workers);
167 
168  sb.bind(FLAGS_port);
169  sb.waitForStop();
170  return 0;
171 }
std::vector< std::string > newSeeds
void setTicketPathToWatch(const std::string &ticketFile)
std::vector< std::string > currentSeeds
void write(const T &in, folly::io::Appender &appender)
Definition: Types-inl.h:112
static folly::Optional< wangle::TLSTicketKeySeeds > processTLSTickets(const std::string &fileName)
int main(int argc, char **argv)
Definition: Server.cpp:117
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
void bind(folly::AsyncServerSocket::UniquePtr s)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
DEFINE_uint32(num_workers, 2,"Number of worker threads")
void init()
Definition: Init.cpp:54
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void init()
ServerBootstrap * childPipeline(std::shared_ptr< PipelineFactory< Pipeline >> factory)
char ** argv
Pipeline< IOBufQueue &, std::string > EchoPipeline
Definition: Server.cpp:46
size_t read(T &out, folly::io::Cursor &cursor)
Definition: Types-inl.h:258
void addCertCallback(std::function< void()> callback)
bool runInEventBaseThread(void(*fn)(T *), T *arg)
Definition: EventBase.h:794
ServerBootstrap * group(std::shared_ptr< folly::IOThreadPoolExecutor > io_group)
DEFINE_string(cert_path,"","Path to cert pem")
void setCertPathsToWatch(std::set< std::string > certFiles)
void forEachWorker(F &&f) const
void addCertificate(const std::string &certPath, const std::string &keyPath, const std::string &passwordPath)
TLSTicketKeySeeds initialTicketSeeds
const char * string
Definition: Conv.cpp:212
static Ptr create()
Definition: Pipeline.h:174
std::shared_ptr< Pipeline > Ptr
Definition: Pipeline.h:172
std::vector< std::string > oldSeeds
ServerBootstrap * acceptorConfig(const ServerSocketConfig &accConfig)
virtual void resetSSLContextConfigs()
Definition: Acceptor.cpp:162
virtual folly::EventBase * getEventBase() const
Definition: Acceptor.h:127
std::vector< SSLContextConfig > sslContextConfigs
DEFINE_int32(port, 8080,"Listen port")
void addTicketCallback(std::function< void(wangle::TLSTicketKeySeeds)> callback)