1*cc02d7e2SAndroid Build Coastguard Worker //
2*cc02d7e2SAndroid Build Coastguard Worker //
3*cc02d7e2SAndroid Build Coastguard Worker // Copyright 2016 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker //
5*cc02d7e2SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker // You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker //
9*cc02d7e2SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker //
11*cc02d7e2SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker // limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker //
17*cc02d7e2SAndroid Build Coastguard Worker //
18*cc02d7e2SAndroid Build Coastguard Worker
19*cc02d7e2SAndroid Build Coastguard Worker #include "test/cpp/util/grpc_tool.h"
20*cc02d7e2SAndroid Build Coastguard Worker
21*cc02d7e2SAndroid Build Coastguard Worker #include <cstdio>
22*cc02d7e2SAndroid Build Coastguard Worker #include <fstream>
23*cc02d7e2SAndroid Build Coastguard Worker #include <iostream>
24*cc02d7e2SAndroid Build Coastguard Worker #include <memory>
25*cc02d7e2SAndroid Build Coastguard Worker #include <sstream>
26*cc02d7e2SAndroid Build Coastguard Worker #include <string>
27*cc02d7e2SAndroid Build Coastguard Worker #include <thread>
28*cc02d7e2SAndroid Build Coastguard Worker
29*cc02d7e2SAndroid Build Coastguard Worker #include "absl/flags/flag.h"
30*cc02d7e2SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
31*cc02d7e2SAndroid Build Coastguard Worker
32*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/grpc.h>
33*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/support/port_platform.h>
34*cc02d7e2SAndroid Build Coastguard Worker #include <grpcpp/channel.h>
35*cc02d7e2SAndroid Build Coastguard Worker #include <grpcpp/create_channel.h>
36*cc02d7e2SAndroid Build Coastguard Worker #include <grpcpp/grpcpp.h>
37*cc02d7e2SAndroid Build Coastguard Worker #include <grpcpp/security/credentials.h>
38*cc02d7e2SAndroid Build Coastguard Worker #include <grpcpp/support/string_ref.h>
39*cc02d7e2SAndroid Build Coastguard Worker
40*cc02d7e2SAndroid Build Coastguard Worker #include "test/cpp/util/cli_call.h"
41*cc02d7e2SAndroid Build Coastguard Worker #include "test/cpp/util/proto_file_parser.h"
42*cc02d7e2SAndroid Build Coastguard Worker #include "test/cpp/util/proto_reflection_descriptor_database.h"
43*cc02d7e2SAndroid Build Coastguard Worker #include "test/cpp/util/service_describer.h"
44*cc02d7e2SAndroid Build Coastguard Worker
45*cc02d7e2SAndroid Build Coastguard Worker #if GPR_WINDOWS
46*cc02d7e2SAndroid Build Coastguard Worker #include <io.h>
47*cc02d7e2SAndroid Build Coastguard Worker #else
48*cc02d7e2SAndroid Build Coastguard Worker #include <unistd.h>
49*cc02d7e2SAndroid Build Coastguard Worker #endif
50*cc02d7e2SAndroid Build Coastguard Worker
51*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, l, false, "Use a long listing format");
52*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, remotedb, true,
53*cc02d7e2SAndroid Build Coastguard Worker "Use server types to parse and format messages");
54*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(std::string, metadata, "",
55*cc02d7e2SAndroid Build Coastguard Worker "Metadata to send to server, in the form of key1:val1:key2:val2");
56*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(std::string, proto_path, ".",
57*cc02d7e2SAndroid Build Coastguard Worker "Path to look for the proto file. "
58*cc02d7e2SAndroid Build Coastguard Worker "Multiple paths can be separated by " GRPC_CLI_PATH_SEPARATOR);
59*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(std::string, protofiles, "", "Name of the proto file.");
60*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, binary_input, false, "Input in binary format");
61*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, binary_output, false, "Output in binary format");
62*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(std::string, default_service_config, "",
63*cc02d7e2SAndroid Build Coastguard Worker "Default service config to use on the channel, if non-empty. Note "
64*cc02d7e2SAndroid Build Coastguard Worker "that this will be ignored if the name resolver returns a service "
65*cc02d7e2SAndroid Build Coastguard Worker "config.");
66*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, display_peer_address, false,
67*cc02d7e2SAndroid Build Coastguard Worker "Log the peer socket address of the connection that each RPC is made "
68*cc02d7e2SAndroid Build Coastguard Worker "on to stderr.");
69*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, json_input, false, "Input in json format");
70*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, json_output, false, "Output in json format");
71*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(std::string, infile, "", "Input file (default is stdin)");
72*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(bool, batch, false,
73*cc02d7e2SAndroid Build Coastguard Worker "Input contains multiple requests. Please do not use this to send "
74*cc02d7e2SAndroid Build Coastguard Worker "more than a few RPCs. gRPC CLI has very different performance "
75*cc02d7e2SAndroid Build Coastguard Worker "characteristics compared with normal RPC calls which make it "
76*cc02d7e2SAndroid Build Coastguard Worker "unsuitable for loadtesting or significant production traffic.");
77*cc02d7e2SAndroid Build Coastguard Worker // TODO(Capstan): Consider using absl::Duration
78*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(double, timeout, -1,
79*cc02d7e2SAndroid Build Coastguard Worker "Specify timeout in seconds, used to set the deadline for all "
80*cc02d7e2SAndroid Build Coastguard Worker "RPCs. The default value of -1 means no deadline has been set.");
81*cc02d7e2SAndroid Build Coastguard Worker ABSL_FLAG(
82*cc02d7e2SAndroid Build Coastguard Worker int, max_recv_msg_size, 0,
83*cc02d7e2SAndroid Build Coastguard Worker "Specify the max receive message size in bytes for all RPCs. -1 indicates "
84*cc02d7e2SAndroid Build Coastguard Worker "unlimited. The default value of 0 means to use the gRPC default.");
85*cc02d7e2SAndroid Build Coastguard Worker
86*cc02d7e2SAndroid Build Coastguard Worker namespace grpc {
87*cc02d7e2SAndroid Build Coastguard Worker namespace testing {
88*cc02d7e2SAndroid Build Coastguard Worker namespace {
89*cc02d7e2SAndroid Build Coastguard Worker
90*cc02d7e2SAndroid Build Coastguard Worker class GrpcTool {
91*cc02d7e2SAndroid Build Coastguard Worker public:
92*cc02d7e2SAndroid Build Coastguard Worker explicit GrpcTool();
~GrpcTool()93*cc02d7e2SAndroid Build Coastguard Worker virtual ~GrpcTool() {}
94*cc02d7e2SAndroid Build Coastguard Worker
95*cc02d7e2SAndroid Build Coastguard Worker bool Help(int argc, const char** argv, const CliCredentials& cred,
96*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
97*cc02d7e2SAndroid Build Coastguard Worker bool CallMethod(int argc, const char** argv, const CliCredentials& cred,
98*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
99*cc02d7e2SAndroid Build Coastguard Worker bool ListServices(int argc, const char** argv, const CliCredentials& cred,
100*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
101*cc02d7e2SAndroid Build Coastguard Worker bool PrintType(int argc, const char** argv, const CliCredentials& cred,
102*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
103*cc02d7e2SAndroid Build Coastguard Worker // TODO(zyc): implement the following methods
104*cc02d7e2SAndroid Build Coastguard Worker // bool ListServices(int argc, const char** argv, GrpcToolOutputCallback
105*cc02d7e2SAndroid Build Coastguard Worker // callback);
106*cc02d7e2SAndroid Build Coastguard Worker // bool PrintTypeId(int argc, const char** argv, GrpcToolOutputCallback
107*cc02d7e2SAndroid Build Coastguard Worker // callback);
108*cc02d7e2SAndroid Build Coastguard Worker bool ParseMessage(int argc, const char** argv, const CliCredentials& cred,
109*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
110*cc02d7e2SAndroid Build Coastguard Worker bool ToText(int argc, const char** argv, const CliCredentials& cred,
111*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
112*cc02d7e2SAndroid Build Coastguard Worker bool ToJson(int argc, const char** argv, const CliCredentials& cred,
113*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
114*cc02d7e2SAndroid Build Coastguard Worker bool ToBinary(int argc, const char** argv, const CliCredentials& cred,
115*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback);
116*cc02d7e2SAndroid Build Coastguard Worker
SetPrintCommandMode(int exit_status)117*cc02d7e2SAndroid Build Coastguard Worker void SetPrintCommandMode(int exit_status) {
118*cc02d7e2SAndroid Build Coastguard Worker print_command_usage_ = true;
119*cc02d7e2SAndroid Build Coastguard Worker usage_exit_status_ = exit_status;
120*cc02d7e2SAndroid Build Coastguard Worker }
121*cc02d7e2SAndroid Build Coastguard Worker
122*cc02d7e2SAndroid Build Coastguard Worker private:
123*cc02d7e2SAndroid Build Coastguard Worker void CommandUsage(const std::string& usage) const;
124*cc02d7e2SAndroid Build Coastguard Worker bool print_command_usage_;
125*cc02d7e2SAndroid Build Coastguard Worker int usage_exit_status_;
126*cc02d7e2SAndroid Build Coastguard Worker const std::string cred_usage_;
127*cc02d7e2SAndroid Build Coastguard Worker };
128*cc02d7e2SAndroid Build Coastguard Worker
129*cc02d7e2SAndroid Build Coastguard Worker template <typename T>
130*cc02d7e2SAndroid Build Coastguard Worker std::function<bool(GrpcTool*, int, const char**, const CliCredentials&,
131*cc02d7e2SAndroid Build Coastguard Worker GrpcToolOutputCallback)>
BindWith5Args(T && func)132*cc02d7e2SAndroid Build Coastguard Worker BindWith5Args(T&& func) {
133*cc02d7e2SAndroid Build Coastguard Worker return std::bind(std::forward<T>(func), std::placeholders::_1,
134*cc02d7e2SAndroid Build Coastguard Worker std::placeholders::_2, std::placeholders::_3,
135*cc02d7e2SAndroid Build Coastguard Worker std::placeholders::_4, std::placeholders::_5);
136*cc02d7e2SAndroid Build Coastguard Worker }
137*cc02d7e2SAndroid Build Coastguard Worker
138*cc02d7e2SAndroid Build Coastguard Worker template <typename T>
ArraySize(T & a)139*cc02d7e2SAndroid Build Coastguard Worker size_t ArraySize(T& a) {
140*cc02d7e2SAndroid Build Coastguard Worker return ((sizeof(a) / sizeof(*(a))) /
141*cc02d7e2SAndroid Build Coastguard Worker static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
142*cc02d7e2SAndroid Build Coastguard Worker }
143*cc02d7e2SAndroid Build Coastguard Worker
ParseMetadataFlag(std::multimap<std::string,std::string> * client_metadata)144*cc02d7e2SAndroid Build Coastguard Worker void ParseMetadataFlag(
145*cc02d7e2SAndroid Build Coastguard Worker std::multimap<std::string, std::string>* client_metadata) {
146*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_metadata).empty()) {
147*cc02d7e2SAndroid Build Coastguard Worker return;
148*cc02d7e2SAndroid Build Coastguard Worker }
149*cc02d7e2SAndroid Build Coastguard Worker std::vector<std::string> fields;
150*cc02d7e2SAndroid Build Coastguard Worker const char delim = ':';
151*cc02d7e2SAndroid Build Coastguard Worker const char escape = '\\';
152*cc02d7e2SAndroid Build Coastguard Worker size_t cur = -1;
153*cc02d7e2SAndroid Build Coastguard Worker std::stringstream ss;
154*cc02d7e2SAndroid Build Coastguard Worker while (++cur < absl::GetFlag(FLAGS_metadata).length()) {
155*cc02d7e2SAndroid Build Coastguard Worker switch (absl::GetFlag(FLAGS_metadata).at(cur)) {
156*cc02d7e2SAndroid Build Coastguard Worker case escape:
157*cc02d7e2SAndroid Build Coastguard Worker if (cur < absl::GetFlag(FLAGS_metadata).length() - 1) {
158*cc02d7e2SAndroid Build Coastguard Worker char c = absl::GetFlag(FLAGS_metadata).at(++cur);
159*cc02d7e2SAndroid Build Coastguard Worker if (c == delim || c == escape) {
160*cc02d7e2SAndroid Build Coastguard Worker ss << c;
161*cc02d7e2SAndroid Build Coastguard Worker continue;
162*cc02d7e2SAndroid Build Coastguard Worker }
163*cc02d7e2SAndroid Build Coastguard Worker }
164*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse metadata flag.\n");
165*cc02d7e2SAndroid Build Coastguard Worker exit(1);
166*cc02d7e2SAndroid Build Coastguard Worker case delim:
167*cc02d7e2SAndroid Build Coastguard Worker fields.push_back(ss.str());
168*cc02d7e2SAndroid Build Coastguard Worker ss.str("");
169*cc02d7e2SAndroid Build Coastguard Worker ss.clear();
170*cc02d7e2SAndroid Build Coastguard Worker break;
171*cc02d7e2SAndroid Build Coastguard Worker default:
172*cc02d7e2SAndroid Build Coastguard Worker ss << absl::GetFlag(FLAGS_metadata).at(cur);
173*cc02d7e2SAndroid Build Coastguard Worker }
174*cc02d7e2SAndroid Build Coastguard Worker }
175*cc02d7e2SAndroid Build Coastguard Worker fields.push_back(ss.str());
176*cc02d7e2SAndroid Build Coastguard Worker if (fields.size() % 2) {
177*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse metadata flag.\n");
178*cc02d7e2SAndroid Build Coastguard Worker exit(1);
179*cc02d7e2SAndroid Build Coastguard Worker }
180*cc02d7e2SAndroid Build Coastguard Worker for (size_t i = 0; i < fields.size(); i += 2) {
181*cc02d7e2SAndroid Build Coastguard Worker client_metadata->insert(
182*cc02d7e2SAndroid Build Coastguard Worker std::pair<std::string, std::string>(fields[i], fields[i + 1]));
183*cc02d7e2SAndroid Build Coastguard Worker }
184*cc02d7e2SAndroid Build Coastguard Worker }
185*cc02d7e2SAndroid Build Coastguard Worker
186*cc02d7e2SAndroid Build Coastguard Worker template <typename T>
PrintMetadata(const T & m,const std::string & message)187*cc02d7e2SAndroid Build Coastguard Worker void PrintMetadata(const T& m, const std::string& message) {
188*cc02d7e2SAndroid Build Coastguard Worker if (m.empty()) {
189*cc02d7e2SAndroid Build Coastguard Worker return;
190*cc02d7e2SAndroid Build Coastguard Worker }
191*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "%s\n", message.c_str());
192*cc02d7e2SAndroid Build Coastguard Worker std::string pair;
193*cc02d7e2SAndroid Build Coastguard Worker for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
194*cc02d7e2SAndroid Build Coastguard Worker pair.clear();
195*cc02d7e2SAndroid Build Coastguard Worker pair.append(iter->first.data(), iter->first.size());
196*cc02d7e2SAndroid Build Coastguard Worker pair.append(" : ");
197*cc02d7e2SAndroid Build Coastguard Worker pair.append(iter->second.data(), iter->second.size());
198*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "%s\n", pair.c_str());
199*cc02d7e2SAndroid Build Coastguard Worker }
200*cc02d7e2SAndroid Build Coastguard Worker }
201*cc02d7e2SAndroid Build Coastguard Worker
ReadResponse(CliCall * call,const std::string & method_name,const GrpcToolOutputCallback & callback,ProtoFileParser * parser,gpr_mu * parser_mu,bool print_mode)202*cc02d7e2SAndroid Build Coastguard Worker void ReadResponse(CliCall* call, const std::string& method_name,
203*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback,
204*cc02d7e2SAndroid Build Coastguard Worker ProtoFileParser* parser, gpr_mu* parser_mu, bool print_mode) {
205*cc02d7e2SAndroid Build Coastguard Worker std::string serialized_response_proto;
206*cc02d7e2SAndroid Build Coastguard Worker std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata;
207*cc02d7e2SAndroid Build Coastguard Worker
208*cc02d7e2SAndroid Build Coastguard Worker for (bool receive_initial_metadata = true; call->ReadAndMaybeNotifyWrite(
209*cc02d7e2SAndroid Build Coastguard Worker &serialized_response_proto,
210*cc02d7e2SAndroid Build Coastguard Worker receive_initial_metadata ? &server_initial_metadata : nullptr);
211*cc02d7e2SAndroid Build Coastguard Worker receive_initial_metadata = false) {
212*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "got response.\n");
213*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_binary_output)) {
214*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_lock(parser_mu);
215*cc02d7e2SAndroid Build Coastguard Worker serialized_response_proto = parser->GetFormattedStringFromMethod(
216*cc02d7e2SAndroid Build Coastguard Worker method_name, serialized_response_proto, false /* is_request */,
217*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_json_output));
218*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError() && print_mode) {
219*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse response.\n");
220*cc02d7e2SAndroid Build Coastguard Worker }
221*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_unlock(parser_mu);
222*cc02d7e2SAndroid Build Coastguard Worker }
223*cc02d7e2SAndroid Build Coastguard Worker if (receive_initial_metadata) {
224*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(server_initial_metadata,
225*cc02d7e2SAndroid Build Coastguard Worker "Received initial metadata from server:");
226*cc02d7e2SAndroid Build Coastguard Worker }
227*cc02d7e2SAndroid Build Coastguard Worker if (!callback(serialized_response_proto) && print_mode) {
228*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to output response.\n");
229*cc02d7e2SAndroid Build Coastguard Worker }
230*cc02d7e2SAndroid Build Coastguard Worker }
231*cc02d7e2SAndroid Build Coastguard Worker }
232*cc02d7e2SAndroid Build Coastguard Worker
CreateCliChannel(const std::string & server_address,const CliCredentials & cred,const grpc::ChannelArguments & extra_args)233*cc02d7e2SAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> CreateCliChannel(
234*cc02d7e2SAndroid Build Coastguard Worker const std::string& server_address, const CliCredentials& cred,
235*cc02d7e2SAndroid Build Coastguard Worker const grpc::ChannelArguments& extra_args) {
236*cc02d7e2SAndroid Build Coastguard Worker grpc::ChannelArguments args(extra_args);
237*cc02d7e2SAndroid Build Coastguard Worker if (!cred.GetSslTargetNameOverride().empty()) {
238*cc02d7e2SAndroid Build Coastguard Worker args.SetSslTargetNameOverride(cred.GetSslTargetNameOverride());
239*cc02d7e2SAndroid Build Coastguard Worker }
240*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_default_service_config).empty()) {
241*cc02d7e2SAndroid Build Coastguard Worker args.SetString(GRPC_ARG_SERVICE_CONFIG,
242*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_default_service_config));
243*cc02d7e2SAndroid Build Coastguard Worker }
244*cc02d7e2SAndroid Build Coastguard Worker // See |GRPC_ARG_MAX_METADATA_SIZE| in |grpc_types.h|.
245*cc02d7e2SAndroid Build Coastguard Worker // Set to large enough size (10M) that should work for most use cases.
246*cc02d7e2SAndroid Build Coastguard Worker args.SetInt(GRPC_ARG_MAX_METADATA_SIZE, 10 * 1024 * 1024);
247*cc02d7e2SAndroid Build Coastguard Worker return grpc::CreateCustomChannel(server_address, cred.GetCredentials(), args);
248*cc02d7e2SAndroid Build Coastguard Worker }
249*cc02d7e2SAndroid Build Coastguard Worker
250*cc02d7e2SAndroid Build Coastguard Worker struct Command {
251*cc02d7e2SAndroid Build Coastguard Worker const char* command;
252*cc02d7e2SAndroid Build Coastguard Worker std::function<bool(GrpcTool*, int, const char**, const CliCredentials&,
253*cc02d7e2SAndroid Build Coastguard Worker GrpcToolOutputCallback)>
254*cc02d7e2SAndroid Build Coastguard Worker function;
255*cc02d7e2SAndroid Build Coastguard Worker int min_args;
256*cc02d7e2SAndroid Build Coastguard Worker int max_args;
257*cc02d7e2SAndroid Build Coastguard Worker };
258*cc02d7e2SAndroid Build Coastguard Worker
259*cc02d7e2SAndroid Build Coastguard Worker const Command ops[] = {
260*cc02d7e2SAndroid Build Coastguard Worker {"help", BindWith5Args(&GrpcTool::Help), 0, INT_MAX},
261*cc02d7e2SAndroid Build Coastguard Worker {"ls", BindWith5Args(&GrpcTool::ListServices), 1, 3},
262*cc02d7e2SAndroid Build Coastguard Worker {"list", BindWith5Args(&GrpcTool::ListServices), 1, 3},
263*cc02d7e2SAndroid Build Coastguard Worker {"call", BindWith5Args(&GrpcTool::CallMethod), 2, 3},
264*cc02d7e2SAndroid Build Coastguard Worker {"type", BindWith5Args(&GrpcTool::PrintType), 2, 2},
265*cc02d7e2SAndroid Build Coastguard Worker {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
266*cc02d7e2SAndroid Build Coastguard Worker {"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
267*cc02d7e2SAndroid Build Coastguard Worker {"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
268*cc02d7e2SAndroid Build Coastguard Worker {"tojson", BindWith5Args(&GrpcTool::ToJson), 2, 3},
269*cc02d7e2SAndroid Build Coastguard Worker };
270*cc02d7e2SAndroid Build Coastguard Worker
Usage(const std::string & msg)271*cc02d7e2SAndroid Build Coastguard Worker void Usage(const std::string& msg) {
272*cc02d7e2SAndroid Build Coastguard Worker fprintf(
273*cc02d7e2SAndroid Build Coastguard Worker stderr,
274*cc02d7e2SAndroid Build Coastguard Worker "%s\n"
275*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli ls ... ; List services\n"
276*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli call ... ; Call method\n"
277*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli type ... ; Print type\n"
278*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli parse ... ; Parse message\n"
279*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli totext ... ; Convert binary message to text\n"
280*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli tojson ... ; Convert binary message to json\n"
281*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli tobinary ... ; Convert text message to binary\n"
282*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli help ... ; Print this message, or per-command usage\n"
283*cc02d7e2SAndroid Build Coastguard Worker "\n",
284*cc02d7e2SAndroid Build Coastguard Worker msg.c_str());
285*cc02d7e2SAndroid Build Coastguard Worker
286*cc02d7e2SAndroid Build Coastguard Worker exit(1);
287*cc02d7e2SAndroid Build Coastguard Worker }
288*cc02d7e2SAndroid Build Coastguard Worker
FindCommand(const std::string & name)289*cc02d7e2SAndroid Build Coastguard Worker const Command* FindCommand(const std::string& name) {
290*cc02d7e2SAndroid Build Coastguard Worker for (int i = 0; i < static_cast<int>(ArraySize(ops)); i++) {
291*cc02d7e2SAndroid Build Coastguard Worker if (name == ops[i].command) {
292*cc02d7e2SAndroid Build Coastguard Worker return &ops[i];
293*cc02d7e2SAndroid Build Coastguard Worker }
294*cc02d7e2SAndroid Build Coastguard Worker }
295*cc02d7e2SAndroid Build Coastguard Worker return nullptr;
296*cc02d7e2SAndroid Build Coastguard Worker }
297*cc02d7e2SAndroid Build Coastguard Worker } // namespace
298*cc02d7e2SAndroid Build Coastguard Worker
GrpcToolMainLib(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)299*cc02d7e2SAndroid Build Coastguard Worker int GrpcToolMainLib(int argc, const char** argv, const CliCredentials& cred,
300*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
301*cc02d7e2SAndroid Build Coastguard Worker if (argc < 2) {
302*cc02d7e2SAndroid Build Coastguard Worker Usage("No command specified");
303*cc02d7e2SAndroid Build Coastguard Worker }
304*cc02d7e2SAndroid Build Coastguard Worker
305*cc02d7e2SAndroid Build Coastguard Worker std::string command = argv[1];
306*cc02d7e2SAndroid Build Coastguard Worker argc -= 2;
307*cc02d7e2SAndroid Build Coastguard Worker argv += 2;
308*cc02d7e2SAndroid Build Coastguard Worker
309*cc02d7e2SAndroid Build Coastguard Worker const Command* cmd = FindCommand(command);
310*cc02d7e2SAndroid Build Coastguard Worker if (cmd != nullptr) {
311*cc02d7e2SAndroid Build Coastguard Worker GrpcTool grpc_tool;
312*cc02d7e2SAndroid Build Coastguard Worker if (argc < cmd->min_args || argc > cmd->max_args) {
313*cc02d7e2SAndroid Build Coastguard Worker // Force the command to print its usage message
314*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "\nWrong number of arguments for %s\n", command.c_str());
315*cc02d7e2SAndroid Build Coastguard Worker grpc_tool.SetPrintCommandMode(1);
316*cc02d7e2SAndroid Build Coastguard Worker return cmd->function(&grpc_tool, -1, nullptr, cred, callback);
317*cc02d7e2SAndroid Build Coastguard Worker }
318*cc02d7e2SAndroid Build Coastguard Worker const bool ok = cmd->function(&grpc_tool, argc, argv, cred, callback);
319*cc02d7e2SAndroid Build Coastguard Worker return ok ? 0 : 1;
320*cc02d7e2SAndroid Build Coastguard Worker } else {
321*cc02d7e2SAndroid Build Coastguard Worker Usage("Invalid command '" + command + "'");
322*cc02d7e2SAndroid Build Coastguard Worker }
323*cc02d7e2SAndroid Build Coastguard Worker return 1;
324*cc02d7e2SAndroid Build Coastguard Worker }
325*cc02d7e2SAndroid Build Coastguard Worker
GrpcTool()326*cc02d7e2SAndroid Build Coastguard Worker GrpcTool::GrpcTool() : print_command_usage_(false), usage_exit_status_(0) {}
327*cc02d7e2SAndroid Build Coastguard Worker
CommandUsage(const std::string & usage) const328*cc02d7e2SAndroid Build Coastguard Worker void GrpcTool::CommandUsage(const std::string& usage) const {
329*cc02d7e2SAndroid Build Coastguard Worker if (print_command_usage_) {
330*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "\n%s%s\n", usage.c_str(),
331*cc02d7e2SAndroid Build Coastguard Worker (usage.empty() || usage[usage.size() - 1] != '\n') ? "\n" : "");
332*cc02d7e2SAndroid Build Coastguard Worker exit(usage_exit_status_);
333*cc02d7e2SAndroid Build Coastguard Worker }
334*cc02d7e2SAndroid Build Coastguard Worker }
335*cc02d7e2SAndroid Build Coastguard Worker
Help(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)336*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::Help(int argc, const char** argv, const CliCredentials& cred,
337*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
338*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
339*cc02d7e2SAndroid Build Coastguard Worker "Print help\n"
340*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli help [subcommand]\n");
341*cc02d7e2SAndroid Build Coastguard Worker
342*cc02d7e2SAndroid Build Coastguard Worker if (argc == 0) {
343*cc02d7e2SAndroid Build Coastguard Worker Usage("");
344*cc02d7e2SAndroid Build Coastguard Worker } else {
345*cc02d7e2SAndroid Build Coastguard Worker const Command* cmd = FindCommand(argv[0]);
346*cc02d7e2SAndroid Build Coastguard Worker if (cmd == nullptr) {
347*cc02d7e2SAndroid Build Coastguard Worker Usage("Unknown command '" + std::string(argv[0]) + "'");
348*cc02d7e2SAndroid Build Coastguard Worker }
349*cc02d7e2SAndroid Build Coastguard Worker SetPrintCommandMode(0);
350*cc02d7e2SAndroid Build Coastguard Worker cmd->function(this, -1, nullptr, cred, callback);
351*cc02d7e2SAndroid Build Coastguard Worker }
352*cc02d7e2SAndroid Build Coastguard Worker return true;
353*cc02d7e2SAndroid Build Coastguard Worker }
354*cc02d7e2SAndroid Build Coastguard Worker
ListServices(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)355*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::ListServices(int argc, const char** argv,
356*cc02d7e2SAndroid Build Coastguard Worker const CliCredentials& cred,
357*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
358*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
359*cc02d7e2SAndroid Build Coastguard Worker "List services\n"
360*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli ls <address> [<service>[/<method>]]\n"
361*cc02d7e2SAndroid Build Coastguard Worker " <address> ; host:port\n"
362*cc02d7e2SAndroid Build Coastguard Worker " <service> ; Exported service name\n"
363*cc02d7e2SAndroid Build Coastguard Worker " <method> ; Method name\n"
364*cc02d7e2SAndroid Build Coastguard Worker " --l ; Use a long listing format\n"
365*cc02d7e2SAndroid Build Coastguard Worker " --outfile ; Output filename (defaults to stdout)\n" +
366*cc02d7e2SAndroid Build Coastguard Worker cred.GetCredentialUsage());
367*cc02d7e2SAndroid Build Coastguard Worker
368*cc02d7e2SAndroid Build Coastguard Worker std::string server_address(argv[0]);
369*cc02d7e2SAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> channel =
370*cc02d7e2SAndroid Build Coastguard Worker CreateCliChannel(server_address, cred, grpc::ChannelArguments());
371*cc02d7e2SAndroid Build Coastguard Worker grpc::ProtoReflectionDescriptorDatabase desc_db(channel);
372*cc02d7e2SAndroid Build Coastguard Worker grpc::protobuf::DescriptorPool desc_pool(&desc_db);
373*cc02d7e2SAndroid Build Coastguard Worker
374*cc02d7e2SAndroid Build Coastguard Worker std::vector<std::string> service_list;
375*cc02d7e2SAndroid Build Coastguard Worker if (!desc_db.GetServices(&service_list)) {
376*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Received an error when querying services endpoint.\n");
377*cc02d7e2SAndroid Build Coastguard Worker return false;
378*cc02d7e2SAndroid Build Coastguard Worker }
379*cc02d7e2SAndroid Build Coastguard Worker
380*cc02d7e2SAndroid Build Coastguard Worker // If no service is specified, dump the list of services.
381*cc02d7e2SAndroid Build Coastguard Worker std::string output;
382*cc02d7e2SAndroid Build Coastguard Worker if (argc < 2) {
383*cc02d7e2SAndroid Build Coastguard Worker // List all services, if --l is passed, then include full description,
384*cc02d7e2SAndroid Build Coastguard Worker // otherwise include a summarized list only.
385*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_l)) {
386*cc02d7e2SAndroid Build Coastguard Worker output = DescribeServiceList(service_list, desc_pool);
387*cc02d7e2SAndroid Build Coastguard Worker } else {
388*cc02d7e2SAndroid Build Coastguard Worker for (auto it = service_list.begin(); it != service_list.end(); it++) {
389*cc02d7e2SAndroid Build Coastguard Worker auto const& service = *it;
390*cc02d7e2SAndroid Build Coastguard Worker output.append(service);
391*cc02d7e2SAndroid Build Coastguard Worker output.append("\n");
392*cc02d7e2SAndroid Build Coastguard Worker }
393*cc02d7e2SAndroid Build Coastguard Worker }
394*cc02d7e2SAndroid Build Coastguard Worker } else {
395*cc02d7e2SAndroid Build Coastguard Worker std::string service_name;
396*cc02d7e2SAndroid Build Coastguard Worker std::string method_name;
397*cc02d7e2SAndroid Build Coastguard Worker std::stringstream ss(argv[1]);
398*cc02d7e2SAndroid Build Coastguard Worker
399*cc02d7e2SAndroid Build Coastguard Worker // Remove leading slashes.
400*cc02d7e2SAndroid Build Coastguard Worker while (ss.peek() == '/') {
401*cc02d7e2SAndroid Build Coastguard Worker ss.get();
402*cc02d7e2SAndroid Build Coastguard Worker }
403*cc02d7e2SAndroid Build Coastguard Worker
404*cc02d7e2SAndroid Build Coastguard Worker // Parse service and method names. Support the following patterns:
405*cc02d7e2SAndroid Build Coastguard Worker // Service
406*cc02d7e2SAndroid Build Coastguard Worker // Service Method
407*cc02d7e2SAndroid Build Coastguard Worker // Service.Method
408*cc02d7e2SAndroid Build Coastguard Worker // Service/Method
409*cc02d7e2SAndroid Build Coastguard Worker if (argc == 3) {
410*cc02d7e2SAndroid Build Coastguard Worker std::getline(ss, service_name, '/');
411*cc02d7e2SAndroid Build Coastguard Worker method_name = argv[2];
412*cc02d7e2SAndroid Build Coastguard Worker } else {
413*cc02d7e2SAndroid Build Coastguard Worker if (std::getline(ss, service_name, '/')) {
414*cc02d7e2SAndroid Build Coastguard Worker std::getline(ss, method_name);
415*cc02d7e2SAndroid Build Coastguard Worker }
416*cc02d7e2SAndroid Build Coastguard Worker }
417*cc02d7e2SAndroid Build Coastguard Worker
418*cc02d7e2SAndroid Build Coastguard Worker const grpc::protobuf::ServiceDescriptor* service =
419*cc02d7e2SAndroid Build Coastguard Worker desc_pool.FindServiceByName(service_name);
420*cc02d7e2SAndroid Build Coastguard Worker if (service != nullptr) {
421*cc02d7e2SAndroid Build Coastguard Worker if (method_name.empty()) {
422*cc02d7e2SAndroid Build Coastguard Worker output = absl::GetFlag(FLAGS_l) ? DescribeService(service)
423*cc02d7e2SAndroid Build Coastguard Worker : SummarizeService(service);
424*cc02d7e2SAndroid Build Coastguard Worker } else {
425*cc02d7e2SAndroid Build Coastguard Worker method_name.insert(0, 1, '.');
426*cc02d7e2SAndroid Build Coastguard Worker method_name.insert(0, service_name);
427*cc02d7e2SAndroid Build Coastguard Worker const grpc::protobuf::MethodDescriptor* method =
428*cc02d7e2SAndroid Build Coastguard Worker desc_pool.FindMethodByName(method_name);
429*cc02d7e2SAndroid Build Coastguard Worker if (method != nullptr) {
430*cc02d7e2SAndroid Build Coastguard Worker output = absl::GetFlag(FLAGS_l) ? DescribeMethod(method)
431*cc02d7e2SAndroid Build Coastguard Worker : SummarizeMethod(method);
432*cc02d7e2SAndroid Build Coastguard Worker } else {
433*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Method %s not found in service %s.\n",
434*cc02d7e2SAndroid Build Coastguard Worker method_name.c_str(), service_name.c_str());
435*cc02d7e2SAndroid Build Coastguard Worker return false;
436*cc02d7e2SAndroid Build Coastguard Worker }
437*cc02d7e2SAndroid Build Coastguard Worker }
438*cc02d7e2SAndroid Build Coastguard Worker } else {
439*cc02d7e2SAndroid Build Coastguard Worker if (!method_name.empty()) {
440*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Service %s not found.\n", service_name.c_str());
441*cc02d7e2SAndroid Build Coastguard Worker return false;
442*cc02d7e2SAndroid Build Coastguard Worker } else {
443*cc02d7e2SAndroid Build Coastguard Worker const grpc::protobuf::MethodDescriptor* method =
444*cc02d7e2SAndroid Build Coastguard Worker desc_pool.FindMethodByName(service_name);
445*cc02d7e2SAndroid Build Coastguard Worker if (method != nullptr) {
446*cc02d7e2SAndroid Build Coastguard Worker output = absl::GetFlag(FLAGS_l) ? DescribeMethod(method)
447*cc02d7e2SAndroid Build Coastguard Worker : SummarizeMethod(method);
448*cc02d7e2SAndroid Build Coastguard Worker } else {
449*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Service or method %s not found.\n",
450*cc02d7e2SAndroid Build Coastguard Worker service_name.c_str());
451*cc02d7e2SAndroid Build Coastguard Worker return false;
452*cc02d7e2SAndroid Build Coastguard Worker }
453*cc02d7e2SAndroid Build Coastguard Worker }
454*cc02d7e2SAndroid Build Coastguard Worker }
455*cc02d7e2SAndroid Build Coastguard Worker }
456*cc02d7e2SAndroid Build Coastguard Worker return callback(output);
457*cc02d7e2SAndroid Build Coastguard Worker }
458*cc02d7e2SAndroid Build Coastguard Worker
PrintType(int,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)459*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::PrintType(int /*argc*/, const char** argv,
460*cc02d7e2SAndroid Build Coastguard Worker const CliCredentials& cred,
461*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
462*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
463*cc02d7e2SAndroid Build Coastguard Worker "Print type\n"
464*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli type <address> <type>\n"
465*cc02d7e2SAndroid Build Coastguard Worker " <address> ; host:port\n"
466*cc02d7e2SAndroid Build Coastguard Worker " <type> ; Protocol buffer type name\n" +
467*cc02d7e2SAndroid Build Coastguard Worker cred.GetCredentialUsage());
468*cc02d7e2SAndroid Build Coastguard Worker
469*cc02d7e2SAndroid Build Coastguard Worker std::string server_address(argv[0]);
470*cc02d7e2SAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> channel =
471*cc02d7e2SAndroid Build Coastguard Worker CreateCliChannel(server_address, cred, grpc::ChannelArguments());
472*cc02d7e2SAndroid Build Coastguard Worker grpc::ProtoReflectionDescriptorDatabase desc_db(channel);
473*cc02d7e2SAndroid Build Coastguard Worker grpc::protobuf::DescriptorPool desc_pool(&desc_db);
474*cc02d7e2SAndroid Build Coastguard Worker
475*cc02d7e2SAndroid Build Coastguard Worker std::string output;
476*cc02d7e2SAndroid Build Coastguard Worker const grpc::protobuf::Descriptor* descriptor =
477*cc02d7e2SAndroid Build Coastguard Worker desc_pool.FindMessageTypeByName(argv[1]);
478*cc02d7e2SAndroid Build Coastguard Worker if (descriptor != nullptr) {
479*cc02d7e2SAndroid Build Coastguard Worker output = descriptor->DebugString();
480*cc02d7e2SAndroid Build Coastguard Worker } else {
481*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Type %s not found.\n", argv[1]);
482*cc02d7e2SAndroid Build Coastguard Worker return false;
483*cc02d7e2SAndroid Build Coastguard Worker }
484*cc02d7e2SAndroid Build Coastguard Worker return callback(output);
485*cc02d7e2SAndroid Build Coastguard Worker }
486*cc02d7e2SAndroid Build Coastguard Worker
CallMethod(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)487*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::CallMethod(int argc, const char** argv,
488*cc02d7e2SAndroid Build Coastguard Worker const CliCredentials& cred,
489*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
490*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
491*cc02d7e2SAndroid Build Coastguard Worker "Call method\n"
492*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli call <address> <service>[.<method>] <request>\n"
493*cc02d7e2SAndroid Build Coastguard Worker " <address> ; host:port\n"
494*cc02d7e2SAndroid Build Coastguard Worker " <service> ; Exported service name\n"
495*cc02d7e2SAndroid Build Coastguard Worker " <method> ; Method name\n"
496*cc02d7e2SAndroid Build Coastguard Worker " <request> ; Text protobuffer (overrides infile)\n"
497*cc02d7e2SAndroid Build Coastguard Worker " --protofiles ; Comma separated proto files used as a"
498*cc02d7e2SAndroid Build Coastguard Worker " fallback when parsing request/response\n"
499*cc02d7e2SAndroid Build Coastguard Worker " --proto_path ; The search paths of proto files"
500*cc02d7e2SAndroid Build Coastguard Worker " (" GRPC_CLI_PATH_SEPARATOR
501*cc02d7e2SAndroid Build Coastguard Worker " separated), valid only when --protofiles is given\n"
502*cc02d7e2SAndroid Build Coastguard Worker " --noremotedb ; Don't attempt to use reflection service"
503*cc02d7e2SAndroid Build Coastguard Worker " at all\n"
504*cc02d7e2SAndroid Build Coastguard Worker " --metadata ; The metadata to be sent to the server\n"
505*cc02d7e2SAndroid Build Coastguard Worker " --infile ; Input filename (defaults to stdin)\n"
506*cc02d7e2SAndroid Build Coastguard Worker " --outfile ; Output filename (defaults to stdout)\n"
507*cc02d7e2SAndroid Build Coastguard Worker " --binary_input ; Input in binary format\n"
508*cc02d7e2SAndroid Build Coastguard Worker " --binary_output ; Output in binary format\n"
509*cc02d7e2SAndroid Build Coastguard Worker " --json_input ; Input in json format\n"
510*cc02d7e2SAndroid Build Coastguard Worker " --json_output ; Output in json format\n"
511*cc02d7e2SAndroid Build Coastguard Worker " --max_recv_msg_size ; Specify max receive message size in "
512*cc02d7e2SAndroid Build Coastguard Worker "bytes. -1 indicates unlimited. The default value of 0 means to use the "
513*cc02d7e2SAndroid Build Coastguard Worker "gRPC default.\n"
514*cc02d7e2SAndroid Build Coastguard Worker " --timeout ; Specify timeout (in seconds), used to "
515*cc02d7e2SAndroid Build Coastguard Worker "set the deadline for RPCs. The default value of -1 means no "
516*cc02d7e2SAndroid Build Coastguard Worker "deadline has been set.\n" +
517*cc02d7e2SAndroid Build Coastguard Worker cred.GetCredentialUsage());
518*cc02d7e2SAndroid Build Coastguard Worker
519*cc02d7e2SAndroid Build Coastguard Worker std::stringstream output_ss;
520*cc02d7e2SAndroid Build Coastguard Worker std::string request_text;
521*cc02d7e2SAndroid Build Coastguard Worker std::string server_address(argv[0]);
522*cc02d7e2SAndroid Build Coastguard Worker std::string method_name(argv[1]);
523*cc02d7e2SAndroid Build Coastguard Worker std::string formatted_method_name;
524*cc02d7e2SAndroid Build Coastguard Worker std::unique_ptr<ProtoFileParser> parser;
525*cc02d7e2SAndroid Build Coastguard Worker std::string serialized_request_proto;
526*cc02d7e2SAndroid Build Coastguard Worker CliArgs cli_args;
527*cc02d7e2SAndroid Build Coastguard Worker cli_args.timeout = absl::GetFlag(FLAGS_timeout);
528*cc02d7e2SAndroid Build Coastguard Worker bool print_mode = false;
529*cc02d7e2SAndroid Build Coastguard Worker
530*cc02d7e2SAndroid Build Coastguard Worker grpc::ChannelArguments args;
531*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_max_recv_msg_size) != 0) {
532*cc02d7e2SAndroid Build Coastguard Worker args.SetMaxReceiveMessageSize(absl::GetFlag(FLAGS_max_recv_msg_size));
533*cc02d7e2SAndroid Build Coastguard Worker }
534*cc02d7e2SAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> channel =
535*cc02d7e2SAndroid Build Coastguard Worker CreateCliChannel(server_address, cred, args);
536*cc02d7e2SAndroid Build Coastguard Worker
537*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_binary_input) ||
538*cc02d7e2SAndroid Build Coastguard Worker !absl::GetFlag(FLAGS_binary_output)) {
539*cc02d7e2SAndroid Build Coastguard Worker parser = std::make_unique<grpc::testing::ProtoFileParser>(
540*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_remotedb) ? channel : nullptr,
541*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_proto_path), absl::GetFlag(FLAGS_protofiles));
542*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
543*cc02d7e2SAndroid Build Coastguard Worker fprintf(
544*cc02d7e2SAndroid Build Coastguard Worker stderr,
545*cc02d7e2SAndroid Build Coastguard Worker "Failed to find remote reflection service and local proto files.\n");
546*cc02d7e2SAndroid Build Coastguard Worker return false;
547*cc02d7e2SAndroid Build Coastguard Worker }
548*cc02d7e2SAndroid Build Coastguard Worker }
549*cc02d7e2SAndroid Build Coastguard Worker
550*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_input)) {
551*cc02d7e2SAndroid Build Coastguard Worker formatted_method_name = method_name;
552*cc02d7e2SAndroid Build Coastguard Worker } else {
553*cc02d7e2SAndroid Build Coastguard Worker formatted_method_name = parser->GetFormattedMethodName(method_name);
554*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
555*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to find method %s in proto files.\n",
556*cc02d7e2SAndroid Build Coastguard Worker method_name.c_str());
557*cc02d7e2SAndroid Build Coastguard Worker }
558*cc02d7e2SAndroid Build Coastguard Worker }
559*cc02d7e2SAndroid Build Coastguard Worker
560*cc02d7e2SAndroid Build Coastguard Worker if (argc == 3) {
561*cc02d7e2SAndroid Build Coastguard Worker request_text = argv[2];
562*cc02d7e2SAndroid Build Coastguard Worker }
563*cc02d7e2SAndroid Build Coastguard Worker
564*cc02d7e2SAndroid Build Coastguard Worker if (parser != nullptr &&
565*cc02d7e2SAndroid Build Coastguard Worker parser->IsStreaming(method_name, true /* is_request */)) {
566*cc02d7e2SAndroid Build Coastguard Worker std::istream* input_stream;
567*cc02d7e2SAndroid Build Coastguard Worker std::ifstream input_file;
568*cc02d7e2SAndroid Build Coastguard Worker
569*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_batch)) {
570*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Batch mode for streaming RPC is not supported.\n");
571*cc02d7e2SAndroid Build Coastguard Worker return false;
572*cc02d7e2SAndroid Build Coastguard Worker }
573*cc02d7e2SAndroid Build Coastguard Worker
574*cc02d7e2SAndroid Build Coastguard Worker std::multimap<std::string, std::string> client_metadata;
575*cc02d7e2SAndroid Build Coastguard Worker ParseMetadataFlag(&client_metadata);
576*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(client_metadata, "Sending client initial metadata:");
577*cc02d7e2SAndroid Build Coastguard Worker
578*cc02d7e2SAndroid Build Coastguard Worker CliCall call(channel, formatted_method_name, client_metadata, cli_args);
579*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_display_peer_address)) {
580*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "New call for method_name:%s has peer address:|%s|\n",
581*cc02d7e2SAndroid Build Coastguard Worker formatted_method_name.c_str(), call.peer().c_str());
582*cc02d7e2SAndroid Build Coastguard Worker }
583*cc02d7e2SAndroid Build Coastguard Worker
584*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_infile).empty()) {
585*cc02d7e2SAndroid Build Coastguard Worker if (isatty(fileno(stdin))) {
586*cc02d7e2SAndroid Build Coastguard Worker print_mode = true;
587*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "reading streaming request message from stdin...\n");
588*cc02d7e2SAndroid Build Coastguard Worker }
589*cc02d7e2SAndroid Build Coastguard Worker input_stream = &std::cin;
590*cc02d7e2SAndroid Build Coastguard Worker } else {
591*cc02d7e2SAndroid Build Coastguard Worker input_file.open(absl::GetFlag(FLAGS_infile),
592*cc02d7e2SAndroid Build Coastguard Worker std::ios::in | std::ios::binary);
593*cc02d7e2SAndroid Build Coastguard Worker if (!input_file) {
594*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to open infile %s.\n",
595*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_infile).c_str());
596*cc02d7e2SAndroid Build Coastguard Worker return false;
597*cc02d7e2SAndroid Build Coastguard Worker }
598*cc02d7e2SAndroid Build Coastguard Worker
599*cc02d7e2SAndroid Build Coastguard Worker input_stream = &input_file;
600*cc02d7e2SAndroid Build Coastguard Worker }
601*cc02d7e2SAndroid Build Coastguard Worker
602*cc02d7e2SAndroid Build Coastguard Worker gpr_mu parser_mu;
603*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_init(&parser_mu);
604*cc02d7e2SAndroid Build Coastguard Worker std::thread read_thread(ReadResponse, &call, method_name, callback,
605*cc02d7e2SAndroid Build Coastguard Worker parser.get(), &parser_mu, print_mode);
606*cc02d7e2SAndroid Build Coastguard Worker
607*cc02d7e2SAndroid Build Coastguard Worker std::stringstream request_ss;
608*cc02d7e2SAndroid Build Coastguard Worker std::string line;
609*cc02d7e2SAndroid Build Coastguard Worker while (!request_text.empty() ||
610*cc02d7e2SAndroid Build Coastguard Worker (!input_stream->eof() && getline(*input_stream, line))) {
611*cc02d7e2SAndroid Build Coastguard Worker if (!request_text.empty()) {
612*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_input)) {
613*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = request_text;
614*cc02d7e2SAndroid Build Coastguard Worker request_text.clear();
615*cc02d7e2SAndroid Build Coastguard Worker } else {
616*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_lock(&parser_mu);
617*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = parser->GetSerializedProtoFromMethod(
618*cc02d7e2SAndroid Build Coastguard Worker method_name, request_text, true /* is_request */,
619*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_json_input));
620*cc02d7e2SAndroid Build Coastguard Worker request_text.clear();
621*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
622*cc02d7e2SAndroid Build Coastguard Worker if (print_mode) {
623*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse request.\n");
624*cc02d7e2SAndroid Build Coastguard Worker }
625*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_unlock(&parser_mu);
626*cc02d7e2SAndroid Build Coastguard Worker continue;
627*cc02d7e2SAndroid Build Coastguard Worker }
628*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_unlock(&parser_mu);
629*cc02d7e2SAndroid Build Coastguard Worker }
630*cc02d7e2SAndroid Build Coastguard Worker
631*cc02d7e2SAndroid Build Coastguard Worker call.WriteAndWait(serialized_request_proto);
632*cc02d7e2SAndroid Build Coastguard Worker if (print_mode) {
633*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Request sent.\n");
634*cc02d7e2SAndroid Build Coastguard Worker }
635*cc02d7e2SAndroid Build Coastguard Worker } else {
636*cc02d7e2SAndroid Build Coastguard Worker if (line.length() == 0) {
637*cc02d7e2SAndroid Build Coastguard Worker request_text = request_ss.str();
638*cc02d7e2SAndroid Build Coastguard Worker request_ss.str(std::string());
639*cc02d7e2SAndroid Build Coastguard Worker request_ss.clear();
640*cc02d7e2SAndroid Build Coastguard Worker } else {
641*cc02d7e2SAndroid Build Coastguard Worker request_ss << line << ' ';
642*cc02d7e2SAndroid Build Coastguard Worker }
643*cc02d7e2SAndroid Build Coastguard Worker }
644*cc02d7e2SAndroid Build Coastguard Worker }
645*cc02d7e2SAndroid Build Coastguard Worker if (input_file.is_open()) {
646*cc02d7e2SAndroid Build Coastguard Worker input_file.close();
647*cc02d7e2SAndroid Build Coastguard Worker }
648*cc02d7e2SAndroid Build Coastguard Worker
649*cc02d7e2SAndroid Build Coastguard Worker call.WritesDoneAndWait();
650*cc02d7e2SAndroid Build Coastguard Worker read_thread.join();
651*cc02d7e2SAndroid Build Coastguard Worker gpr_mu_destroy(&parser_mu);
652*cc02d7e2SAndroid Build Coastguard Worker
653*cc02d7e2SAndroid Build Coastguard Worker std::multimap<grpc::string_ref, grpc::string_ref> server_trailing_metadata;
654*cc02d7e2SAndroid Build Coastguard Worker Status status = call.Finish(&server_trailing_metadata);
655*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(server_trailing_metadata,
656*cc02d7e2SAndroid Build Coastguard Worker "Received trailing metadata from server:");
657*cc02d7e2SAndroid Build Coastguard Worker
658*cc02d7e2SAndroid Build Coastguard Worker if (status.ok()) {
659*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Stream RPC succeeded with OK status\n");
660*cc02d7e2SAndroid Build Coastguard Worker return true;
661*cc02d7e2SAndroid Build Coastguard Worker } else {
662*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Rpc failed with status code %d, error message: %s\n",
663*cc02d7e2SAndroid Build Coastguard Worker status.error_code(), status.error_message().c_str());
664*cc02d7e2SAndroid Build Coastguard Worker return false;
665*cc02d7e2SAndroid Build Coastguard Worker }
666*cc02d7e2SAndroid Build Coastguard Worker
667*cc02d7e2SAndroid Build Coastguard Worker } else { // parser->IsStreaming(method_name, true /* is_request */)
668*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_batch)) {
669*cc02d7e2SAndroid Build Coastguard Worker if (parser != nullptr &&
670*cc02d7e2SAndroid Build Coastguard Worker parser->IsStreaming(method_name, false /* is_request */)) {
671*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Batch mode for streaming RPC is not supported.\n");
672*cc02d7e2SAndroid Build Coastguard Worker return false;
673*cc02d7e2SAndroid Build Coastguard Worker }
674*cc02d7e2SAndroid Build Coastguard Worker
675*cc02d7e2SAndroid Build Coastguard Worker std::istream* input_stream;
676*cc02d7e2SAndroid Build Coastguard Worker std::ifstream input_file;
677*cc02d7e2SAndroid Build Coastguard Worker
678*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_infile).empty()) {
679*cc02d7e2SAndroid Build Coastguard Worker if (isatty(fileno(stdin))) {
680*cc02d7e2SAndroid Build Coastguard Worker print_mode = true;
681*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "reading request messages from stdin...\n");
682*cc02d7e2SAndroid Build Coastguard Worker }
683*cc02d7e2SAndroid Build Coastguard Worker input_stream = &std::cin;
684*cc02d7e2SAndroid Build Coastguard Worker } else {
685*cc02d7e2SAndroid Build Coastguard Worker input_file.open(absl::GetFlag(FLAGS_infile),
686*cc02d7e2SAndroid Build Coastguard Worker std::ios::in | std::ios::binary);
687*cc02d7e2SAndroid Build Coastguard Worker input_stream = &input_file;
688*cc02d7e2SAndroid Build Coastguard Worker }
689*cc02d7e2SAndroid Build Coastguard Worker
690*cc02d7e2SAndroid Build Coastguard Worker std::multimap<std::string, std::string> client_metadata;
691*cc02d7e2SAndroid Build Coastguard Worker ParseMetadataFlag(&client_metadata);
692*cc02d7e2SAndroid Build Coastguard Worker if (print_mode) {
693*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(client_metadata, "Sending client initial metadata:");
694*cc02d7e2SAndroid Build Coastguard Worker }
695*cc02d7e2SAndroid Build Coastguard Worker
696*cc02d7e2SAndroid Build Coastguard Worker std::stringstream request_ss;
697*cc02d7e2SAndroid Build Coastguard Worker std::string line;
698*cc02d7e2SAndroid Build Coastguard Worker while (!request_text.empty() ||
699*cc02d7e2SAndroid Build Coastguard Worker (!input_stream->eof() && getline(*input_stream, line))) {
700*cc02d7e2SAndroid Build Coastguard Worker if (!request_text.empty()) {
701*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_input)) {
702*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = request_text;
703*cc02d7e2SAndroid Build Coastguard Worker request_text.clear();
704*cc02d7e2SAndroid Build Coastguard Worker } else {
705*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = parser->GetSerializedProtoFromMethod(
706*cc02d7e2SAndroid Build Coastguard Worker method_name, request_text, true /* is_request */,
707*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_json_input));
708*cc02d7e2SAndroid Build Coastguard Worker request_text.clear();
709*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
710*cc02d7e2SAndroid Build Coastguard Worker if (print_mode) {
711*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse request.\n");
712*cc02d7e2SAndroid Build Coastguard Worker }
713*cc02d7e2SAndroid Build Coastguard Worker continue;
714*cc02d7e2SAndroid Build Coastguard Worker }
715*cc02d7e2SAndroid Build Coastguard Worker }
716*cc02d7e2SAndroid Build Coastguard Worker
717*cc02d7e2SAndroid Build Coastguard Worker std::string serialized_response_proto;
718*cc02d7e2SAndroid Build Coastguard Worker std::multimap<grpc::string_ref, grpc::string_ref>
719*cc02d7e2SAndroid Build Coastguard Worker server_initial_metadata, server_trailing_metadata;
720*cc02d7e2SAndroid Build Coastguard Worker CliCall call(channel, formatted_method_name, client_metadata,
721*cc02d7e2SAndroid Build Coastguard Worker cli_args);
722*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_display_peer_address)) {
723*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr,
724*cc02d7e2SAndroid Build Coastguard Worker "New call for method_name:%s has peer address:|%s|\n",
725*cc02d7e2SAndroid Build Coastguard Worker formatted_method_name.c_str(), call.peer().c_str());
726*cc02d7e2SAndroid Build Coastguard Worker }
727*cc02d7e2SAndroid Build Coastguard Worker call.Write(serialized_request_proto);
728*cc02d7e2SAndroid Build Coastguard Worker call.WritesDone();
729*cc02d7e2SAndroid Build Coastguard Worker if (!call.Read(&serialized_response_proto,
730*cc02d7e2SAndroid Build Coastguard Worker &server_initial_metadata)) {
731*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to read response.\n");
732*cc02d7e2SAndroid Build Coastguard Worker }
733*cc02d7e2SAndroid Build Coastguard Worker Status status = call.Finish(&server_trailing_metadata);
734*cc02d7e2SAndroid Build Coastguard Worker
735*cc02d7e2SAndroid Build Coastguard Worker if (status.ok()) {
736*cc02d7e2SAndroid Build Coastguard Worker if (print_mode) {
737*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Rpc succeeded with OK status.\n");
738*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(server_initial_metadata,
739*cc02d7e2SAndroid Build Coastguard Worker "Received initial metadata from server:");
740*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(server_trailing_metadata,
741*cc02d7e2SAndroid Build Coastguard Worker "Received trailing metadata from server:");
742*cc02d7e2SAndroid Build Coastguard Worker }
743*cc02d7e2SAndroid Build Coastguard Worker
744*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_output)) {
745*cc02d7e2SAndroid Build Coastguard Worker if (!callback(serialized_response_proto)) {
746*cc02d7e2SAndroid Build Coastguard Worker break;
747*cc02d7e2SAndroid Build Coastguard Worker }
748*cc02d7e2SAndroid Build Coastguard Worker } else {
749*cc02d7e2SAndroid Build Coastguard Worker std::string response_text = parser->GetFormattedStringFromMethod(
750*cc02d7e2SAndroid Build Coastguard Worker method_name, serialized_response_proto,
751*cc02d7e2SAndroid Build Coastguard Worker false /* is_request */, absl::GetFlag(FLAGS_json_output));
752*cc02d7e2SAndroid Build Coastguard Worker
753*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError() && print_mode) {
754*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse response.\n");
755*cc02d7e2SAndroid Build Coastguard Worker } else {
756*cc02d7e2SAndroid Build Coastguard Worker if (!callback(response_text)) {
757*cc02d7e2SAndroid Build Coastguard Worker break;
758*cc02d7e2SAndroid Build Coastguard Worker }
759*cc02d7e2SAndroid Build Coastguard Worker }
760*cc02d7e2SAndroid Build Coastguard Worker }
761*cc02d7e2SAndroid Build Coastguard Worker } else {
762*cc02d7e2SAndroid Build Coastguard Worker if (print_mode) {
763*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr,
764*cc02d7e2SAndroid Build Coastguard Worker "Rpc failed with status code %d, error message: %s\n",
765*cc02d7e2SAndroid Build Coastguard Worker status.error_code(), status.error_message().c_str());
766*cc02d7e2SAndroid Build Coastguard Worker }
767*cc02d7e2SAndroid Build Coastguard Worker }
768*cc02d7e2SAndroid Build Coastguard Worker } else {
769*cc02d7e2SAndroid Build Coastguard Worker if (line.length() == 0) {
770*cc02d7e2SAndroid Build Coastguard Worker request_text = request_ss.str();
771*cc02d7e2SAndroid Build Coastguard Worker request_ss.str(std::string());
772*cc02d7e2SAndroid Build Coastguard Worker request_ss.clear();
773*cc02d7e2SAndroid Build Coastguard Worker } else {
774*cc02d7e2SAndroid Build Coastguard Worker request_ss << line << ' ';
775*cc02d7e2SAndroid Build Coastguard Worker }
776*cc02d7e2SAndroid Build Coastguard Worker }
777*cc02d7e2SAndroid Build Coastguard Worker }
778*cc02d7e2SAndroid Build Coastguard Worker
779*cc02d7e2SAndroid Build Coastguard Worker if (input_file.is_open()) {
780*cc02d7e2SAndroid Build Coastguard Worker input_file.close();
781*cc02d7e2SAndroid Build Coastguard Worker }
782*cc02d7e2SAndroid Build Coastguard Worker
783*cc02d7e2SAndroid Build Coastguard Worker return true;
784*cc02d7e2SAndroid Build Coastguard Worker }
785*cc02d7e2SAndroid Build Coastguard Worker
786*cc02d7e2SAndroid Build Coastguard Worker if (argc == 3) {
787*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_infile).empty()) {
788*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "warning: request given in argv, ignoring --infile\n");
789*cc02d7e2SAndroid Build Coastguard Worker }
790*cc02d7e2SAndroid Build Coastguard Worker } else {
791*cc02d7e2SAndroid Build Coastguard Worker std::stringstream input_stream;
792*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_infile).empty()) {
793*cc02d7e2SAndroid Build Coastguard Worker if (isatty(fileno(stdin))) {
794*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "reading request message from stdin...\n");
795*cc02d7e2SAndroid Build Coastguard Worker }
796*cc02d7e2SAndroid Build Coastguard Worker input_stream << std::cin.rdbuf();
797*cc02d7e2SAndroid Build Coastguard Worker } else {
798*cc02d7e2SAndroid Build Coastguard Worker std::ifstream input_file(absl::GetFlag(FLAGS_infile),
799*cc02d7e2SAndroid Build Coastguard Worker std::ios::in | std::ios::binary);
800*cc02d7e2SAndroid Build Coastguard Worker input_stream << input_file.rdbuf();
801*cc02d7e2SAndroid Build Coastguard Worker input_file.close();
802*cc02d7e2SAndroid Build Coastguard Worker }
803*cc02d7e2SAndroid Build Coastguard Worker request_text = input_stream.str();
804*cc02d7e2SAndroid Build Coastguard Worker }
805*cc02d7e2SAndroid Build Coastguard Worker
806*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_input)) {
807*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = request_text;
808*cc02d7e2SAndroid Build Coastguard Worker } else {
809*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = parser->GetSerializedProtoFromMethod(
810*cc02d7e2SAndroid Build Coastguard Worker method_name, request_text, true /* is_request */,
811*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_json_input));
812*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
813*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse request.\n");
814*cc02d7e2SAndroid Build Coastguard Worker return false;
815*cc02d7e2SAndroid Build Coastguard Worker }
816*cc02d7e2SAndroid Build Coastguard Worker }
817*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "connecting to %s\n", server_address.c_str());
818*cc02d7e2SAndroid Build Coastguard Worker
819*cc02d7e2SAndroid Build Coastguard Worker std::string serialized_response_proto;
820*cc02d7e2SAndroid Build Coastguard Worker std::multimap<std::string, std::string> client_metadata;
821*cc02d7e2SAndroid Build Coastguard Worker std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
822*cc02d7e2SAndroid Build Coastguard Worker server_trailing_metadata;
823*cc02d7e2SAndroid Build Coastguard Worker ParseMetadataFlag(&client_metadata);
824*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(client_metadata, "Sending client initial metadata:");
825*cc02d7e2SAndroid Build Coastguard Worker
826*cc02d7e2SAndroid Build Coastguard Worker CliCall call(channel, formatted_method_name, client_metadata, cli_args);
827*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_display_peer_address)) {
828*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "New call for method_name:%s has peer address:|%s|\n",
829*cc02d7e2SAndroid Build Coastguard Worker formatted_method_name.c_str(), call.peer().c_str());
830*cc02d7e2SAndroid Build Coastguard Worker }
831*cc02d7e2SAndroid Build Coastguard Worker call.Write(serialized_request_proto);
832*cc02d7e2SAndroid Build Coastguard Worker call.WritesDone();
833*cc02d7e2SAndroid Build Coastguard Worker
834*cc02d7e2SAndroid Build Coastguard Worker for (bool receive_initial_metadata = true; call.Read(
835*cc02d7e2SAndroid Build Coastguard Worker &serialized_response_proto,
836*cc02d7e2SAndroid Build Coastguard Worker receive_initial_metadata ? &server_initial_metadata : nullptr);
837*cc02d7e2SAndroid Build Coastguard Worker receive_initial_metadata = false) {
838*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_binary_output)) {
839*cc02d7e2SAndroid Build Coastguard Worker serialized_response_proto = parser->GetFormattedStringFromMethod(
840*cc02d7e2SAndroid Build Coastguard Worker method_name, serialized_response_proto, false /* is_request */,
841*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_json_output));
842*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
843*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to parse response.\n");
844*cc02d7e2SAndroid Build Coastguard Worker return false;
845*cc02d7e2SAndroid Build Coastguard Worker }
846*cc02d7e2SAndroid Build Coastguard Worker }
847*cc02d7e2SAndroid Build Coastguard Worker
848*cc02d7e2SAndroid Build Coastguard Worker if (receive_initial_metadata) {
849*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(server_initial_metadata,
850*cc02d7e2SAndroid Build Coastguard Worker "Received initial metadata from server:");
851*cc02d7e2SAndroid Build Coastguard Worker }
852*cc02d7e2SAndroid Build Coastguard Worker if (!callback(serialized_response_proto)) {
853*cc02d7e2SAndroid Build Coastguard Worker return false;
854*cc02d7e2SAndroid Build Coastguard Worker }
855*cc02d7e2SAndroid Build Coastguard Worker }
856*cc02d7e2SAndroid Build Coastguard Worker Status status = call.Finish(&server_trailing_metadata);
857*cc02d7e2SAndroid Build Coastguard Worker PrintMetadata(server_trailing_metadata,
858*cc02d7e2SAndroid Build Coastguard Worker "Received trailing metadata from server:");
859*cc02d7e2SAndroid Build Coastguard Worker if (status.ok()) {
860*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Rpc succeeded with OK status\n");
861*cc02d7e2SAndroid Build Coastguard Worker return true;
862*cc02d7e2SAndroid Build Coastguard Worker } else {
863*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Rpc failed with status code %d, error message: %s\n",
864*cc02d7e2SAndroid Build Coastguard Worker status.error_code(), status.error_message().c_str());
865*cc02d7e2SAndroid Build Coastguard Worker return false;
866*cc02d7e2SAndroid Build Coastguard Worker }
867*cc02d7e2SAndroid Build Coastguard Worker }
868*cc02d7e2SAndroid Build Coastguard Worker GPR_UNREACHABLE_CODE(return false);
869*cc02d7e2SAndroid Build Coastguard Worker }
870*cc02d7e2SAndroid Build Coastguard Worker
ParseMessage(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)871*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::ParseMessage(int argc, const char** argv,
872*cc02d7e2SAndroid Build Coastguard Worker const CliCredentials& cred,
873*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
874*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
875*cc02d7e2SAndroid Build Coastguard Worker "Parse message\n"
876*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli parse <address> <type> [<message>]\n"
877*cc02d7e2SAndroid Build Coastguard Worker " <address> ; host:port\n"
878*cc02d7e2SAndroid Build Coastguard Worker " <type> ; Protocol buffer type name\n"
879*cc02d7e2SAndroid Build Coastguard Worker " <message> ; Text protobuffer (overrides --infile)\n"
880*cc02d7e2SAndroid Build Coastguard Worker " --protofiles ; Comma separated proto files used as a"
881*cc02d7e2SAndroid Build Coastguard Worker " fallback when parsing request/response\n"
882*cc02d7e2SAndroid Build Coastguard Worker " --proto_path ; The search paths of proto files"
883*cc02d7e2SAndroid Build Coastguard Worker " (" GRPC_CLI_PATH_SEPARATOR
884*cc02d7e2SAndroid Build Coastguard Worker " separated), valid only when --protofiles is given\n"
885*cc02d7e2SAndroid Build Coastguard Worker " --noremotedb ; Don't attempt to use reflection service"
886*cc02d7e2SAndroid Build Coastguard Worker " at all\n"
887*cc02d7e2SAndroid Build Coastguard Worker " --infile ; Input filename (defaults to stdin)\n"
888*cc02d7e2SAndroid Build Coastguard Worker " --outfile ; Output filename (defaults to stdout)\n"
889*cc02d7e2SAndroid Build Coastguard Worker " --binary_input ; Input in binary format\n"
890*cc02d7e2SAndroid Build Coastguard Worker " --binary_output ; Output in binary format\n"
891*cc02d7e2SAndroid Build Coastguard Worker " --json_input ; Input in json format\n"
892*cc02d7e2SAndroid Build Coastguard Worker " --json_output ; Output in json format\n" +
893*cc02d7e2SAndroid Build Coastguard Worker cred.GetCredentialUsage());
894*cc02d7e2SAndroid Build Coastguard Worker
895*cc02d7e2SAndroid Build Coastguard Worker std::stringstream output_ss;
896*cc02d7e2SAndroid Build Coastguard Worker std::string message_text;
897*cc02d7e2SAndroid Build Coastguard Worker std::string server_address(argv[0]);
898*cc02d7e2SAndroid Build Coastguard Worker std::string type_name(argv[1]);
899*cc02d7e2SAndroid Build Coastguard Worker std::unique_ptr<grpc::testing::ProtoFileParser> parser;
900*cc02d7e2SAndroid Build Coastguard Worker std::string serialized_request_proto;
901*cc02d7e2SAndroid Build Coastguard Worker
902*cc02d7e2SAndroid Build Coastguard Worker if (argc == 3) {
903*cc02d7e2SAndroid Build Coastguard Worker message_text = argv[2];
904*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_infile).empty()) {
905*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "warning: message given in argv, ignoring --infile.\n");
906*cc02d7e2SAndroid Build Coastguard Worker }
907*cc02d7e2SAndroid Build Coastguard Worker } else {
908*cc02d7e2SAndroid Build Coastguard Worker std::stringstream input_stream;
909*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_infile).empty()) {
910*cc02d7e2SAndroid Build Coastguard Worker if (isatty(fileno(stdin))) {
911*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "reading request message from stdin...\n");
912*cc02d7e2SAndroid Build Coastguard Worker }
913*cc02d7e2SAndroid Build Coastguard Worker input_stream << std::cin.rdbuf();
914*cc02d7e2SAndroid Build Coastguard Worker } else {
915*cc02d7e2SAndroid Build Coastguard Worker std::ifstream input_file(absl::GetFlag(FLAGS_infile),
916*cc02d7e2SAndroid Build Coastguard Worker std::ios::in | std::ios::binary);
917*cc02d7e2SAndroid Build Coastguard Worker input_stream << input_file.rdbuf();
918*cc02d7e2SAndroid Build Coastguard Worker input_file.close();
919*cc02d7e2SAndroid Build Coastguard Worker }
920*cc02d7e2SAndroid Build Coastguard Worker message_text = input_stream.str();
921*cc02d7e2SAndroid Build Coastguard Worker }
922*cc02d7e2SAndroid Build Coastguard Worker
923*cc02d7e2SAndroid Build Coastguard Worker if (!absl::GetFlag(FLAGS_binary_input) ||
924*cc02d7e2SAndroid Build Coastguard Worker !absl::GetFlag(FLAGS_binary_output)) {
925*cc02d7e2SAndroid Build Coastguard Worker std::shared_ptr<grpc::Channel> channel =
926*cc02d7e2SAndroid Build Coastguard Worker CreateCliChannel(server_address, cred, grpc::ChannelArguments());
927*cc02d7e2SAndroid Build Coastguard Worker parser = std::make_unique<grpc::testing::ProtoFileParser>(
928*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_remotedb) ? channel : nullptr,
929*cc02d7e2SAndroid Build Coastguard Worker absl::GetFlag(FLAGS_proto_path), absl::GetFlag(FLAGS_protofiles));
930*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
931*cc02d7e2SAndroid Build Coastguard Worker fprintf(
932*cc02d7e2SAndroid Build Coastguard Worker stderr,
933*cc02d7e2SAndroid Build Coastguard Worker "Failed to find remote reflection service and local proto files.\n");
934*cc02d7e2SAndroid Build Coastguard Worker return false;
935*cc02d7e2SAndroid Build Coastguard Worker }
936*cc02d7e2SAndroid Build Coastguard Worker }
937*cc02d7e2SAndroid Build Coastguard Worker
938*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_input)) {
939*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = message_text;
940*cc02d7e2SAndroid Build Coastguard Worker } else {
941*cc02d7e2SAndroid Build Coastguard Worker serialized_request_proto = parser->GetSerializedProtoFromMessageType(
942*cc02d7e2SAndroid Build Coastguard Worker type_name, message_text, absl::GetFlag(FLAGS_json_input));
943*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
944*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to serialize the message.\n");
945*cc02d7e2SAndroid Build Coastguard Worker return false;
946*cc02d7e2SAndroid Build Coastguard Worker }
947*cc02d7e2SAndroid Build Coastguard Worker }
948*cc02d7e2SAndroid Build Coastguard Worker
949*cc02d7e2SAndroid Build Coastguard Worker if (absl::GetFlag(FLAGS_binary_output)) {
950*cc02d7e2SAndroid Build Coastguard Worker output_ss << serialized_request_proto;
951*cc02d7e2SAndroid Build Coastguard Worker } else {
952*cc02d7e2SAndroid Build Coastguard Worker std::string output_text;
953*cc02d7e2SAndroid Build Coastguard Worker output_text = parser->GetFormattedStringFromMessageType(
954*cc02d7e2SAndroid Build Coastguard Worker type_name, serialized_request_proto, absl::GetFlag(FLAGS_json_output));
955*cc02d7e2SAndroid Build Coastguard Worker if (parser->HasError()) {
956*cc02d7e2SAndroid Build Coastguard Worker fprintf(stderr, "Failed to deserialize the message.\n");
957*cc02d7e2SAndroid Build Coastguard Worker return false;
958*cc02d7e2SAndroid Build Coastguard Worker }
959*cc02d7e2SAndroid Build Coastguard Worker
960*cc02d7e2SAndroid Build Coastguard Worker output_ss << output_text << std::endl;
961*cc02d7e2SAndroid Build Coastguard Worker }
962*cc02d7e2SAndroid Build Coastguard Worker
963*cc02d7e2SAndroid Build Coastguard Worker return callback(output_ss.str());
964*cc02d7e2SAndroid Build Coastguard Worker }
965*cc02d7e2SAndroid Build Coastguard Worker
ToText(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)966*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::ToText(int argc, const char** argv, const CliCredentials& cred,
967*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
968*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
969*cc02d7e2SAndroid Build Coastguard Worker "Convert binary message to text\n"
970*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli totext <protofiles> <type>\n"
971*cc02d7e2SAndroid Build Coastguard Worker " <protofiles> ; Comma separated list of proto files\n"
972*cc02d7e2SAndroid Build Coastguard Worker " <type> ; Protocol buffer type name\n"
973*cc02d7e2SAndroid Build Coastguard Worker " --proto_path ; The search paths of proto files"
974*cc02d7e2SAndroid Build Coastguard Worker " (" GRPC_CLI_PATH_SEPARATOR
975*cc02d7e2SAndroid Build Coastguard Worker " separated)\n"
976*cc02d7e2SAndroid Build Coastguard Worker " --infile ; Input filename (defaults to stdin)\n"
977*cc02d7e2SAndroid Build Coastguard Worker " --outfile ; Output filename (defaults to stdout)\n");
978*cc02d7e2SAndroid Build Coastguard Worker
979*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_protofiles, argv[0]);
980*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_remotedb, false);
981*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_binary_input, true);
982*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_binary_output, false);
983*cc02d7e2SAndroid Build Coastguard Worker return ParseMessage(argc, argv, cred, callback);
984*cc02d7e2SAndroid Build Coastguard Worker }
985*cc02d7e2SAndroid Build Coastguard Worker
ToJson(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)986*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::ToJson(int argc, const char** argv, const CliCredentials& cred,
987*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
988*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
989*cc02d7e2SAndroid Build Coastguard Worker "Convert binary message to json\n"
990*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli tojson <protofiles> <type>\n"
991*cc02d7e2SAndroid Build Coastguard Worker " <protofiles> ; Comma separated list of proto files\n"
992*cc02d7e2SAndroid Build Coastguard Worker " <type> ; Protocol buffer type name\n"
993*cc02d7e2SAndroid Build Coastguard Worker " --proto_path ; The search paths of proto files"
994*cc02d7e2SAndroid Build Coastguard Worker " (" GRPC_CLI_PATH_SEPARATOR
995*cc02d7e2SAndroid Build Coastguard Worker " separated)\n"
996*cc02d7e2SAndroid Build Coastguard Worker " --infile ; Input filename (defaults to stdin)\n"
997*cc02d7e2SAndroid Build Coastguard Worker " --outfile ; Output filename (defaults to stdout)\n");
998*cc02d7e2SAndroid Build Coastguard Worker
999*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_protofiles, argv[0]);
1000*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_remotedb, false);
1001*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_binary_input, true);
1002*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_binary_output, false);
1003*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_json_output, true);
1004*cc02d7e2SAndroid Build Coastguard Worker return ParseMessage(argc, argv, cred, callback);
1005*cc02d7e2SAndroid Build Coastguard Worker }
1006*cc02d7e2SAndroid Build Coastguard Worker
ToBinary(int argc,const char ** argv,const CliCredentials & cred,const GrpcToolOutputCallback & callback)1007*cc02d7e2SAndroid Build Coastguard Worker bool GrpcTool::ToBinary(int argc, const char** argv, const CliCredentials& cred,
1008*cc02d7e2SAndroid Build Coastguard Worker const GrpcToolOutputCallback& callback) {
1009*cc02d7e2SAndroid Build Coastguard Worker CommandUsage(
1010*cc02d7e2SAndroid Build Coastguard Worker "Convert text message to binary\n"
1011*cc02d7e2SAndroid Build Coastguard Worker " grpc_cli tobinary <protofiles> <type> [<message>]\n"
1012*cc02d7e2SAndroid Build Coastguard Worker " <protofiles> ; Comma separated list of proto files\n"
1013*cc02d7e2SAndroid Build Coastguard Worker " <type> ; Protocol buffer type name\n"
1014*cc02d7e2SAndroid Build Coastguard Worker " --proto_path ; The search paths of proto files"
1015*cc02d7e2SAndroid Build Coastguard Worker " (" GRPC_CLI_PATH_SEPARATOR
1016*cc02d7e2SAndroid Build Coastguard Worker " separated)\n"
1017*cc02d7e2SAndroid Build Coastguard Worker " --infile ; Input filename (defaults to stdin)\n"
1018*cc02d7e2SAndroid Build Coastguard Worker " --outfile ; Output filename (defaults to stdout)\n");
1019*cc02d7e2SAndroid Build Coastguard Worker
1020*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_protofiles, argv[0]);
1021*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_remotedb, false);
1022*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_binary_input, false);
1023*cc02d7e2SAndroid Build Coastguard Worker absl::SetFlag(&FLAGS_binary_output, true);
1024*cc02d7e2SAndroid Build Coastguard Worker return ParseMessage(argc, argv, cred, callback);
1025*cc02d7e2SAndroid Build Coastguard Worker }
1026*cc02d7e2SAndroid Build Coastguard Worker
1027*cc02d7e2SAndroid Build Coastguard Worker } // namespace testing
1028*cc02d7e2SAndroid Build Coastguard Worker } // namespace grpc
1029