blob: 99b560ae27fc74410296f7847cbac1e38bfd8af5 [file] [log] [blame]
David Garcia Quintas862c8e92016-04-06 16:30:51 -07001/*
2 *
3 * Copyright 2016, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070034#include <grpc/support/alloc.h>
David Garcia Quintas862c8e92016-04-06 16:30:51 -070035#include <grpc/support/log.h>
David Garcia Quintas1621c4d2016-05-04 19:44:37 -070036#include <grpc/support/string_util.h>
David Garcia Quintas0d83db52016-05-04 00:14:14 -070037#include <grpc/support/sync.h>
David Garcia Quintas4bb11ac2016-05-02 09:20:21 -070038#include <string.h>
David Garcia Quintas862c8e92016-04-06 16:30:51 -070039
David Garcia Quintasb41363e2016-04-29 00:41:21 -070040#include "src/core/ext/load_reporting/load_reporting.h"
David Garcia Quintas862c8e92016-04-06 16:30:51 -070041#include "src/core/ext/load_reporting/load_reporting_filter.h"
42#include "src/core/lib/channel/channel_args.h"
David Garcia Quintas862c8e92016-04-06 16:30:51 -070043#include "src/core/lib/profiling/timers.h"
David Garcia Quintas1621c4d2016-05-04 19:44:37 -070044#include "src/core/lib/transport/static_metadata.h"
David Garcia Quintas862c8e92016-04-06 16:30:51 -070045
David Garcia Quintas01c4d992016-07-07 20:11:27 -070046typedef struct call_data {
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070047 intptr_t id; /**< an id unique to the call */
48 char *trailing_md_string;
49 char *initial_md_string;
David Garcia Quintas01c4d992016-07-07 20:11:27 -070050 const char *service_method;
51
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070052 /* stores the recv_initial_metadata op's ready closure, which we wrap with our
53 * own (on_initial_md_ready) in order to capture the incoming initial metadata
54 * */
David Garcia Quintas01c4d992016-07-07 20:11:27 -070055 grpc_closure *ops_recv_initial_metadata_ready;
56
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070057 /* to get notified of the availability of the incoming initial metadata. */
David Garcia Quintas01c4d992016-07-07 20:11:27 -070058 grpc_closure on_initial_md_ready;
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070059 grpc_metadata_batch *recv_initial_metadata;
David Garcia Quintas01c4d992016-07-07 20:11:27 -070060} call_data;
61
David Garcia Quintas0d83db52016-05-04 00:14:14 -070062typedef struct channel_data {
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070063 intptr_t id; /**< an id unique to the channel */
David Garcia Quintas0d83db52016-05-04 00:14:14 -070064} channel_data;
David Garcia Quintas862c8e92016-04-06 16:30:51 -070065
David Garcia Quintas01c4d992016-07-07 20:11:27 -070066typedef struct {
67 grpc_call_element *elem;
68 grpc_exec_ctx *exec_ctx;
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070069} recv_md_filter_args;
David Garcia Quintas01c4d992016-07-07 20:11:27 -070070
71static grpc_mdelem *recv_md_filter(void *user_data, grpc_mdelem *md) {
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070072 recv_md_filter_args *a = user_data;
David Garcia Quintas01c4d992016-07-07 20:11:27 -070073 grpc_call_element *elem = a->elem;
74 call_data *calld = elem->call_data;
75
76 if (md->key == GRPC_MDSTR_PATH) {
77 calld->service_method = grpc_mdstr_as_c_string(md->value);
78 } else if (md->key == GRPC_MDSTR_LOAD_REPORTING_INITIAL) {
79 calld->initial_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
David Garcia Quintasfa30de92016-07-26 19:52:13 -070080 return NULL;
David Garcia Quintas01c4d992016-07-07 20:11:27 -070081 }
82
83 return md;
84}
85
86static void on_initial_md_ready(grpc_exec_ctx *exec_ctx, void *user_data,
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070087 grpc_error *err) {
David Garcia Quintas01c4d992016-07-07 20:11:27 -070088 grpc_call_element *elem = user_data;
89 call_data *calld = elem->call_data;
90
91 if (err == GRPC_ERROR_NONE) {
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070092 recv_md_filter_args a;
David Garcia Quintas01c4d992016-07-07 20:11:27 -070093 a.elem = elem;
94 a.exec_ctx = exec_ctx;
David Garcia Quintas6eee24c2016-07-11 22:56:50 -070095 grpc_metadata_batch_filter(calld->recv_initial_metadata, recv_md_filter,
96 &a);
David Garcia Quintas01c4d992016-07-07 20:11:27 -070097 if (calld->service_method == NULL) {
98 err =
99 grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header"));
100 }
101 } else {
102 GRPC_ERROR_REF(err);
103 }
104 calld->ops_recv_initial_metadata_ready->cb(
105 exec_ctx, calld->ops_recv_initial_metadata_ready->cb_arg, err);
106 GRPC_ERROR_UNREF(err);
107}
108
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700109/* Constructor for call_data */
110static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700111 grpc_call_element_args *args) {
112 call_data *calld = elem->call_data;
113 memset(calld, 0, sizeof(call_data));
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700114
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700115 calld->id = (intptr_t)args->call_stack;
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700116 grpc_closure_init(&calld->on_initial_md_ready, on_initial_md_ready, elem);
117
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700118 /* TODO(dgq): do something with the data
119 channel_data *chand = elem->channel_data;
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700120 grpc_load_reporting_call_data lr_call_data = {GRPC_LR_POINT_CALL_CREATION,
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700121 (intptr_t)chand->id,
122 (intptr_t)calld->id,
123 NULL,
124 NULL,
125 NULL,
126 NULL};
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700127 */
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700128}
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700129
130/* Destructor for call_data */
David Garcia Quintasa5234862016-04-14 15:08:43 -0700131static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700132 const grpc_call_final_info *final_info,
133 void *ignored) {
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700134 call_data *calld = elem->call_data;
135
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700136 /* TODO(dgq): do something with the data
137 channel_data *chand = elem->channel_data;
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700138 grpc_load_reporting_call_data lr_call_data = {GRPC_LR_POINT_CALL_DESTRUCTION,
139 (intptr_t)chand->id,
140 (intptr_t)calld->id,
141 final_info,
142 calld->initial_md_string,
143 calld->trailing_md_string,
144 calld->service_method};
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700145 */
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700146
147 gpr_free(calld->initial_md_string);
148 gpr_free(calld->trailing_md_string);
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700149}
150
151/* Constructor for channel_data */
152static void init_channel_elem(grpc_exec_ctx *exec_ctx,
153 grpc_channel_element *elem,
154 grpc_channel_element_args *args) {
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700155 GPR_ASSERT(!args->is_last);
David Garcia Quintasb41363e2016-04-29 00:41:21 -0700156
157 channel_data *chand = elem->channel_data;
158 memset(chand, 0, sizeof(channel_data));
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700159
160 chand->id = (intptr_t)args->channel_stack;
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700161
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700162 /* TODO(dgq): do something with the data
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700163 grpc_load_reporting_call_data lr_call_data = {GRPC_LR_POINT_CHANNEL_CREATION,
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700164 (intptr_t)chand,
165 0,
166 NULL,
167 NULL,
168 NULL,
169 NULL};
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700170 */
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700171}
172
173/* Destructor for channel data */
174static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
David Garcia Quintasb41363e2016-04-29 00:41:21 -0700175 grpc_channel_element *elem) {
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700176 /* TODO(dgq): do something with the data
David Garcia Quintasb41363e2016-04-29 00:41:21 -0700177 channel_data *chand = elem->channel_data;
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700178 grpc_load_reporting_call_data lr_call_data = {
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700179 GRPC_LR_POINT_CHANNEL_DESTRUCTION,
180 (intptr_t)chand->id,
181 0,
182 NULL,
183 NULL,
184 NULL,
185 NULL};
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700186 */
David Garcia Quintasb41363e2016-04-29 00:41:21 -0700187}
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700188
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700189static grpc_mdelem *lr_trailing_md_filter(void *user_data, grpc_mdelem *md) {
190 grpc_call_element *elem = user_data;
191 call_data *calld = elem->call_data;
192
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700193 if (md->key == GRPC_MDSTR_LOAD_REPORTING_TRAILING) {
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700194 calld->trailing_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
David Garcia Quintasfa30de92016-07-26 19:52:13 -0700195 return NULL;
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700196 }
197
198 return md;
199}
200
201static void lr_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
202 grpc_call_element *elem,
203 grpc_transport_stream_op *op) {
204 GPR_TIMER_BEGIN("lr_start_transport_stream_op", 0);
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700205 call_data *calld = elem->call_data;
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700206
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700207 if (op->recv_initial_metadata) {
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700208 calld->recv_initial_metadata = op->recv_initial_metadata;
David Garcia Quintas6eee24c2016-07-11 22:56:50 -0700209 /* substitute our callback for the higher callback */
210 calld->ops_recv_initial_metadata_ready = op->recv_initial_metadata_ready;
David Garcia Quintas01c4d992016-07-07 20:11:27 -0700211 op->recv_initial_metadata_ready = &calld->on_initial_md_ready;
212 } else if (op->send_trailing_metadata) {
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700213 grpc_metadata_batch_filter(op->send_trailing_metadata,
214 lr_trailing_md_filter, elem);
215 }
216 grpc_call_next_op(exec_ctx, elem, op);
217
218 GPR_TIMER_END("lr_start_transport_stream_op", 0);
219}
220
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700221const grpc_channel_filter grpc_load_reporting_filter = {
David Garcia Quintas1621c4d2016-05-04 19:44:37 -0700222 lr_start_transport_stream_op,
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700223 grpc_channel_next_op,
224 sizeof(call_data),
225 init_call_elem,
David Garcia Quintas1cf4ec72016-06-06 16:33:14 -0700226 grpc_call_stack_ignore_set_pollset_or_pollset_set,
David Garcia Quintas862c8e92016-04-06 16:30:51 -0700227 destroy_call_elem,
228 sizeof(channel_data),
229 init_channel_elem,
230 destroy_channel_elem,
231 grpc_call_next_get_peer,
232 "load_reporting"};