123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- // Licensed to the Apache Software Foundation (ASF) under one
- // or more contributor license agreements. See the NOTICE file
- // distributed with this work for additional information
- // regarding copyright ownership. The ASF licenses this file
- // to you under the Apache License, Version 2.0 (the
- // "License"); you may not use this file except in compliance
- // with the License. You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing,
- // software distributed under the License is distributed on an
- // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- // KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations
- // under the License.
- // Baidu RPC - A framework to host and access services throughout Baidu.
- // Date: Sun Jul 13 15:04:18 CST 2014
- #include <fstream>
- #include <gtest/gtest.h>
- #include <google/protobuf/descriptor.h>
- #include <butil/time.h>
- #include <butil/macros.h>
- #include <butil/fd_guard.h>
- #include <butil/files/scoped_file.h>
- #include "brpc/global.h"
- #include "brpc/socket.h"
- #include "brpc/server.h"
- #include "brpc/channel.h"
- #include "brpc/socket_map.h"
- #include "brpc/controller.h"
- #include "echo.pb.h"
- namespace brpc {
- void ExtractHostnames(X509* x, std::vector<std::string>* hostnames);
- } // namespace brpc
- int main(int argc, char* argv[]) {
- testing::InitGoogleTest(&argc, argv);
- GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);
- brpc::GlobalInitializeOrDie();
- return RUN_ALL_TESTS();
- }
- bool g_delete = false;
- const std::string EXP_REQUEST = "hello";
- const std::string EXP_RESPONSE = "world";
- class EchoServiceImpl : public test::EchoService {
- public:
- EchoServiceImpl() : count(0) {}
- virtual ~EchoServiceImpl() { g_delete = true; }
- virtual void Echo(google::protobuf::RpcController* cntl_base,
- const test::EchoRequest* request,
- test::EchoResponse* response,
- google::protobuf::Closure* done) {
- brpc::ClosureGuard done_guard(done);
- brpc::Controller* cntl = (brpc::Controller*)cntl_base;
- count.fetch_add(1, butil::memory_order_relaxed);
- EXPECT_EQ(EXP_REQUEST, request->message());
- EXPECT_TRUE(cntl->is_ssl());
- response->set_message(EXP_RESPONSE);
- if (request->sleep_us() > 0) {
- LOG(INFO) << "Sleep " << request->sleep_us() << " us, protocol="
- << cntl->request_protocol();
- bthread_usleep(request->sleep_us());
- }
- }
- butil::atomic<int64_t> count;
- };
- class SSLTest : public ::testing::Test{
- protected:
- SSLTest() {};
- virtual ~SSLTest(){};
- virtual void SetUp() {};
- virtual void TearDown() {};
- };
- void* RunClosure(void* arg) {
- google::protobuf::Closure* done = (google::protobuf::Closure*)arg;
- done->Run();
- return NULL;
- }
- void SendMultipleRPC(brpc::Channel* channel, int count) {
- for (int i = 0; i < count; ++i) {
- brpc::Controller cntl;
- test::EchoRequest req;
- test::EchoResponse res;
- req.set_message(EXP_REQUEST);
- test::EchoService_Stub stub(channel);
- stub.Echo(&cntl, &req, &res, NULL);
- EXPECT_EQ(EXP_RESPONSE, res.message()) << cntl.ErrorText();
- }
- }
- TEST_F(SSLTest, sanity) {
- // Test RPC based on SSL + brpc protocol
- const int port = 8613;
- brpc::Server server;
- brpc::ServerOptions options;
- brpc::CertInfo cert;
- cert.certificate = "cert1.crt";
- cert.private_key = "cert1.key";
- options.mutable_ssl_options()->default_cert = cert;
- EchoServiceImpl echo_svc;
- ASSERT_EQ(0, server.AddService(
- &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
- ASSERT_EQ(0, server.Start(port, &options));
- test::EchoRequest req;
- test::EchoResponse res;
- req.set_message(EXP_REQUEST);
- {
- brpc::Channel channel;
- brpc::ChannelOptions coptions;
- coptions.mutable_ssl_options();
- coptions.mutable_ssl_options()->sni_name = "localhost";
- ASSERT_EQ(0, channel.Init("localhost", port, &coptions));
- brpc::Controller cntl;
- test::EchoService_Stub stub(&channel);
- stub.Echo(&cntl, &req, &res, NULL);
- EXPECT_EQ(EXP_RESPONSE, res.message()) << cntl.ErrorText();
- }
- // stress test
- const int NUM = 5;
- const int COUNT = 3000;
- pthread_t tids[NUM];
- {
- brpc::Channel channel;
- brpc::ChannelOptions coptions;
- coptions.mutable_ssl_options();
- coptions.mutable_ssl_options()->sni_name = "localhost";
- ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions));
- for (int i = 0; i < NUM; ++i) {
- google::protobuf::Closure* thrd_func =
- brpc::NewCallback(SendMultipleRPC, &channel, COUNT);
- EXPECT_EQ(0, pthread_create(&tids[i], NULL, RunClosure, thrd_func));
- }
- for (int i = 0; i < NUM; ++i) {
- pthread_join(tids[i], NULL);
- }
- }
- {
- // Use HTTP
- brpc::Channel channel;
- brpc::ChannelOptions coptions;
- coptions.protocol = "http";
- coptions.mutable_ssl_options();
- coptions.mutable_ssl_options()->sni_name = "localhost";
- ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions));
- for (int i = 0; i < NUM; ++i) {
- google::protobuf::Closure* thrd_func =
- brpc::NewCallback(SendMultipleRPC, &channel, COUNT);
- EXPECT_EQ(0, pthread_create(&tids[i], NULL, RunClosure, thrd_func));
- }
- for (int i = 0; i < NUM; ++i) {
- pthread_join(tids[i], NULL);
- }
- }
- ASSERT_EQ(0, server.Stop(0));
- ASSERT_EQ(0, server.Join());
- }
- void CheckCert(const char* cname, const char* cert) {
- const int port = 8613;
- brpc::Channel channel;
- brpc::ChannelOptions coptions;
- coptions.mutable_ssl_options()->sni_name = cname;
- ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions));
- SendMultipleRPC(&channel, 1);
- // client has no access to the sending socket
- std::vector<brpc::SocketId> ids;
- brpc::SocketMapList(&ids);
- ASSERT_EQ(1u, ids.size());
- brpc::SocketUniquePtr sock;
- ASSERT_EQ(0, brpc::Socket::Address(ids[0], &sock));
- X509* x509 = sock->GetPeerCertificate();
- ASSERT_TRUE(x509 != NULL);
- std::vector<std::string> cnames;
- brpc::ExtractHostnames(x509, &cnames);
- ASSERT_EQ(cert, cnames[0]) << x509;
- }
- std::string GetRawPemString(const char* fname) {
- butil::ScopedFILE fp(fname, "r");
- char buf[4096];
- int size = read(fileno(fp), buf, sizeof(buf));
- std::string raw;
- raw.append(buf, size);
- return raw;
- }
- #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- TEST_F(SSLTest, ssl_sni) {
- const int port = 8613;
- brpc::Server server;
- brpc::ServerOptions options;
- {
- brpc::CertInfo cert;
- cert.certificate = "cert1.crt";
- cert.private_key = "cert1.key";
- cert.sni_filters.push_back("cert1.com");
- options.mutable_ssl_options()->default_cert = cert;
- }
- {
- brpc::CertInfo cert;
- cert.certificate = GetRawPemString("cert2.crt");
- cert.private_key = GetRawPemString("cert2.key");
- cert.sni_filters.push_back("*.cert2.com");
- options.mutable_ssl_options()->certs.push_back(cert);
- }
- EchoServiceImpl echo_svc;
- ASSERT_EQ(0, server.AddService(
- &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
- ASSERT_EQ(0, server.Start(port, &options));
- CheckCert("cert1.com", "cert1");
- CheckCert("www.cert2.com", "cert2");
- CheckCert("noexist", "cert1"); // default cert
- server.Stop(0);
- server.Join();
- }
- TEST_F(SSLTest, ssl_reload) {
- const int port = 8613;
- brpc::Server server;
- brpc::ServerOptions options;
- {
- brpc::CertInfo cert;
- cert.certificate = "cert1.crt";
- cert.private_key = "cert1.key";
- cert.sni_filters.push_back("cert1.com");
- options.mutable_ssl_options()->default_cert = cert;
- }
- EchoServiceImpl echo_svc;
- ASSERT_EQ(0, server.AddService(
- &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
- ASSERT_EQ(0, server.Start(port, &options));
- CheckCert("cert2.com", "cert1"); // default cert
- {
- brpc::CertInfo cert;
- cert.certificate = GetRawPemString("cert2.crt");
- cert.private_key = GetRawPemString("cert2.key");
- cert.sni_filters.push_back("cert2.com");
- ASSERT_EQ(0, server.AddCertificate(cert));
- }
- CheckCert("cert2.com", "cert2");
- {
- brpc::CertInfo cert;
- cert.certificate = GetRawPemString("cert2.crt");
- cert.private_key = GetRawPemString("cert2.key");
- ASSERT_EQ(0, server.RemoveCertificate(cert));
- }
- CheckCert("cert2.com", "cert1"); // default cert after remove cert2
- {
- brpc::CertInfo cert;
- cert.certificate = GetRawPemString("cert2.crt");
- cert.private_key = GetRawPemString("cert2.key");
- cert.sni_filters.push_back("cert2.com");
- std::vector<brpc::CertInfo> certs;
- certs.push_back(cert);
- ASSERT_EQ(0, server.ResetCertificates(certs));
- }
- CheckCert("cert2.com", "cert2");
- server.Stop(0);
- server.Join();
- }
- #endif // SSL_CTRL_SET_TLSEXT_HOSTNAME
- const int BUFSIZE[] = {64, 128, 256, 1024, 4096};
- const int REP = 100000;
- void* ssl_perf_client(void* arg) {
- SSL* ssl = (SSL*)arg;
- EXPECT_EQ(1, SSL_do_handshake(ssl));
- char buf[4096];
- butil::Timer tm;
- for (size_t i = 0; i < ARRAY_SIZE(BUFSIZE); ++i) {
- int size = BUFSIZE[i];
- tm.start();
- for (int j = 0; j < REP; ++j) {
- SSL_write(ssl, buf, size);
- }
- tm.stop();
- LOG(INFO) << "SSL_write(" << size << ") tp="
- << size * REP / tm.u_elapsed() << "M/s"
- << ", latency=" << tm.u_elapsed() / REP << "us";
- }
- return NULL;
- }
- void* ssl_perf_server(void* arg) {
- SSL* ssl = (SSL*)arg;
- EXPECT_EQ(1, SSL_do_handshake(ssl));
- char buf[4096];
- for (size_t i = 0; i < ARRAY_SIZE(BUFSIZE); ++i) {
- int size = BUFSIZE[i];
- for (int j = 0; j < REP; ++j) {
- SSL_read(ssl, buf, size);
- }
- }
- return NULL;
- }
- TEST_F(SSLTest, ssl_perf) {
- const butil::EndPoint ep(butil::IP_ANY, 5961);
- butil::fd_guard listenfd(butil::tcp_listen(ep));
- ASSERT_GT(listenfd, 0);
- int clifd = tcp_connect(ep, NULL);
- ASSERT_GT(clifd, 0);
- int servfd = accept(listenfd, NULL, NULL);
- ASSERT_GT(servfd, 0);
- brpc::ChannelSSLOptions opt;
- SSL_CTX* cli_ctx = brpc::CreateClientSSLContext(opt);
- SSL_CTX* serv_ctx =
- brpc::CreateServerSSLContext("cert1.crt", "cert1.key",
- brpc::SSLOptions(), NULL);
- SSL* cli_ssl = brpc::CreateSSLSession(cli_ctx, 0, clifd, false);
- #if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME) || defined(USE_MESALINK)
- SSL_set_tlsext_host_name(cli_ssl, "localhost");
- #endif
- SSL* serv_ssl = brpc::CreateSSLSession(serv_ctx, 0, servfd, true);
- pthread_t cpid;
- pthread_t spid;
- ASSERT_EQ(0, pthread_create(&cpid, NULL, ssl_perf_client, cli_ssl));
- ASSERT_EQ(0, pthread_create(&spid, NULL, ssl_perf_server , serv_ssl));
- ASSERT_EQ(0, pthread_join(cpid, NULL));
- ASSERT_EQ(0, pthread_join(spid, NULL));
- close(clifd);
- close(servfd);
- }
|