google_c2p_resolver.cc
Go to the documentation of this file.
1 //
2 // Copyright 2021 gRPC authors.
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 
18 
19 #include <string.h>
20 
21 #include <cstdint>
22 #include <map>
23 #include <memory>
24 #include <random>
25 #include <string>
26 #include <utility>
27 
28 #include "absl/memory/memory.h"
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "absl/strings/str_cat.h"
32 #include "absl/strings/str_format.h"
33 #include "absl/strings/string_view.h"
34 #include "absl/strings/strip.h"
35 #include "absl/types/optional.h"
36 
37 #include <grpc/grpc.h>
38 #include <grpc/grpc_security.h>
40 #include <grpc/support/log.h>
41 
45 #include "src/core/lib/gpr/env.h"
58 #include "src/core/lib/json/json.h"
67 
68 namespace grpc_core {
69 
70 namespace {
71 
72 class GoogleCloud2ProdResolver : public Resolver {
73  public:
74  explicit GoogleCloud2ProdResolver(ResolverArgs args);
75 
76  void StartLocked() override;
77  void RequestReresolutionLocked() override;
78  void ResetBackoffLocked() override;
79  void ShutdownLocked() override;
80 
81  private:
82  // Represents an HTTP request to the metadata server.
83  class MetadataQuery : public InternallyRefCounted<MetadataQuery> {
84  public:
85  MetadataQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
86  const char* path, grpc_polling_entity* pollent);
87  ~MetadataQuery() override;
88 
89  void Orphan() override;
90 
91  private:
92  static void OnHttpRequestDone(void* arg, grpc_error_handle error);
93 
94  // If error is not GRPC_ERROR_NONE, then it's not safe to look at response.
95  virtual void OnDone(GoogleCloud2ProdResolver* resolver,
98 
99  RefCountedPtr<GoogleCloud2ProdResolver> resolver_;
100  OrphanablePtr<HttpRequest> http_request_;
103  };
104 
105  // A metadata server query to get the zone.
106  class ZoneQuery : public MetadataQuery {
107  public:
108  ZoneQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
109  grpc_polling_entity* pollent);
110 
111  private:
112  void OnDone(GoogleCloud2ProdResolver* resolver,
114  grpc_error_handle error) override;
115  };
116 
117  // A metadata server query to get the IPv6 address.
118  class IPv6Query : public MetadataQuery {
119  public:
120  IPv6Query(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
121  grpc_polling_entity* pollent);
122 
123  private:
124  void OnDone(GoogleCloud2ProdResolver* resolver,
126  grpc_error_handle error) override;
127  };
128 
129  void ZoneQueryDone(std::string zone);
130  void IPv6QueryDone(bool ipv6_supported);
131  void StartXdsResolver();
132 
134  std::shared_ptr<WorkSerializer> work_serializer_;
136  bool using_dns_ = false;
137  OrphanablePtr<Resolver> child_resolver_;
138  std::string metadata_server_name_ = "metadata.google.internal.";
139  bool shutdown_ = false;
140 
141  OrphanablePtr<ZoneQuery> zone_query_;
143 
144  OrphanablePtr<IPv6Query> ipv6_query_;
146 };
147 
148 //
149 // GoogleCloud2ProdResolver::MetadataQuery
150 //
151 
152 GoogleCloud2ProdResolver::MetadataQuery::MetadataQuery(
153  RefCountedPtr<GoogleCloud2ProdResolver> resolver, const char* path,
154  grpc_polling_entity* pollent)
155  : resolver_(std::move(resolver)) {
156  // Start HTTP request.
157  GRPC_CLOSURE_INIT(&on_done_, OnHttpRequestDone, this, nullptr);
158  Ref().release(); // Ref held by callback.
160  memset(&request, 0, sizeof(grpc_http_request));
161  grpc_http_header header = {const_cast<char*>("Metadata-Flavor"),
162  const_cast<char*>("Google")};
163  request.hdr_count = 1;
164  request.hdrs = &header;
165  auto uri = URI::Create("http", resolver_->metadata_server_name_, path,
166  {} /* query params */, "" /* fragment */);
167  GPR_ASSERT(uri.ok()); // params are hardcoded
168  grpc_arg resource_quota_arg = grpc_channel_arg_pointer_create(
169  const_cast<char*>(GRPC_ARG_RESOURCE_QUOTA),
170  resolver_->resource_quota_.get(), grpc_resource_quota_arg_vtable());
171  grpc_channel_args args = {1, &resource_quota_arg};
173  std::move(*uri), &args, pollent, &request,
174  ExecCtx::Get()->Now() + Duration::Seconds(10), // 10s timeout
175  &on_done_, &response_,
176  RefCountedPtr<grpc_channel_credentials>(
178  http_request_->Start();
179 }
180 
181 GoogleCloud2ProdResolver::MetadataQuery::~MetadataQuery() {
183 }
184 
185 void GoogleCloud2ProdResolver::MetadataQuery::Orphan() {
186  http_request_.reset();
187  Unref();
188 }
189 
190 void GoogleCloud2ProdResolver::MetadataQuery::OnHttpRequestDone(
191  void* arg, grpc_error_handle error) {
192  auto* self = static_cast<MetadataQuery*>(arg);
193  // Hop back into WorkSerializer to call OnDone().
194  // Note: We implicitly pass our ref to the callback here.
195  (void)GRPC_ERROR_REF(error);
196  self->resolver_->work_serializer_->Run(
197  [self, error]() {
198  self->OnDone(self->resolver_.get(), &self->response_, error);
199  self->Unref();
200  },
202 }
203 
204 //
205 // GoogleCloud2ProdResolver::ZoneQuery
206 //
207 
208 GoogleCloud2ProdResolver::ZoneQuery::ZoneQuery(
209  RefCountedPtr<GoogleCloud2ProdResolver> resolver,
210  grpc_polling_entity* pollent)
211  : MetadataQuery(std::move(resolver), "/computeMetadata/v1/instance/zone",
212  pollent) {}
213 
214 void GoogleCloud2ProdResolver::ZoneQuery::OnDone(
215  GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
218  if (!GRPC_ERROR_IS_NONE(error)) {
219  zone = absl::UnknownError(
220  absl::StrCat("error fetching zone from metadata server: ",
222  } else if (response->status != 200) {
224  "zone query received non-200 status: %d", response->status));
225  } else {
226  absl::string_view body(response->body, response->body_length);
227  size_t i = body.find_last_of('/');
228  if (i == body.npos) {
229  zone = absl::UnknownError(
230  absl::StrCat("could not parse zone from metadata server: ", body));
231  } else {
232  zone = std::string(body.substr(i + 1));
233  }
234  }
235  if (!zone.ok()) {
236  gpr_log(GPR_ERROR, "zone query failed: %s",
237  zone.status().ToString().c_str());
238  resolver->ZoneQueryDone("");
239  } else {
240  resolver->ZoneQueryDone(std::move(*zone));
241  }
243 }
244 
245 //
246 // GoogleCloud2ProdResolver::IPv6Query
247 //
248 
249 GoogleCloud2ProdResolver::IPv6Query::IPv6Query(
250  RefCountedPtr<GoogleCloud2ProdResolver> resolver,
251  grpc_polling_entity* pollent)
252  : MetadataQuery(std::move(resolver),
253  "/computeMetadata/v1/instance/network-interfaces/0/ipv6s",
254  pollent) {}
255 
256 void GoogleCloud2ProdResolver::IPv6Query::OnDone(
257  GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
259  if (!GRPC_ERROR_IS_NONE(error)) {
260  gpr_log(GPR_ERROR, "error fetching IPv6 address from metadata server: %s",
262  }
263  resolver->IPv6QueryDone(GRPC_ERROR_IS_NONE(error) && response->status == 200);
265 }
266 
267 //
268 // GoogleCloud2ProdResolver
269 //
270 
271 GoogleCloud2ProdResolver::GoogleCloud2ProdResolver(ResolverArgs args)
273  work_serializer_(std::move(args.work_serializer)),
275  absl::string_view name_to_resolve = absl::StripPrefix(args.uri.path(), "/");
276  // If we're not running on GCP, we can't use DirectPath, so delegate
277  // to the DNS resolver.
278  bool test_only_pretend_running_on_gcp = grpc_channel_args_find_bool(
279  args.args, "grpc.testing.google_c2p_resolver_pretend_running_on_gcp",
280  false);
281  bool running_on_gcp =
282  test_only_pretend_running_on_gcp || grpc_alts_is_running_on_gcp();
283  if (!running_on_gcp ||
284  // If the client is already using xDS, we can't use it here, because
285  // they may be talking to a completely different xDS server than we
286  // want to.
287  // TODO(roth): When we implement xDS federation, remove this constraint.
288  UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP")) != nullptr ||
289  UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG")) != nullptr) {
290  using_dns_ = true;
292  CoreConfiguration::Get().resolver_registry().CreateResolver(
293  absl::StrCat("dns:", name_to_resolve).c_str(), args.args,
294  args.pollset_set, work_serializer_, std::move(args.result_handler));
295  GPR_ASSERT(child_resolver_ != nullptr);
296  return;
297  }
298  // Maybe override metadata server name for testing
299  const char* test_only_metadata_server_override =
301  args.args,
302  "grpc.testing.google_c2p_resolver_metadata_server_override");
303  if (test_only_metadata_server_override != nullptr &&
304  strlen(test_only_metadata_server_override) > 0) {
305  metadata_server_name_ = std::string(test_only_metadata_server_override);
306  }
307  // Create xds resolver.
308  child_resolver_ = CoreConfiguration::Get().resolver_registry().CreateResolver(
309  absl::StrCat("xds:", name_to_resolve).c_str(), args.args,
310  args.pollset_set, work_serializer_, std::move(args.result_handler));
311  GPR_ASSERT(child_resolver_ != nullptr);
312 }
313 
314 void GoogleCloud2ProdResolver::StartLocked() {
315  if (using_dns_) {
316  child_resolver_->StartLocked();
317  return;
318  }
319  // Using xDS. Start metadata server queries.
320  zone_query_ = MakeOrphanable<ZoneQuery>(Ref(), &pollent_);
321  ipv6_query_ = MakeOrphanable<IPv6Query>(Ref(), &pollent_);
322 }
323 
324 void GoogleCloud2ProdResolver::RequestReresolutionLocked() {
325  if (child_resolver_ != nullptr) {
326  child_resolver_->RequestReresolutionLocked();
327  }
328 }
329 
330 void GoogleCloud2ProdResolver::ResetBackoffLocked() {
331  if (child_resolver_ != nullptr) {
332  child_resolver_->ResetBackoffLocked();
333  }
334 }
335 
336 void GoogleCloud2ProdResolver::ShutdownLocked() {
337  shutdown_ = true;
338  zone_query_.reset();
339  ipv6_query_.reset();
340  child_resolver_.reset();
341 }
342 
343 void GoogleCloud2ProdResolver::ZoneQueryDone(std::string zone) {
344  zone_query_.reset();
345  zone_ = std::move(zone);
346  if (supports_ipv6_.has_value()) StartXdsResolver();
347 }
348 
349 void GoogleCloud2ProdResolver::IPv6QueryDone(bool ipv6_supported) {
350  ipv6_query_.reset();
351  supports_ipv6_ = ipv6_supported;
352  if (zone_.has_value()) StartXdsResolver();
353 }
354 
355 void GoogleCloud2ProdResolver::StartXdsResolver() {
356  if (shutdown_) {
357  return;
358  }
359  // Construct bootstrap JSON.
360  std::random_device rd;
361  std::mt19937 mt(rd());
362  std::uniform_int_distribution<uint64_t> dist(1, UINT64_MAX);
363  Json::Object node = {
364  {"id", absl::StrCat("C2P-", dist(mt))},
365  };
366  if (!zone_->empty()) {
367  node["locality"] = Json::Object{
368  {"zone", *zone_},
369  };
370  };
371  if (*supports_ipv6_) {
372  node["metadata"] = Json::Object{
373  {"TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE", true},
374  };
375  }
376  // Allow the TD server uri to be overridden for testing purposes.
377  UniquePtr<char> override_server(
378  gpr_getenv("GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI"));
379  const char* server_uri =
380  override_server != nullptr && strlen(override_server.get()) > 0
381  ? override_server.get()
382  : "directpath-pa.googleapis.com";
383  Json xds_server = Json::Array{
384  Json::Object{
385  {"server_uri", server_uri},
386  {"channel_creds",
387  Json::Array{
388  Json::Object{
389  {"type", "google_default"},
390  },
391  }},
392  {"server_features", Json::Array{"xds_v3"}},
393  },
394  };
395  Json bootstrap = Json::Object{
396  {"xds_servers", xds_server},
397  {"authorities",
398  Json::Object{
399  {"traffic-director-c2p.xds.googleapis.com",
400  Json::Object{
401  {"xds_servers", std::move(xds_server)},
402  }},
403  }},
404  {"node", std::move(node)},
405  };
406  // Inject bootstrap JSON as fallback config.
407  internal::SetXdsFallbackBootstrapConfig(bootstrap.Dump().c_str());
408  // Now start xDS resolver.
409  child_resolver_->StartLocked();
410 }
411 
412 //
413 // Factory
414 //
415 
416 class GoogleCloud2ProdResolverFactory : public ResolverFactory {
417  public:
418  // TODO(roth): Remove experimental suffix once this code is proven stable,
419  // and update the scheme in google_c2p_resolver_test.cc when doing so.
420  absl::string_view scheme() const override {
421  return "google-c2p-experimental";
422  }
423 
424  bool IsValidUri(const URI& uri) const override {
425  if (GPR_UNLIKELY(!uri.authority().empty())) {
426  gpr_log(GPR_ERROR, "google-c2p URI scheme does not support authorities");
427  return false;
428  }
429  return true;
430  }
431 
432  OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
433  if (!IsValidUri(args.uri)) return nullptr;
434  return MakeOrphanable<GoogleCloud2ProdResolver>(std::move(args));
435  }
436 };
437 
438 } // namespace
439 
441  builder->resolver_registry()->RegisterResolverFactory(
442  absl::make_unique<GoogleCloud2ProdResolverFactory>());
443 }
444 
445 } // namespace grpc_core
GRPC_CLOSURE_INIT
#define GRPC_CLOSURE_INIT(closure, cb, cb_arg, scheduler)
Definition: closure.h:115
grpc_arg
Definition: grpc_types.h:103
grpc_channel_args_find_string
char * grpc_channel_args_find_string(const grpc_channel_args *args, const char *name)
Definition: channel_args.cc:441
zone_query_
OrphanablePtr< ZoneQuery > zone_query_
Definition: google_c2p_resolver.cc:141
orphanable.h
log.h
core_configuration.h
absl::Status::ToString
std::string ToString(StatusToStringMode mode=StatusToStringMode::kDefault) const
Definition: third_party/abseil-cpp/absl/status/status.h:821
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
memset
return memset(p, 0, total)
metadata_server_name_
std::string metadata_server_name_
Definition: google_c2p_resolver.cc:138
response_
grpc_http_response response_
Definition: google_c2p_resolver.cc:101
absl::StrFormat
ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec< Args... > &format, const Args &... args)
Definition: abseil-cpp/absl/strings/str_format.h:338
polling_entity.h
resolver_
RefCountedPtr< GoogleCloud2ProdResolver > resolver_
Definition: google_c2p_resolver.cc:99
grpc_core
Definition: call_metric_recorder.h:31
GRPC_ARG_RESOURCE_QUOTA
#define GRPC_ARG_RESOURCE_QUOTA
Definition: grpc_types.h:299
grpc_core::CoreConfiguration::Builder
Definition: core_configuration.h:41
using_dns_
bool using_dns_
Definition: google_c2p_resolver.cc:136
string.h
benchmark.request
request
Definition: benchmark.py:77
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
supports_ipv6_
absl::optional< bool > supports_ipv6_
Definition: google_c2p_resolver.cc:145
error
grpc_error_handle error
Definition: retry_filter.cc:499
grpc_alts_is_running_on_gcp
bool grpc_alts_is_running_on_gcp()
Definition: check_gcp_environment_no_op.cc:27
UINT64_MAX
#define UINT64_MAX
Definition: stdint-msvc2008.h:143
resource_quota_
ResourceQuotaRefPtr resource_quota_
Definition: google_c2p_resolver.cc:133
closure.h
check_gcp_environment.h
shutdown_
bool shutdown_
Definition: google_c2p_resolver.cc:139
env.h
check_documentation.path
path
Definition: check_documentation.py:57
absl::StripPrefix
ABSL_MUST_USE_RESULT absl::string_view StripPrefix(absl::string_view str, absl::string_view prefix)
Definition: abseil-cpp/absl/strings/strip.h:73
run_xds_tests.server_uri
string server_uri
Definition: run_xds_tests.py:3320
grpc_security.h
ipv6_query_
OrphanablePtr< IPv6Query > ipv6_query_
Definition: google_c2p_resolver.cc:144
credentials.h
grpc_channel_args_find_bool
bool grpc_channel_args_find_bool(const grpc_channel_args *args, const char *name, bool default_value)
Definition: channel_args.cc:465
grpc_channel_args
Definition: grpc_types.h:132
on_done_
grpc_closure on_done_
Definition: google_c2p_resolver.cc:102
grpc_types.h
absl::synchronization_internal::Get
static GraphId Get(const IdMap &id, int num)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles_test.cc:44
memory.h
child_resolver_
OrphanablePtr< Resolver > child_resolver_
Definition: google_c2p_resolver.cc:137
resolver_factory.h
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
grpc_http_response
Definition: src/core/lib/http/parser.h:85
profile_analyzer.builder
builder
Definition: profile_analyzer.py:159
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
gpr_getenv
char * gpr_getenv(const char *name)
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
grpc_http_header
Definition: src/core/lib/http/parser.h:36
absl::optional::has_value
constexpr bool has_value() const noexcept
Definition: abseil-cpp/absl/types/optional.h:461
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
Json
JSON (JavaScript Object Notation).
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:227
grpc_resource_quota_arg_vtable
const GRPCAPI grpc_arg_pointer_vtable * grpc_resource_quota_arg_vtable(void)
Definition: api.cc:62
xds_client.h
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
work_serializer.h
GPR_UNLIKELY
#define GPR_UNLIKELY(x)
Definition: impl/codegen/port_platform.h:770
absl::UnknownError
Status UnknownError(absl::string_view message)
Definition: third_party/abseil-cpp/absl/status/status.cc:383
httpcli.h
grpc.h
header
struct absl::base_internal::@2940::AllocList::Header header
absl::optional< std::string >
grpc_insecure_credentials_create
GRPCAPI grpc_channel_credentials * grpc_insecure_credentials_create()
Definition: core/lib/security/credentials/insecure/insecure_credentials.cc:64
arg
Definition: cmdline.cc:40
time.h
grpc_http_response_destroy
void grpc_http_response_destroy(grpc_http_response *response)
Definition: src/core/lib/http/parser.cc:434
error.h
grpc_polling_entity
Definition: polling_entity.h:38
json.h
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
resource_quota.h
resolver_registry.h
http_request_
OrphanablePtr< HttpRequest > http_request_
Definition: google_c2p_resolver.cc:100
resolver.h
grpc_core::internal::SetXdsFallbackBootstrapConfig
void SetXdsFallbackBootstrapConfig(const char *config)
Definition: xds_client.cc:2523
absl::Seconds
constexpr Duration Seconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:419
absl::Now
ABSL_NAMESPACE_BEGIN Time Now()
Definition: abseil-cpp/absl/time/clock.cc:39
absl::StatusOr::ok
ABSL_MUST_USE_RESULT bool ok() const
Definition: abseil-cpp/absl/status/statusor.h:491
parser.h
GRPC_ERROR_REF
#define GRPC_ERROR_REF(err)
Definition: error.h:261
debug_location.h
grpc_core::ResourceQuotaFromChannelArgs
ResourceQuotaRefPtr ResourceQuotaFromChannelArgs(const grpc_channel_args *args)
Definition: api.cc:40
grpc_error_std_string
std::string grpc_error_std_string(grpc_error_handle error)
Definition: error.cc:944
asyncio_get_stats.response
response
Definition: asyncio_get_stats.py:28
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
arg
struct arg arg
exec_ctx.h
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
ref_counted_ptr.h
channel_args.h
grpc_core::ResourceQuotaRefPtr
RefCountedPtr< ResourceQuota > ResourceQuotaRefPtr
Definition: src/core/lib/resource_quota/resource_quota.h:38
work_serializer_
std::shared_ptr< WorkSerializer > work_serializer_
Definition: google_c2p_resolver.cc:134
absl::StatusOr< std::string >
uri_parser.h
grpc_error
Definition: error_internal.h:42
grpc_polling_entity_create_from_pollset_set
grpc_polling_entity grpc_polling_entity_create_from_pollset_set(grpc_pollset_set *pollset_set)
Definition: polling_entity.cc:26
self
PHP_PROTO_OBJECT_FREE_END PHP_PROTO_OBJECT_DTOR_END intern self
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/map.c:543
testing::Ref
internal::RefMatcher< T & > Ref(T &x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8628
zone_
absl::optional< std::string > zone_
Definition: google_c2p_resolver.cc:142
grpc_closure
Definition: closure.h:56
grpc_channel_arg_pointer_create
grpc_arg grpc_channel_arg_pointer_create(char *name, void *value, const grpc_arg_pointer_vtable *vtable)
Definition: channel_args.cc:492
grpc_core::RegisterCloud2ProdResolver
void RegisterCloud2ProdResolver(CoreConfiguration::Builder *builder)
Definition: google_c2p_resolver.cc:440
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
pollent_
grpc_polling_entity pollent_
Definition: google_c2p_resolver.cc:135
absl::StatusOr::status
const Status & status() const &
Definition: abseil-cpp/absl/status/statusor.h:678
GRPC_ERROR_IS_NONE
#define GRPC_ERROR_IS_NONE(err)
Definition: error.h:241
grpc_http_request
Definition: src/core/lib/http/parser.h:69
api.h
port_platform.h


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:39