Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / ext / filters / client_channel / lb_policy_registry.cc
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * 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, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
22
23 #include <string.h>
24
25 #include "src/core/lib/gpr/string.h"
26 #include "src/core/lib/gprpp/inlined_vector.h"
27
28 namespace grpc_core {
29
30 namespace {
31
32 class RegistryState {
33  public:
34   RegistryState() {}
35
36   void RegisterLoadBalancingPolicyFactory(
37       UniquePtr<LoadBalancingPolicyFactory> factory) {
38     for (size_t i = 0; i < factories_.size(); ++i) {
39       GPR_ASSERT(strcmp(factories_[i]->name(), factory->name()) != 0);
40     }
41     factories_.push_back(std::move(factory));
42   }
43
44   LoadBalancingPolicyFactory* GetLoadBalancingPolicyFactory(
45       const char* name) const {
46     for (size_t i = 0; i < factories_.size(); ++i) {
47       if (strcmp(name, factories_[i]->name()) == 0) {
48         return factories_[i].get();
49       }
50     }
51     return nullptr;
52   }
53
54  private:
55   InlinedVector<UniquePtr<LoadBalancingPolicyFactory>, 10> factories_;
56 };
57
58 RegistryState* g_state = nullptr;
59
60 }  // namespace
61
62 //
63 // LoadBalancingPolicyRegistry::Builder
64 //
65
66 void LoadBalancingPolicyRegistry::Builder::InitRegistry() {
67   if (g_state == nullptr) g_state = New<RegistryState>();
68 }
69
70 void LoadBalancingPolicyRegistry::Builder::ShutdownRegistry() {
71   Delete(g_state);
72   g_state = nullptr;
73 }
74
75 void LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
76     UniquePtr<LoadBalancingPolicyFactory> factory) {
77   InitRegistry();
78   g_state->RegisterLoadBalancingPolicyFactory(std::move(factory));
79 }
80
81 //
82 // LoadBalancingPolicyRegistry
83 //
84
85 OrphanablePtr<LoadBalancingPolicy>
86 LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
87     const char* name, LoadBalancingPolicy::Args args) {
88   GPR_ASSERT(g_state != nullptr);
89   // Find factory.
90   LoadBalancingPolicyFactory* factory =
91       g_state->GetLoadBalancingPolicyFactory(name);
92   if (factory == nullptr) return nullptr;  // Specified name not found.
93   // Create policy via factory.
94   return factory->CreateLoadBalancingPolicy(std::move(args));
95 }
96
97 bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
98     const char* name, bool* requires_config) {
99   GPR_ASSERT(g_state != nullptr);
100   auto* factory = g_state->GetLoadBalancingPolicyFactory(name);
101   if (factory == nullptr) {
102     return false;
103   }
104   if (requires_config != nullptr) {
105     grpc_error* error = GRPC_ERROR_NONE;
106     // Check if the load balancing policy allows an empty config
107     *requires_config =
108         factory->ParseLoadBalancingConfig(nullptr, &error) == nullptr;
109     GRPC_ERROR_UNREF(error);
110   }
111   return true;
112 }
113
114 namespace {
115 // Returns the JSON node of policy (with both policy name and config content)
116 // given the JSON node of a LoadBalancingConfig array.
117 grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array,
118                                           grpc_error** error) {
119   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
120   if (lb_config_array == nullptr) {
121     *error =
122         GRPC_ERROR_CREATE_FROM_STATIC_STRING("LB config JSON tree is null");
123     return nullptr;
124   }
125   char* error_msg;
126   if (lb_config_array->type != GRPC_JSON_ARRAY) {
127     gpr_asprintf(&error_msg, "field:%s error:type should be array",
128                  lb_config_array->key);
129     *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
130     gpr_free(error_msg);
131     return nullptr;
132   }
133   const char* field_name = lb_config_array->key;
134   // Find the first LB policy that this client supports.
135   for (const grpc_json* lb_config = lb_config_array->child;
136        lb_config != nullptr; lb_config = lb_config->next) {
137     if (lb_config->type != GRPC_JSON_OBJECT) {
138       gpr_asprintf(&error_msg,
139                    "field:%s error:child entry should be of type object",
140                    field_name);
141       *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
142       gpr_free(error_msg);
143       return nullptr;
144     }
145     grpc_json* policy = nullptr;
146     for (grpc_json* field = lb_config->child; field != nullptr;
147          field = field->next) {
148       if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) {
149         gpr_asprintf(&error_msg,
150                      "field:%s error:child entry should be of type object",
151                      field_name);
152         *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
153         gpr_free(error_msg);
154         return nullptr;
155       }
156       if (policy != nullptr) {
157         gpr_asprintf(&error_msg, "field:%s error:oneOf violation", field_name);
158         *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
159         gpr_free(error_msg);
160         return nullptr;
161       }  // Violate "oneof" type.
162       policy = field;
163     }
164     if (policy == nullptr) {
165       gpr_asprintf(&error_msg, "field:%s error:no policy found in child entry",
166                    field_name);
167       *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
168       gpr_free(error_msg);
169       return nullptr;
170     }
171     // If we support this policy, then select it.
172     if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key,
173                                                                nullptr)) {
174       return policy;
175     }
176   }
177   gpr_asprintf(&error_msg, "field:%s error:No known policy", field_name);
178   *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
179   gpr_free(error_msg);
180   return nullptr;
181 }
182 }  // namespace
183
184 RefCountedPtr<LoadBalancingPolicy::Config>
185 LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
186                                                       grpc_error** error) {
187   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
188   GPR_ASSERT(g_state != nullptr);
189   const grpc_json* policy = ParseLoadBalancingConfigHelper(json, error);
190   if (policy == nullptr) {
191     return nullptr;
192   } else {
193     GPR_DEBUG_ASSERT(*error == GRPC_ERROR_NONE && json != nullptr);
194     // Find factory.
195     LoadBalancingPolicyFactory* factory =
196         g_state->GetLoadBalancingPolicyFactory(policy->key);
197     if (factory == nullptr) {
198       char* msg;
199       gpr_asprintf(&msg, "field:%s error:Factory not found to create policy",
200                    json->key);
201       *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
202       gpr_free(msg);
203       return nullptr;
204     }
205     // Parse load balancing config via factory.
206     return factory->ParseLoadBalancingConfig(policy, error);
207   }
208 }
209
210 }  // namespace grpc_core