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);
64 if (session_ && !FLAGS_global)
65 SSL_SESSION_free(session_);
66 if (socket_ != nullptr) {
67 if (sslSocket_ != nullptr) {
68 sslSocket_->destroy();
78 virtual void connectSuccess() noexcept;
80 virtual void connectErr(const AsyncSocketException& ex)
83 virtual void handshakeSuc(AsyncSSLSocket* sock) noexcept;
85 virtual void handshakeErr(
87 const AsyncSocketException& ex) noexcept;
92 main(int argc, char* argv[])
94 gflags::SetUsageMessage(std::string("\n\n"
95 "usage: sslcachetest [options] -c <clients> -t <threads> servers\n"
97 gflags::ParseCommandLineFlags(&argc, &argv, true);
101 struct timeval start;
103 struct timeval result;
105 srand((unsigned int)time(nullptr));
107 for (int i = 1; i < argc; i++) {
108 f_servers[f_num_servers++] = argv[i];
110 if (f_num_servers == 0) {
111 cout << "require at least one server\n";
115 gettimeofday(&start, nullptr);
116 if (FLAGS_threads == 1) {
119 gettimeofday(&end, nullptr);
125 std::vector<ClientRunner> clients;
126 std::vector<std::thread> threads;
127 for (int t = 0; t < FLAGS_threads; t++) {
128 threads.emplace_back([&] {
132 for (auto& thr: threads) {
135 gettimeofday(&end, nullptr);
137 for (const auto& client: clients) {
144 timersub(&end, &start, &result);
146 cout << "Requests: " << reqs << endl;
147 cout << "Handshakes: " << miss << endl;
148 cout << "Resumes: " << hits << endl;
149 cout << "Runtime(ms): " << result.tv_sec << "." << result.tv_usec / 1000 <<
152 cout << "ops/sec: " << (reqs * 1.0) /
153 ((double)result.tv_sec * 1.0 + (double)result.tv_usec / 1000000.0) << endl;
162 std::list<SSLCacheClient *> clients;
163 SSL_SESSION* session = nullptr;
165 for (int i = 0; i < FLAGS_clients; i++) {
166 SSLCacheClient* c = new SSLCacheClient(&eb, &session, this);
168 clients.push_back(c);
173 for (auto it = clients.begin(); it != clients.end(); it++) {
180 SSLCacheClient::SSLCacheClient(EventBase* eb,
192 ctx_.reset(new SSLContext());
193 ctx_->setOptions(SSL_OP_NO_TICKET);
197 SSLCacheClient::start()
199 if (currReq_ >= FLAGS_requests) {
204 if (currReq_ == 0 || !FLAGS_sticky) {
205 serverIdx_ = rand() % f_num_servers;
207 if (socket_ != nullptr) {
208 if (sslSocket_ != nullptr) {
209 sslSocket_->destroy();
210 sslSocket_ = nullptr;
215 socket_ = new AsyncSocket(eventBase_);
216 socket_->connect(this, f_servers[serverIdx_], (uint16_t)FLAGS_port);
220 SSLCacheClient::connectSuccess() noexcept
222 sslSocket_ = new AsyncSSLSocket(ctx_, eventBase_, socket_->detachFd(),
225 if (!FLAGS_handshakes) {
226 if (session_ != nullptr)
227 sslSocket_->setSSLSession(session_);
228 else if (FLAGS_global && pSess_ != nullptr)
229 sslSocket_->setSSLSession(*pSess_);
231 sslSocket_->sslConn(this);
235 SSLCacheClient::connectErr(const AsyncSocketException& ex)
238 cout << "connectError: " << ex.what() << endl;
242 SSLCacheClient::handshakeSuc(AsyncSSLSocket* socket) noexcept
244 if (sslSocket_->getSSLSessionReused()) {
248 if (session_ != nullptr) {
249 SSL_SESSION_free(session_);
251 session_ = sslSocket_->getSSLSession();
252 if (FLAGS_global && pSess_ != nullptr && *pSess_ == nullptr) {
256 if ( ((cr_->hits + cr_->miss) % 100) == ((100 / FLAGS_threads) * cr_->num)) {
260 sslSocket_->closeNow();
266 SSLCacheClient::handshakeErr(
267 AsyncSSLSocket* sock,
268 const AsyncSocketException& ex)
271 cout << "handshakeError: " << ex.what() << endl;