proxygen
Client.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 <iostream>
18 
19 #include <folly/init/Init.h>
23 #include <folly/ssl/Init.h>
32 
33 using namespace wangle;
34 using namespace folly;
35 
36 DEFINE_string(ip, "::1", "Ip address to connect to");
37 DEFINE_uint32(port, 8080, "Port to connect to");
38 DEFINE_bool(ssl, true, "Whether to use SSL");
39 DEFINE_string(cache_file, "", "Session cache file");
40 DEFINE_string(cert_path, "", "Path to client cert pem");
41 DEFINE_string(key_path, "", "Path to client cert key pem");
42 DEFINE_string(ca_path, "", "Path to trusted CA file");
43 
44 const std::string SESSION_KEY = "test_client";
45 
56 namespace {
58 
59 // the handler for receiving messages back from the server
60 class EchoHandler : public HandlerAdapter<std::string> {
61  public:
62  void read(Context*, std::string msg) override {
63  std::cout << "received back: " << msg;
64  }
65  void readException(Context* ctx, exception_wrapper e) override {
66  std::cout << exceptionStr(e) << std::endl;
67  close(ctx);
68  }
69  void readEOF(Context* ctx) override {
70  std::cout << "EOF received :(" << std::endl;
71  close(ctx);
72  }
73 };
74 
75 // chains the handlers together to define the response pipeline
76 class EchoPipelineFactory : public PipelineFactory<EchoPipeline> {
77  public:
78  EchoPipeline::Ptr newPipeline(
79  std::shared_ptr<AsyncTransportWrapper> sock) override {
80  auto pipeline = EchoPipeline::create();
81  pipeline->addBack(AsyncSocketHandler(sock));
82  pipeline->addBack(
83  EventBaseHandler()); // ensure we can write from any thread
84  pipeline->addBack(LineBasedFrameDecoder(8192, false));
85  pipeline->addBack(StringCodec());
86  pipeline->addBack(EchoHandler());
87  pipeline->finalize();
88  return pipeline;
89  }
90 };
91 
92 class EchoClientBootstrap : public ClientBootstrap<EchoPipeline> {
93  public:
94  void makePipeline(
95  std::shared_ptr<folly::AsyncTransportWrapper> socket) override {
96  auto sslSock = socket->getUnderlyingTransport<AsyncSSLSocket>();
97  if (sslSock) {
98  sslSock->setSessionKey(SESSION_KEY);
99  }
101  }
102 };
103 
104 std::shared_ptr<SSLContext> createSSLContext() {
105  auto context = std::make_shared<SSLContext>();
106  if (!FLAGS_ca_path.empty()) {
107  context->loadTrustedCertificates(FLAGS_ca_path.c_str());
108  // don't do peer name validation
109  context->authenticate(true, false);
110  // verify the server cert
111  context->setVerificationOption(SSLContext::SSLVerifyPeerEnum::VERIFY);
112  }
113  if (!FLAGS_cert_path.empty() && !FLAGS_key_path.empty()) {
114  context->loadCertificate(FLAGS_cert_path.c_str());
115  context->loadPrivateKey(FLAGS_key_path.c_str());
116  if (!context->isCertKeyPairValid()) {
117  throw std::runtime_error("Cert and key do not match");
118  }
119  }
120  folly::ssl::setSignatureAlgorithms<folly::ssl::SSLCommonOptions>(*context);
121  return context;
122 }
123 } // namespace
124 
125 int main(int argc, char** argv) {
126  folly::Init init(&argc, &argv);
128 
129  // an in memory ssl session cache used for caching sessions
130  std::shared_ptr<SSLSessionPersistentCache> cache;
131  if (!FLAGS_cache_file.empty()) {
132  cache = std::make_shared<SSLSessionPersistentCache>(
133  FLAGS_cache_file, 100, std::chrono::seconds(60));
134  }
135 
136  EchoClientBootstrap client;
137  client.group(std::make_shared<IOThreadPoolExecutor>(1));
138  client.pipelineFactory(std::make_shared<EchoPipelineFactory>());
139 
140  if (FLAGS_ssl) {
141  auto ctx = createSSLContext();
142  // attach the context to the cache
143  if (cache) {
145  ctx->getSSLCtx(), cache.get());
146  auto session = cache->getSSLSession(SESSION_KEY);
147  if (session) {
148  VLOG(0) << "Reusing session";
149  client.sslSession(session.release());
150  }
151  }
152  client.sslContext(ctx);
153  }
154 
155  SocketAddress addr(FLAGS_ip.c_str(), FLAGS_port);
156  VLOG(0) << "Connecting";
157  auto pipeline = client.connect(addr).get();
158  VLOG(0) << "Connected";
159  try {
160  while (true) {
161  std::string line;
162  std::getline(std::cin, line);
163  if (line == "") {
164  VLOG(0) << "End";
165  break;
166  }
167  VLOG(0) << "Sending " << line;
168  pipeline->write(line + "\r\n").get();
169  if (line == "bye") {
170  pipeline->close();
171  break;
172  }
173  }
174  } catch (const std::exception& e) {
175  std::cout << exceptionStr(e) << std::endl;
176  }
177  return 0;
178 }
const std::string SESSION_KEY
Definition: Client.cpp:44
context
Definition: CMakeCache.txt:563
fbstring exceptionStr(const std::exception &e)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void BENCHFUN() getline(size_t iters, size_t arg)
void init()
Definition: Init.cpp:54
DEFINE_bool(ssl, true,"Whether to use SSL")
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void init()
char ** argv
void setSessionKey(std::string sessionKey)
size_t read(T &out, folly::io::Cursor &cursor)
Definition: Types-inl.h:258
int main(int argc, char **argv)
Definition: Client.cpp:125
NetworkSocket socket(int af, int type, int protocol)
Definition: NetOps.cpp:412
static void attachCallbacksToContext(SSL_CTX *ctx, SSLSessionCallbacks *callbacks)
Pipeline< folly::IOBufQueue &, std::string > EchoPipeline
Definition: EchoClient.cpp:34
DEFINE_string(ip,"::1","Ip address to connect to")
const char * string
Definition: Conv.cpp:212
virtual void makePipeline(std::shared_ptr< folly::AsyncTransportWrapper > socket)
static Ptr create()
Definition: Pipeline.h:174
std::shared_ptr< Pipeline > Ptr
Definition: Pipeline.h:172
DEFINE_uint32(port, 8080,"Port to connect to")
int close(NetworkSocket s)
Definition: NetOps.cpp:90
ThreadPoolListHook * addr