blob: fc781da330fb39197da30b1accd2d67cf280ef08 [file] [log] [blame]
Craig Tillereb841e22016-02-11 15:49:16 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2016 gRPC authors.
Craig Tillereb841e22016-02-11 15:49:16 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
Craig Tillereb841e22016-02-11 15:49:16 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Craig Tillereb841e22016-02-11 15:49:16 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
Craig Tillereb841e22016-02-11 15:49:16 -080016 *
17 */
18
Craig Tiller9eb0fde2017-03-31 16:59:30 -070019#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
Craig Tillereb841e22016-02-11 15:49:16 -080020#include "third_party/nanopb/pb_decode.h"
21#include "third_party/nanopb/pb_encode.h"
22
23#include <grpc/support/alloc.h>
24
Mark D. Rothd7389b42017-05-17 12:22:17 -070025/* invoked once for every Server in ServerList */
Craig Tillerbaa14a92017-11-03 09:09:36 -070026static bool count_serverlist(pb_istream_t* stream, const pb_field_t* field,
27 void** arg) {
28 grpc_grpclb_serverlist* sl = (grpc_grpclb_serverlist*)*arg;
Mark D. Rothd7389b42017-05-17 12:22:17 -070029 grpc_grpclb_server server;
30 if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) {
31 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
32 return false;
33 }
34 ++sl->num_servers;
35 return true;
36}
37
Craig Tillereb841e22016-02-11 15:49:16 -080038typedef struct decode_serverlist_arg {
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -070039 /* The decoding callback is invoked once per server in serverlist. Remember
40 * which index of the serverlist are we currently decoding */
41 size_t decoding_idx;
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -070042 /* The decoded serverlist */
Craig Tillerbaa14a92017-11-03 09:09:36 -070043 grpc_grpclb_serverlist* serverlist;
Craig Tillereb841e22016-02-11 15:49:16 -080044} decode_serverlist_arg;
45
46/* invoked once for every Server in ServerList */
Craig Tillerbaa14a92017-11-03 09:09:36 -070047static bool decode_serverlist(pb_istream_t* stream, const pb_field_t* field,
48 void** arg) {
49 decode_serverlist_arg* dec_arg = (decode_serverlist_arg*)*arg;
Mark D. Rothd7389b42017-05-17 12:22:17 -070050 GPR_ASSERT(dec_arg->serverlist->num_servers >= dec_arg->decoding_idx);
Craig Tillerbaa14a92017-11-03 09:09:36 -070051 grpc_grpclb_server* server =
52 (grpc_grpclb_server*)gpr_zalloc(sizeof(grpc_grpclb_server));
Mark D. Rothd7389b42017-05-17 12:22:17 -070053 if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) {
54 gpr_free(server);
55 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
56 return false;
Craig Tillereb841e22016-02-11 15:49:16 -080057 }
Mark D. Rothd7389b42017-05-17 12:22:17 -070058 dec_arg->serverlist->servers[dec_arg->decoding_idx++] = server;
Craig Tillereb841e22016-02-11 15:49:16 -080059 return true;
60}
61
Craig Tillerbaa14a92017-11-03 09:09:36 -070062grpc_grpclb_request* grpc_grpclb_request_create(const char* lb_service_name) {
63 grpc_grpclb_request* req =
64 (grpc_grpclb_request*)gpr_malloc(sizeof(grpc_grpclb_request));
Mark D. Roth09e458c2017-05-02 08:13:26 -070065 req->has_client_stats = false;
66 req->has_initial_request = true;
67 req->initial_request.has_name = true;
Craig Tillereb841e22016-02-11 15:49:16 -080068 strncpy(req->initial_request.name, lb_service_name,
69 GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH);
70 return req;
71}
72
Mark D. Roth09e458c2017-05-02 08:13:26 -070073static void populate_timestamp(gpr_timespec timestamp,
Craig Tillerbaa14a92017-11-03 09:09:36 -070074 struct _grpc_lb_v1_Timestamp* timestamp_pb) {
Mark D. Roth09e458c2017-05-02 08:13:26 -070075 timestamp_pb->has_seconds = true;
76 timestamp_pb->seconds = timestamp.tv_sec;
77 timestamp_pb->has_nanos = true;
78 timestamp_pb->nanos = timestamp.tv_nsec;
79}
80
Craig Tillerbaa14a92017-11-03 09:09:36 -070081static bool encode_string(pb_ostream_t* stream, const pb_field_t* field,
82 void* const* arg) {
83 char* str = (char*)*arg;
Mark D. Rothe7751802017-07-27 12:31:45 -070084 if (!pb_encode_tag_for_field(stream, field)) return false;
Craig Tillerbaa14a92017-11-03 09:09:36 -070085 return pb_encode_string(stream, (uint8_t*)str, strlen(str));
Mark D. Rothe7751802017-07-27 12:31:45 -070086}
87
Craig Tillerbaa14a92017-11-03 09:09:36 -070088static bool encode_drops(pb_ostream_t* stream, const pb_field_t* field,
89 void* const* arg) {
90 grpc_grpclb_dropped_call_counts* drop_entries =
91 (grpc_grpclb_dropped_call_counts*)*arg;
Craig Tiller4782d922017-11-10 09:53:21 -080092 if (drop_entries == nullptr) return true;
Mark D. Rothe7751802017-07-27 12:31:45 -070093 for (size_t i = 0; i < drop_entries->num_entries; ++i) {
94 if (!pb_encode_tag_for_field(stream, field)) return false;
95 grpc_lb_v1_ClientStatsPerToken drop_message;
96 drop_message.load_balance_token.funcs.encode = encode_string;
97 drop_message.load_balance_token.arg = drop_entries->token_counts[i].token;
98 drop_message.has_num_calls = true;
99 drop_message.num_calls = drop_entries->token_counts[i].count;
100 if (!pb_encode_submessage(stream, grpc_lb_v1_ClientStatsPerToken_fields,
101 &drop_message)) {
102 return false;
103 }
104 }
105 return true;
106}
107
Craig Tillerbaa14a92017-11-03 09:09:36 -0700108grpc_grpclb_request* grpc_grpclb_load_report_request_create_locked(
109 grpc_grpclb_client_stats* client_stats) {
110 grpc_grpclb_request* req =
111 (grpc_grpclb_request*)gpr_zalloc(sizeof(grpc_grpclb_request));
Mark D. Roth09e458c2017-05-02 08:13:26 -0700112 req->has_client_stats = true;
113 req->client_stats.has_timestamp = true;
114 populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp);
115 req->client_stats.has_num_calls_started = true;
116 req->client_stats.has_num_calls_finished = true;
Mark D. Roth09e458c2017-05-02 08:13:26 -0700117 req->client_stats.has_num_calls_finished_with_client_failed_to_send = true;
118 req->client_stats.has_num_calls_finished_with_client_failed_to_send = true;
119 req->client_stats.has_num_calls_finished_known_received = true;
Mark D. Rothe7751802017-07-27 12:31:45 -0700120 req->client_stats.calls_finished_with_drop.funcs.encode = encode_drops;
121 grpc_grpclb_client_stats_get_locked(
Mark D. Roth09e458c2017-05-02 08:13:26 -0700122 client_stats, &req->client_stats.num_calls_started,
123 &req->client_stats.num_calls_finished,
Mark D. Roth09e458c2017-05-02 08:13:26 -0700124 &req->client_stats.num_calls_finished_with_client_failed_to_send,
Mark D. Rothe7751802017-07-27 12:31:45 -0700125 &req->client_stats.num_calls_finished_known_received,
Craig Tillerbaa14a92017-11-03 09:09:36 -0700126 (grpc_grpclb_dropped_call_counts**)&req->client_stats
Mark D. Rothe7751802017-07-27 12:31:45 -0700127 .calls_finished_with_drop.arg);
Mark D. Roth09e458c2017-05-02 08:13:26 -0700128 return req;
129}
130
Craig Tillerbaa14a92017-11-03 09:09:36 -0700131grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request* request) {
Craig Tillereb841e22016-02-11 15:49:16 -0800132 size_t encoded_length;
133 pb_ostream_t sizestream;
134 pb_ostream_t outputstream;
Craig Tillerd41a4a72016-10-26 16:16:06 -0700135 grpc_slice slice;
Craig Tillereb841e22016-02-11 15:49:16 -0800136 memset(&sizestream, 0, sizeof(pb_ostream_t));
David Garcia Quintas7f0793a2016-04-25 12:35:58 -0700137 pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request);
Craig Tillereb841e22016-02-11 15:49:16 -0800138 encoded_length = sizestream.bytes_written;
139
Craig Tiller423d6fd2017-04-12 13:15:45 -0700140 slice = GRPC_SLICE_MALLOC(encoded_length);
Craig Tillereb841e22016-02-11 15:49:16 -0800141 outputstream =
Craig Tiller618e67d2016-10-26 21:08:10 -0700142 pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length);
David Garcia Quintas7f0793a2016-04-25 12:35:58 -0700143 GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields,
Craig Tillereb841e22016-02-11 15:49:16 -0800144 request) != 0);
145 return slice;
146}
147
Craig Tillerbaa14a92017-11-03 09:09:36 -0700148void grpc_grpclb_request_destroy(grpc_grpclb_request* request) {
Mark D. Rothe7751802017-07-27 12:31:45 -0700149 if (request->has_client_stats) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700150 grpc_grpclb_dropped_call_counts* drop_entries =
151 (grpc_grpclb_dropped_call_counts*)
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700152 request->client_stats.calls_finished_with_drop.arg;
Mark D. Rothe7751802017-07-27 12:31:45 -0700153 grpc_grpclb_dropped_call_counts_destroy(drop_entries);
154 }
Craig Tillereb841e22016-02-11 15:49:16 -0800155 gpr_free(request);
156}
157
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700158typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700159grpc_grpclb_initial_response* grpc_grpclb_initial_response_parse(
Craig Tillerd41a4a72016-10-26 16:16:06 -0700160 grpc_slice encoded_grpc_grpclb_response) {
Craig Tillereb841e22016-02-11 15:49:16 -0800161 pb_istream_t stream =
Craig Tiller618e67d2016-10-26 21:08:10 -0700162 pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response),
163 GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response));
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700164 grpc_grpclb_response res;
165 memset(&res, 0, sizeof(grpc_grpclb_response));
166 if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) {
David Garcia Quintas18bc43b2016-08-22 15:05:32 -0700167 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
Craig Tiller4782d922017-11-10 09:53:21 -0800168 return nullptr;
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700169 }
Mark D. Roth09e458c2017-05-02 08:13:26 -0700170
Craig Tiller4782d922017-11-10 09:53:21 -0800171 if (!res.has_initial_response) return nullptr;
Mark D. Roth09e458c2017-05-02 08:13:26 -0700172
Craig Tillerbaa14a92017-11-03 09:09:36 -0700173 grpc_grpclb_initial_response* initial_res =
174 (grpc_grpclb_initial_response*)gpr_malloc(
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700175 sizeof(grpc_grpclb_initial_response));
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700176 memcpy(initial_res, &res.initial_response,
177 sizeof(grpc_grpclb_initial_response));
178
179 return initial_res;
Craig Tillereb841e22016-02-11 15:49:16 -0800180}
181
Craig Tillerbaa14a92017-11-03 09:09:36 -0700182grpc_grpclb_serverlist* grpc_grpclb_response_parse_serverlist(
Craig Tillerd41a4a72016-10-26 16:16:06 -0700183 grpc_slice encoded_grpc_grpclb_response) {
Craig Tillereb841e22016-02-11 15:49:16 -0800184 pb_istream_t stream =
Craig Tiller618e67d2016-10-26 21:08:10 -0700185 pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response),
186 GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response));
Craig Tillereb841e22016-02-11 15:49:16 -0800187 pb_istream_t stream_at_start = stream;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700188 grpc_grpclb_serverlist* sl =
189 (grpc_grpclb_serverlist*)gpr_zalloc(sizeof(grpc_grpclb_serverlist));
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700190 grpc_grpclb_response res;
191 memset(&res, 0, sizeof(grpc_grpclb_response));
Mark D. Rothd7389b42017-05-17 12:22:17 -0700192 // First pass: count number of servers.
193 res.server_list.servers.funcs.decode = count_serverlist;
194 res.server_list.servers.arg = sl;
195 bool status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res);
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700196 if (!status) {
Mark D. Rothd7389b42017-05-17 12:22:17 -0700197 gpr_free(sl);
David Garcia Quintas18bc43b2016-08-22 15:05:32 -0700198 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
Craig Tiller4782d922017-11-10 09:53:21 -0800199 return nullptr;
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700200 }
Mark D. Rothd7389b42017-05-17 12:22:17 -0700201 // Second pass: populate servers.
202 if (sl->num_servers > 0) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700203 sl->servers = (grpc_grpclb_server**)gpr_zalloc(sizeof(grpc_grpclb_server*) *
204 sl->num_servers);
Mark D. Rothd7389b42017-05-17 12:22:17 -0700205 decode_serverlist_arg decode_arg;
206 memset(&decode_arg, 0, sizeof(decode_arg));
207 decode_arg.serverlist = sl;
208 res.server_list.servers.funcs.decode = decode_serverlist;
209 res.server_list.servers.arg = &decode_arg;
210 status = pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields,
211 &res);
212 if (!status) {
213 grpc_grpclb_destroy_serverlist(sl);
214 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
Craig Tiller4782d922017-11-10 09:53:21 -0800215 return nullptr;
Mark D. Rothd7389b42017-05-17 12:22:17 -0700216 }
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700217 }
Craig Tillereb841e22016-02-11 15:49:16 -0800218 return sl;
219}
220
Craig Tillerbaa14a92017-11-03 09:09:36 -0700221void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist* serverlist) {
Craig Tiller4782d922017-11-10 09:53:21 -0800222 if (serverlist == nullptr) {
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700223 return;
224 }
225 for (size_t i = 0; i < serverlist->num_servers; i++) {
Craig Tillereb841e22016-02-11 15:49:16 -0800226 gpr_free(serverlist->servers[i]);
227 }
228 gpr_free(serverlist->servers);
229 gpr_free(serverlist);
230}
231
Craig Tillerbaa14a92017-11-03 09:09:36 -0700232grpc_grpclb_serverlist* grpc_grpclb_serverlist_copy(
233 const grpc_grpclb_serverlist* sl) {
234 grpc_grpclb_serverlist* copy =
235 (grpc_grpclb_serverlist*)gpr_zalloc(sizeof(grpc_grpclb_serverlist));
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700236 copy->num_servers = sl->num_servers;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700237 copy->servers = (grpc_grpclb_server**)gpr_malloc(sizeof(grpc_grpclb_server*) *
238 sl->num_servers);
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700239 for (size_t i = 0; i < sl->num_servers; i++) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700240 copy->servers[i] =
Craig Tillerbaa14a92017-11-03 09:09:36 -0700241 (grpc_grpclb_server*)gpr_malloc(sizeof(grpc_grpclb_server));
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700242 memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server));
243 }
244 return copy;
245}
246
Craig Tillerbaa14a92017-11-03 09:09:36 -0700247bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist* lhs,
248 const grpc_grpclb_serverlist* rhs) {
Craig Tiller4782d922017-11-10 09:53:21 -0800249 if (lhs == nullptr || rhs == nullptr) {
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700250 return false;
251 }
252 if (lhs->num_servers != rhs->num_servers) {
253 return false;
254 }
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700255 for (size_t i = 0; i < lhs->num_servers; i++) {
256 if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) {
257 return false;
258 }
259 }
260 return true;
261}
262
Craig Tillerbaa14a92017-11-03 09:09:36 -0700263bool grpc_grpclb_server_equals(const grpc_grpclb_server* lhs,
264 const grpc_grpclb_server* rhs) {
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700265 return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0;
266}
267
Craig Tillerbaa14a92017-11-03 09:09:36 -0700268int grpc_grpclb_duration_compare(const grpc_grpclb_duration* lhs,
269 const grpc_grpclb_duration* rhs) {
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700270 GPR_ASSERT(lhs && rhs);
271 if (lhs->has_seconds && rhs->has_seconds) {
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700272 if (lhs->seconds < rhs->seconds) return -1;
273 if (lhs->seconds > rhs->seconds) return 1;
274 } else if (lhs->has_seconds) {
275 return 1;
276 } else if (rhs->has_seconds) {
277 return -1;
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700278 }
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700279
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700280 GPR_ASSERT(lhs->seconds == rhs->seconds);
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700281 if (lhs->has_nanos && rhs->has_nanos) {
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700282 if (lhs->nanos < rhs->nanos) return -1;
283 if (lhs->nanos > rhs->nanos) return 1;
284 } else if (lhs->has_nanos) {
285 return 1;
286 } else if (rhs->has_nanos) {
287 return -1;
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700288 }
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700289
290 return 0;
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700291}
292
Craig Tillerbaa14a92017-11-03 09:09:36 -0700293grpc_millis grpc_grpclb_duration_to_millis(grpc_grpclb_duration* duration_pb) {
Craig Tiller301d4c92017-10-03 09:43:01 -0700294 return (grpc_millis)(
295 (duration_pb->has_seconds ? duration_pb->seconds : 0) * GPR_MS_PER_SEC +
296 (duration_pb->has_nanos ? duration_pb->nanos : 0) / GPR_NS_PER_MS);
Mark D. Roth09e458c2017-05-02 08:13:26 -0700297}
298
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700299void grpc_grpclb_initial_response_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700300 grpc_grpclb_initial_response* response) {
Craig Tillereb841e22016-02-11 15:49:16 -0800301 gpr_free(response);
302}