proxygen
SSLCacheTest.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 #include <gflags/gflags.h>
18 #include <iostream>
19 #include <thread>
22 #include <vector>
23 
24 using namespace std;
25 using namespace folly;
26 
27 DEFINE_int32(clients, 1, "Number of simulated SSL clients");
28 DEFINE_int32(threads, 1, "Number of threads to spread clients across");
29 DEFINE_int32(requests, 2, "Total number of requests per client");
30 DEFINE_int32(port, 9423, "Server port");
31 DEFINE_bool(sticky, false, "A given client sends all reqs to one "
32  "(random) server");
33 DEFINE_bool(global, false, "All clients in a thread use the same SSL session");
34 DEFINE_bool(handshakes, false, "Force 100% handshakes");
35 
36 string f_servers[10];
37 int f_num_servers = 0;
38 int tnum = 0;
39 
40 class ClientRunner {
41  public:
42 
43  ClientRunner(): reqs(0), hits(0), miss(0), num(tnum++) {}
44  void run();
45 
46  int reqs;
47  int hits;
48  int miss;
49  int num;
50 };
51 
54 {
55 private:
57  int currReq_;
61  SSL_SESSION* session_;
62  SSL_SESSION **pSess_;
63  std::shared_ptr<SSLContext> ctx_;
65 
66 public:
67  SSLCacheClient(EventBase* eventBase, SSL_SESSION **pSess, ClientRunner* cr);
68  ~SSLCacheClient() override {
69  if (session_ && !FLAGS_global)
70  SSL_SESSION_free(session_);
71  if (socket_ != nullptr) {
72  if (sslSocket_ != nullptr) {
73  sslSocket_->destroy();
74  sslSocket_ = nullptr;
75  }
76  socket_->destroy();
77  socket_ = nullptr;
78  }
79  }
80 
81  void start();
82 
83  void connectSuccess() noexcept override;
84 
85  void connectErr(const AsyncSocketException& ex) noexcept override;
86 
87  void handshakeSuc(AsyncSSLSocket* sock) noexcept override;
88 
89  void handshakeErr(AsyncSSLSocket* sock,
90  const AsyncSocketException& ex) noexcept override;
91 };
92 
93 int
94 main(int argc, char* argv[])
95 {
96  gflags::SetUsageMessage(std::string("\n\n"
97 "usage: sslcachetest [options] -c <clients> -t <threads> servers\n"
98 ));
99  gflags::ParseCommandLineFlags(&argc, &argv, true);
100  int reqs = 0;
101  int hits = 0;
102  int miss = 0;
103  struct timeval start;
104  struct timeval end;
105  struct timeval result;
106 
107  srand((unsigned int)time(nullptr));
108 
109  for (int i = 1; i < argc; i++) {
110  f_servers[f_num_servers++] = argv[i];
111  }
112  if (f_num_servers == 0) {
113  cout << "require at least one server\n";
114  return 1;
115  }
116 
117  gettimeofday(&start, nullptr);
118  if (FLAGS_threads == 1) {
119  ClientRunner r;
120  r.run();
121  gettimeofday(&end, nullptr);
122  reqs = r.reqs;
123  hits = r.hits;
124  miss = r.miss;
125  }
126  else {
127  std::vector<ClientRunner> clients;
128  std::vector<std::thread> threads;
129  for (int t = 0; t < FLAGS_threads; t++) {
130  threads.emplace_back([&] {
131  clients[t].run();
132  });
133  }
134  for (auto& thr: threads) {
135  thr.join();
136  }
137  gettimeofday(&end, nullptr);
138 
139  for (const auto& client: clients) {
140  reqs += client.reqs;
141  hits += client.hits;
142  miss += client.miss;
143  }
144  }
145 
146  timersub(&end, &start, &result);
147 
148  cout << "Requests: " << reqs << endl;
149  cout << "Handshakes: " << miss << endl;
150  cout << "Resumes: " << hits << endl;
151  cout << "Runtime(ms): " << result.tv_sec << "." << result.tv_usec / 1000 <<
152  endl;
153 
154  cout << "ops/sec: " << (reqs * 1.0) /
155  ((double)result.tv_sec * 1.0 + (double)result.tv_usec / 1000000.0) << endl;
156 
157  return 0;
158 }
159 
160 void
162 {
163  EventBase eb;
164  std::list<SSLCacheClient *> clients;
165  SSL_SESSION* session = nullptr;
166 
167  for (int i = 0; i < FLAGS_clients; i++) {
168  SSLCacheClient* c = new SSLCacheClient(&eb, &session, this);
169  c->start();
170  clients.push_back(c);
171  }
172 
173  eb.loop();
174 
175  for (auto it = clients.begin(); it != clients.end(); it++) {
176  delete* it;
177  }
178 
179  reqs += hits + miss;
180 }
181 
183  SSL_SESSION **pSess,
184  ClientRunner* cr)
185  : eventBase_(eb),
186  currReq_(0),
187  serverIdx_(0),
188  socket_(nullptr),
190  session_(nullptr),
191  pSess_(pSess),
192  cr_(cr)
193 {
194  ctx_.reset(new SSLContext());
195  ctx_->setOptions(SSL_OP_NO_TICKET);
196 }
197 
198 void
200 {
201  if (currReq_ >= FLAGS_requests) {
202  cout << "+";
203  return;
204  }
205 
206  if (currReq_ == 0 || !FLAGS_sticky) {
207  serverIdx_ = rand() % f_num_servers;
208  }
209  if (socket_ != nullptr) {
210  if (sslSocket_ != nullptr) {
211  sslSocket_->destroy();
212  sslSocket_ = nullptr;
213  }
214  socket_->destroy();
215  socket_ = nullptr;
216  }
218  socket_->connect(this, f_servers[serverIdx_], (uint16_t)FLAGS_port);
219 }
220 
221 void
223 {
225  false);
226 
227  if (!FLAGS_handshakes) {
228  if (session_ != nullptr)
230  else if (FLAGS_global && pSess_ != nullptr)
232  }
233  sslSocket_->sslConn(this);
234 }
235 
236 void
238  noexcept
239 {
240  cout << "connectError: " << ex.what() << endl;
241 }
242 
243 void
245 {
247  cr_->hits++;
248  } else {
249  cr_->miss++;
250  if (session_ != nullptr) {
251  SSL_SESSION_free(session_);
252  }
254  if (FLAGS_global && pSess_ != nullptr && *pSess_ == nullptr) {
255  *pSess_ = session_;
256  }
257  }
258  if ( ((cr_->hits + cr_->miss) % 100) == ((100 / FLAGS_threads) * cr_->num)) {
259  cout << ".";
260  cout.flush();
261  }
262  sslSocket_->closeNow();
263  currReq_++;
264  this->start();
265 }
266 
267 void
270  const AsyncSocketException& ex)
271  noexcept
272 {
273  cout << "handshakeError: " << ex.what() << endl;
274 }
void handshakeSuc(AsyncSSLSocket *sock) noexceptoverride
virtual int detachFd()
DEFINE_int32(clients, 1,"Number of simulated SSL clients")
const struct message requests[]
Definition: test.c:80
string f_servers[10]
int tnum
std::shared_ptr< SSLContext > ctx_
STL namespace.
virtual void sslConn(HandshakeCB *callback, std::chrono::milliseconds timeout=std::chrono::milliseconds::zero(), const folly::SSLContext::SSLVerifyPeerEnum &verifyPeer=folly::SSLContext::SSLVerifyPeerEnum::USE_CTX)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
int f_num_servers
requires E e noexcept(noexcept(s.error(std::move(e))))
#define nullptr
Definition: http_parser.c:41
SSL_SESSION * session_
SSL_SESSION ** pSess_
void handshakeErr(AsyncSSLSocket *sock, const AsyncSocketException &ex) noexceptoverride
std::vector< std::thread::id > threads
virtual void connect(ConnectCallback *callback, const folly::SocketAddress &address, int timeout=0, const OptionMap &options=emptyOptionMap, const folly::SocketAddress &bindAddr=anyAddress()) noexcept
char ** argv
void destroy() override
static void run(EventBaseManager *ebm, EventBase *eb, folly::Baton<> *stop, const StringPiece &name)
AsyncSSLSocket::UniquePtr sslSocket_
EventBase * eventBase_
AsyncServerSocket::UniquePtr socket_
virtual bool getSSLSessionReused() const
auto start
DEFINE_bool(sticky, false,"A given client sends all reqs to one ""(random) server")
AsyncSocket * socket_
int main(int argc, char *argv[])
SSLCacheClient(EventBase *eventBase, SSL_SESSION **pSess, ClientRunner *cr)
const char * string
Definition: Conv.cpp:212
ClientRunner * cr_
SSL_SESSION * getSSLSession()
void connectSuccess() noexceptoverride
~SSLCacheClient() override
void setSSLSession(SSL_SESSION *session, bool takeOwnership=false)
void connectErr(const AsyncSocketException &ex) noexceptoverride
AsyncSSLSocket * sslSocket_
char c
std::chrono::nanoseconds time()
void closeNow() override