Line data Source code
1 : #include "source/common/grpc/google_grpc_utils.h" 2 : 3 : #include <atomic> 4 : #include <cstdint> 5 : #include <cstring> 6 : #include <string> 7 : 8 : #include "envoy/grpc/google_grpc_creds.h" 9 : #include "envoy/registry/registry.h" 10 : 11 : #include "source/common/buffer/buffer_impl.h" 12 : #include "source/common/common/assert.h" 13 : #include "source/common/common/empty_string.h" 14 : #include "source/common/common/enum_to_int.h" 15 : #include "source/common/common/fmt.h" 16 : #include "source/common/common/macros.h" 17 : #include "source/common/common/utility.h" 18 : 19 : #include "absl/container/fixed_array.h" 20 : #include "absl/strings/match.h" 21 : 22 : namespace Envoy { 23 : namespace Grpc { 24 : 25 : namespace { 26 : 27 : std::shared_ptr<grpc::ChannelCredentials> 28 : getGoogleGrpcChannelCredentials(const envoy::config::core::v3::GrpcService& grpc_service, 29 2 : Api::Api& api) { 30 2 : GoogleGrpcCredentialsFactory* credentials_factory = nullptr; 31 2 : const std::string& google_grpc_credentials_factory_name = 32 2 : grpc_service.google_grpc().credentials_factory_name(); 33 2 : if (google_grpc_credentials_factory_name.empty()) { 34 2 : credentials_factory = Registry::FactoryRegistry<GoogleGrpcCredentialsFactory>::getFactory( 35 2 : "envoy.grpc_credentials.default"); 36 2 : } else { 37 0 : credentials_factory = Registry::FactoryRegistry<GoogleGrpcCredentialsFactory>::getFactory( 38 0 : google_grpc_credentials_factory_name); 39 0 : } 40 2 : if (credentials_factory == nullptr) { 41 0 : throw EnvoyException(absl::StrCat("Unknown google grpc credentials factory: ", 42 0 : google_grpc_credentials_factory_name)); 43 0 : } 44 2 : return credentials_factory->getChannelCredentials(grpc_service, api); 45 2 : } 46 : 47 : } // namespace 48 : 49 : struct BufferInstanceContainer { 50 : BufferInstanceContainer(int ref_count, Buffer::InstancePtr&& buffer) 51 1 : : ref_count_(ref_count), buffer_(std::move(buffer)) {} 52 : std::atomic<uint32_t> ref_count_; // In case gPRC dereferences in a different threads. 53 : Buffer::InstancePtr buffer_; 54 : 55 1 : static void derefBufferInstanceContainer(void* container_ptr) { 56 1 : auto container = static_cast<BufferInstanceContainer*>(container_ptr); 57 1 : container->ref_count_--; 58 : // This is safe because the ref_count_ is never incremented. 59 1 : if (container->ref_count_ <= 0) { 60 1 : delete container; 61 1 : } 62 1 : } 63 : }; 64 : 65 1 : grpc::ByteBuffer GoogleGrpcUtils::makeByteBuffer(Buffer::InstancePtr&& buffer_instance) { 66 1 : if (!buffer_instance) { 67 0 : return {}; 68 0 : } 69 1 : Buffer::RawSliceVector raw_slices = buffer_instance->getRawSlices(); 70 1 : if (raw_slices.empty()) { 71 0 : return {}; 72 0 : } 73 : 74 1 : auto* container = 75 1 : new BufferInstanceContainer{static_cast<int>(raw_slices.size()), std::move(buffer_instance)}; 76 1 : std::vector<grpc::Slice> slices; 77 1 : slices.reserve(raw_slices.size()); 78 1 : for (Buffer::RawSlice& raw_slice : raw_slices) { 79 1 : slices.emplace_back(raw_slice.mem_, raw_slice.len_, 80 1 : &BufferInstanceContainer::derefBufferInstanceContainer, container); 81 1 : } 82 1 : return {&slices[0], slices.size()}; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) 83 1 : } 84 : 85 : class GrpcSliceBufferFragmentImpl : public Buffer::BufferFragment { 86 : public: 87 0 : explicit GrpcSliceBufferFragmentImpl(grpc::Slice&& slice) : slice_(std::move(slice)) {} 88 : 89 : // Buffer::BufferFragment 90 0 : const void* data() const override { return slice_.begin(); } 91 0 : size_t size() const override { return slice_.size(); } 92 0 : void done() override { delete this; } 93 : 94 : private: 95 : const grpc::Slice slice_; 96 : }; 97 : 98 0 : Buffer::InstancePtr GoogleGrpcUtils::makeBufferInstance(const grpc::ByteBuffer& byte_buffer) { 99 0 : auto buffer = std::make_unique<Buffer::OwnedImpl>(); 100 0 : if (byte_buffer.Length() == 0) { 101 0 : return buffer; 102 0 : } 103 : // NB: ByteBuffer::Dump moves the data out of the ByteBuffer so we need to ensure that the 104 : // lifetime of the Slice(s) exceeds our Buffer::Instance. 105 0 : std::vector<grpc::Slice> slices; 106 0 : if (!byte_buffer.Dump(&slices).ok()) { 107 0 : return nullptr; 108 0 : } 109 : 110 0 : for (auto& slice : slices) { 111 0 : buffer->addBufferFragment(*new GrpcSliceBufferFragmentImpl(std::move(slice))); 112 0 : } 113 0 : return buffer; 114 0 : } 115 : 116 : grpc::ChannelArguments 117 2 : GoogleGrpcUtils::channelArgsFromConfig(const envoy::config::core::v3::GrpcService& config) { 118 2 : grpc::ChannelArguments args; 119 2 : for (const auto& channel_arg : config.google_grpc().channel_args().args()) { 120 1 : switch (channel_arg.second.value_specifier_case()) { 121 1 : case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelArgs::Value::kStringValue: 122 1 : args.SetString(channel_arg.first, channel_arg.second.string_value()); 123 1 : break; 124 0 : case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelArgs::Value::kIntValue: 125 0 : args.SetInt(channel_arg.first, channel_arg.second.int_value()); 126 0 : break; 127 0 : case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelArgs::Value:: 128 0 : VALUE_SPECIFIER_NOT_SET: 129 0 : PANIC_DUE_TO_PROTO_UNSET; 130 1 : } 131 1 : } 132 2 : return args; 133 2 : } 134 : 135 : std::shared_ptr<grpc::Channel> 136 2 : GoogleGrpcUtils::createChannel(const envoy::config::core::v3::GrpcService& config, Api::Api& api) { 137 2 : std::shared_ptr<grpc::ChannelCredentials> creds = getGoogleGrpcChannelCredentials(config, api); 138 2 : const grpc::ChannelArguments args = channelArgsFromConfig(config); 139 2 : return CreateCustomChannel(config.google_grpc().target_uri(), creds, args); 140 2 : } 141 : 142 : } // namespace Grpc 143 : } // namespace Envoy