Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, 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 :
34 : #include <grpc/grpc.h>
35 :
36 : #include <string.h>
37 :
38 : #include "src/core/channel/channel_stack.h"
39 : #include "src/core/support/string.h"
40 : #include "src/core/surface/api_trace.h"
41 : #include "src/core/surface/channel.h"
42 : #include "src/core/surface/call.h"
43 : #include <grpc/support/alloc.h>
44 : #include <grpc/support/log.h>
45 :
46 : typedef struct {
47 : grpc_linked_mdelem status;
48 : grpc_linked_mdelem details;
49 : } call_data;
50 :
51 : typedef struct {
52 : grpc_channel *master;
53 : grpc_status_code error_code;
54 : const char *error_message;
55 : } channel_data;
56 :
57 2 : static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) {
58 2 : call_data *calld = elem->call_data;
59 2 : channel_data *chand = elem->channel_data;
60 : char tmp[GPR_LTOA_MIN_BUFSIZE];
61 2 : gpr_ltoa(chand->error_code, tmp);
62 2 : calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp);
63 2 : calld->details.md =
64 2 : grpc_mdelem_from_strings("grpc-message", chand->error_message);
65 2 : calld->status.prev = calld->details.next = NULL;
66 2 : calld->status.next = &calld->details;
67 2 : calld->details.prev = &calld->status;
68 2 : mdb->list.head = &calld->status;
69 2 : mdb->list.tail = &calld->details;
70 2 : mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
71 2 : }
72 :
73 2 : static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
74 : grpc_call_element *elem,
75 : grpc_transport_stream_op *op) {
76 2 : GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
77 2 : if (op->recv_initial_metadata != NULL) {
78 1 : fill_metadata(elem, op->recv_initial_metadata);
79 1 : } else if (op->recv_trailing_metadata != NULL) {
80 1 : fill_metadata(elem, op->recv_trailing_metadata);
81 : }
82 2 : grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, 0);
83 2 : grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, 0);
84 2 : }
85 :
86 1 : static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
87 1 : channel_data *chand = elem->channel_data;
88 1 : return grpc_channel_get_target(chand->master);
89 : }
90 :
91 1 : static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
92 : grpc_channel_element *elem,
93 : grpc_transport_op *op) {
94 1 : if (op->on_connectivity_state_change) {
95 0 : GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE);
96 0 : *op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
97 0 : op->on_connectivity_state_change->cb(
98 0 : exec_ctx, op->on_connectivity_state_change->cb_arg, 1);
99 : }
100 1 : if (op->on_consumed != NULL) {
101 0 : op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 1);
102 : }
103 1 : }
104 :
105 1 : static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
106 1 : grpc_call_element_args *args) {}
107 :
108 1 : static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
109 1 : grpc_call_element *elem) {}
110 :
111 1 : static void init_channel_elem(grpc_exec_ctx *exec_ctx,
112 : grpc_channel_element *elem,
113 : grpc_channel_element_args *args) {
114 1 : channel_data *chand = elem->channel_data;
115 1 : GPR_ASSERT(args->is_first);
116 1 : GPR_ASSERT(args->is_last);
117 1 : chand->master = args->master;
118 1 : }
119 :
120 1 : static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
121 1 : grpc_channel_element *elem) {}
122 :
123 : static const grpc_channel_filter lame_filter = {
124 : lame_start_transport_stream_op, lame_start_transport_op, sizeof(call_data),
125 : init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
126 : sizeof(channel_data), init_channel_elem, destroy_channel_elem,
127 : lame_get_peer, "lame-client",
128 : };
129 :
130 : #define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
131 :
132 1 : grpc_channel *grpc_lame_client_channel_create(const char *target,
133 : grpc_status_code error_code,
134 : const char *error_message) {
135 : grpc_channel *channel;
136 : grpc_channel_element *elem;
137 : channel_data *chand;
138 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
139 : static const grpc_channel_filter *filters[] = {&lame_filter};
140 1 : channel =
141 : grpc_channel_create_from_filters(&exec_ctx, target, filters, 1, NULL, 1);
142 1 : elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
143 1 : GRPC_API_TRACE(
144 : "grpc_lame_client_channel_create(target=%s, error_code=%d, "
145 : "error_message=%s)",
146 : 3, (target, (int)error_code, error_message));
147 1 : GPR_ASSERT(elem->filter == &lame_filter);
148 1 : chand = (channel_data *)elem->channel_data;
149 1 : chand->error_code = error_code;
150 1 : chand->error_message = error_message;
151 1 : grpc_exec_ctx_finish(&exec_ctx);
152 1 : return channel;
153 : }
|