2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
10 #include <folly/Portability.h>
11 #include <folly/io/async/EventBase.h>
12 #include <gflags/gflags.h>
15 #include <folly/io/async/AsyncSSLSocket.h>
16 #include <folly/io/async/AsyncSocket.h>
20 using namespace folly;
22 DEFINE_int32(clients, 1, "Number of simulated SSL clients");
23 DEFINE_int32(threads, 1, "Number of threads to spread clients across");
24 DEFINE_int32(requests, 2, "Total number of requests per client");
25 DEFINE_int32(port, 9423, "Server port");
26 DEFINE_bool(sticky, false, "A given client sends all reqs to one "
28 DEFINE_bool(global, false, "All clients in a thread use the same SSL session");
29 DEFINE_bool(handshakes, false, "Force 100% handshakes");
32 int f_num_servers = 0;
38 ClientRunner(): reqs(0), hits(0), miss(0), num(tnum++) {}
47 class SSLCacheClient : public AsyncSocket::ConnectCallback,
48 public AsyncSSLSocket::HandshakeCB
51 EventBase* eventBase_;
55 AsyncSSLSocket* sslSocket_;
56 SSL_SESSION* session_;
58 std::shared_ptr<SSLContext> ctx_;
62 SSLCacheClient(EventBase* eventBase, SSL_SESSION **pSess, ClientRunner* cr);
63 ~SSLCacheClient() override {
64 if (session_ && !FLAGS_global)
65 SSL_SESSION_free(session_);
66 if (socket_ != nullptr) {
67 if (sslSocket_ != nullptr) {
68 sslSocket_->destroy();
78 void connectSuccess() noexcept override;
80 void connectErr(const AsyncSocketException& ex) noexcept override;
82 void handshakeSuc(AsyncSSLSocket* sock) noexcept override;
84 void handshakeErr(AsyncSSLSocket* sock,
85 const AsyncSocketException& ex) noexcept override;
89 main(int argc, char* argv[])
91 gflags::SetUsageMessage(std::string("\n\n"
92 "usage: sslcachetest [options] -c <clients> -t <threads> servers\n"
94 gflags::ParseCommandLineFlags(&argc, &argv, true);
100 struct timeval result;
102 srand((unsigned int)time(nullptr));
104 for (int i = 1; i < argc; i++) {
105 f_servers[f_num_servers++] = argv[i];
107 if (f_num_servers == 0) {
108 cout << "require at least one server\n";
112 gettimeofday(&start, nullptr);
113 if (FLAGS_threads == 1) {
116 gettimeofday(&end, nullptr);
122 std::vector<ClientRunner> clients;
123 std::vector<std::thread> threads;
124 for (int t = 0; t < FLAGS_threads; t++) {
125 threads.emplace_back([&] {
129 for (auto& thr: threads) {
132 gettimeofday(&end, nullptr);
134 for (const auto& client: clients) {
141 timersub(&end, &start, &result);
143 cout << "Requests: " << reqs << endl;
144 cout << "Handshakes: " << miss << endl;
145 cout << "Resumes: " << hits << endl;
146 cout << "Runtime(ms): " << result.tv_sec << "." << result.tv_usec / 1000 <<
149 cout << "ops/sec: " << (reqs * 1.0) /
150 ((double)result.tv_sec * 1.0 + (double)result.tv_usec / 1000000.0) << endl;
159 std::list<SSLCacheClient *> clients;
160 SSL_SESSION* session = nullptr;
162 for (int i = 0; i < FLAGS_clients; i++) {
163 SSLCacheClient* c = new SSLCacheClient(&eb, &session, this);
165 clients.push_back(c);
170 for (auto it = clients.begin(); it != clients.end(); it++) {
177 SSLCacheClient::SSLCacheClient(EventBase* eb,
189 ctx_.reset(new SSLContext());
190 ctx_->setOptions(SSL_OP_NO_TICKET);
194 SSLCacheClient::start()
196 if (currReq_ >= FLAGS_requests) {
201 if (currReq_ == 0 || !FLAGS_sticky) {
202 serverIdx_ = rand() % f_num_servers;
204 if (socket_ != nullptr) {
205 if (sslSocket_ != nullptr) {
206 sslSocket_->destroy();
207 sslSocket_ = nullptr;
212 socket_ = new AsyncSocket(eventBase_);
213 socket_->connect(this, f_servers[serverIdx_], (uint16_t)FLAGS_port);
217 SSLCacheClient::connectSuccess() noexcept
219 sslSocket_ = new AsyncSSLSocket(ctx_, eventBase_, socket_->detachFd(),
222 if (!FLAGS_handshakes) {
223 if (session_ != nullptr)
224 sslSocket_->setSSLSession(session_);
225 else if (FLAGS_global && pSess_ != nullptr)
226 sslSocket_->setSSLSession(*pSess_);
228 sslSocket_->sslConn(this);
232 SSLCacheClient::connectErr(const AsyncSocketException& ex)
235 cout << "connectError: " << ex.what() << endl;
239 SSLCacheClient::handshakeSuc(AsyncSSLSocket* socket) noexcept
241 if (sslSocket_->getSSLSessionReused()) {
245 if (session_ != nullptr) {
246 SSL_SESSION_free(session_);
248 session_ = sslSocket_->getSSLSession();
249 if (FLAGS_global && pSess_ != nullptr && *pSess_ == nullptr) {
253 if ( ((cr_->hits + cr_->miss) % 100) == ((100 / FLAGS_threads) * cr_->num)) {
257 sslSocket_->closeNow();
263 SSLCacheClient::handshakeErr(
264 AsyncSSLSocket* sock,
265 const AsyncSocketException& ex)
268 cout << "handshakeError: " << ex.what() << endl;