brpc_ssl_unittest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. // Baidu RPC - A framework to host and access services throughout Baidu.
  18. // Date: Sun Jul 13 15:04:18 CST 2014
  19. #include <fstream>
  20. #include <gtest/gtest.h>
  21. #include <google/protobuf/descriptor.h>
  22. #include <butil/time.h>
  23. #include <butil/macros.h>
  24. #include <butil/fd_guard.h>
  25. #include <butil/files/scoped_file.h>
  26. #include "brpc/global.h"
  27. #include "brpc/socket.h"
  28. #include "brpc/server.h"
  29. #include "brpc/channel.h"
  30. #include "brpc/socket_map.h"
  31. #include "brpc/controller.h"
  32. #include "echo.pb.h"
  33. namespace brpc {
  34. void ExtractHostnames(X509* x, std::vector<std::string>* hostnames);
  35. } // namespace brpc
  36. int main(int argc, char* argv[]) {
  37. testing::InitGoogleTest(&argc, argv);
  38. GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);
  39. brpc::GlobalInitializeOrDie();
  40. return RUN_ALL_TESTS();
  41. }
  42. bool g_delete = false;
  43. const std::string EXP_REQUEST = "hello";
  44. const std::string EXP_RESPONSE = "world";
  45. class EchoServiceImpl : public test::EchoService {
  46. public:
  47. EchoServiceImpl() : count(0) {}
  48. virtual ~EchoServiceImpl() { g_delete = true; }
  49. virtual void Echo(google::protobuf::RpcController* cntl_base,
  50. const test::EchoRequest* request,
  51. test::EchoResponse* response,
  52. google::protobuf::Closure* done) {
  53. brpc::ClosureGuard done_guard(done);
  54. brpc::Controller* cntl = (brpc::Controller*)cntl_base;
  55. count.fetch_add(1, butil::memory_order_relaxed);
  56. EXPECT_EQ(EXP_REQUEST, request->message());
  57. EXPECT_TRUE(cntl->is_ssl());
  58. response->set_message(EXP_RESPONSE);
  59. if (request->sleep_us() > 0) {
  60. LOG(INFO) << "Sleep " << request->sleep_us() << " us, protocol="
  61. << cntl->request_protocol();
  62. bthread_usleep(request->sleep_us());
  63. }
  64. }
  65. butil::atomic<int64_t> count;
  66. };
  67. class SSLTest : public ::testing::Test{
  68. protected:
  69. SSLTest() {};
  70. virtual ~SSLTest(){};
  71. virtual void SetUp() {};
  72. virtual void TearDown() {};
  73. };
  74. void* RunClosure(void* arg) {
  75. google::protobuf::Closure* done = (google::protobuf::Closure*)arg;
  76. done->Run();
  77. return NULL;
  78. }
  79. void SendMultipleRPC(brpc::Channel* channel, int count) {
  80. for (int i = 0; i < count; ++i) {
  81. brpc::Controller cntl;
  82. test::EchoRequest req;
  83. test::EchoResponse res;
  84. req.set_message(EXP_REQUEST);
  85. test::EchoService_Stub stub(channel);
  86. stub.Echo(&cntl, &req, &res, NULL);
  87. EXPECT_EQ(EXP_RESPONSE, res.message()) << cntl.ErrorText();
  88. }
  89. }
  90. TEST_F(SSLTest, sanity) {
  91. // Test RPC based on SSL + brpc protocol
  92. const int port = 8613;
  93. brpc::Server server;
  94. brpc::ServerOptions options;
  95. brpc::CertInfo cert;
  96. cert.certificate = "cert1.crt";
  97. cert.private_key = "cert1.key";
  98. options.mutable_ssl_options()->default_cert = cert;
  99. EchoServiceImpl echo_svc;
  100. ASSERT_EQ(0, server.AddService(
  101. &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
  102. ASSERT_EQ(0, server.Start(port, &options));
  103. test::EchoRequest req;
  104. test::EchoResponse res;
  105. req.set_message(EXP_REQUEST);
  106. {
  107. brpc::Channel channel;
  108. brpc::ChannelOptions coptions;
  109. coptions.mutable_ssl_options();
  110. coptions.mutable_ssl_options()->sni_name = "localhost";
  111. ASSERT_EQ(0, channel.Init("localhost", port, &coptions));
  112. brpc::Controller cntl;
  113. test::EchoService_Stub stub(&channel);
  114. stub.Echo(&cntl, &req, &res, NULL);
  115. EXPECT_EQ(EXP_RESPONSE, res.message()) << cntl.ErrorText();
  116. }
  117. // stress test
  118. const int NUM = 5;
  119. const int COUNT = 3000;
  120. pthread_t tids[NUM];
  121. {
  122. brpc::Channel channel;
  123. brpc::ChannelOptions coptions;
  124. coptions.mutable_ssl_options();
  125. coptions.mutable_ssl_options()->sni_name = "localhost";
  126. ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions));
  127. for (int i = 0; i < NUM; ++i) {
  128. google::protobuf::Closure* thrd_func =
  129. brpc::NewCallback(SendMultipleRPC, &channel, COUNT);
  130. EXPECT_EQ(0, pthread_create(&tids[i], NULL, RunClosure, thrd_func));
  131. }
  132. for (int i = 0; i < NUM; ++i) {
  133. pthread_join(tids[i], NULL);
  134. }
  135. }
  136. {
  137. // Use HTTP
  138. brpc::Channel channel;
  139. brpc::ChannelOptions coptions;
  140. coptions.protocol = "http";
  141. coptions.mutable_ssl_options();
  142. coptions.mutable_ssl_options()->sni_name = "localhost";
  143. ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions));
  144. for (int i = 0; i < NUM; ++i) {
  145. google::protobuf::Closure* thrd_func =
  146. brpc::NewCallback(SendMultipleRPC, &channel, COUNT);
  147. EXPECT_EQ(0, pthread_create(&tids[i], NULL, RunClosure, thrd_func));
  148. }
  149. for (int i = 0; i < NUM; ++i) {
  150. pthread_join(tids[i], NULL);
  151. }
  152. }
  153. ASSERT_EQ(0, server.Stop(0));
  154. ASSERT_EQ(0, server.Join());
  155. }
  156. void CheckCert(const char* cname, const char* cert) {
  157. const int port = 8613;
  158. brpc::Channel channel;
  159. brpc::ChannelOptions coptions;
  160. coptions.mutable_ssl_options()->sni_name = cname;
  161. ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions));
  162. SendMultipleRPC(&channel, 1);
  163. // client has no access to the sending socket
  164. std::vector<brpc::SocketId> ids;
  165. brpc::SocketMapList(&ids);
  166. ASSERT_EQ(1u, ids.size());
  167. brpc::SocketUniquePtr sock;
  168. ASSERT_EQ(0, brpc::Socket::Address(ids[0], &sock));
  169. X509* x509 = sock->GetPeerCertificate();
  170. ASSERT_TRUE(x509 != NULL);
  171. std::vector<std::string> cnames;
  172. brpc::ExtractHostnames(x509, &cnames);
  173. ASSERT_EQ(cert, cnames[0]) << x509;
  174. }
  175. std::string GetRawPemString(const char* fname) {
  176. butil::ScopedFILE fp(fname, "r");
  177. char buf[4096];
  178. int size = read(fileno(fp), buf, sizeof(buf));
  179. std::string raw;
  180. raw.append(buf, size);
  181. return raw;
  182. }
  183. #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
  184. TEST_F(SSLTest, ssl_sni) {
  185. const int port = 8613;
  186. brpc::Server server;
  187. brpc::ServerOptions options;
  188. {
  189. brpc::CertInfo cert;
  190. cert.certificate = "cert1.crt";
  191. cert.private_key = "cert1.key";
  192. cert.sni_filters.push_back("cert1.com");
  193. options.mutable_ssl_options()->default_cert = cert;
  194. }
  195. {
  196. brpc::CertInfo cert;
  197. cert.certificate = GetRawPemString("cert2.crt");
  198. cert.private_key = GetRawPemString("cert2.key");
  199. cert.sni_filters.push_back("*.cert2.com");
  200. options.mutable_ssl_options()->certs.push_back(cert);
  201. }
  202. EchoServiceImpl echo_svc;
  203. ASSERT_EQ(0, server.AddService(
  204. &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
  205. ASSERT_EQ(0, server.Start(port, &options));
  206. CheckCert("cert1.com", "cert1");
  207. CheckCert("www.cert2.com", "cert2");
  208. CheckCert("noexist", "cert1"); // default cert
  209. server.Stop(0);
  210. server.Join();
  211. }
  212. TEST_F(SSLTest, ssl_reload) {
  213. const int port = 8613;
  214. brpc::Server server;
  215. brpc::ServerOptions options;
  216. {
  217. brpc::CertInfo cert;
  218. cert.certificate = "cert1.crt";
  219. cert.private_key = "cert1.key";
  220. cert.sni_filters.push_back("cert1.com");
  221. options.mutable_ssl_options()->default_cert = cert;
  222. }
  223. EchoServiceImpl echo_svc;
  224. ASSERT_EQ(0, server.AddService(
  225. &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
  226. ASSERT_EQ(0, server.Start(port, &options));
  227. CheckCert("cert2.com", "cert1"); // default cert
  228. {
  229. brpc::CertInfo cert;
  230. cert.certificate = GetRawPemString("cert2.crt");
  231. cert.private_key = GetRawPemString("cert2.key");
  232. cert.sni_filters.push_back("cert2.com");
  233. ASSERT_EQ(0, server.AddCertificate(cert));
  234. }
  235. CheckCert("cert2.com", "cert2");
  236. {
  237. brpc::CertInfo cert;
  238. cert.certificate = GetRawPemString("cert2.crt");
  239. cert.private_key = GetRawPemString("cert2.key");
  240. ASSERT_EQ(0, server.RemoveCertificate(cert));
  241. }
  242. CheckCert("cert2.com", "cert1"); // default cert after remove cert2
  243. {
  244. brpc::CertInfo cert;
  245. cert.certificate = GetRawPemString("cert2.crt");
  246. cert.private_key = GetRawPemString("cert2.key");
  247. cert.sni_filters.push_back("cert2.com");
  248. std::vector<brpc::CertInfo> certs;
  249. certs.push_back(cert);
  250. ASSERT_EQ(0, server.ResetCertificates(certs));
  251. }
  252. CheckCert("cert2.com", "cert2");
  253. server.Stop(0);
  254. server.Join();
  255. }
  256. #endif // SSL_CTRL_SET_TLSEXT_HOSTNAME
  257. const int BUFSIZE[] = {64, 128, 256, 1024, 4096};
  258. const int REP = 100000;
  259. void* ssl_perf_client(void* arg) {
  260. SSL* ssl = (SSL*)arg;
  261. EXPECT_EQ(1, SSL_do_handshake(ssl));
  262. char buf[4096];
  263. butil::Timer tm;
  264. for (size_t i = 0; i < ARRAY_SIZE(BUFSIZE); ++i) {
  265. int size = BUFSIZE[i];
  266. tm.start();
  267. for (int j = 0; j < REP; ++j) {
  268. SSL_write(ssl, buf, size);
  269. }
  270. tm.stop();
  271. LOG(INFO) << "SSL_write(" << size << ") tp="
  272. << size * REP / tm.u_elapsed() << "M/s"
  273. << ", latency=" << tm.u_elapsed() / REP << "us";
  274. }
  275. return NULL;
  276. }
  277. void* ssl_perf_server(void* arg) {
  278. SSL* ssl = (SSL*)arg;
  279. EXPECT_EQ(1, SSL_do_handshake(ssl));
  280. char buf[4096];
  281. for (size_t i = 0; i < ARRAY_SIZE(BUFSIZE); ++i) {
  282. int size = BUFSIZE[i];
  283. for (int j = 0; j < REP; ++j) {
  284. SSL_read(ssl, buf, size);
  285. }
  286. }
  287. return NULL;
  288. }
  289. TEST_F(SSLTest, ssl_perf) {
  290. const butil::EndPoint ep(butil::IP_ANY, 5961);
  291. butil::fd_guard listenfd(butil::tcp_listen(ep));
  292. ASSERT_GT(listenfd, 0);
  293. int clifd = tcp_connect(ep, NULL);
  294. ASSERT_GT(clifd, 0);
  295. int servfd = accept(listenfd, NULL, NULL);
  296. ASSERT_GT(servfd, 0);
  297. brpc::ChannelSSLOptions opt;
  298. SSL_CTX* cli_ctx = brpc::CreateClientSSLContext(opt);
  299. SSL_CTX* serv_ctx =
  300. brpc::CreateServerSSLContext("cert1.crt", "cert1.key",
  301. brpc::SSLOptions(), NULL);
  302. SSL* cli_ssl = brpc::CreateSSLSession(cli_ctx, 0, clifd, false);
  303. #if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME) || defined(USE_MESALINK)
  304. SSL_set_tlsext_host_name(cli_ssl, "localhost");
  305. #endif
  306. SSL* serv_ssl = brpc::CreateSSLSession(serv_ctx, 0, servfd, true);
  307. pthread_t cpid;
  308. pthread_t spid;
  309. ASSERT_EQ(0, pthread_create(&cpid, NULL, ssl_perf_client, cli_ssl));
  310. ASSERT_EQ(0, pthread_create(&spid, NULL, ssl_perf_server , serv_ssl));
  311. ASSERT_EQ(0, pthread_join(cpid, NULL));
  312. ASSERT_EQ(0, pthread_join(spid, NULL));
  313. close(clifd);
  314. close(servfd);
  315. }