1 /* 2 * Copyright 2019 Google LLC 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 */ 16 17 #ifndef FCP_CLIENT_GRPC_BIDI_CHANNEL_H_ 18 #define FCP_CLIENT_GRPC_BIDI_CHANNEL_H_ 19 20 #include <dirent.h> 21 #include <sys/stat.h> 22 #include <sys/types.h> 23 24 #include <fstream> 25 #include <iostream> 26 #include <memory> 27 #include <sstream> 28 #include <string> 29 30 #include "absl/base/attributes.h" 31 #include "absl/strings/match.h" 32 #include "absl/strings/str_cat.h" 33 #include "absl/strings/strip.h" 34 #include "fcp/base/monitoring.h" 35 #include "grpcpp/channel.h" 36 #include "grpcpp/create_channel.h" 37 #include "grpcpp/security/credentials.h" 38 39 namespace fcp { 40 namespace client { 41 42 class GrpcBidiChannel { 43 public: 44 static constexpr int kChannelMaxMessageSize = 20 * 1000 * 1000; 45 static constexpr int kKeepAliveTimeSeconds = 60; 46 static constexpr const absl::string_view kSecurePrefix = "https://"; 47 static constexpr const absl::string_view kSecureTestPrefix = "https+test://"; 48 49 /** 50 * Create a channel to the remote endpoint. 51 * @param target URI of the remote endpoint. 52 * @param cert_path If the URI is https:// or https+test://, an optional 53 * path to a certificate root file or directory. 54 * @return A shared pointer to the channel interface. 55 */ Create(const std::string & target,std::string cert_path)56 static std::shared_ptr<grpc::ChannelInterface> Create( 57 const std::string& target, std::string cert_path) { 58 bool secure = false; 59 bool test = false; 60 // This double check avoids a dependency on re2: 61 if (absl::StartsWith(target, kSecureTestPrefix)) { 62 secure = true; 63 test = true; 64 } else if (absl::StartsWith(target, kSecurePrefix)) { 65 secure = true; 66 } 67 68 grpc::ChannelArguments channel_arguments; 69 channel_arguments.SetMaxReceiveMessageSize(kChannelMaxMessageSize); 70 channel_arguments.SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, 71 kKeepAliveTimeSeconds * 1000); 72 73 if (!secure) 74 return grpc::CreateCustomChannel( 75 target, grpc::InsecureChannelCredentials(), channel_arguments); 76 77 std::shared_ptr<grpc::ChannelCredentials> channel_creds; 78 grpc::SslCredentialsOptions ssl_opts{}; 79 80 if (!cert_path.empty()) { 81 std::ifstream cert_file(cert_path); 82 FCP_LOG_IF(ERROR, cert_file.fail()) 83 << "Open for: " << cert_path << " failed: " << strerror(errno); 84 std::stringstream string_stream; 85 if (cert_file) { 86 string_stream << cert_file.rdbuf(); 87 } 88 FCP_LOG_IF(WARNING, string_stream.str().empty()) 89 << "Cert: " << cert_path << " is empty."; 90 ssl_opts = {string_stream.str(), "", ""}; 91 } 92 93 channel_creds = grpc::SslCredentials(ssl_opts); 94 auto target_uri = absl::StrCat( 95 "dns:///", 96 absl::StripPrefix(target, test ? kSecureTestPrefix : kSecurePrefix)); 97 FCP_LOG(INFO) << "Creating channel to: " << target_uri; 98 return CreateCustomChannel(target_uri, channel_creds, channel_arguments); 99 } 100 }; 101 102 } // namespace client 103 } // namespace fcp 104 105 #endif // FCP_CLIENT_GRPC_BIDI_CHANNEL_H_ 106