blob: 8ef6dfc6f40a1efea67ff8b189d9b0e0af544d2b [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 */
26static bool count_serverlist(pb_istream_t *stream, const pb_field_t *field,
27 void **arg) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070028 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 */
Mark D. Rothd7389b42017-05-17 12:22:17 -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 */
47static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
48 void **arg) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070049 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);
Yash Tibrewalca3c1c02017-09-07 22:47:16 -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
62grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070063 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,
74 struct _grpc_lb_v1_Timestamp *timestamp_pb) {
75 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
Mark D. Rothe7751802017-07-27 12:31:45 -070081static bool encode_string(pb_ostream_t *stream, const pb_field_t *field,
82 void *const *arg) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070083 char *str = (char *)*arg;
Mark D. Rothe7751802017-07-27 12:31:45 -070084 if (!pb_encode_tag_for_field(stream, field)) return false;
85 return pb_encode_string(stream, (uint8_t *)str, strlen(str));
86}
87
88static bool encode_drops(pb_ostream_t *stream, const pb_field_t *field,
89 void *const *arg) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070090 grpc_grpclb_dropped_call_counts *drop_entries =
91 (grpc_grpclb_dropped_call_counts *)*arg;
Mark D. Rothe7751802017-07-27 12:31:45 -070092 if (drop_entries == NULL) return true;
93 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
108grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked(
Mark D. Roth09e458c2017-05-02 08:13:26 -0700109 grpc_grpclb_client_stats *client_stats) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700110 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,
126 (grpc_grpclb_dropped_call_counts **)&req->client_stats
127 .calls_finished_with_drop.arg);
Mark D. Roth09e458c2017-05-02 08:13:26 -0700128 return req;
129}
130
Craig Tillerd41a4a72016-10-26 16:16:06 -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
148void grpc_grpclb_request_destroy(grpc_grpclb_request *request) {
Mark D. Rothe7751802017-07-27 12:31:45 -0700149 if (request->has_client_stats) {
150 grpc_grpclb_dropped_call_counts *drop_entries =
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700151 (grpc_grpclb_dropped_call_counts *)
152 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;
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -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));
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700168 return NULL;
169 }
Mark D. Roth09e458c2017-05-02 08:13:26 -0700170
171 if (!res.has_initial_response) return NULL;
172
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700173 grpc_grpclb_initial_response *initial_res =
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700174 (grpc_grpclb_initial_response *)gpr_malloc(
175 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
182grpc_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;
Yash Tibrewalca3c1c02017-09-07 22:47:16 -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));
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700199 return NULL;
200 }
Mark D. Rothd7389b42017-05-17 12:22:17 -0700201 // Second pass: populate servers.
202 if (sl->num_servers > 0) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700203 sl->servers = (grpc_grpclb_server **)gpr_zalloc(
204 sizeof(grpc_grpclb_server *) * 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));
215 return NULL;
216 }
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700217 }
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700218 if (res.server_list.has_expiration_interval) {
219 sl->expiration_interval = res.server_list.expiration_interval;
Craig Tillereb841e22016-02-11 15:49:16 -0800220 }
Craig Tillereb841e22016-02-11 15:49:16 -0800221 return sl;
222}
223
224void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) {
David Garcia Quintasbf2e73d2016-04-04 18:03:47 -0700225 if (serverlist == NULL) {
226 return;
227 }
228 for (size_t i = 0; i < serverlist->num_servers; i++) {
Craig Tillereb841e22016-02-11 15:49:16 -0800229 gpr_free(serverlist->servers[i]);
230 }
231 gpr_free(serverlist->servers);
232 gpr_free(serverlist);
233}
234
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700235grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy(
236 const grpc_grpclb_serverlist *sl) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700237 grpc_grpclb_serverlist *copy =
238 (grpc_grpclb_serverlist *)gpr_zalloc(sizeof(grpc_grpclb_serverlist));
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700239 copy->num_servers = sl->num_servers;
240 memcpy(&copy->expiration_interval, &sl->expiration_interval,
241 sizeof(grpc_grpclb_duration));
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700242 copy->servers = (grpc_grpclb_server **)gpr_malloc(
243 sizeof(grpc_grpclb_server *) * sl->num_servers);
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700244 for (size_t i = 0; i < sl->num_servers; i++) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700245 copy->servers[i] =
246 (grpc_grpclb_server *)gpr_malloc(sizeof(grpc_grpclb_server));
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700247 memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server));
248 }
249 return copy;
250}
251
252bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs,
253 const grpc_grpclb_serverlist *rhs) {
Mark D. Rothd7389b42017-05-17 12:22:17 -0700254 if (lhs == NULL || rhs == NULL) {
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700255 return false;
256 }
257 if (lhs->num_servers != rhs->num_servers) {
258 return false;
259 }
260 if (grpc_grpclb_duration_compare(&lhs->expiration_interval,
261 &rhs->expiration_interval) != 0) {
262 return false;
263 }
264 for (size_t i = 0; i < lhs->num_servers; i++) {
265 if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) {
266 return false;
267 }
268 }
269 return true;
270}
271
272bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs,
273 const grpc_grpclb_server *rhs) {
274 return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0;
275}
276
277int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs,
278 const grpc_grpclb_duration *rhs) {
279 GPR_ASSERT(lhs && rhs);
280 if (lhs->has_seconds && rhs->has_seconds) {
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700281 if (lhs->seconds < rhs->seconds) return -1;
282 if (lhs->seconds > rhs->seconds) return 1;
283 } else if (lhs->has_seconds) {
284 return 1;
285 } else if (rhs->has_seconds) {
286 return -1;
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700287 }
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700288
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700289 GPR_ASSERT(lhs->seconds == rhs->seconds);
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700290 if (lhs->has_nanos && rhs->has_nanos) {
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700291 if (lhs->nanos < rhs->nanos) return -1;
292 if (lhs->nanos > rhs->nanos) return 1;
293 } else if (lhs->has_nanos) {
294 return 1;
295 } else if (rhs->has_nanos) {
296 return -1;
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700297 }
David Garcia Quintas4166cb02016-07-29 14:33:15 -0700298
299 return 0;
David Garcia Quintas3fb8f732016-06-15 22:53:08 -0700300}
301
Mark D. Roth09e458c2017-05-02 08:13:26 -0700302gpr_timespec grpc_grpclb_duration_to_timespec(
303 grpc_grpclb_duration *duration_pb) {
304 gpr_timespec duration;
305 duration.tv_sec = duration_pb->has_seconds ? duration_pb->seconds : 0;
306 duration.tv_nsec = duration_pb->has_nanos ? duration_pb->nanos : 0;
307 duration.clock_type = GPR_TIMESPAN;
308 return duration;
309}
310
David Garcia Quintas1d5cb2a2016-07-18 12:56:53 -0700311void grpc_grpclb_initial_response_destroy(
312 grpc_grpclb_initial_response *response) {
Craig Tillereb841e22016-02-11 15:49:16 -0800313 gpr_free(response);
314}