3 * Copyright 2016 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
22 #include "src/core/lib/gpr/useful.h"
24 #include "google/protobuf/duration.upb.h"
25 #include "google/protobuf/timestamp.upb.h"
27 #include <grpc/support/alloc.h>
31 grpc_grpclb_request* grpc_grpclb_request_create(const char* lb_service_name,
33 grpc_grpclb_request* req = grpc_lb_v1_LoadBalanceRequest_new(arena);
34 grpc_lb_v1_InitialLoadBalanceRequest* initial_request =
35 grpc_lb_v1_LoadBalanceRequest_mutable_initial_request(req, arena);
37 GPR_MIN(strlen(lb_service_name), GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH);
38 grpc_lb_v1_InitialLoadBalanceRequest_set_name(
39 initial_request, upb_strview_make(lb_service_name, name_len));
45 void google_protobuf_Timestamp_assign(google_protobuf_Timestamp* timestamp,
46 const gpr_timespec& value) {
47 google_protobuf_Timestamp_set_seconds(timestamp, value.tv_sec);
48 google_protobuf_Timestamp_set_nanos(timestamp, value.tv_nsec);
53 grpc_grpclb_request* grpc_grpclb_load_report_request_create(
54 GrpcLbClientStats* client_stats, upb_arena* arena) {
55 grpc_grpclb_request* req = grpc_lb_v1_LoadBalanceRequest_new(arena);
56 grpc_lb_v1_ClientStats* req_stats =
57 grpc_lb_v1_LoadBalanceRequest_mutable_client_stats(req, arena);
58 google_protobuf_Timestamp_assign(
59 grpc_lb_v1_ClientStats_mutable_timestamp(req_stats, arena),
60 gpr_now(GPR_CLOCK_REALTIME));
62 int64_t num_calls_started;
63 int64_t num_calls_finished;
64 int64_t num_calls_finished_with_client_failed_to_send;
65 int64_t num_calls_finished_known_received;
66 UniquePtr<GrpcLbClientStats::DroppedCallCounts> drop_token_counts;
67 client_stats->Get(&num_calls_started, &num_calls_finished,
68 &num_calls_finished_with_client_failed_to_send,
69 &num_calls_finished_known_received, &drop_token_counts);
70 grpc_lb_v1_ClientStats_set_num_calls_started(req_stats, num_calls_started);
71 grpc_lb_v1_ClientStats_set_num_calls_finished(req_stats, num_calls_finished);
72 grpc_lb_v1_ClientStats_set_num_calls_finished_with_client_failed_to_send(
73 req_stats, num_calls_finished_with_client_failed_to_send);
74 grpc_lb_v1_ClientStats_set_num_calls_finished_known_received(
75 req_stats, num_calls_finished_known_received);
76 if (drop_token_counts != nullptr) {
77 for (size_t i = 0; i < drop_token_counts->size(); ++i) {
78 GrpcLbClientStats::DropTokenCount& cur = (*drop_token_counts)[i];
79 grpc_lb_v1_ClientStatsPerToken* cur_msg =
80 grpc_lb_v1_ClientStats_add_calls_finished_with_drop(req_stats, arena);
82 const size_t token_len = strlen(cur.token.get());
83 char* token = reinterpret_cast<char*>(upb_arena_malloc(arena, token_len));
84 memcpy(token, cur.token.get(), token_len);
86 grpc_lb_v1_ClientStatsPerToken_set_load_balance_token(
87 cur_msg, upb_strview_make(token, token_len));
88 grpc_lb_v1_ClientStatsPerToken_set_num_calls(cur_msg, cur.count);
94 grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request* request,
98 grpc_lb_v1_LoadBalanceRequest_serialize(request, arena, &buf_length);
99 return grpc_slice_from_copied_buffer(buf, buf_length);
102 const grpc_grpclb_initial_response* grpc_grpclb_initial_response_parse(
103 const grpc_slice& encoded_grpc_grpclb_response, upb_arena* arena) {
104 grpc_lb_v1_LoadBalanceResponse* response =
105 grpc_lb_v1_LoadBalanceResponse_parse(
106 reinterpret_cast<const char*>(
107 GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response)),
108 GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response), arena);
109 if (response == nullptr) {
110 gpr_log(GPR_ERROR, "grpc_lb_v1_LoadBalanceResponse parse error");
113 return grpc_lb_v1_LoadBalanceResponse_initial_response(response);
116 grpc_grpclb_serverlist* grpc_grpclb_response_parse_serverlist(
117 const grpc_slice& encoded_grpc_grpclb_response) {
119 grpc_lb_v1_LoadBalanceResponse* response =
120 grpc_lb_v1_LoadBalanceResponse_parse(
121 reinterpret_cast<const char*>(
122 GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response)),
123 GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response), arena.ptr());
124 if (response == nullptr) {
125 gpr_log(GPR_ERROR, "grpc_lb_v1_LoadBalanceResponse parse error");
128 grpc_grpclb_serverlist* server_list = static_cast<grpc_grpclb_serverlist*>(
129 gpr_zalloc(sizeof(grpc_grpclb_serverlist)));
130 // First pass: count number of servers.
131 const grpc_lb_v1_ServerList* server_list_msg =
132 grpc_lb_v1_LoadBalanceResponse_server_list(response);
133 size_t server_count = 0;
134 const grpc_lb_v1_Server* const* servers = nullptr;
135 if (server_list_msg != nullptr) {
136 servers = grpc_lb_v1_ServerList_servers(server_list_msg, &server_count);
138 // Second pass: populate servers.
139 if (server_count > 0) {
140 server_list->servers = static_cast<grpc_grpclb_server**>(
141 gpr_zalloc(sizeof(grpc_grpclb_server*) * server_count));
142 server_list->num_servers = server_count;
143 for (size_t i = 0; i < server_count; ++i) {
144 grpc_grpclb_server* cur = server_list->servers[i] =
145 static_cast<grpc_grpclb_server*>(
146 gpr_zalloc(sizeof(grpc_grpclb_server)));
147 upb_strview address = grpc_lb_v1_Server_ip_address(servers[i]);
148 if (address.size == 0) {
149 ; // Nothing to do because cur->ip_address is an empty string.
150 } else if (address.size <= GRPC_GRPCLB_SERVER_IP_ADDRESS_MAX_SIZE) {
151 cur->ip_address.size = static_cast<int32_t>(address.size);
152 memcpy(cur->ip_address.data, address.data, address.size);
154 cur->port = grpc_lb_v1_Server_port(servers[i]);
155 upb_strview token = grpc_lb_v1_Server_load_balance_token(servers[i]);
156 if (token.size == 0) {
157 ; // Nothing to do because cur->load_balance_token is an empty string.
158 } else if (token.size <= GRPC_GRPCLB_SERVER_LOAD_BALANCE_TOKEN_MAX_SIZE) {
159 memcpy(cur->load_balance_token, token.data, token.size);
162 "grpc_lb_v1_LoadBalanceResponse has too long token. len=%zu",
165 cur->drop = grpc_lb_v1_Server_drop(servers[i]);
171 void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist* serverlist) {
172 if (serverlist == nullptr) {
175 for (size_t i = 0; i < serverlist->num_servers; i++) {
176 gpr_free(serverlist->servers[i]);
178 gpr_free(serverlist->servers);
179 gpr_free(serverlist);
182 grpc_grpclb_serverlist* grpc_grpclb_serverlist_copy(
183 const grpc_grpclb_serverlist* server_list) {
184 grpc_grpclb_serverlist* copy = static_cast<grpc_grpclb_serverlist*>(
185 gpr_zalloc(sizeof(grpc_grpclb_serverlist)));
186 copy->num_servers = server_list->num_servers;
187 copy->servers = static_cast<grpc_grpclb_server**>(
188 gpr_malloc(sizeof(grpc_grpclb_server*) * server_list->num_servers));
189 for (size_t i = 0; i < server_list->num_servers; i++) {
190 copy->servers[i] = static_cast<grpc_grpclb_server*>(
191 gpr_malloc(sizeof(grpc_grpclb_server)));
192 memcpy(copy->servers[i], server_list->servers[i],
193 sizeof(grpc_grpclb_server));
198 bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist* lhs,
199 const grpc_grpclb_serverlist* rhs) {
200 if (lhs == nullptr || rhs == nullptr) {
203 if (lhs->num_servers != rhs->num_servers) {
206 for (size_t i = 0; i < lhs->num_servers; i++) {
207 if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) {
214 bool grpc_grpclb_server_equals(const grpc_grpclb_server* lhs,
215 const grpc_grpclb_server* rhs) {
216 return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0;
219 grpc_millis grpc_grpclb_duration_to_millis(
220 const grpc_grpclb_duration* duration_pb) {
221 return static_cast<grpc_millis>(
222 google_protobuf_Duration_seconds(duration_pb) * GPR_MS_PER_SEC +
223 google_protobuf_Duration_nanos(duration_pb) / GPR_NS_PER_MS);
226 } // namespace grpc_core