Merge github.com:google/grpc

pull/2/head
Craig Tiller 10 years ago
commit 225d31fd40
  1. 428
      Makefile
  2. 66
      build.json
  3. 1
      include/grpc++/create_channel.h
  4. 30
      include/grpc++/credentials.h
  5. 6
      include/grpc++/impl/internal_stub.h
  6. 10
      include/grpc++/impl/rpc_method.h
  7. 14
      include/grpc++/impl/rpc_service_method.h
  8. 18
      include/grpc/support/log.h
  9. 2
      include/grpc/support/port_platform.h
  10. 2
      include/grpc/support/time.h
  11. 11
      src/compiler/cpp_generator.cc
  12. 520
      src/compiler/go_generator.cc
  13. 51
      src/compiler/go_generator.h
  14. 83
      src/compiler/go_plugin.cc
  15. 18
      src/core/channel/census_filter.c
  16. 43
      src/core/channel/connected_channel.c
  17. 108
      src/core/channel/http_server_filter.c
  18. 12
      src/core/security/security_context.c
  19. 17
      src/core/statistics/census_init.c
  20. 206
      src/core/statistics/census_rpc_stats.c
  21. 26
      src/core/statistics/census_rpc_stats.h
  22. 171
      src/core/statistics/census_tracing.c
  23. 59
      src/core/statistics/census_tracing.h
  24. 6
      src/core/statistics/hash_table.c
  25. 23
      src/core/support/log.c
  26. 24
      src/core/support/log_android.c
  27. 28
      src/core/support/log_linux.c
  28. 41
      src/core/support/log_posix.c
  29. 40
      src/core/support/log_win32.c
  30. 4
      src/core/support/time.c
  31. 29
      src/core/surface/lame_client.c
  32. 130
      src/core/transport/chttp2/stream_encoder.c
  33. 15
      src/core/transport/chttp2/stream_encoder.h
  34. 246
      src/core/transport/chttp2_transport.c
  35. 12
      src/cpp/client/channel.cc
  36. 37
      src/cpp/client/credentials.cc
  37. 2
      src/cpp/client/internal_stub.cc
  38. 2
      src/cpp/common/rpc_method.cc
  39. 2
      src/cpp/server/server.cc
  40. 2
      src/cpp/server/server_rpc_handler.cc
  41. 6
      src/cpp/stream/stream_context.cc
  42. 1
      test/core/end2end/gen_build_json.py
  43. 176
      test/core/end2end/tests/census_simple_request.c
  44. 6
      test/core/statistics/census_stub_test.c
  45. 14
      test/core/statistics/hash_table_test.c
  46. 197
      test/core/statistics/rpc_stats_test.c
  47. 184
      test/core/statistics/trace_test.c
  48. 12
      test/core/support/log_test.c
  49. 24
      test/core/transport/chttp2/stream_encoder_test.c
  50. 73
      test/cpp/client/credentials_test.cc
  51. 177
      test/cpp/end2end/end2end_test.cc
  52. 6
      test/cpp/end2end/sync_client_async_server_test.cc
  53. 163
      test/cpp/interop/client.cc
  54. 231
      test/cpp/interop/server.cc
  55. 20
      test/cpp/util/echo.proto
  56. 12
      test/cpp/util/echo_duplicate.proto
  57. 21
      test/cpp/util/messages.proto
  58. 6
      tools/buildgen/generate_projects.sh
  59. 3
      tools/dockerfile/grpc_ruby/Dockerfile
  60. 39
      tools/gce_setup/grpc_docker.sh
  61. 13
      tools/run_tests/jobset.py
  62. 2
      tools/run_tests/run_tests.py
  63. 14
      tools/run_tests/watch_dirs.py
  64. 1
      vsprojects/vs2013/grpc.vcxproj
  65. 1
      vsprojects/vs2013/grpc_unsecure.vcxproj

File diff suppressed because one or more lines are too long

@ -141,6 +141,7 @@
"src/core/statistics/census_interface.h",
"src/core/statistics/census_log.h",
"src/core/statistics/census_rpc_stats.h",
"src/core/statistics/census_tracing.h",
"src/core/statistics/hash_table.h",
"src/core/statistics/window_stats.h",
"src/core/surface/call.h",
@ -334,7 +335,7 @@
"src/cpp/client/credentials.cc",
"src/cpp/client/internal_stub.cc",
"src/cpp/proto/proto_utils.cc",
"src/cpp/rpc_method.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/server/async_server.cc",
"src/cpp/server/async_server_context.cc",
"src/cpp/server/completion_queue.cc",
@ -358,6 +359,9 @@
"include/grpc++/config.h",
"include/grpc++/create_channel.h",
"include/grpc++/credentials.h",
"include/grpc++/impl/internal_stub.h",
"include/grpc++/impl/rpc_method.h",
"include/grpc++/impl/rpc_service_method.h",
"include/grpc++/server_builder.h",
"include/grpc++/server_context.h",
"include/grpc++/server_credentials.h",
@ -368,10 +372,7 @@
],
"headers": [
"src/cpp/client/channel.h",
"src/cpp/client/internal_stub.h",
"src/cpp/proto/proto_utils.h",
"src/cpp/rpc_method.h",
"src/cpp/server/rpc_service_method.h",
"src/cpp/server/server_rpc_handler.h",
"src/cpp/server/thread_pool.h",
"src/cpp/stream/stream_context.h",
@ -385,7 +386,9 @@
"name": "grpc++_test_util",
"build": "test",
"src": [
"test/cpp/util/messages.proto",
"test/cpp/util/echo.proto",
"test/cpp/util/echo_duplicate.proto",
"test/cpp/util/create_test_channel.cc",
"test/cpp/end2end/async_test_server.cc"
],
@ -439,6 +442,24 @@
"deps": []
},
{
"name": "go_plugin",
"build": "protoc",
"c++": true,
"secure": false,
"src": [
"src/compiler/go_plugin.cpp",
"src/compiler/go_generator.cpp"
],
"headers": [
"src/compiler/go_generator.h",
"src/compiler/go_generator_helpers-inl.h",
"src/compiler/go_generator_map-inl.h",
"src/compiler/go_generator_string-inl.h"
],
"deps": []
},
{
"name": "grpc_byte_buffer_reader_test",
"build": "test",
@ -847,6 +868,30 @@
"gpr"
]
},
{
"name": "census_trace_store_test",
"build": "executable",
"src": [
"test/core/statistics/trace_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr"
]
},
{
"name": "census_stats_store_test",
"build": "executable",
"src": [
"test/core/statistics/rpc_stats_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr"
]
},
{
"name": "census_window_stats_test",
"build": "test",
@ -1323,6 +1368,7 @@
"test/cpp/end2end/end2end_test.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
@ -1341,6 +1387,18 @@
"grpc"
]
},
{
"name": "credentials_test",
"build": "test",
"c++": true,
"src": [
"test/cpp/client/credentials_test.cc"
],
"deps": [
"grpc++",
"grpc"
]
},
{
"name": "alarm_test",
"build": "test",

@ -46,6 +46,7 @@ class ChannelInterface;
std::shared_ptr<ChannelInterface> CreateChannel(const grpc::string& target,
const ChannelArguments& args);
// If creds does not hold an object or is invalid, a lame channel is returned.
std::shared_ptr<ChannelInterface> CreateChannel(
const grpc::string& target, const std::unique_ptr<Credentials>& creds,
const ChannelArguments& args);

@ -34,6 +34,7 @@
#ifndef __GRPCPP_CREDENTIALS_H_
#define __GRPCPP_CREDENTIALS_H_
#include <chrono>
#include <memory>
#include <grpc++/config.h>
@ -49,6 +50,7 @@ namespace grpc {
class Credentials final {
public:
~Credentials();
// TODO(abhikumar): Specify a plugin API here to be implemented by
// credentials that do not have a corresponding implementation in C.
@ -63,6 +65,15 @@ class Credentials final {
};
// Options used to build SslCredentials
// pem_roots_cert is the buffer containing the PEM encoding of the server root
// certificates. This parameter cannot be empty.
// pem_private_key is the buffer containing the PEM encoding of the client's
// private key. This parameter can be empty if the client does not have a
// private key.
// pem_cert_chain is the buffer containing the PEM encoding of the client's
// certificate chain. This parameter can be empty if the client does not have
// a certificate chain.
// TODO(jboeuf) Change it to point to a file.
struct SslCredentialsOptions {
grpc::string pem_root_certs;
grpc::string pem_private_key;
@ -70,6 +81,10 @@ struct SslCredentialsOptions {
};
// Factory for building different types of Credentials
// The methods may return empty unique_ptr when credentials cannot be created.
// If a Credentials pointer is returned, it can still be invalid when used to
// create a channel. A lame channel will be created then and all rpcs will
// fail on it.
class CredentialsFactory {
public:
// Builds credentials with reasonable defaults.
@ -82,6 +97,21 @@ class CredentialsFactory {
// Builds credentials for use when running in GCE
static std::unique_ptr<Credentials> ComputeEngineCredentials();
// Builds service account credentials.
// json_key is the JSON key string containing the client's private key.
// scope is a space-delimited list of the requested permissions.
// token_lifetime is the lifetime of each token acquired through this service
// account credentials. It should be positive and should not exceed
// grpc_max_auth_token_lifetime or will be cropped to this value.
static std::unique_ptr<Credentials> ServiceAccountCredentials(
const grpc::string& json_key, const grpc::string& scope,
std::chrono::seconds token_lifetime);
// Builds IAM credentials.
static std::unique_ptr<Credentials> IAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector);
// Combines two credentials objects into a composite credentials
static std::unique_ptr<Credentials> ComposeCredentials(

@ -31,8 +31,8 @@
*
*/
#ifndef __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
#define __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
#ifndef __GRPCPP_IMPL_INTERNAL_STUB_H__
#define __GRPCPP_IMPL_INTERNAL_STUB_H__
#include <memory>
@ -57,4 +57,4 @@ class InternalStub {
} // namespace grpc
#endif // __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
#endif // __GRPCPP_IMPL_INTERNAL_STUB_H__

@ -31,8 +31,8 @@
*
*/
#ifndef __GRPCPP_INTERNAL_RPC_METHOD_H__
#define __GRPCPP_INTERNAL_RPC_METHOD_H__
#ifndef __GRPCPP_IMPL_RPC_METHOD_H__
#define __GRPCPP_IMPL_RPC_METHOD_H__
namespace google {
namespace protobuf {
@ -55,15 +55,15 @@ class RpcMethod {
: name_(name), method_type_(NORMAL_RPC) {}
RpcMethod(const char* name, RpcType type) : name_(name), method_type_(type) {}
const char *name() const { return name_; }
const char* name() const { return name_; }
RpcType method_type() const { return method_type_; }
private:
const char *name_;
const char* name_;
const RpcType method_type_;
};
} // namespace grpc
#endif // __GRPCPP_INTERNAL_RPC_METHOD_H__
#endif // __GRPCPP_IMPL_RPC_METHOD_H__

@ -31,18 +31,18 @@
*
*/
#ifndef __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
#define __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
#ifndef __GRPCPP_IMPL_RPC_SERVICE_METHOD_H__
#define __GRPCPP_IMPL_RPC_SERVICE_METHOD_H__
#include <functional>
#include <map>
#include <memory>
#include <vector>
#include "src/cpp/rpc_method.h"
#include <google/protobuf/message.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include <google/protobuf/message.h>
namespace grpc {
class ServerContext;
@ -200,9 +200,7 @@ class RpcService {
methods_.push_back(std::unique_ptr<RpcServiceMethod>(method));
}
RpcServiceMethod* GetMethod(int i) {
return methods_[i].get();
}
RpcServiceMethod* GetMethod(int i) { return methods_[i].get(); }
int GetMethodCount() const { return methods_.size(); }
private:
@ -211,4 +209,4 @@ class RpcService {
} // namespace grpc
#endif // __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
#endif // __GRPCPP_IMPL_RPC_SERVICE_METHOD_H__

@ -72,9 +72,21 @@ const char *gpr_log_severity_string(gpr_log_severity severity);
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...);
/* Same as above, but using a va_list instead. */
void gpr_vlog(const char *file, int line, gpr_log_severity severity,
const char *format, va_list args);
void gpr_log_message(const char *file, int line, gpr_log_severity severity,
const char *message);
/* Log overrides: applications can use this API to intercept logging calls
and use their own implementations */
typedef struct {
const char *file;
int line;
gpr_log_severity severity;
const char *message;
} gpr_log_func_args;
typedef void (*gpr_log_func)(gpr_log_func_args *args);
void gpr_set_log_function(gpr_log_func func);
/* abort() the process if x is zero, having written a line to the log.

@ -127,7 +127,7 @@
#endif
#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) != 1
#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX
#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32
#endif
typedef int16_t gpr_int16;

@ -107,6 +107,8 @@ struct timeval gpr_timeval_from_timespec(gpr_timespec t);
gpr_timespec gpr_timespec_from_timeval(struct timeval t);
double gpr_timespec_to_micros(gpr_timespec t);
#ifdef __cplusplus
}
#endif

@ -53,8 +53,7 @@ bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
}
bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
return !method->client_streaming() &&
method->server_streaming();
return !method->client_streaming() && method->server_streaming();
}
bool BidiStreaming(const google::protobuf::MethodDescriptor* method) {
@ -98,7 +97,7 @@ bool HasBidiStreaming(const google::protobuf::FileDescriptor* file) {
string GetHeaderIncludes(const google::protobuf::FileDescriptor* file) {
string temp =
"#include \"src/cpp/client/internal_stub.h\"\n"
"#include \"grpc++/impl/internal_stub.h\"\n"
"#include \"grpc++/status.h\"\n"
"\n"
"namespace grpc {\n"
@ -126,9 +125,9 @@ string GetHeaderIncludes(const google::protobuf::FileDescriptor* file) {
}
string GetSourceIncludes() {
return "#include \"src/cpp/rpc_method.h\"\n"
"#include \"src/cpp/server/rpc_service_method.h\"\n"
"#include \"grpc++/channel_interface.h\"\n"
return "#include \"grpc++/channel_interface.h\"\n"
"#include \"grpc++/impl/rpc_method.h\"\n"
"#include \"grpc++/impl/rpc_service_method.h\"\n"
"#include \"grpc++/stream.h\"\n";
}

@ -0,0 +1,520 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using namespace std;
#include "src/compiler/go_generator.h"
#include <cctype>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
namespace grpc_go_generator {
bool NoStreaming(const google::protobuf::MethodDescriptor* method) {
return !method->client_streaming() &&
!method->server_streaming();
}
bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
return method->client_streaming() &&
!method->server_streaming();
}
bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
return !method->client_streaming() &&
method->server_streaming();
}
bool BidiStreaming(const google::protobuf::MethodDescriptor* method) {
return method->client_streaming() &&
method->server_streaming();
}
bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor* file) {
for (int i = 0; i < file->service_count(); i++) {
for (int j = 0; j < file->service(i)->method_count(); j++) {
if (ClientOnlyStreaming(file->service(i)->method(j))) {
return true;
}
}
}
return false;
}
string LowerCaseService(const string& service) {
string ret = service;
if (!ret.empty() && ret[0] >= 'A' && ret[0] <= 'Z') {
ret[0] = ret[0] - 'A' + 'a';
}
return ret;
}
void PrintClientMethodDef(google::protobuf::io::Printer* printer,
const google::protobuf::MethodDescriptor* method,
map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type()->name();
(*vars)["Response"] = method->output_type()->name();
if (NoStreaming(method)) {
printer->Print(*vars,
"\t$Method$(ctx context.Context, in *$Request$, opts ...rpc.CallOption) "
"(*$Response$, error)\n");
} else if (BidiStreaming(method)) {
printer->Print(*vars,
"\t$Method$(ctx context.Context, opts ...rpc.CallOption) "
"($Service$_$Method$Client, error)\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
"\t$Method$(ctx context.Context, m *$Request$, opts ...rpc.CallOption) "
"($Service$_$Method$Client, error)\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"\t$Method$(ctx context.Context, opts ...rpc.CallOption) "
"($Service$_$Method$Client, error)\n");
}
}
void PrintClientMethodImpl(google::protobuf::io::Printer* printer,
const google::protobuf::MethodDescriptor* method,
map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type()->name();
(*vars)["Response"] = method->output_type()->name();
if (NoStreaming(method)) {
printer->Print(*vars,
"func (c *$ServiceStruct$Client) $Method$(ctx context.Context, "
"in *$Request$, opts ...rpc.CallOption) (*$Response$, error) {\n");
printer->Print(*vars,
"\tout := new($Response$)\n");
printer->Print(*vars,
"\terr := rpc.Invoke(ctx, \"/$Package$$Service$/$Method$\", "
"in, out, c.cc, opts...)\n");
printer->Print("\tif err != nil {\n");
printer->Print("\t\treturn nil, err\n");
printer->Print("\t}\n");
printer->Print("\treturn out, nil\n");
printer->Print("}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
"func (c *$ServiceStruct$Client) $Method$(ctx context.Context, opts "
"...rpc.CallOption) ($Service$_$Method$Client, error) {\n"
"\tstream, err := rpc.NewClientStream(ctx, c.cc, "
"\"/$Package$$Service$/$Method$\", opts...)\n"
"\tif err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn &$ServiceStruct$$Method$Client{stream}, nil\n"
"}\n\n");
printer->Print(*vars,
"type $Service$_$Method$Client interface {\n"
"\tSend(*$Request$) error\n"
"\tRecv() (*$Response$, error)\n"
"\trpc.ClientStream\n"
"}\n\n");
printer->Print(*vars,
"type $ServiceStruct$$Method$Client struct {\n"
"\trpc.ClientStream\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Client) Send(m *$Request$) error {\n"
"\treturn x.ClientStream.SendProto(m)\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Client) Recv() (*$Response$, error) "
"{\n"
"\tm := new($Response$)\n"
"\tif err := x.ClientStream.RecvProto(m); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn m, nil\n"
"}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"func (c *$ServiceStruct$Client) $Method$(ctx context.Context, m "
"*$Request$, "
"opts ...rpc.CallOption) ($Service$_$Method$Client, error) {\n"
"\tstream, err := rpc.NewClientStream(ctx, c.cc, "
"\"/$Package$$Service$/$Method$\", opts...)\n"
"\tif err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\tx := &$ServiceStruct$$Method$Client{stream}\n"
"\tif err := x.ClientStream.SendProto(m); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\tif err := x.ClientStream.CloseSend(); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn x, nil\n"
"}\n\n");
printer->Print(*vars,
"type $Service$_$Method$Client interface {\n"
"\tRecv() (*$Response$, error)\n"
"\trpc.ClientStream\n"
"}\n\n");
printer->Print(*vars,
"type $ServiceStruct$$Method$Client struct {\n"
"\trpc.ClientStream\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Client) Recv() (*$Response$, error) "
"{\n"
"\tm := new($Response$)\n"
"\tif err := x.ClientStream.RecvProto(m); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn m, nil\n"
"}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
"func (c *$ServiceStruct$Client) $Method$(ctx context.Context, opts "
"...rpc.CallOption) ($Service$_$Method$Client, error) {\n"
"\tstream, err := rpc.NewClientStream(ctx, c.cc, "
"\"/$Package$$Service$/$Method$\", opts...)\n"
"\tif err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn &$ServiceStruct$$Method$Client{stream}, nil\n"
"}\n\n");
printer->Print(*vars,
"type $Service$_$Method$Client interface {\n"
"\tSend(*$Request$) error\n"
"\tCloseAndRecv() (*$Response$, error)\n"
"\trpc.ClientStream\n"
"}\n\n");
printer->Print(*vars,
"type $ServiceStruct$$Method$Client struct {\n"
"\trpc.ClientStream\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Client) Send(m *$Request$) error {\n"
"\treturn x.ClientStream.SendProto(m)\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Client) CloseAndRecv() (*$Response$, "
"error) {\n"
"\tif err := x.ClientStream.CloseSend(); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\tm := new($Response$)\n"
"\tif err := x.ClientStream.RecvProto(m); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\t// Read EOF.\n"
"\tif err := x.ClientStream.RecvProto(m); err == io.EOF {\n"
"\t\treturn m, io.EOF\n"
"\t}\n"
"\t// gRPC protocol violation.\n"
"\treturn m, fmt.Errorf(\"Violate gRPC client streaming protocol: no "
"EOF after the response.\")\n"
"}\n\n");
}
}
void PrintClient(google::protobuf::io::Printer* printer,
const google::protobuf::ServiceDescriptor* service,
map<string, string>* vars) {
(*vars)["Service"] = service->name();
(*vars)["ServiceStruct"] = LowerCaseService(service->name());
printer->Print(*vars, "type $Service$Client interface {\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintClientMethodDef(printer, service->method(i), vars);
}
printer->Print("}\n\n");
printer->Print(*vars,
"type $ServiceStruct$Client struct {\n"
"\tcc *rpc.ClientConn\n"
"}\n\n");
printer->Print(*vars,
"func New$Service$Client(cc *rpc.ClientConn) $Service$Client {\n"
"\treturn &$ServiceStruct$Client{cc}\n"
"}\n\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintClientMethodImpl(printer, service->method(i), vars);
}
}
void PrintServerMethodDef(google::protobuf::io::Printer* printer,
const google::protobuf::MethodDescriptor* method,
map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type()->name();
(*vars)["Response"] = method->output_type()->name();
if (NoStreaming(method)) {
printer->Print(*vars,
"\t$Method$(context.Context, *$Request$) (*$Response$, error)\n");
} else if (BidiStreaming(method)) {
printer->Print(*vars,
"\t$Method$($Service$_$Method$Server) error\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
"\t$Method$(*$Request$, $Service$_$Method$Server) error\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"\t$Method$($Service$_$Method$Server) error\n");
}
}
void PrintServerHandler(google::protobuf::io::Printer* printer,
const google::protobuf::MethodDescriptor* method,
map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type()->name();
(*vars)["Response"] = method->output_type()->name();
if (NoStreaming(method)) {
printer->Print(*vars,
"func _$Service$_$Method$_Handler(srv interface{}, ctx context.Context,"
" buf []byte) (proto.Message, error) {\n");
printer->Print(*vars,
"\tin := new($Request$)\n");
printer->Print("\tif err := proto.Unmarshal(buf, in); err != nil {\n");
printer->Print("\t\treturn nil, err\n");
printer->Print("\t}\n");
printer->Print(*vars,
"\tout, err := srv.($Service$Server).$Method$(ctx, in)\n");
printer->Print("\tif err != nil {\n");
printer->Print("\t\treturn nil, err\n");
printer->Print("\t}\n");
printer->Print("\treturn out, nil\n");
printer->Print("}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(*vars,
"func _$Service$_$Method$_Handler(srv interface{}, stream rpc.Stream) "
"error {\n"
"\treturn srv.($Service$Server).$Method$(&$ServiceStruct$$Method$Server"
"{stream})\n"
"}\n\n");
printer->Print(*vars,
"type $Service$_$Method$Server interface {\n"
"\tSend(*$Response$) error\n"
"\tRecv() (*$Request$, error)\n"
"\trpc.Stream\n"
"}\n\n");
printer->Print(*vars,
"type $ServiceStruct$$Method$Server struct {\n"
"\trpc.Stream\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Server) Send(m *$Response$) error {\n"
"\treturn x.Stream.SendProto(m)\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Server) Recv() (*$Request$, error) "
"{\n"
"\tm := new($Request$)\n"
"\tif err := x.Stream.RecvProto(m); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn m, nil\n"
"}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
"func _$Service$_$Method$_Handler(srv interface{}, stream rpc.Stream) "
"error {\n"
"\tm := new($Request$)\n"
"\tif err := stream.RecvProto(m); err != nil {\n"
"\t\treturn err\n"
"\t}\n"
"\treturn srv.($Service$Server).$Method$(m, "
"&$ServiceStruct$$Method$Server{stream})\n"
"}\n\n");
printer->Print(*vars,
"type $Service$_$Method$Server interface {\n"
"\tSend(*$Response$) error\n"
"\trpc.Stream\n"
"}\n\n");
printer->Print(*vars,
"type $ServiceStruct$$Method$Server struct {\n"
"\trpc.Stream\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Server) Send(m *$Response$) error {\n"
"\treturn x.Stream.SendProto(m)\n"
"}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"func _$Service$_$Method$_Handler(srv interface{}, stream rpc.Stream) "
"error {\n"
"\treturn srv.($Service$Server).$Method$(&$ServiceStruct$$Method$Server"
"{stream})\n"
"}\n\n");
printer->Print(*vars,
"type $Service$_$Method$Server interface {\n"
"\tSendAndClose(*$Response$) error\n"
"\tRecv() (*$Request$, error)\n"
"\trpc.Stream\n"
"}\n\n");
printer->Print(*vars,
"type $ServiceStruct$$Method$Server struct {\n"
"\trpc.Stream\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Server) SendAndClose(m *$Response$) "
"error {\n"
"\tif err := x.Stream.SendProto(m); err != nil {\n"
"\t\treturn err\n"
"\t}\n"
"\treturn nil\n"
"}\n\n");
printer->Print(*vars,
"func (x *$ServiceStruct$$Method$Server) Recv() (*$Request$, error) {\n"
"\tm := new($Request$)\n"
"\tif err := x.Stream.RecvProto(m); err != nil {\n"
"\t\treturn nil, err\n"
"\t}\n"
"\treturn m, nil\n"
"}\n\n");
}
}
void PrintServerMethodDesc(google::protobuf::io::Printer* printer,
const google::protobuf::MethodDescriptor* method,
map<string, string>* vars) {
(*vars)["Method"] = method->name();
printer->Print("\t\t{\n");
printer->Print(*vars,
"\t\t\tMethodName:\t\"$Method$\",\n");
printer->Print(*vars,
"\t\t\tHandler:\t_$Service$_$Method$_Handler,\n");
printer->Print("\t\t},\n");
}
void PrintServerStreamingMethodDesc(google::protobuf::io::Printer* printer,
const google::protobuf::MethodDescriptor* method,
map<string, string>* vars) {
(*vars)["Method"] = method->name();
printer->Print("\t\t{\n");
printer->Print(*vars,
"\t\t\tStreamName:\t\"$Method$\",\n");
printer->Print(*vars,
"\t\t\tHandler:\t_$Service$_$Method$_Handler,\n");
printer->Print("\t\t},\n");
}
void PrintServer(google::protobuf::io::Printer* printer,
const google::protobuf::ServiceDescriptor* service,
map<string, string>* vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars, "type $Service$Server interface {\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintServerMethodDef(printer, service->method(i), vars);
}
printer->Print("}\n\n");
printer->Print(*vars,
"func RegisterService(s *rpc.Server, srv $Service$Server) {\n"
"\ts.RegisterService(&_$Service$_serviceDesc, srv)\n"
"}\n\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintServerHandler(printer, service->method(i), vars);
}
printer->Print(*vars,
"var _$Service$_serviceDesc = rpc.ServiceDesc{\n"
"\tServiceName: \"$Package$$Service$\",\n"
"\tHandlerType: (*$Service$Server)(nil),\n"
"\tMethods: []rpc.MethodDesc{\n");
for (int i = 0; i < service->method_count(); ++i) {
if (NoStreaming(service->method(i))) {
PrintServerMethodDesc(printer, service->method(i), vars);
}
}
printer->Print("\t},\n");
printer->Print("\tStreams: []rpc.StreamDesc{\n");
for (int i = 0; i < service->method_count(); ++i) {
if (!NoStreaming(service->method(i))) {
PrintServerStreamingMethodDesc(printer, service->method(i), vars);
}
}
printer->Print("\t},\n"
"}\n\n");
}
std::string BadToUnderscore(std::string str) {
for (unsigned i = 0; i < str.size(); ++i) {
if (!std::isalnum(str[i])) {
str[i] = '_';
}
}
return str;
}
string GetServices(const google::protobuf::FileDescriptor* file) {
string output;
google::protobuf::io::StringOutputStream output_stream(&output);
google::protobuf::io::Printer printer(&output_stream, '$');
map<string, string> vars;
string package_name = !file->options().go_package().empty()
? file->options().go_package()
: file->package();
vars["PackageName"] = BadToUnderscore(package_name);
printer.Print(vars, "package $PackageName$\n\n");
printer.Print("import (\n");
if (HasClientOnlyStreaming(file)) {
printer.Print("\t\"fmt\"\n"
"\t\"io\"\n");
}
printer.Print(
"\t\"google/net/grpc/go/rpc\"\n"
"\tcontext \"google/third_party/golang/go_net/context/context\"\n"
"\tproto \"google/net/proto2/go/proto\"\n"
")\n\n");
// $Package$ is used to fully qualify method names.
vars["Package"] = file->package();
if (!file->package().empty()) {
vars["Package"].append(".");
}
for (int i = 0; i < file->service_count(); ++i) {
PrintClient(&printer, file->service(0), &vars);
printer.Print("\n");
PrintServer(&printer, file->service(0), &vars);
printer.Print("\n");
}
return output;
}
} // namespace grpc_go_generator

@ -0,0 +1,51 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NET_GRPC_COMPILER_GO_GENERATOR_H_
#define NET_GRPC_COMPILER_GO_GENERATOR_H_
#include <string>
namespace google {
namespace protobuf {
class FileDescriptor;
} // namespace protobuf
} // namespace google
namespace grpc_go_generator {
string GetServices(const google::protobuf::FileDescriptor* file);
} // namespace grpc_go_generator
#endif // NET_GRPC_COMPILER_GO_GENERATOR_H_

@ -0,0 +1,83 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// Generates go gRPC service interface out of Protobuf IDL.
//
// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto
// and net/proto2/compiler/public/plugin.h for more information on plugins.
#include <fstream>
#include <memory>
using namespace std;
#include "src/compiler/go_generator.h"
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.h>
class GoGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
public:
GoGrpcGenerator() {}
virtual ~GoGrpcGenerator() {}
virtual bool Generate(const google::protobuf::FileDescriptor* file,
const string& parameter,
google::protobuf::compiler::GeneratorContext* context,
string* error) const {
// Get output file name.
string file_name;
if (file->name().size() > 6 &&
file->name().find_last_of(".proto") == file->name().size() - 1) {
file_name = file->name().substr(0, file->name().size() - 6) +
"_grpc.pb.go";
} else {
*error = "Invalid proto file name. Proto file must end with .proto";
return false;
}
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
context->Open(file_name));
google::protobuf::io::CodedOutputStream coded_out(output.get());
string code = grpc_go_generator::GetServices(file);
coded_out.WriteRaw(code.data(), code.size());
return true;
}
};
int main(int argc, char* argv[]) {
GoGrpcGenerator generator;
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
}

@ -60,13 +60,11 @@ static void init_rpc_stats(census_rpc_stats* stats) {
stats->cnt = 1;
}
static double gpr_timespec_to_micros(gpr_timespec t) {
return t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
}
static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld,
channel_data* chand) {
if (op->data.metadata->key == chand->path_str) {
gpr_log(GPR_DEBUG,
(const char*)GPR_SLICE_START_PTR(op->data.metadata->value->slice));
census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR(
op->data.metadata->value->slice));
}
@ -78,7 +76,7 @@ static void client_call_op(grpc_call_element* elem,
channel_data* chand = elem->channel_data;
GPR_ASSERT(calld != NULL);
GPR_ASSERT(chand != NULL);
GPR_ASSERT((calld->op_id.upper != 0) && (calld->op_id.lower != 0));
GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
switch (op->type) {
case GRPC_SEND_METADATA:
extract_and_annotate_method_tag(op, calld, chand);
@ -99,7 +97,7 @@ static void server_call_op(grpc_call_element* elem,
channel_data* chand = elem->channel_data;
GPR_ASSERT(calld != NULL);
GPR_ASSERT(chand != NULL);
GPR_ASSERT((calld->op_id.upper != 0) && (calld->op_id.lower != 0));
GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
switch (op->type) {
case GRPC_RECV_METADATA:
extract_and_annotate_method_tag(op, calld, chand);
@ -171,7 +169,13 @@ static void init_channel_elem(grpc_channel_element* elem,
chand->path_str = grpc_mdstr_from_string(mdctx, ":path");
}
static void destroy_channel_elem(grpc_channel_element* elem) {}
static void destroy_channel_elem(grpc_channel_element* elem) {
channel_data* chand = elem->channel_data;
GPR_ASSERT(chand != NULL);
if (chand->path_str != NULL) {
grpc_mdstr_unref(chand->path_str);
}
}
const grpc_channel_filter grpc_client_census_filter = {
client_call_op, channel_op,

@ -289,12 +289,8 @@ static void accept_stream(void *user_data, grpc_transport *transport,
}
static void recv_error(channel_data *chand, call_data *calld, int line,
const char *fmt, ...) {
va_list a;
va_start(a, fmt);
gpr_vlog(__FILE__, line, GPR_LOG_SEVERITY_ERROR, fmt, a);
va_end(a);
const char *message) {
gpr_log_message(__FILE__, line, GPR_LOG_SEVERITY_ERROR, message);
if (chand->transport) {
grpc_transport_abort_stream(chand->transport,
@ -388,19 +384,23 @@ static void recv_batch(void *user_data, grpc_transport *transport,
case GRPC_OP_BEGIN_MESSAGE:
/* can't begin a message when we're still reading a message */
if (calld->reading_message) {
recv_error(chand, calld, __LINE__,
"Message terminated early; read %d bytes, expected %d",
calld->incoming_message.length,
calld->incoming_message_length);
char message[128];
sprintf(message,
"Message terminated early; read %d bytes, expected %d",
(int)calld->incoming_message.length,
(int)calld->incoming_message_length);
recv_error(chand, calld, __LINE__, message);
return;
}
/* stash away parameters, and prepare for incoming slices */
length = stream_op->data.begin_message.length;
if (length > calld->max_message_length) {
recv_error(
chand, calld, __LINE__,
char message[128];
sprintf(
message,
"Maximum message length of %d exceeded by a message of length %d",
calld->max_message_length, length);
recv_error(chand, calld, __LINE__, message);
} else if (length > 0) {
calld->reading_message = 1;
calld->incoming_message_length = length;
@ -423,10 +423,12 @@ static void recv_batch(void *user_data, grpc_transport *transport,
gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice);
if (calld->incoming_message.length > calld->incoming_message_length) {
/* if we got too many bytes, complain */
recv_error(chand, calld, __LINE__,
"Receiving message overflow; read %d bytes, expected %d",
calld->incoming_message.length,
calld->incoming_message_length);
char message[128];
sprintf(message,
"Receiving message overflow; read %d bytes, expected %d",
(int)calld->incoming_message.length,
(int)calld->incoming_message_length);
recv_error(chand, calld, __LINE__, message);
return;
} else if (calld->incoming_message.length ==
calld->incoming_message_length) {
@ -439,10 +441,11 @@ static void recv_batch(void *user_data, grpc_transport *transport,
final_state == GRPC_STREAM_CLOSED)) {
calld->got_read_close = 1;
if (calld->reading_message) {
recv_error(chand, calld, __LINE__,
"Last message truncated; read %d bytes, expected %d",
calld->incoming_message.length,
calld->incoming_message_length);
char message[128];
sprintf(message, "Last message truncated; read %d bytes, expected %d",
(int)calld->incoming_message.length,
(int)calld->incoming_message_length);
recv_error(chand, calld, __LINE__, message);
}
call_op.type = GRPC_RECV_HALF_CLOSE;
call_op.dir = GRPC_CALL_UP;

@ -32,13 +32,26 @@
*/
#include "src/core/channel/http_server_filter.h"
#include <string.h>
#include <grpc/support/log.h>
typedef struct call_data { int sent_status; } call_data;
typedef struct call_data {
int sent_status;
int seen_scheme;
int seen_method;
int seen_te_trailers;
} call_data;
typedef struct channel_data {
grpc_mdelem *te_trailers;
grpc_mdelem *status_md;
grpc_mdelem *method;
grpc_mdelem *http_scheme;
grpc_mdelem *https_scheme;
/* TODO(klempner): Remove this once we stop using it */
grpc_mdelem *grpc_scheme;
grpc_mdelem *content_type;
grpc_mdelem *status;
} channel_data;
/* used to silence 'variable not used' warnings */
@ -56,20 +69,54 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
ignore_unused(calld);
ignore_unused(channeld);
switch (op->type) {
case GRPC_RECV_METADATA:
/* check if it's a te: trailers header */
if (op->data.metadata == channeld->te_trailers) {
/* Check if it is one of the headers we care about. */
if (op->data.metadata == channeld->te_trailers ||
op->data.metadata == channeld->method ||
op->data.metadata == channeld->http_scheme ||
op->data.metadata == channeld->https_scheme ||
op->data.metadata == channeld->grpc_scheme ||
op->data.metadata == channeld->content_type) {
/* swallow it */
if (op->data.metadata == channeld->method) {
calld->seen_method = 1;
} else if (op->data.metadata->key == channeld->http_scheme->key) {
calld->seen_scheme = 1;
} else if (op->data.metadata == channeld->te_trailers) {
calld->seen_te_trailers = 1;
}
/* TODO(klempner): Track that we've seen all the headers we should
require */
grpc_mdelem_unref(op->data.metadata);
op->done_cb(op->user_data, GRPC_OP_OK);
} else if (op->data.metadata->key == channeld->te_trailers->key) {
gpr_log(GPR_ERROR, "Invalid te: header: '%s'",
} else if (op->data.metadata->key == channeld->content_type->key) {
if (strncmp(grpc_mdstr_as_c_string(op->data.metadata->value),
"application/grpc+", 17) == 0) {
/* Although the C implementation doesn't (currently) generate them,
any
custom +-suffix is explicitly valid. */
/* TODO(klempner): We should consider preallocating common values such
as +proto or +json, or at least stashing them if we see them. */
/* TODO(klempner): Should we be surfacing this to application code? */
} else {
/* TODO(klempner): We're currently allowing this, but we shouldn't
see it without a proxy so log for now. */
gpr_log(GPR_INFO, "Unexpected content-type %s",
channeld->content_type->key);
}
grpc_mdelem_unref(op->data.metadata);
op->done_cb(op->user_data, GRPC_OP_OK);
} else if (op->data.metadata->key == channeld->te_trailers->key ||
op->data.metadata->key == channeld->method->key ||
op->data.metadata->key == channeld->http_scheme->key ||
op->data.metadata->key == channeld->content_type->key) {
gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
grpc_mdstr_as_c_string(op->data.metadata->key),
grpc_mdstr_as_c_string(op->data.metadata->value));
/* swallow it */
/* swallow it and error everything out. */
/* TODO(klempner): We ought to generate more descriptive error messages
on the wire here. */
grpc_mdelem_unref(op->data.metadata);
op->done_cb(op->user_data, GRPC_OP_OK);
grpc_call_element_send_cancel(elem);
@ -78,14 +125,33 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
grpc_call_next_op(elem, op);
}
break;
case GRPC_RECV_END_OF_INITIAL_METADATA:
/* Have we seen the required http2 transport headers?
(:method, :scheme, content-type, with :path and :authority covered
at the channel level right now) */
if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers) {
grpc_call_next_op(elem, op);
} else {
if (!calld->seen_method) {
gpr_log(GPR_ERROR, "Missing :method header");
} else if (!calld->seen_scheme) {
gpr_log(GPR_ERROR, "Missing :scheme header");
} else if (!calld->seen_te_trailers) {
gpr_log(GPR_ERROR, "Missing te trailers header");
}
/* Error this call out */
op->done_cb(op->user_data, GRPC_OP_OK);
grpc_call_element_send_cancel(elem);
}
break;
case GRPC_SEND_START:
case GRPC_SEND_METADATA:
/* If we haven't sent status 200 yet, we need to so so because it needs to
come before any non : prefixed metadata. */
if (!calld->sent_status) {
calld->sent_status = 1;
/* status_md is reffed by grpc_call_element_send_metadata */
grpc_call_element_send_metadata(elem, channeld->status_md);
/* status is reffed by grpc_call_element_send_metadata */
grpc_call_element_send_metadata(elem, channeld->status);
}
grpc_call_next_op(elem, op);
break;
@ -124,6 +190,9 @@ static void init_call_elem(grpc_call_element *elem,
/* initialize members */
calld->sent_status = 0;
calld->seen_scheme = 0;
calld->seen_method = 0;
calld->seen_te_trailers = 0;
}
/* Destructor for call_data */
@ -151,7 +220,13 @@ static void init_channel_elem(grpc_channel_element *elem,
/* initialize members */
channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
channeld->status_md = grpc_mdelem_from_strings(mdctx, ":status", "200");
channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200");
channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST");
channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http");
channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
channeld->content_type =
grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
}
/* Destructor for channel data */
@ -160,7 +235,12 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_mdelem_unref(channeld->te_trailers);
grpc_mdelem_unref(channeld->status_md);
grpc_mdelem_unref(channeld->status);
grpc_mdelem_unref(channeld->method);
grpc_mdelem_unref(channeld->http_scheme);
grpc_mdelem_unref(channeld->https_scheme);
grpc_mdelem_unref(channeld->grpc_scheme);
grpc_mdelem_unref(channeld->content_type);
}
const grpc_channel_filter grpc_http_server_filter = {

@ -451,7 +451,7 @@ static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds,
grpc_security_status status = GRPC_SECURITY_OK;
size_t i = 0;
const char *secure_peer_name = target;
for (i = 0; i < args->num_args; i++) {
for (i = 0; args && i < args->num_args; i++) {
grpc_arg *arg = &args->args[i];
if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) &&
arg->type == GRPC_ARG_STRING) {
@ -492,12 +492,17 @@ static grpc_channel *grpc_channel_create_from_composite_creds(
return grpc_ssl_channel_create(
composite_creds, grpc_ssl_credentials_get_config(creds), target, args);
}
return NULL; /* TODO(ctiller): return lame channel. */
gpr_log(GPR_ERROR, "Credentials is insufficient to create a secure channel.");
return grpc_lame_client_channel_create();
}
grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
const char *target,
const grpc_channel_args *args) {
if (creds == NULL) {
gpr_log(GPR_ERROR, "No credentials to create a secure channel.");
return grpc_lame_client_channel_create();
}
if (grpc_credentials_has_request_metadata_only(creds)) {
gpr_log(GPR_ERROR,
"Credentials is insufficient to create a secure channel.");
@ -518,7 +523,8 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
return grpc_channel_create_from_composite_creds(creds, target, args);
} else {
gpr_log(GPR_ERROR,
"Unknown credentials type %s for creating a secure channel.");
"Unknown credentials type %s for creating a secure channel.",
creds->type);
return grpc_lame_client_channel_create();
}
}

@ -33,5 +33,18 @@
#include "src/core/statistics/census_interface.h"
void census_init() {}
void census_shutdown() {}
#include <grpc/support/log.h>
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/statistics/census_tracing.h"
void census_init() {
gpr_log(GPR_INFO, "Initialize census library.");
census_tracing_init();
census_stats_store_init();
}
void census_shutdown() {
gpr_log(GPR_INFO, "Shutdown census library.");
census_stats_store_shutdown();
census_tracing_shutdown();
}

@ -35,7 +35,85 @@
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/statistics/hash_table.h"
#include "src/core/statistics/census_tracing.h"
#include "src/core/statistics/window_stats.h"
#include "src/core/support/murmur_hash.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#define NUM_INTERVALS 3
#define MINUTE_INTERVAL 0
#define HOUR_INTERVAL 1
#define TOTAL_INTERVAL 2
/* for easier typing */
typedef census_per_method_rpc_stats per_method_stats;
/* Ensure mu is only initialized once. */
static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT;
/* Guards two stats stores. */
static gpr_mu g_mu;
static census_ht* g_client_stats_store = NULL;
static census_ht* g_server_stats_store = NULL;
static void init_mutex() { gpr_mu_init(&g_mu); }
static void init_mutex_once() {
gpr_once_init(&g_stats_store_mu_init, init_mutex);
}
static int cmp_str_keys(const void* k1, const void* k2) {
return strcmp((const char*)k1, (const char*)k2);
}
/* TODO(hongyu): replace it with cityhash64 */
static gpr_uint64 simple_hash(const void* k) {
size_t len = strlen(k);
gpr_uint64 higher = gpr_murmur_hash3((const char*)k, len / 2, 0);
return higher << 32 |
gpr_murmur_hash3((const char*)k + len / 2, len - len / 2, 0);
}
static void delete_stats(void* stats) {
census_window_stats_destroy((struct census_window_stats*)stats);
}
static void delete_key(void* key) { gpr_free(key); }
static const census_ht_option ht_opt = {
CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */,
simple_hash /* hash function */, cmp_str_keys /* key comparator */,
delete_stats /* data deleter */, delete_key /* key deleter */};
static void init_rpc_stats(void* stats) {
memset(stats, 0, sizeof(census_rpc_stats));
}
static void stat_add_proportion(double p, void* base, const void* addme) {
census_rpc_stats* b = (census_rpc_stats*)base;
census_rpc_stats* a = (census_rpc_stats*)addme;
b->cnt += p * a->cnt;
b->rpc_error_cnt += p * a->rpc_error_cnt;
b->app_error_cnt += p * a->app_error_cnt;
b->elapsed_time_ms += p * a->elapsed_time_ms;
b->api_request_bytes += p * a->api_request_bytes;
b->wire_request_bytes += p * a->wire_request_bytes;
b->api_response_bytes += p * a->api_response_bytes;
b->wire_response_bytes += p * a->wire_response_bytes;
}
static void stat_add(void* base, const void* addme) {
stat_add_proportion(1.0, base, addme);
}
static gpr_timespec min_hour_total_intervals[3] = {
{60, 0}, {3600, 0}, {36000000, 0}};
static const census_window_stats_stat_info window_stats_settings = {
sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion};
census_rpc_stats* census_rpc_stats_create_empty() {
census_rpc_stats* ret =
@ -44,14 +122,132 @@ census_rpc_stats* census_rpc_stats_create_empty() {
return ret;
}
void census_aggregated_rpc_stats_destroy(census_aggregated_rpc_stats* data) {}
void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats* data) {
int i = 0;
for (i = 0; i < data->num_entries; i++) {
if (data->stats[i].method != NULL) {
gpr_free((void*)data->stats[i].method);
}
}
if (data->stats != NULL) {
gpr_free(data->stats);
}
data->num_entries = 0;
data->stats = NULL;
}
static void record_stats(census_ht* store, census_op_id op_id,
const census_rpc_stats* stats) {
gpr_mu_lock(&g_mu);
if (store != NULL) {
trace_obj* trace = NULL;
census_internal_lock_trace_store();
trace = census_get_trace_obj_locked(op_id);
if (trace != NULL) {
const char* method_name = census_get_trace_method_name(trace);
struct census_window_stats* window_stats = NULL;
census_ht_key key;
key.ptr = (void*)method_name;
window_stats = census_ht_find(store, key);
census_internal_unlock_trace_store();
if (window_stats == NULL) {
window_stats = census_window_stats_create(3, min_hour_total_intervals,
30, &window_stats_settings);
key.ptr = gpr_strdup(key.ptr);
census_ht_insert(store, key, (void*)window_stats);
}
census_window_stats_add(window_stats, gpr_now(), stats);
} else {
census_internal_unlock_trace_store();
}
}
gpr_mu_unlock(&g_mu);
}
void census_record_rpc_client_stats(census_op_id op_id,
const census_rpc_stats* stats) {}
const census_rpc_stats* stats) {
record_stats(g_client_stats_store, op_id, stats);
}
void census_record_rpc_server_stats(census_op_id op_id,
const census_rpc_stats* stats) {}
const census_rpc_stats* stats) {
record_stats(g_server_stats_store, op_id, stats);
}
void census_get_server_stats(census_aggregated_rpc_stats* data) {}
/* Get stats from input stats store */
static void get_stats(census_ht* store, census_aggregated_rpc_stats* data) {
GPR_ASSERT(data != NULL);
if (data->num_entries != 0) {
census_aggregated_rpc_stats_set_empty(data);
}
gpr_mu_lock(&g_mu);
if (store != NULL) {
size_t n;
int i, j;
gpr_timespec now = gpr_now();
census_ht_kv* kv = census_ht_get_all_elements(store, &n);
if (kv != NULL) {
data->num_entries = n;
data->stats = (per_method_stats*)gpr_malloc(sizeof(per_method_stats) * n);
for (i = 0; i < n; i++) {
census_window_stats_sums sums[NUM_INTERVALS];
for (j = 0; j < NUM_INTERVALS; j++) {
sums[j].statistic = (void*)census_rpc_stats_create_empty();
}
data->stats[i].method = gpr_strdup(kv[i].k.ptr);
census_window_stats_get_sums(kv[i].v, now, sums);
data->stats[i].minute_stats =
*(census_rpc_stats*)sums[MINUTE_INTERVAL].statistic;
data->stats[i].hour_stats =
*(census_rpc_stats*)sums[HOUR_INTERVAL].statistic;
data->stats[i].total_stats =
*(census_rpc_stats*)sums[TOTAL_INTERVAL].statistic;
for (j = 0; j < NUM_INTERVALS; j++) {
gpr_free(sums[j].statistic);
}
}
gpr_free(kv);
}
}
gpr_mu_unlock(&g_mu);
}
void census_get_client_stats(census_aggregated_rpc_stats* data) {
get_stats(g_client_stats_store, data);
}
void census_get_server_stats(census_aggregated_rpc_stats* data) {
get_stats(g_server_stats_store, data);
}
void census_stats_store_init() {
gpr_log(GPR_INFO, "Initialize census stats store.");
init_mutex_once();
gpr_mu_lock(&g_mu);
if (g_client_stats_store == NULL && g_server_stats_store == NULL) {
g_client_stats_store = census_ht_create(&ht_opt);
g_server_stats_store = census_ht_create(&ht_opt);
} else {
gpr_log(GPR_ERROR, "Census stats store already initialized.");
}
gpr_mu_unlock(&g_mu);
}
void census_get_client_stats(census_aggregated_rpc_stats* data) {}
void census_stats_store_shutdown() {
gpr_log(GPR_INFO, "Shutdown census stats store.");
init_mutex_once();
gpr_mu_lock(&g_mu);
if (g_client_stats_store != NULL) {
census_ht_destroy(g_client_stats_store);
g_client_stats_store = NULL;
} else {
gpr_log(GPR_ERROR, "Census server stats store not initialized.");
}
if (g_server_stats_store != NULL) {
census_ht_destroy(g_server_stats_store);
g_server_stats_store = NULL;
} else {
gpr_log(GPR_ERROR, "Census client stats store not initialized.");
}
gpr_mu_unlock(&g_mu);
}

@ -37,6 +37,10 @@
#include "src/core/statistics/census_interface.h"
#include <grpc/support/port_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
struct census_rpc_stats {
gpr_uint64 cnt;
gpr_uint64 rpc_error_cnt;
@ -51,19 +55,20 @@ struct census_rpc_stats {
/* Creates an empty rpc stats object on heap. */
census_rpc_stats* census_rpc_stats_create_empty();
typedef struct census_per_service_per_method_rpc_stats {
const char* service;
typedef struct census_per_method_rpc_stats {
const char* method;
census_rpc_stats data;
} census_per_service_per_method_rpc_stats;
census_rpc_stats minute_stats; /* cumulative stats in the past minute */
census_rpc_stats hour_stats; /* cumulative stats in the past hour */
census_rpc_stats total_stats; /* cumulative stats from last gc */
} census_per_method_rpc_stats;
typedef struct census_aggregated_rpc_stats {
int num_entries;
census_per_service_per_method_rpc_stats* stats;
census_per_method_rpc_stats* stats;
} census_aggregated_rpc_stats;
/* Deletes aggregated data. */
void census_aggregated_rpc_stats_destroy(census_aggregated_rpc_stats* data);
/* Initializes an aggregated rpc stats object to an empty state. */
void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats* data);
/* Records client side stats of a rpc. */
void census_record_rpc_client_stats(census_op_id op_id,
@ -86,4 +91,11 @@ void census_get_server_stats(census_aggregated_rpc_stats* data_map);
DO NOT CALL from outside of grpc code. */
void census_get_client_stats(census_aggregated_rpc_stats* data_map);
void census_stats_store_init();
void census_stats_store_shutdown();
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_INTERNAL_STATISTICS_CENSUS_RPC_STATS_H__ */

@ -33,15 +33,174 @@
#include "src/core/statistics/census_interface.h"
#include <stdio.h>
#include <string.h>
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/statistics/hash_table.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
/* Struct for a trace annotation. */
typedef struct annotation {
gpr_timespec ts; /* timestamp of the annotation */
char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
struct annotation* next;
} annotation;
typedef struct trace_obj {
census_op_id id;
gpr_timespec ts;
census_rpc_stats rpc_stats;
char* method;
annotation* annotations;
} trace_obj;
static void trace_obj_destroy(trace_obj* obj) {
annotation* p = obj->annotations;
while (p != NULL) {
annotation* next = p->next;
gpr_free(p);
p = next;
}
gpr_free(obj->method);
gpr_free(obj);
}
static void delete_trace_obj(void* obj) { trace_obj_destroy((trace_obj*)obj); }
static const census_ht_option ht_opt = {
CENSUS_HT_UINT64 /* key type*/, 571 /* n_of_buckets */, NULL /* hash */,
NULL /* compare_keys */, delete_trace_obj /* delete data */,
NULL /* delete key */};
static gpr_once g_init_mutex_once = GPR_ONCE_INIT;
static gpr_mu g_mu; /* Guards following two static variables. */
static census_ht* g_trace_store = NULL;
static gpr_uint64 g_id = 0;
static census_ht_key op_id_as_key(census_op_id* id) {
return *(census_ht_key*)id;
}
static gpr_uint64 op_id_2_uint64(census_op_id* id) {
gpr_uint64 ret;
memcpy(&ret, id, sizeof(census_op_id));
return ret;
}
static void init_mutex() { gpr_mu_init(&g_mu); }
static void init_mutex_once() { gpr_once_init(&g_init_mutex_once, init_mutex); }
census_op_id census_tracing_start_op() {
census_op_id empty_op_id = {0, 0};
return empty_op_id;
gpr_mu_lock(&g_mu);
{
trace_obj* ret = (trace_obj*)gpr_malloc(sizeof(trace_obj));
memset(ret, 0, sizeof(trace_obj));
g_id++;
memcpy(&ret->id, &g_id, sizeof(census_op_id));
ret->rpc_stats.cnt = 1;
ret->ts = gpr_now();
census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void*)ret);
gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id);
gpr_mu_unlock(&g_mu);
return ret->id;
}
}
int census_add_method_tag(census_op_id op_id, const char* method) {
int ret = 0;
trace_obj* trace = NULL;
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace == NULL) {
ret = 1;
} else {
trace->method = gpr_strdup(method);
}
gpr_mu_unlock(&g_mu);
return ret;
}
int census_add_method_tag(census_op_id op_id, const char* method_name) {
return 0;
void census_tracing_print(census_op_id op_id, const char* anno_txt) {
trace_obj* trace = NULL;
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace != NULL) {
annotation* anno = gpr_malloc(sizeof(annotation));
anno->ts = gpr_now();
{
char* d = anno->txt;
const char* s = anno_txt;
int n = 0;
for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) {
*d++ = *s++;
}
*d = '\0';
}
anno->next = trace->annotations;
trace->annotations = anno;
}
gpr_mu_unlock(&g_mu);
}
void census_tracing_print(census_op_id op_id, const char* annotation) {}
void census_tracing_end_op(census_op_id op_id) {
trace_obj* trace = NULL;
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace != NULL) {
trace->rpc_stats.elapsed_time_ms =
gpr_timespec_to_micros(gpr_time_sub(gpr_now(), trace->ts));
gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us",
op_id_2_uint64(&op_id), trace->method,
trace->rpc_stats.elapsed_time_ms);
census_ht_erase(g_trace_store, op_id_as_key(&op_id));
}
gpr_mu_unlock(&g_mu);
}
void census_tracing_end_op(census_op_id op_id) {}
void census_tracing_init() {
gpr_log(GPR_INFO, "Initialize census trace store.");
init_mutex_once();
gpr_mu_lock(&g_mu);
if (g_trace_store == NULL) {
g_id = 1;
g_trace_store = census_ht_create(&ht_opt);
} else {
gpr_log(GPR_ERROR, "Census trace store already initialized.");
}
gpr_mu_unlock(&g_mu);
}
void census_tracing_shutdown() {
gpr_log(GPR_INFO, "Shutdown census trace store.");
gpr_mu_lock(&g_mu);
if (g_trace_store != NULL) {
census_ht_destroy(g_trace_store);
g_trace_store = NULL;
} else {
gpr_log(GPR_ERROR, "Census trace store is not initialized.");
}
gpr_mu_unlock(&g_mu);
}
void census_internal_lock_trace_store() { gpr_mu_lock(&g_mu); }
void census_internal_unlock_trace_store() { gpr_mu_unlock(&g_mu); }
trace_obj* census_get_trace_obj_locked(census_op_id op_id) {
if (g_trace_store == NULL) {
gpr_log(GPR_ERROR, "Census trace store is not initialized.");
return NULL;
}
return (trace_obj*)census_ht_find(g_trace_store, op_id_as_key(&op_id));
}
const char* census_get_trace_method_name(const trace_obj* trace) {
return (const char*)trace->method;
}

@ -0,0 +1,59 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_
#define __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_
/* Opaque structure for trace object */
typedef struct trace_obj trace_obj;
/* Initializes trace store. This function is thread safe. */
void census_tracing_init();
/* Shutsdown trace store. This function is thread safe. */
void census_tracing_shutdown();
/* Gets trace obj corresponding to the input op_id. Returns NULL if trace store
is not initialized or trace obj is not found. Requires trace store being
locked before calling this function. */
trace_obj* census_get_trace_obj_locked(census_op_id op_id);
/* The following two functions acquire and release the trace store global lock.
They are for census internal use only. */
void census_internal_lock_trace_store();
void census_internal_unlock_trace_store();
/* Gets method tag name associated with the input trace object. */
const char* census_get_trace_method_name(const trace_obj* trace);
#endif /* __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_ */

@ -141,10 +141,10 @@ static gpr_int32 find_bucket_idx(const census_ht* ht, census_ht_key key) {
static int keys_match(const census_ht_option* opt, const ht_entry* p,
const census_ht_key key) {
GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 ||
opt->key_type == CENSUS_HT_POINTER);
if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val;
if (opt->key_type == CENSUS_HT_POINTER)
return !opt->compare_keys((p->key).ptr, key.ptr);
return 0;
return !opt->compare_keys((p->key).ptr, key.ptr);
}
static entry_locator ht_find(const census_ht* ht, census_ht_key key) {

@ -34,6 +34,10 @@
#include <grpc/support/log.h>
#include <stdio.h>
#include <string.h>
extern void gpr_default_log(gpr_log_func_args *args);
static gpr_log_func g_log_func = gpr_default_log;
const char *gpr_log_severity_string(gpr_log_severity severity) {
switch (severity) {
@ -47,12 +51,15 @@ const char *gpr_log_severity_string(gpr_log_severity severity) {
return "UNKNOWN";
}
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...) {
va_list args;
va_start(args, format);
gpr_vlog(file, line, severity, format, args);
va_end(args);
void gpr_log_message(const char *file, int line, gpr_log_severity severity,
const char *message) {
gpr_log_func_args lfargs;
memset(&lfargs, 0, sizeof(lfargs));
lfargs.file = file;
lfargs.line = line;
lfargs.severity = severity;
lfargs.message = message;
g_log_func(&lfargs);
}
void gpr_set_log_function(gpr_log_func f) { g_log_func = f; }

@ -54,25 +54,31 @@ static android_LogPriority severity_to_log_priority(gpr_log_severity severity) {
return ANDROID_LOG_DEFAULT;
}
void gpr_vlog(const char *file, int line, gpr_log_severity severity,
const char *format, va_list args) {
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...) {
char *message = NULL;
va_list args;
va_start(args, format);
vasprintf(&message, format, args);
va_end(args);
gpr_log_message(file, line, severity, message);
free(message);
}
void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char *prefix = NULL;
char *suffix = NULL;
char *output = NULL;
final_slash = strrchr(file, '/');
final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
display_file = file;
else
display_file = final_slash + 1;
asprintf(&prefix, "%s:%d] ", display_file, line);
vasprintf(&suffix, format, args);
asprintf(&output, "%s%s", prefix, suffix);
asprintf(&prefix, "%s:%d] %s", display_file, args->line, args->message);
__android_log_write(severity_to_log_priority(severity), "GRPC", output);
__android_log_write(severity_to_log_priority(args->severity), "GRPC", output);
/* allocated by asprintf => use free, not gpr_free */
free(prefix);

@ -49,17 +49,27 @@
static long gettid() { return syscall(__NR_gettid); }
void gpr_vlog(const char *file, int line, gpr_log_severity severity,
const char *format, va_list args) {
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...) {
char *message = NULL;
va_list args;
va_start(args, format);
vasprintf(&message, format, args);
va_end(args);
gpr_log_message(file, line, severity, message);
free(message);
}
void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
struct tm tm;
final_slash = strrchr(file, '/');
final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
display_file = file;
display_file = args->file;
else
display_file = final_slash + 1;
@ -70,12 +80,10 @@ void gpr_vlog(const char *file, int line, gpr_log_severity severity,
strcpy(time_buffer, "error:strftime");
}
flockfile(stderr);
fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity),
time_buffer, (int)(now.tv_nsec), gettid(), display_file, line);
vfprintf(stderr, format, args);
fputc('\n', stderr);
funlockfile(stderr);
fprintf(stderr, "%s%s.%09d %7ld %s:%d] %s\n",
gpr_log_severity_string(args->severity), time_buffer,
(int)(now.tv_nsec), gettid(), display_file, args->line,
args->message);
}
#endif

@ -47,17 +47,40 @@
static long gettid() { return pthread_self(); }
void gpr_vlog(const char *file, int line, gpr_log_severity severity,
const char *format, va_list args) {
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...) {
char buf[64];
char *allocated = NULL;
char *message = NULL;
int ret;
va_list args;
va_start(args, format);
ret = vsnprintf(buf, format, args);
va_end(args);
if (ret < 0) {
message = NULL;
} else if (ret <= sizeof(buf) - 1) {
message = buf;
} else {
message = allocated = gpr_malloc(ret + 1);
va_start(args, format);
vsnprintf(message, format, args);
va_end(args);
}
gpr_log_message(file, line, severity, message);
gpr_free(allocated);
}
void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
struct tm tm;
final_slash = strrchr(file, '/');
final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
display_file = file;
display_file = args->file;
else
display_file = final_slash + 1;
@ -68,12 +91,10 @@ void gpr_vlog(const char *file, int line, gpr_log_severity severity,
strcpy(time_buffer, "error:strftime");
}
flockfile(stderr);
fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity),
time_buffer, (int)(now.tv_nsec), gettid(), display_file, line);
vfprintf(stderr, format, args);
fputc('\n', stderr);
funlockfile(stderr);
fprintf(stderr, "%s%s.%09d %7ld %s:%d] %s\n",
gpr_log_severity_string(args->severity), time_buffer,
(int)(now.tv_nsec), gettid(), display_file, args->line,
args->message);
}
#endif /* defined(GPR_POSIX_LOG) */

@ -39,12 +39,42 @@
#include <stdio.h>
#include <stdarg.h>
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *message) {
const char *message = NULL;
va_list args;
int ret;
/* Determine the length. */
va_start(args, format);
ret = _vscprintf(format, args);
va_end(args);
if (!(0 <= ret && ret < ~(size_t)0)) {
message = NULL;
} else {
/* Allocate a new buffer, with space for the NUL terminator. */
strp_buflen = (size_t)ret + 1;
message = gpr_malloc(strp_buflen);
/* Print to the buffer. */
va_start(args, format);
ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args);
va_end(args);
if (ret != strp_buflen - 1) {
/* This should never happen. */
gpr_free(message);
message = NULL;
}
}
gpr_log_message(file, line, severity, message);
gpr_free(message);
}
/* Simple starter implementation */
void gpr_vlog(const char *file, int line, gpr_log_severity severity,
const char *format, va_list args) {
fprintf(stderr, "%s %s:%d: ", gpr_log_severity_string(severity), file, line);
vfprintf(stderr, format, args);
fputc('\n', stderr);
void gpr_default_log(gpr_log_func_args *args) {
fprintf(stderr, "%s %s:%d: %s\n", gpr_log_severity_string(severity),
args->file, args->line, args->message);
}
#endif

@ -264,3 +264,7 @@ gpr_int32 gpr_time_to_millis(gpr_timespec t) {
return t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS;
}
}
double gpr_timespec_to_micros(gpr_timespec t) {
return t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
}

@ -33,6 +33,8 @@
#include "src/core/surface/lame_client.h"
#include <string.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/call.h"
@ -42,16 +44,28 @@
typedef struct { void *unused; } call_data;
typedef struct { void *unused; } channel_data;
typedef struct { grpc_mdelem *message; } channel_data;
static void do_nothing(void *data, grpc_op_error error) {}
static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
grpc_call_op *op) {
channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
switch (op->type) {
case GRPC_SEND_START:
case GRPC_SEND_START: {
grpc_call_op set_status_op;
grpc_mdelem_ref(channeld->message);
memset(&set_status_op, 0, sizeof(grpc_call_op));
set_status_op.dir = GRPC_CALL_UP;
set_status_op.type = GRPC_RECV_METADATA;
set_status_op.done_cb = do_nothing;
set_status_op.data.metadata = channeld->message;
grpc_call_recv_metadata(elem, &set_status_op);
grpc_call_recv_finish(elem, 1);
break;
}
case GRPC_SEND_METADATA:
grpc_mdelem_unref(op->data.metadata);
break;
@ -81,11 +95,20 @@ static void destroy_call_elem(grpc_call_element *elem) {}
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
channel_data *channeld = elem->channel_data;
GPR_ASSERT(is_first);
GPR_ASSERT(is_last);
channeld->message = grpc_mdelem_from_strings(mdctx, "grpc-message",
"Rpc sent on a lame channel.");
}
static void destroy_channel_elem(grpc_channel_element *elem) {}
static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_mdelem_unref(channeld->message);
}
static const grpc_channel_filter lame_filter = {
call_op, channel_op,

@ -68,8 +68,6 @@ typedef struct {
gpr_uint8 last_was_header;
/* output stream id */
gpr_uint32 stream_id;
/* number of flow controlled bytes written */
gpr_uint32 output_size;
gpr_slice_buffer *output;
} framer_state;
@ -464,49 +462,31 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
grpc_mdstr_unref(c->timeout_key_str);
}
gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
int eof, gpr_slice_buffer *output,
gpr_uint32 max_bytes, gpr_uint32 stream_id,
grpc_chttp2_hpack_compressor *compressor) {
framer_state st;
gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
gpr_uint32 max_flow_controlled_bytes,
grpc_stream_op_buffer *outops) {
gpr_slice slice;
grpc_stream_op *op;
gpr_uint32 max_take_size;
gpr_uint32 flow_controlled_bytes_taken = 0;
gpr_uint32 curop = 0;
gpr_uint32 nops = *ops_count;
gpr_uint8 *p;
GPR_ASSERT(stream_id != 0);
st.cur_frame_type = NONE;
st.last_was_header = 0;
st.stream_id = stream_id;
st.output = output;
st.output_size = 0;
while (curop < nops) {
GPR_ASSERT(st.output_size <= max_bytes);
op = &ops[curop];
while (curop < *inops_count) {
GPR_ASSERT(flow_controlled_bytes_taken <= max_flow_controlled_bytes);
op = &inops[curop];
switch (op->type) {
case GRPC_NO_OP:
/* skip */
curop++;
break;
case GRPC_OP_FLOW_CTL_CB:
op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
curop++;
break;
case GRPC_OP_METADATA:
hpack_enc(compressor, op->data.metadata, &st);
curop++;
break;
case GRPC_OP_DEADLINE:
deadline_enc(compressor, op->data.deadline, &st);
curop++;
break;
case GRPC_OP_METADATA:
case GRPC_OP_METADATA_BOUNDARY:
ensure_frame_type(&st, HEADER, 0);
finish_frame(&st, 1, 0);
st.last_was_header = 0; /* force a new header frame */
/* these just get copied as they don't impact the number of flow
controlled bytes */
grpc_sopb_append(outops, op, 1);
curop++;
break;
case GRPC_OP_BEGIN_MESSAGE:
@ -525,42 +505,100 @@ gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
case GRPC_OP_SLICE:
slice = op->data.slice;
if (!GPR_SLICE_LENGTH(slice)) {
/* skip zero length slices */
gpr_slice_unref(slice);
curop++;
break;
}
if (st.output_size == max_bytes) {
max_take_size = max_flow_controlled_bytes - flow_controlled_bytes_taken;
if (max_take_size == 0) {
goto exit_loop;
}
if (GPR_SLICE_LENGTH(slice) > max_take_size) {
slice = gpr_slice_split_head(&op->data.slice, max_take_size);
grpc_sopb_add_slice(outops, slice);
} else {
/* consume this op immediately */
grpc_sopb_append(outops, op, 1);
curop++;
}
flow_controlled_bytes_taken += GPR_SLICE_LENGTH(slice);
break;
}
}
exit_loop:
*inops_count -= curop;
memmove(inops, inops + curop, *inops_count * sizeof(grpc_stream_op));
return flow_controlled_bytes_taken;
}
void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
gpr_uint32 stream_id,
grpc_chttp2_hpack_compressor *compressor,
gpr_slice_buffer *output) {
framer_state st;
gpr_slice slice;
grpc_stream_op *op;
gpr_uint32 max_take_size;
gpr_uint32 curop = 0;
GPR_ASSERT(stream_id != 0);
st.cur_frame_type = NONE;
st.last_was_header = 0;
st.stream_id = stream_id;
st.output = output;
while (curop < ops_count) {
op = &ops[curop];
switch (op->type) {
case GRPC_NO_OP:
case GRPC_OP_BEGIN_MESSAGE:
gpr_log(
GPR_ERROR,
"These stream ops should be filtered out by grpc_chttp2_preencode");
abort();
case GRPC_OP_FLOW_CTL_CB:
op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
curop++;
break;
case GRPC_OP_METADATA:
hpack_enc(compressor, op->data.metadata, &st);
curop++;
break;
case GRPC_OP_DEADLINE:
deadline_enc(compressor, op->data.deadline, &st);
curop++;
break;
case GRPC_OP_METADATA_BOUNDARY:
ensure_frame_type(&st, HEADER, 0);
finish_frame(&st, 1, 0);
st.last_was_header = 0; /* force a new header frame */
curop++;
break;
case GRPC_OP_SLICE:
slice = op->data.slice;
if (st.cur_frame_type == DATA &&
st.output->length - st.output_length_at_start_of_frame ==
GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
finish_frame(&st, 0, 0);
}
ensure_frame_type(&st, DATA, 1);
max_take_size =
GPR_MIN(max_bytes - st.output_size,
GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
st.output_length_at_start_of_frame - st.output->length);
max_take_size = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
st.output_length_at_start_of_frame - st.output->length;
if (GPR_SLICE_LENGTH(slice) > max_take_size) {
slice = gpr_slice_split_head(&op->data.slice, max_take_size);
} else {
/* consume this op immediately */
curop++;
}
st.output_size += GPR_SLICE_LENGTH(slice);
gpr_slice_buffer_add(output, slice);
break;
}
}
exit_loop:
if (eof && st.cur_frame_type == NONE) {
begin_frame(&st, DATA);
}
finish_frame(&st, 1, eof && curop == nops);
nops -= curop;
*ops_count = nops;
memmove(ops, ops + curop, nops * sizeof(grpc_stream_op));
return st.output_size;
finish_frame(&st, 1, eof);
}

@ -78,9 +78,16 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
grpc_mdctx *mdctx);
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
int eof, gpr_slice_buffer *output,
gpr_uint32 max_bytes, gpr_uint32 stream_id,
grpc_chttp2_hpack_compressor *compressor);
/* select stream ops to be encoded, moving them from inops to outops, and
moving subsequent ops in inops forward in the queue */
gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
gpr_uint32 max_flow_controlled_bytes,
grpc_stream_op_buffer *outops);
/* encode stream ops to output */
void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
gpr_uint32 stream_id,
grpc_chttp2_hpack_compressor *compressor,
gpr_slice_buffer *output);
#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_ENCODER_H__ */

@ -71,6 +71,13 @@ typedef struct stream stream;
typedef enum {
/* streams that have pending writes */
WRITABLE = 0,
/* streams that have been selected to be written */
WRITING,
/* streams that have just been written, and included a close */
WRITTEN_CLOSED,
/* streams that have been cancelled and have some pending state updates
to perform */
CANCELLED,
/* streams that want to send window updates */
WINDOW_UPDATE,
/* streams that are waiting to start because there are too many concurrent
@ -258,7 +265,12 @@ struct stream {
gpr_uint32 outgoing_window;
gpr_uint32 incoming_window;
gpr_uint8 write_closed;
/* when the application requests writes be closed, the write_closed is
'queued'; when the close is flow controlled into the send path, we are
'sending' it; when the write has been performed it is 'sent' */
gpr_uint8 queued_write_closed;
gpr_uint8 sending_write_closed;
gpr_uint8 sent_write_closed;
gpr_uint8 read_closed;
gpr_uint8 cancelled;
gpr_uint8 allow_window_updates;
@ -267,7 +279,10 @@ struct stream {
stream_link links[STREAM_LIST_COUNT];
gpr_uint8 included[STREAM_LIST_COUNT];
/* sops from application */
grpc_stream_op_buffer outgoing_sopb;
/* sops that have passed flow control to be written */
grpc_stream_op_buffer writing_sopb;
grpc_chttp2_data_parser parser;
@ -284,7 +299,7 @@ static int prepare_callbacks(transport *t);
static void run_callbacks(transport *t);
static int prepare_write(transport *t);
static void finish_write(void *t, grpc_endpoint_cb_status status);
static void perform_write(transport *t, grpc_endpoint *ep);
static void lock(transport *t);
static void unlock(transport *t);
@ -303,6 +318,7 @@ static void cancel_stream_id(transport *t, gpr_uint32 id,
static void cancel_stream(transport *t, stream *s,
grpc_status_code local_status,
grpc_chttp2_error_code error_code, int send_rst);
static void finalize_cancellations(transport *t);
static stream *lookup_stream(transport *t, gpr_uint32 id);
static void remove_from_stream_map(transport *t, stream *s);
static void maybe_start_some_streams(transport *t);
@ -518,7 +534,9 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
s->incoming_window =
t->settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
s->write_closed = 0;
s->queued_write_closed = 0;
s->sending_write_closed = 0;
s->sent_write_closed = 0;
s->read_closed = 0;
s->cancelled = 0;
s->allow_window_updates = 0;
@ -526,8 +544,9 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
memset(&s->links, 0, sizeof(s->links));
memset(&s->included, 0, sizeof(s->included));
grpc_sopb_init(&s->outgoing_sopb);
grpc_chttp2_data_parser_init(&s->parser);
grpc_sopb_init(&s->writing_sopb);
grpc_sopb_init(&s->callback_sopb);
grpc_chttp2_data_parser_init(&s->parser);
if (!server_data) {
unlock(t);
@ -565,8 +584,9 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
gpr_mu_unlock(&t->mu);
grpc_sopb_destroy(&s->outgoing_sopb);
grpc_chttp2_data_parser_destroy(&s->parser);
grpc_sopb_destroy(&s->writing_sopb);
grpc_sopb_destroy(&s->callback_sopb);
grpc_chttp2_data_parser_destroy(&s->parser);
unref_transport(t);
}
@ -575,6 +595,10 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
* LIST MANAGEMENT
*/
static int stream_list_empty(transport *t, stream_list_id id) {
return t->lists[id].head == NULL;
}
static stream *stream_list_remove_head(transport *t, stream_list_id id) {
stream *s = t->lists[id].head;
if (s) {
@ -666,6 +690,10 @@ static void unlock(transport *t) {
}
}
if (!t->writing) {
finalize_cancellations(t);
}
/* gather any callbacks that need to be made */
if (!t->calling_back && t->cb) {
perform_callbacks = prepare_callbacks(t);
@ -709,53 +737,9 @@ static void unlock(transport *t) {
}
/* write some bytes if necessary */
while (start_write) {
switch (grpc_endpoint_write(ep, t->outbuf.slices, t->outbuf.count,
finish_write, t)) {
case GRPC_ENDPOINT_WRITE_DONE:
/* grab the lock directly without wrappers since we just want to
continue writes if we loop: no need to check read callbacks again */
gpr_mu_lock(&t->mu);
t->outbuf.count = 0;
t->outbuf.length = 0;
t->writing = start_write = prepare_write(t);
if (!start_write) {
if (!t->reading) {
grpc_endpoint_destroy(t->ep);
t->ep = NULL;
gpr_cv_broadcast(&t->cv);
/* endpoint ref: safe because we'll still have the ref for write */
unref_transport(t);
}
}
gpr_mu_unlock(&t->mu);
if (!start_write) {
unref_transport(t);
}
break;
case GRPC_ENDPOINT_WRITE_ERROR:
start_write = 0;
/* use the wrapper lock/unlock here as we drop_connection, causing
read callbacks to be queued (which will be cleared during unlock) */
lock(t);
t->outbuf.count = 0;
t->outbuf.length = 0;
t->writing = 0;
drop_connection(t);
if (!t->reading) {
grpc_endpoint_destroy(t->ep);
t->ep = NULL;
gpr_cv_broadcast(&t->cv);
/* endpoint ref: safe because we'll still have the ref for write */
unref_transport(t);
}
unlock(t);
unref_transport(t);
break;
case GRPC_ENDPOINT_WRITE_PENDING:
start_write = 0;
break;
}
if (start_write) {
/* ultimately calls unref_transport(t); and clears t->writing */
perform_write(t, ep);
}
if (perform_callbacks || call_closed || num_goaways) {
@ -788,32 +772,10 @@ static void push_setting(transport *t, grpc_chttp2_setting_id id,
}
}
static void finish_write(void *tp, grpc_endpoint_cb_status error) {
transport *t = tp;
lock(t);
if (error != GRPC_ENDPOINT_CB_OK) {
drop_connection(t);
}
t->outbuf.count = 0;
t->outbuf.length = 0;
/* leave the writing flag up on shutdown to prevent further writes in unlock()
from starting */
t->writing = 0;
if (!t->reading) {
grpc_endpoint_destroy(t->ep);
t->ep = NULL;
gpr_cv_broadcast(&t->cv);
unref_transport(t); /* safe because we'll still have the ref for write */
}
unlock(t);
unref_transport(t);
}
static int prepare_write(transport *t) {
stream *s;
gpr_slice_buffer tempbuf;
gpr_uint32 window_delta;
/* simple writes are queued to qbuf, and flushed here */
tempbuf = t->qbuf;
@ -834,17 +796,16 @@ static int prepare_write(transport *t) {
/* for each stream that's become writable, frame it's data (according to
available window sizes) and add to the output buffer */
while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE))) {
gpr_uint32 written = grpc_chttp2_encode_some(
s->outgoing_sopb.ops, &s->outgoing_sopb.nops, s->write_closed,
&t->outbuf, GPR_MIN(t->outgoing_window, s->outgoing_window), s->id,
&t->hpack_compressor);
t->outgoing_window -= written;
s->outgoing_window -= written;
/* if there are no more writes to do and writes are closed, we need to
queue a callback to let the application know */
if (s->write_closed && s->outgoing_sopb.nops == 0) {
stream_list_join(t, s, PENDING_CALLBACKS);
window_delta = grpc_chttp2_preencode(
s->outgoing_sopb.ops, &s->outgoing_sopb.nops,
GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb);
t->outgoing_window -= window_delta;
s->outgoing_window -= window_delta;
s->sending_write_closed =
s->queued_write_closed && s->outgoing_sopb.nops == 0;
if (s->writing_sopb.nops > 0 || s->sending_write_closed) {
stream_list_join(t, s, WRITING);
}
/* if there are still writes to do and the stream still has window
@ -857,25 +818,89 @@ static int prepare_write(transport *t) {
/* for each stream that wants to update its window, add that window here */
while ((s = stream_list_remove_head(t, WINDOW_UPDATE))) {
gpr_uint32 window_add =
window_delta =
t->settings[LOCAL_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] -
s->incoming_window;
if (!s->read_closed && window_add) {
gpr_slice_buffer_add(&t->outbuf,
grpc_chttp2_window_update_create(s->id, window_add));
s->incoming_window += window_add;
if (!s->read_closed && window_delta) {
gpr_slice_buffer_add(
&t->outbuf, grpc_chttp2_window_update_create(s->id, window_delta));
s->incoming_window += window_delta;
}
}
/* if the transport is ready to send a window update, do so here also */
if (t->incoming_window < t->connection_window_target * 3 / 4) {
gpr_uint32 window_add = t->connection_window_target - t->incoming_window;
window_delta = t->connection_window_target - t->incoming_window;
gpr_slice_buffer_add(&t->outbuf,
grpc_chttp2_window_update_create(0, window_add));
t->incoming_window += window_add;
grpc_chttp2_window_update_create(0, window_delta));
t->incoming_window += window_delta;
}
return t->outbuf.length > 0;
return t->outbuf.length > 0 || !stream_list_empty(t, WRITING);
}
static void finalize_outbuf(transport *t) {
stream *s;
while ((s = stream_list_remove_head(t, WRITING))) {
grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops,
s->sending_write_closed, s->id, &t->hpack_compressor,
&t->outbuf);
s->writing_sopb.nops = 0;
if (s->sending_write_closed) {
stream_list_join(t, s, WRITTEN_CLOSED);
}
}
}
static void finish_write_common(transport *t, int success) {
stream *s;
lock(t);
if (!success) {
drop_connection(t);
}
while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) {
s->sent_write_closed = 1;
stream_list_join(t, s, PENDING_CALLBACKS);
}
t->outbuf.count = 0;
t->outbuf.length = 0;
/* leave the writing flag up on shutdown to prevent further writes in unlock()
from starting */
t->writing = 0;
if (!t->reading) {
grpc_endpoint_destroy(t->ep);
t->ep = NULL;
gpr_cv_broadcast(&t->cv);
unref_transport(t); /* safe because we'll still have the ref for write */
}
unlock(t);
unref_transport(t);
}
static void finish_write(void *tp, grpc_endpoint_cb_status error) {
transport *t = tp;
finish_write_common(t, error == GRPC_ENDPOINT_CB_OK);
}
static void perform_write(transport *t, grpc_endpoint *ep) {
finalize_outbuf(t);
GPR_ASSERT(t->outbuf.count > 0);
switch (grpc_endpoint_write(ep, t->outbuf.slices, t->outbuf.count,
finish_write, t)) {
case GRPC_ENDPOINT_WRITE_DONE:
finish_write_common(t, 1);
break;
case GRPC_ENDPOINT_WRITE_ERROR:
finish_write_common(t, 0);
break;
case GRPC_ENDPOINT_WRITE_PENDING:
break;
}
}
static void maybe_start_some_streams(transport *t) {
@ -901,19 +926,14 @@ static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops,
lock(t);
if (is_last) {
s->write_closed = 1;
s->queued_write_closed = 1;
}
if (!s->cancelled) {
grpc_sopb_append(&s->outgoing_sopb, ops, ops_count);
if (is_last && s->outgoing_sopb.nops == 0) {
if (s->id != 0) {
gpr_slice_buffer_add(&t->qbuf,
grpc_chttp2_data_frame_create_empty_close(s->id));
}
} else if (s->id == 0) {
if (s->id == 0) {
stream_list_join(t, s, WAITING_FOR_CONCURRENCY);
maybe_start_some_streams(t);
} else if (s->outgoing_window) {
} else {
stream_list_join(t, s, WRITABLE);
}
} else {
@ -967,12 +987,22 @@ static void send_ping(grpc_transport *gt, void (*cb)(void *user_data),
* INPUT PROCESSING
*/
static void finalize_cancellations(transport *t) {
stream *s;
while ((s = stream_list_remove_head(t, CANCELLED))) {
s->read_closed = 1;
s->sent_write_closed = 1;
stream_list_join(t, s, PENDING_CALLBACKS);
}
}
static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
grpc_status_code local_status,
grpc_chttp2_error_code error_code,
int send_rst) {
char buffer[32];
int had_outgoing;
char buffer[32];
if (s) {
/* clear out any unreported input & output: nobody cares anymore */
@ -981,10 +1011,9 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
grpc_sopb_reset(&s->outgoing_sopb);
if (s->cancelled) {
send_rst = 0;
} else if (!s->read_closed || !s->write_closed || had_outgoing) {
} else if (!s->read_closed || !s->sent_write_closed || had_outgoing) {
s->cancelled = 1;
s->read_closed = 1;
s->write_closed = 1;
stream_list_join(t, s, CANCELLED);
sprintf(buffer, "%d", local_status);
grpc_sopb_add_metadata(
@ -1667,8 +1696,7 @@ static int prepare_callbacks(transport *t) {
s->parser.incoming_sopb = s->callback_sopb;
s->callback_sopb = temp_sopb;
s->callback_state = compute_state(
s->write_closed && s->outgoing_sopb.nops == 0, s->read_closed);
s->callback_state = compute_state(s->sent_write_closed, s->read_closed);
if (s->callback_state == GRPC_STREAM_CLOSED) {
remove_from_stream_map(t, s);
if (s->published_close) {

@ -41,13 +41,13 @@
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include "src/cpp/rpc_method.h"
#include "src/cpp/proto/proto_utils.h"
#include "src/cpp/stream/stream_context.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h>
#include <grpc++/config.h>
#include <grpc++/credentials.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <google/protobuf/message.h>
@ -69,8 +69,9 @@ Channel::Channel(const grpc::string& target,
: args.GetSslTargetNameOverride()) {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
grpc_credentials* c_creds = creds ? creds->GetRawCreds() : nullptr;
c_channel_ = grpc_secure_channel_create(
creds->GetRawCreds(), target.c_str(),
c_creds, target.c_str(),
channel_args.num_args > 0 ? &channel_args : nullptr);
}
@ -118,10 +119,15 @@ Status Channel::StartBlockingRpc(const RpcMethod& method,
finished_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
ev = grpc_completion_queue_pluck(cq, invoke_tag, gpr_inf_future);
bool success = ev->data.invoke_accepted == GRPC_OP_OK;
grpc_event_finish(ev);
if (!success) {
GetFinalStatus(cq, finished_tag, &status);
return status;
}
// write request
grpc_byte_buffer* write_buffer = nullptr;
bool success = SerializeProto(request, &write_buffer);
success = SerializeProto(request, &write_buffer);
if (!success) {
grpc_call_cancel(call);
status =

@ -35,6 +35,7 @@
#include <string>
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
#include <grpc++/credentials.h>
@ -58,6 +59,9 @@ std::unique_ptr<Credentials> CredentialsFactory::SslCredentials(
options.pem_root_certs.empty() ? nullptr
: reinterpret_cast<const unsigned char*>(
options.pem_root_certs.c_str());
if (pem_root_certs == nullptr) {
return std::unique_ptr<Credentials>();
}
const unsigned char* pem_private_key =
options.pem_private_key.empty() ? nullptr
: reinterpret_cast<const unsigned char*>(
@ -71,14 +75,40 @@ std::unique_ptr<Credentials> CredentialsFactory::SslCredentials(
pem_root_certs, options.pem_root_certs.size(), pem_private_key,
options.pem_private_key.size(), pem_cert_chain,
options.pem_cert_chain.size());
std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
std::unique_ptr<Credentials> cpp_creds(
c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
// Builds credentials for use when running in GCE
std::unique_ptr<Credentials> CredentialsFactory::ComputeEngineCredentials() {
grpc_credentials* c_creds = grpc_compute_engine_credentials_create();
std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
std::unique_ptr<Credentials> cpp_creds(
c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
// Builds service account credentials.
std::unique_ptr<Credentials> CredentialsFactory::ServiceAccountCredentials(
const grpc::string& json_key, const grpc::string& scope,
std::chrono::seconds token_lifetime) {
gpr_timespec lifetime = gpr_time_from_seconds(
token_lifetime.count() > 0 ? token_lifetime.count() : 0);
grpc_credentials* c_creds = grpc_service_account_credentials_create(
json_key.c_str(), scope.c_str(), lifetime);
std::unique_ptr<Credentials> cpp_creds(
c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
// Builds IAM credentials.
std::unique_ptr<Credentials> CredentialsFactory::IAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector) {
grpc_credentials* c_creds = grpc_iam_credentials_create(
authorization_token.c_str(), authority_selector.c_str());
std::unique_ptr<Credentials> cpp_creds(
c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
@ -93,7 +123,8 @@ std::unique_ptr<Credentials> CredentialsFactory::ComposeCredentials(
// refcounts incremented.
grpc_credentials* c_creds = grpc_composite_credentials_create(
creds1->GetRawCreds(), creds2->GetRawCreds());
std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
std::unique_ptr<Credentials> cpp_creds(
c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}

@ -31,6 +31,6 @@
*
*/
#include "src/cpp/client/internal_stub.h"
#include <grpc++/impl/internal_stub.h>
namespace grpc {} // namespace grpc

@ -31,6 +31,6 @@
*
*/
#include "src/cpp/rpc_method.h"
#include <grpc++/impl/rpc_method.h>
namespace grpc {} // namespace grpc

@ -37,11 +37,11 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
#include "src/cpp/server/rpc_service_method.h"
#include "src/cpp/server/server_rpc_handler.h"
#include "src/cpp/server/thread_pool.h"
#include <grpc++/async_server_context.h>
#include <grpc++/completion_queue.h>
#include <grpc++/impl/rpc_service_method.h>
#include <grpc++/server_credentials.h>
namespace grpc {

@ -34,10 +34,10 @@
#include "src/cpp/server/server_rpc_handler.h"
#include <grpc/support/log.h>
#include "src/cpp/server/rpc_service_method.h"
#include "src/cpp/server/server_context_impl.h"
#include "src/cpp/stream/stream_context.h"
#include <grpc++/async_server_context.h>
#include <grpc++/impl/rpc_service_method.h>
namespace grpc {

@ -34,11 +34,11 @@
#include "src/cpp/stream/stream_context.h"
#include <grpc/support/log.h>
#include "src/cpp/rpc_method.h"
#include "src/cpp/proto/proto_utils.h"
#include "src/cpp/util/time.h"
#include <grpc++/client_context.h>
#include <grpc++/config.h>
#include <grpc++/impl/rpc_method.h>
#include <google/protobuf/message.h>
namespace grpc {
@ -85,6 +85,10 @@ void StreamContext::Start(bool buffered) {
GPR_ASSERT(GRPC_CALL_OK == error);
grpc_event* invoke_ev =
grpc_completion_queue_pluck(cq(), invoke_tag(), gpr_inf_future);
if (invoke_ev->data.invoke_accepted != GRPC_OP_OK) {
peer_halfclosed_ = true;
self_halfclosed_ = true;
}
grpc_event_finish(invoke_ev);
} else {
// TODO(yangg) metadata needs to be added before accept

@ -21,6 +21,7 @@ END2END_TESTS = [
'cancel_after_invoke',
'cancel_before_invoke',
'cancel_in_a_vacuum',
'census_simple_request',
'disappearing_server',
'early_server_shutdown_finishes_inflight_calls',
'early_server_shutdown_finishes_tags',

@ -0,0 +1,176 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "test/core/end2end/cq_verifier.h"
static gpr_timespec n_seconds_time(int n) {
return gpr_time_add(gpr_now(), gpr_time_from_micros(GPR_US_PER_SEC * n));
}
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char *test_name,
grpc_channel_args *client_args,
grpc_channel_args *server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args);
return f;
}
static void shutdown_server(grpc_end2end_test_fixture *f) {
if (!f->server) return;
grpc_server_shutdown(f->server);
grpc_server_destroy(f->server);
f->server = NULL;
}
static void shutdown_client(grpc_end2end_test_fixture *f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = NULL;
}
static void drain_cq(grpc_completion_queue *cq) {
grpc_event *ev;
grpc_completion_type type;
do {
ev = grpc_completion_queue_next(cq, n_seconds_time(5));
GPR_ASSERT(ev);
type = ev->type;
grpc_event_finish(ev);
} while (type != GRPC_QUEUE_SHUTDOWN);
}
static void end_test(grpc_end2end_test_fixture *f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->server_cq);
drain_cq(f->server_cq);
grpc_completion_queue_destroy(f->server_cq);
grpc_completion_queue_shutdown(f->client_cq);
drain_cq(f->client_cq);
grpc_completion_queue_destroy(f->client_cq);
}
static void *tag(gpr_intptr t) { return (void *)t; }
static void test_body(grpc_end2end_test_fixture f) {
grpc_call *c;
grpc_call *s;
gpr_timespec deadline = n_seconds_time(10);
cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq);
c = grpc_channel_create_call(f.client, "/foo", "test.google.com", deadline);
GPR_ASSERT(c);
tag(1);
GPR_ASSERT(GRPC_CALL_OK ==
grpc_call_start_invoke(c, f.client_cq, tag(1), tag(2), tag(3), 0));
cq_expect_invoke_accepted(v_client, tag(1), GRPC_OP_OK);
cq_verify(v_client);
GPR_ASSERT(GRPC_CALL_OK == grpc_call_writes_done(c, tag(4)));
cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK);
cq_verify(v_client);
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, tag(100)));
cq_expect_server_rpc_new(v_server, &s, tag(100), "/foo", "test.google.com",
deadline, NULL);
cq_verify(v_server);
GPR_ASSERT(GRPC_CALL_OK == grpc_call_accept(s, f.server_cq, tag(102), 0));
cq_expect_client_metadata_read(v_client, tag(2), NULL);
cq_verify(v_client);
GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_write_status(
s, GRPC_STATUS_UNIMPLEMENTED, "xyz", tag(5)));
cq_expect_finished_with_status(v_client, tag(3), GRPC_STATUS_UNIMPLEMENTED,
"xyz", NULL);
cq_verify(v_client);
cq_expect_finish_accepted(v_server, tag(5), GRPC_OP_OK);
cq_verify(v_server);
cq_expect_finished(v_server, tag(102), NULL);
cq_verify(v_server);
grpc_call_destroy(c);
grpc_call_destroy(s);
cq_verifier_destroy(v_client);
cq_verifier_destroy(v_server);
}
static void test_invoke_request_with_census(
grpc_end2end_test_config config, const char *name,
void (*body)(grpc_end2end_test_fixture f)) {
char fullname[64];
grpc_end2end_test_fixture f;
grpc_arg client_arg, server_arg;
grpc_channel_args client_args, server_args;
client_arg.type = GRPC_ARG_INTEGER;
client_arg.key = GRPC_ARG_ENABLE_CENSUS;
client_arg.value.integer = 1;
client_args.num_args = 1;
client_args.args = &client_arg;
server_arg.type = GRPC_ARG_INTEGER;
server_arg.key = GRPC_ARG_ENABLE_CENSUS;
server_arg.value.integer = 1;
server_args.num_args = 1;
server_args.args = &server_arg;
sprintf(fullname, "%s/%s", __FUNCTION__, name);
f = begin_test(config, fullname, &client_args, &server_args);
body(f);
end_test(&f);
config.tear_down_data(&f);
}
void grpc_end2end_tests(grpc_end2end_test_config config) {
test_invoke_request_with_census(config, "census_simple_request", test_body);
}

@ -44,7 +44,8 @@
void test_census_stubs() {
census_op_id op_id;
census_rpc_stats* stats = census_rpc_stats_create_empty();
census_aggregated_rpc_stats data_map;
census_aggregated_rpc_stats data_map = {0, NULL};
/* Initializes census library at server start up time. */
census_init();
/* Starts tracing at the beginning of a rpc. */
@ -62,8 +63,9 @@ void test_census_stubs() {
census_tracing_end_op(op_id);
/* In process stats queries. */
census_get_server_stats(&data_map);
census_aggregated_rpc_stats_set_empty(&data_map);
census_get_client_stats(&data_map);
census_aggregated_rpc_stats_destroy(&data_map);
census_aggregated_rpc_stats_set_empty(&data_map);
gpr_free(stats);
census_shutdown();
}

@ -123,7 +123,8 @@ static void test_value_and_key_deleter() {
&free_data, &free_data};
census_ht* ht = census_ht_create(&opt);
census_ht_key key;
char* val;
char* val = NULL;
char* val2 = NULL;
key.ptr = gpr_malloc(100);
val = gpr_malloc(10);
strcpy(val, "value");
@ -132,6 +133,17 @@ static void test_value_and_key_deleter() {
GPR_ASSERT(census_ht_get_size(ht) == 0);
census_ht_insert(ht, key, val);
GPR_ASSERT(census_ht_get_size(ht) == 1);
val = census_ht_find(ht, key);
GPR_ASSERT(val != NULL);
GPR_ASSERT(strcmp(val, "value") == 0);
/* Insert same key different value, old value is overwritten. */
val2 = gpr_malloc(10);
strcpy(val2, "v2");
census_ht_insert(ht, key, val2);
GPR_ASSERT(census_ht_get_size(ht) == 1);
val2 = census_ht_find(ht, key);
GPR_ASSERT(val2 != NULL);
GPR_ASSERT(strcmp(val2, "v2") == 0);
census_ht_destroy(ht);
}

@ -0,0 +1,197 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/statistics/census_tracing.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/string.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include "test/core/util/test_config.h"
/* Ensure all possible state transitions are called without causing problem */
static void test_init_shutdown() {
census_stats_store_init();
census_stats_store_init();
census_stats_store_shutdown();
census_stats_store_shutdown();
census_stats_store_init();
}
static void test_create_and_destroy() {
census_rpc_stats* stats = NULL;
census_aggregated_rpc_stats agg_stats = {0, NULL};
stats = census_rpc_stats_create_empty();
GPR_ASSERT(stats != NULL);
GPR_ASSERT(stats->cnt == 0 && stats->rpc_error_cnt == 0 &&
stats->app_error_cnt == 0 && stats->elapsed_time_ms == 0.0 &&
stats->api_request_bytes == 0 && stats->wire_request_bytes == 0 &&
stats->api_response_bytes == 0 && stats->wire_response_bytes == 0);
gpr_free(stats);
census_aggregated_rpc_stats_set_empty(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 0);
GPR_ASSERT(agg_stats.stats == NULL);
agg_stats.num_entries = 1;
agg_stats.stats = (census_per_method_rpc_stats*)gpr_malloc(
sizeof(census_per_method_rpc_stats));
agg_stats.stats[0].method = gpr_strdup("foo");
census_aggregated_rpc_stats_set_empty(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 0);
GPR_ASSERT(agg_stats.stats == NULL);
}
#define ASSERT_NEAR(a, b) \
GPR_ASSERT((a - b) * (a - b) < 1e-24 * (a + b) * (a + b))
static void test_record_and_get_stats() {
census_rpc_stats stats = {1, 2, 3, 4, 5.1, 6.2, 7.3, 8.4};
census_op_id id;
census_aggregated_rpc_stats agg_stats = {0, NULL};
/* Record client stats twice with the same op_id. */
census_init();
id = census_tracing_start_op();
census_add_method_tag(id, "m1");
census_record_rpc_client_stats(id, &stats);
census_record_rpc_client_stats(id, &stats);
census_tracing_end_op(id);
/* Server stats expect to be empty */
census_get_server_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 0);
GPR_ASSERT(agg_stats.stats == NULL);
/* Client stats expect to have one entry */
census_get_client_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 1);
GPR_ASSERT(agg_stats.stats != NULL);
GPR_ASSERT(strcmp(agg_stats.stats[0].method, "m1") == 0);
GPR_ASSERT(agg_stats.stats[0].minute_stats.cnt == 2 &&
agg_stats.stats[0].hour_stats.cnt == 2 &&
agg_stats.stats[0].total_stats.cnt == 2);
ASSERT_NEAR(agg_stats.stats[0].minute_stats.wire_response_bytes, 16.8);
ASSERT_NEAR(agg_stats.stats[0].hour_stats.wire_response_bytes, 16.8);
ASSERT_NEAR(agg_stats.stats[0].total_stats.wire_response_bytes, 16.8);
/* Get stats again, results should be the same. */
census_get_client_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 1);
census_aggregated_rpc_stats_set_empty(&agg_stats);
census_shutdown();
/* Record both server (once) and client (twice) stats with different op_ids.*/
census_init();
id = census_tracing_start_op();
census_add_method_tag(id, "m2");
census_record_rpc_client_stats(id, &stats);
census_tracing_end_op(id);
id = census_tracing_start_op();
census_add_method_tag(id, "m3");
census_record_rpc_server_stats(id, &stats);
census_tracing_end_op(id);
id = census_tracing_start_op();
census_add_method_tag(id, "m4");
census_record_rpc_client_stats(id, &stats);
census_tracing_end_op(id);
/* Check server stats */
census_get_server_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 1);
GPR_ASSERT(strcmp(agg_stats.stats[0].method, "m3") == 0);
GPR_ASSERT(agg_stats.stats[0].minute_stats.app_error_cnt == 3 &&
agg_stats.stats[0].hour_stats.app_error_cnt == 3 &&
agg_stats.stats[0].total_stats.app_error_cnt == 3);
census_aggregated_rpc_stats_set_empty(&agg_stats);
/* Check client stats */
census_get_client_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 2);
GPR_ASSERT(agg_stats.stats != NULL);
GPR_ASSERT((strcmp(agg_stats.stats[0].method, "m2") == 0 &&
strcmp(agg_stats.stats[1].method, "m4") == 0) ||
(strcmp(agg_stats.stats[0].method, "m4") == 0 &&
strcmp(agg_stats.stats[1].method, "m2") == 0));
GPR_ASSERT(agg_stats.stats[0].minute_stats.cnt == 1 &&
agg_stats.stats[1].minute_stats.cnt == 1);
census_aggregated_rpc_stats_set_empty(&agg_stats);
census_shutdown();
}
static void test_record_stats_on_unknown_op_id() {
census_op_id unknown_id = {0xDEAD, 0xBEEF};
census_rpc_stats stats = {1, 2, 3, 4, 5.1, 6.2, 7.3, 8.4};
census_aggregated_rpc_stats agg_stats = {0, NULL};
census_init();
/* Tests that recording stats against unknown id is noop. */
census_record_rpc_client_stats(unknown_id, &stats);
census_record_rpc_server_stats(unknown_id, &stats);
census_get_server_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 0);
GPR_ASSERT(agg_stats.stats == NULL);
census_get_client_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 0);
GPR_ASSERT(agg_stats.stats == NULL);
census_aggregated_rpc_stats_set_empty(&agg_stats);
census_shutdown();
}
/* Test that record stats is noop when trace store is uninitialized. */
static void test_record_stats_with_trace_store_uninitialized() {
census_rpc_stats stats = {1, 2, 3, 4, 5.1, 6.2, 7.3, 8.4};
census_op_id id = {0, 0};
census_aggregated_rpc_stats agg_stats = {0, NULL};
census_init();
id = census_tracing_start_op();
census_add_method_tag(id, "m");
census_tracing_end_op(id);
/* shuts down trace store only. */
census_tracing_shutdown();
census_record_rpc_client_stats(id, &stats);
census_get_client_stats(&agg_stats);
GPR_ASSERT(agg_stats.num_entries == 0);
census_stats_store_shutdown();
}
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
test_init_shutdown();
test_create_and_destroy();
test_record_and_get_stats();
test_record_stats_on_unknown_op_id();
test_record_stats_with_trace_store_uninitialized();
return 0;
}

@ -0,0 +1,184 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_tracing.h"
#include "src/core/statistics/census_tracing.h"
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "test/core/util/test_config.h"
/* Ensure all possible state transitions are called without causing problem */
static void test_init_shutdown() {
census_tracing_init();
census_tracing_init();
census_tracing_shutdown();
census_tracing_shutdown();
census_tracing_init();
}
static void test_start_op_generates_locally_unique_ids() {
/* Check that ids generated within window size of 1000 are unique.
TODO(hongyu): Replace O(n^2) duplicate detection algorithm with O(nlogn)
algorithm. Enhance the test to larger window size (>10^6) */
#define WINDOW_SIZE 1000
census_op_id ids[WINDOW_SIZE];
int i;
census_init();
for (i = 0; i < WINDOW_SIZE; i++) {
ids[i] = census_tracing_start_op();
census_tracing_end_op(ids[i]);
}
for (i = 0; i < WINDOW_SIZE - 1; i++) {
int j;
for (j = i + 1; j < WINDOW_SIZE; j++) {
GPR_ASSERT(ids[i].upper != ids[j].upper || ids[i].lower != ids[j].lower);
}
}
#undef WINDOW_SIZE
census_shutdown();
}
static void test_get_trace_method_name() {
census_op_id id;
const char write_name[] = "service/method";
census_tracing_init();
id = census_tracing_start_op();
census_add_method_tag(id, write_name);
census_internal_lock_trace_store();
{
const char* read_name =
census_get_trace_method_name(census_get_trace_obj_locked(id));
GPR_ASSERT(strcmp(read_name, write_name) == 0);
}
census_internal_unlock_trace_store();
census_tracing_shutdown();
}
typedef struct thd_arg {
int num_done;
gpr_cv done;
gpr_mu mu;
} thd_arg;
static void mimic_trace_op_sequences(void* arg) {
census_op_id id;
const char* method_name = "service_foo/method_bar";
int i = 0;
const int num_iter = 200;
thd_arg* args = (thd_arg*)arg;
GPR_ASSERT(args != NULL);
gpr_log(GPR_INFO, "Start trace op sequence thread.");
for (i = 0; i < num_iter; i++) {
id = census_tracing_start_op();
census_add_method_tag(id, method_name);
/* pretend doing 1us work. */
gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_micros(1)));
census_tracing_end_op(id);
}
gpr_log(GPR_INFO, "End trace op sequence thread.");
gpr_mu_lock(&args->mu);
args->num_done += 1;
gpr_cv_broadcast(&args->done);
gpr_mu_unlock(&args->mu);
}
static void test_concurrency() {
#define NUM_THREADS 1000
gpr_thd_id tid[NUM_THREADS];
int i = 0;
thd_arg arg;
arg.num_done = 0;
gpr_mu_init(&arg.mu);
gpr_cv_init(&arg.done);
census_tracing_init();
for (i = 0; i < NUM_THREADS; ++i) {
gpr_thd_new(tid + i, mimic_trace_op_sequences, &arg, NULL);
}
gpr_mu_lock(&arg.mu);
while (arg.num_done < NUM_THREADS) {
gpr_log(GPR_INFO, "num done %d", arg.num_done);
gpr_cv_wait(&arg.done, &arg.mu, gpr_inf_future);
}
gpr_mu_unlock(&arg.mu);
census_tracing_shutdown();
#undef NUM_THREADS
}
static void test_add_method_tag_to_unknown_op_id() {
census_op_id unknown_id = {0xDEAD, 0xBEEF};
int ret = 0;
census_tracing_init();
ret = census_add_method_tag(unknown_id, "foo");
GPR_ASSERT(ret != 0);
census_tracing_shutdown();
}
static void test_trace_print() {
census_op_id id;
int i;
const char* annotation_txt[4] = {"abc", "", "$%^ *()_"};
char long_txt[CENSUS_MAX_ANNOTATION_LENGTH + 10];
memset(long_txt, 'a', GPR_ARRAY_SIZE(long_txt));
long_txt[CENSUS_MAX_ANNOTATION_LENGTH + 9] = '\0';
annotation_txt[3] = long_txt;
census_tracing_init();
id = census_tracing_start_op();
/* Adds large number of annotations to each trace */
for (i = 0; i < 1000; i++) {
census_tracing_print(id,
annotation_txt[i % GPR_ARRAY_SIZE(annotation_txt)]);
}
census_tracing_end_op(id);
census_tracing_shutdown();
}
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
test_init_shutdown();
test_start_op_generates_locally_unique_ids();
test_get_trace_method_name();
test_concurrency();
test_add_method_tag_to_unknown_op_id();
test_trace_print();
return 0;
}

@ -32,8 +32,17 @@
*/
#include <grpc/support/log.h>
#include <string.h>
#include "test/core/util/test_config.h"
static void test_callback(gpr_log_func_args *args) {
GPR_ASSERT(0 == strcmp(__FILE__, args->file));
GPR_ASSERT(args->severity == GPR_LOG_SEVERITY_INFO);
GPR_ASSERT(0 == strcmp(args->message, "hello 1 2 3"));
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
/* test logging at various verbosity levels */
@ -42,6 +51,9 @@ int main(int argc, char **argv) {
gpr_log(GPR_ERROR, "%s", "hello world");
/* should succeed */
GPR_ASSERT(1);
gpr_set_log_function(test_callback);
gpr_log_message(GPR_INFO, "hello 1 2 3");
gpr_log(GPR_INFO, "hello %d %d %d", 1, 2, 3);
/* TODO(ctiller): should we add a GPR_ASSERT failure test here */
return 0;
}

@ -64,15 +64,20 @@ static gpr_slice create_test_slice(size_t length) {
static void verify_sopb(size_t window_available, int eof,
size_t expect_window_used, const char *expected) {
gpr_slice_buffer output;
grpc_stream_op_buffer encops;
gpr_slice merged;
gpr_slice expect = parse_hexstring(expected);
gpr_slice_buffer_init(&output);
grpc_sopb_init(&encops);
GPR_ASSERT(expect_window_used ==
grpc_chttp2_encode_some(g_sopb.ops, &g_sopb.nops, eof, &output,
window_available, 0xdeadbeef,
&g_compressor));
grpc_chttp2_preencode(g_sopb.ops, &g_sopb.nops, window_available,
&encops));
grpc_chttp2_encode(encops.ops, encops.nops, eof, 0xdeadbeef, &g_compressor,
&output);
encops.nops = 0;
merged = grpc_slice_merge(output.slices, output.count);
gpr_slice_buffer_destroy(&output);
grpc_sopb_destroy(&encops);
if (0 != gpr_slice_cmp(merged, expect)) {
char *expect_str =
@ -240,21 +245,25 @@ static void test_decode_random_headers_inner(int max_len) {
test_decode_random_header_state st;
gpr_slice_buffer output;
gpr_slice merged;
grpc_stream_op_buffer encops;
grpc_chttp2_hpack_parser parser;
grpc_chttp2_hpack_parser_init(&parser, g_mdctx);
grpc_sopb_init(&encops);
gpr_log(GPR_INFO, "max_len = %d", max_len);
for (i = 0; i < 100000; i++) {
for (i = 0; i < 10000; i++) {
randstr(st.key, max_len);
randstr(st.value, max_len);
add_sopb_header(st.key, st.value);
gpr_slice_buffer_init(&output);
GPR_ASSERT(0 == grpc_chttp2_encode_some(g_sopb.ops, &g_sopb.nops, 0,
&output, 0, 0xdeadbeef,
&g_compressor));
GPR_ASSERT(0 ==
grpc_chttp2_preencode(g_sopb.ops, &g_sopb.nops, 0, &encops));
grpc_chttp2_encode(encops.ops, encops.nops, 0, 0xdeadbeef, &g_compressor,
&output);
encops.nops = 0;
merged = grpc_slice_merge(output.slices, output.count);
gpr_slice_buffer_destroy(&output);
@ -269,6 +278,7 @@ static void test_decode_random_headers_inner(int max_len) {
}
grpc_chttp2_hpack_parser_destroy(&parser);
grpc_sopb_destroy(&encops);
}
#define DECL_TEST_DECODE_RANDOM_HEADERS(n) \

@ -0,0 +1,73 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc++/credentials.h>
#include <memory>
#include <grpc/grpc.h>
#include <gtest/gtest.h>
namespace grpc {
namespace testing {
class CredentialsTest : public ::testing::Test {
protected:
};
TEST_F(CredentialsTest, InvalidSslCreds) {
std::unique_ptr<Credentials> bad1 =
CredentialsFactory::SslCredentials({"", "", ""});
EXPECT_EQ(nullptr, bad1.get());
std::unique_ptr<Credentials> bad2 =
CredentialsFactory::SslCredentials({"", "bla", "bla"});
EXPECT_EQ(nullptr, bad2.get());
}
TEST_F(CredentialsTest, InvalidServiceAccountCreds) {
std::unique_ptr<Credentials> bad1 =
CredentialsFactory::ServiceAccountCredentials("", "",
std::chrono::seconds(1));
EXPECT_EQ(nullptr, bad1.get());
}
} // namespace testing
} // namespace grpc
int main(int argc, char **argv) {
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -34,13 +34,14 @@
#include <chrono>
#include <thread>
#include "net/grpc/cpp/echo_duplicate_proto_cc.pb.h"
#include "test/cpp/util/echo.pb.h"
#include "src/cpp/server/rpc_service_method.h"
#include "src/cpp/util/time.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/credentials.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
@ -55,7 +56,6 @@
using grpc::cpp::test::util::EchoRequest;
using grpc::cpp::test::util::EchoResponse;
using grpc::cpp::test::util::TestService;
using std::chrono::system_clock;
namespace grpc {
@ -77,10 +77,10 @@ void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
}
} // namespace
class TestServiceImpl : public TestService::Service {
class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
public:
Status Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) {
EchoResponse* response) override {
response->set_message(request->message());
MaybeEchoDeadline(context, request, response);
return Status::OK;
@ -90,7 +90,7 @@ class TestServiceImpl : public TestService::Service {
Status RequestStream(ServerContext* context,
ServerReader<EchoRequest>* reader,
EchoResponse* response) {
EchoResponse* response) override {
EchoRequest request;
response->set_message("");
while (reader->Read(&request)) {
@ -102,7 +102,7 @@ class TestServiceImpl : public TestService::Service {
// Return 3 messages.
// TODO(yangg) make it generic by adding a parameter into EchoRequest
Status ResponseStream(ServerContext* context, const EchoRequest* request,
ServerWriter<EchoResponse>* writer) {
ServerWriter<EchoResponse>* writer) override {
EchoResponse response;
response.set_message(request->message() + "0");
writer->Write(response);
@ -114,8 +114,9 @@ class TestServiceImpl : public TestService::Service {
return Status::OK;
}
Status BidiStream(ServerContext* context,
ServerReaderWriter<EchoResponse, EchoRequest>* stream) {
Status BidiStream(
ServerContext* context,
ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
EchoRequest request;
EchoResponse response;
while (stream->Read(&request)) {
@ -127,6 +128,16 @@ class TestServiceImpl : public TestService::Service {
}
};
class TestServiceImplDupPkg
: public ::grpc::cpp::test::util::duplicate::TestService::Service {
public:
Status Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) override {
response->set_message("no package");
return Status::OK;
}
};
class End2endTest : public ::testing::Test {
protected:
void SetUp() override {
@ -136,6 +147,7 @@ class End2endTest : public ::testing::Test {
ServerBuilder builder;
builder.AddPort(server_address_.str());
builder.RegisterService(service_.service());
builder.RegisterService(dup_pkg_service_.service());
server_ = builder.BuildAndStart();
}
@ -143,15 +155,21 @@ class End2endTest : public ::testing::Test {
server_->Shutdown();
}
void ResetStub() {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
stub_.reset(grpc::cpp::test::util::TestService::NewStub(channel));
}
std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
std::unique_ptr<Server> server_;
std::ostringstream server_address_;
TestServiceImpl service_;
TestServiceImplDupPkg dup_pkg_service_;
};
static void SendRpc(const grpc::string& server_address, int num_rpcs) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address, ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub,
int num_rpcs) {
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
@ -162,18 +180,18 @@ static void SendRpc(const grpc::string& server_address, int num_rpcs) {
EXPECT_EQ(response.message(), request.message());
EXPECT_TRUE(s.IsOk());
}
delete stub;
}
TEST_F(End2endTest, SimpleRpc) {
SendRpc(server_address_.str(), 1);
ResetStub();
SendRpc(stub_.get(), 1);
}
TEST_F(End2endTest, MultipleRpcs) {
ResetStub();
vector<std::thread*> threads;
for (int i = 0; i < 10; ++i) {
threads.push_back(new std::thread(SendRpc, server_address_.str(), 10));
threads.push_back(new std::thread(SendRpc, stub_.get(), 10));
}
for (int i = 0; i < 10; ++i) {
threads[i]->join();
@ -183,9 +201,7 @@ TEST_F(End2endTest, MultipleRpcs) {
// Set a 10us deadline and make sure proper error is returned.
TEST_F(End2endTest, RpcDeadlineExpires) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
@ -194,19 +210,15 @@ TEST_F(End2endTest, RpcDeadlineExpires) {
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() + std::chrono::microseconds(10);
context.set_absolute_deadline(deadline);
Status s = stub->Echo(&context, request, &response);
Status s = stub_->Echo(&context, request, &response);
// TODO(yangg) use correct error code when b/18793983 is fixed.
// EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, s.code());
EXPECT_EQ(StatusCode::CANCELLED, s.code());
delete stub;
}
// Set a long but finite deadline.
TEST_F(End2endTest, RpcLongDeadline) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
@ -215,18 +227,14 @@ TEST_F(End2endTest, RpcLongDeadline) {
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() + std::chrono::hours(1);
context.set_absolute_deadline(deadline);
Status s = stub->Echo(&context, request, &response);
Status s = stub_->Echo(&context, request, &response);
EXPECT_EQ(response.message(), request.message());
EXPECT_TRUE(s.IsOk());
delete stub;
}
// Ask server to echo back the deadline it sees.
TEST_F(End2endTest, EchoDeadline) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
@ -236,7 +244,7 @@ TEST_F(End2endTest, EchoDeadline) {
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() + std::chrono::seconds(100);
context.set_absolute_deadline(deadline);
Status s = stub->Echo(&context, request, &response);
Status s = stub_->Echo(&context, request, &response);
EXPECT_EQ(response.message(), request.message());
EXPECT_TRUE(s.IsOk());
gpr_timespec sent_deadline;
@ -244,56 +252,44 @@ TEST_F(End2endTest, EchoDeadline) {
// Allow 1 second error.
EXPECT_LE(response.param().request_deadline() - sent_deadline.tv_sec, 1);
EXPECT_GE(response.param().request_deadline() - sent_deadline.tv_sec, -1);
delete stub;
}
// Ask server to echo back the deadline it sees. The rpc has no deadline.
TEST_F(End2endTest, EchoDeadlineForNoDeadlineRpc) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
request.mutable_param()->set_echo_deadline(true);
ClientContext context;
Status s = stub->Echo(&context, request, &response);
Status s = stub_->Echo(&context, request, &response);
EXPECT_EQ(response.message(), request.message());
EXPECT_TRUE(s.IsOk());
EXPECT_EQ(response.param().request_deadline(), gpr_inf_future.tv_sec);
delete stub;
}
TEST_F(End2endTest, UnimplementedRpc) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
ClientContext context;
Status s = stub->Unimplemented(&context, request, &response);
Status s = stub_->Unimplemented(&context, request, &response);
EXPECT_FALSE(s.IsOk());
EXPECT_EQ(s.code(), grpc::StatusCode::UNIMPLEMENTED);
EXPECT_EQ(s.details(), "");
EXPECT_EQ(response.message(), "");
delete stub;
}
TEST_F(End2endTest, RequestStreamOneRequest) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
ClientWriter<EchoRequest>* stream = stub->RequestStream(&context, &response);
ClientWriter<EchoRequest>* stream = stub_->RequestStream(&context, &response);
request.set_message("hello");
EXPECT_TRUE(stream->Write(request));
stream->WritesDone();
@ -302,18 +298,15 @@ TEST_F(End2endTest, RequestStreamOneRequest) {
EXPECT_TRUE(s.IsOk());
delete stream;
delete stub;
}
TEST_F(End2endTest, RequestStreamTwoRequests) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
ClientWriter<EchoRequest>* stream = stub->RequestStream(&context, &response);
ClientWriter<EchoRequest>* stream = stub_->RequestStream(&context, &response);
request.set_message("hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Write(request));
@ -323,19 +316,17 @@ TEST_F(End2endTest, RequestStreamTwoRequests) {
EXPECT_TRUE(s.IsOk());
delete stream;
delete stub;
}
TEST_F(End2endTest, ResponseStream) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("hello");
ClientReader<EchoResponse>* stream = stub->ResponseStream(&context, &request);
ClientReader<EchoResponse>* stream =
stub_->ResponseStream(&context, &request);
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(response.message(), request.message() + "0");
EXPECT_TRUE(stream->Read(&response));
@ -348,20 +339,17 @@ TEST_F(End2endTest, ResponseStream) {
EXPECT_TRUE(s.IsOk());
delete stream;
delete stub;
}
TEST_F(End2endTest, BidiStream) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
TestService::Stub* stub = TestService::NewStub(channel);
ResetStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
grpc::string msg("hello");
ClientReaderWriter<EchoRequest, EchoResponse>* stream =
stub->BidiStream(&context);
stub_->BidiStream(&context);
request.set_message(msg + "0");
EXPECT_TRUE(stream->Write(request));
@ -385,7 +373,64 @@ TEST_F(End2endTest, BidiStream) {
EXPECT_TRUE(s.IsOk());
delete stream;
delete stub;
}
// Talk to the two services with the same name but different package names.
// The two stubs are created on the same channel.
TEST_F(End2endTest, DiffPackageServices) {
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), ChannelArguments());
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub(
grpc::cpp::test::util::TestService::NewStub(channel));
ClientContext context;
Status s = stub->Echo(&context, request, &response);
EXPECT_EQ(response.message(), request.message());
EXPECT_TRUE(s.IsOk());
std::unique_ptr<grpc::cpp::test::util::duplicate::TestService::Stub>
dup_pkg_stub(
grpc::cpp::test::util::duplicate::TestService::NewStub(channel));
ClientContext context2;
s = dup_pkg_stub->Echo(&context2, request, &response);
EXPECT_EQ("no package", response.message());
EXPECT_TRUE(s.IsOk());
}
// rpc and stream should fail on bad credentials.
TEST_F(End2endTest, BadCredentials) {
std::unique_ptr<Credentials> bad_creds =
CredentialsFactory::ServiceAccountCredentials("", "",
std::chrono::seconds(1));
EXPECT_EQ(nullptr, bad_creds.get());
std::shared_ptr<ChannelInterface> channel =
CreateChannel(server_address_.str(), bad_creds, ChannelArguments());
std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub(
grpc::cpp::test::util::TestService::NewStub(channel));
EchoRequest request;
EchoResponse response;
ClientContext context;
grpc::string msg("hello");
Status s = stub->Echo(&context, request, &response);
EXPECT_EQ("", response.message());
EXPECT_FALSE(s.IsOk());
EXPECT_EQ(StatusCode::UNKNOWN, s.code());
EXPECT_EQ("Rpc sent on a lame channel.", s.details());
ClientContext context2;
ClientReaderWriter<EchoRequest, EchoResponse>* stream =
stub->BidiStream(&context2);
s = stream->Wait();
EXPECT_FALSE(s.IsOk());
EXPECT_EQ(StatusCode::UNKNOWN, s.code());
EXPECT_EQ("Rpc sent on a lame channel.", s.details());
delete stream;
}
} // namespace testing

@ -39,17 +39,17 @@
#include <grpc/grpc.h>
#include <grpc/support/thd.h>
#include "src/cpp/client/internal_stub.h"
#include "src/cpp/rpc_method.h"
#include "test/cpp/util/echo.pb.h"
#include "net/util/netutil.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/impl/internal_stub.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include "test/cpp/end2end/async_test_server.h"
#include "net/util/netutil.h"
#include <gtest/gtest.h>
using grpc::cpp::test::util::EchoRequest;

@ -128,6 +128,152 @@ void DoLargeUnary(std::shared_ptr<ChannelInterface> channel) {
gpr_log(GPR_INFO, "Large unary done.");
}
void DoRequestStreaming(std::shared_ptr<ChannelInterface> channel) {
gpr_log(GPR_INFO, "Sending request steaming rpc ...");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
grpc::ClientContext context;
StreamingInputCallRequest request;
StreamingInputCallResponse response;
std::unique_ptr<grpc::ClientWriter<StreamingInputCallRequest>> stream(
stub->StreamingInputCall(&context, &response));
int aggregated_payload_size = 0;
for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
grpc::testing::Payload* payload = request.mutable_payload();
payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
GPR_ASSERT(stream->Write(request));
aggregated_payload_size += request_stream_sizes[i];
}
stream->WritesDone();
grpc::Status s = stream->Wait();
GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Request streaming done.");
}
void DoResponseStreaming(std::shared_ptr<ChannelInterface> channel) {
gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
grpc::ClientContext context;
StreamingOutputCallRequest request;
for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
ResponseParameters* response_parameter = request.add_response_parameters();
response_parameter->set_size(response_stream_sizes[i]);
}
StreamingOutputCallResponse response;
std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
stub->StreamingOutputCall(&context, &request));
unsigned int i = 0;
while (stream->Read(&response)) {
GPR_ASSERT(response.payload().body() ==
grpc::string(response_stream_sizes[i], '\0'));
++i;
}
GPR_ASSERT(response_stream_sizes.size() == i);
grpc::Status s = stream->Wait();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Response streaming done.");
}
void DoResponseStreamingWithSlowConsumer(
std::shared_ptr<ChannelInterface> channel) {
gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
grpc::ClientContext context;
StreamingOutputCallRequest request;
for (unsigned int i = 0; i < kNumResponseMessages; ++i) {
ResponseParameters* response_parameter = request.add_response_parameters();
response_parameter->set_size(kResponseMessageSize);
}
StreamingOutputCallResponse response;
std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
stub->StreamingOutputCall(&context, &request));
unsigned int i = 0;
while (stream->Read(&response)) {
GPR_ASSERT(response.payload().body() ==
grpc::string(kResponseMessageSize, '\0'));
gpr_log(GPR_INFO, "received message %d", i);
std::this_thread::sleep_for(
std::chrono::milliseconds(kReceiveDelayMilliSeconds));
++i;
}
GPR_ASSERT(kNumResponseMessages == i);
grpc::Status s = stream->Wait();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Response streaming done.");
}
void DoHalfDuplex(std::shared_ptr<ChannelInterface> channel) {
gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
grpc::ClientContext context;
std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
StreamingOutputCallResponse>>
stream(stub->HalfDuplexCall(&context));
StreamingOutputCallRequest request;
ResponseParameters* response_parameter = request.add_response_parameters();
for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
response_parameter->set_size(response_stream_sizes[i]);
GPR_ASSERT(stream->Write(request));
}
stream->WritesDone();
unsigned int i = 0;
StreamingOutputCallResponse response;
while (stream->Read(&response)) {
GPR_ASSERT(response.payload().has_body());
GPR_ASSERT(response.payload().body() ==
grpc::string(response_stream_sizes[i], '\0'));
++i;
}
GPR_ASSERT(response_stream_sizes.size() == i);
grpc::Status s = stream->Wait();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
}
void DoPingPong(std::shared_ptr<ChannelInterface> channel) {
gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
grpc::ClientContext context;
std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
StreamingOutputCallResponse>>
stream(stub->FullDuplexCall(&context));
StreamingOutputCallRequest request;
request.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
ResponseParameters* response_parameter = request.add_response_parameters();
grpc::testing::Payload* payload = request.mutable_payload();
StreamingOutputCallResponse response;
for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
response_parameter->set_size(response_stream_sizes[i]);
payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
GPR_ASSERT(stream->Write(request));
GPR_ASSERT(stream->Read(&response));
GPR_ASSERT(response.payload().has_body());
GPR_ASSERT(response.payload().body() ==
grpc::string(response_stream_sizes[i], '\0'));
}
stream->WritesDone();
GPR_ASSERT(!stream->Read(&response));
grpc::Status s = stream->Wait();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Ping pong streaming done.");
}
int main(int argc, char** argv) {
grpc_init();
@ -148,6 +294,23 @@ int main(int argc, char** argv) {
DoEmpty(channel);
} else if (FLAGS_test_case == "large_unary") {
DoLargeUnary(channel);
} else if (FLAGS_test_case == "client_streaming") {
DoRequestStreaming(channel);
} else if (FLAGS_test_case == "server_streaming") {
DoResponseStreaming(channel);
} else if (FLAGS_test_case == "slow_consumer") {
DoResponseStreamingWithSlowConsumer(channel);
} else if (FLAGS_test_case == "half_duplex") {
DoHalfDuplex(channel);
} else if (FLAGS_test_case == "ping_pong") {
DoPingPong(channel);
} else if (FLAGS_test_case == "all") {
DoEmpty(channel);
DoLargeUnary(channel);
DoRequestStreaming(channel);
DoResponseStreaming(channel);
DoHalfDuplex(channel);
DoPingPong(channel);
} else {
gpr_log(
GPR_ERROR,

@ -0,0 +1,231 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <memory>
#include <sstream>
#include <thread>
#include <google/gflags.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include "test/core/end2end/data/ssl_test_data.h"
#include <grpc++/config.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include "test/cpp/interop/test.pb.h"
#include "test/cpp/interop/empty.pb.h"
#include "test/cpp/interop/messages.pb.h"
DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
DEFINE_int32(port, 0, "Server port.");
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerCredentials;
using grpc::ServerCredentialsFactory;
using grpc::ServerReader;
using grpc::ServerReaderWriter;
using grpc::ServerWriter;
using grpc::SslServerCredentialsOptions;
using grpc::testing::Payload;
using grpc::testing::PayloadType;
using grpc::testing::SimpleRequest;
using grpc::testing::SimpleResponse;
using grpc::testing::StreamingInputCallRequest;
using grpc::testing::StreamingInputCallResponse;
using grpc::testing::StreamingOutputCallRequest;
using grpc::testing::StreamingOutputCallResponse;
using grpc::testing::TestService;
using grpc::Status;
bool SetPayload(PayloadType type, int size, Payload* payload) {
PayloadType response_type = type;
// TODO(yangg): Support UNCOMPRESSABLE payload.
if (type != PayloadType::COMPRESSABLE) {
return false;
}
payload->set_type(response_type);
std::unique_ptr<char[]> body(new char[size]());
payload->set_body(body.get(), size);
return true;
}
class TestServiceImpl : public TestService::Service {
public:
Status EmptyCall(ServerContext* context, const grpc::testing::Empty* request,
grpc::testing::Empty* response) {
return Status::OK;
}
Status UnaryCall(ServerContext* context, const SimpleRequest* request,
SimpleResponse* response) {
if (request->has_response_size() && request->response_size() > 0) {
if (!SetPayload(request->response_type(), request->response_size(),
response->mutable_payload())) {
return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
}
}
return Status::OK;
}
Status StreamingOutputCall(
ServerContext* context, const StreamingOutputCallRequest* request,
ServerWriter<StreamingOutputCallResponse>* writer) {
StreamingOutputCallResponse response;
bool write_success = true;
response.mutable_payload()->set_type(request->response_type());
for (int i = 0; write_success && i < request->response_parameters_size();
i++) {
response.mutable_payload()->set_body(
grpc::string(request->response_parameters(i).size(), '\0'));
write_success = writer->Write(response);
}
if (write_success) {
return Status::OK;
} else {
return Status(grpc::StatusCode::INTERNAL, "Error writing response.");
}
}
Status StreamingInputCall(ServerContext* context,
ServerReader<StreamingInputCallRequest>* reader,
StreamingInputCallResponse* response) {
StreamingInputCallRequest request;
int aggregated_payload_size = 0;
while (reader->Read(&request)) {
if (request.has_payload() && request.payload().has_body()) {
aggregated_payload_size += request.payload().body().size();
}
}
response->set_aggregated_payload_size(aggregated_payload_size);
return Status::OK;
}
Status FullDuplexCall(
ServerContext* context,
ServerReaderWriter<StreamingOutputCallResponse,
StreamingOutputCallRequest>* stream) {
StreamingOutputCallRequest request;
StreamingOutputCallResponse response;
bool write_success = true;
while (write_success && stream->Read(&request)) {
response.mutable_payload()->set_type(request.payload().type());
if (request.response_parameters_size() == 0) {
return Status(grpc::StatusCode::INTERNAL,
"Request does not have response parameters.");
}
response.mutable_payload()->set_body(
grpc::string(request.response_parameters(0).size(), '\0'));
write_success = stream->Write(response);
}
if (write_success) {
return Status::OK;
} else {
return Status(grpc::StatusCode::INTERNAL, "Error writing response.");
}
}
Status HalfDuplexCall(
ServerContext* context,
ServerReaderWriter<StreamingOutputCallResponse,
StreamingOutputCallRequest>* stream) {
std::vector<StreamingOutputCallRequest> requests;
StreamingOutputCallRequest request;
while (stream->Read(&request)) {
requests.push_back(request);
}
StreamingOutputCallResponse response;
bool write_success = true;
for (unsigned int i = 0; write_success && i < requests.size(); i++) {
response.mutable_payload()->set_type(requests[i].payload().type());
if (requests[i].response_parameters_size() == 0) {
return Status(grpc::StatusCode::INTERNAL,
"Request does not have response parameters.");
}
response.mutable_payload()->set_body(
grpc::string(requests[i].response_parameters(0).size(), '\0'));
write_success = stream->Write(response);
}
if (write_success) {
return Status::OK;
} else {
return Status(grpc::StatusCode::INTERNAL, "Error writing response.");
}
}
};
void RunServer() {
std::ostringstream server_address;
server_address << "localhost:" << FLAGS_port;
TestServiceImpl service;
SimpleRequest request;
SimpleResponse response;
ServerBuilder builder;
builder.AddPort(server_address.str());
builder.RegisterService(service.service());
if (FLAGS_enable_ssl) {
SslServerCredentialsOptions ssl_opts = {
"",
{reinterpret_cast<const char*>(test_server1_key),
test_server1_key_size},
{reinterpret_cast<const char*>(test_server1_cert),
test_server1_cert_size}};
std::shared_ptr<ServerCredentials> creds =
ServerCredentialsFactory::SslCredentials(ssl_opts);
builder.SetCredentials(creds);
}
std::unique_ptr<Server> server(builder.BuildAndStart());
gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str());
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(5));
}
}
int main(int argc, char** argv) {
grpc_init();
google::ParseCommandLineFlags(&argc, &argv, true);
GPR_ASSERT(FLAGS_port != 0);
RunServer();
grpc_shutdown();
return 0;
}

@ -1,24 +1,8 @@
syntax = "proto2";
package grpc.cpp.test.util;
message RequestParams {
optional bool echo_deadline = 1;
}
message EchoRequest {
optional string message = 1;
optional RequestParams param = 2;
}
import "test/cpp/util/messages.proto";
message ResponseParams {
optional int64 request_deadline = 1;
}
message EchoResponse {
optional string message = 1;
optional ResponseParams param = 2;
}
package grpc.cpp.test.util;
service TestService {
rpc Echo(EchoRequest) returns (EchoResponse);

@ -0,0 +1,12 @@
// This is a partial copy of echo.proto with a different package name.
syntax = "proto2";
import "test/cpp/util/messages.proto";
package grpc.cpp.test.util.duplicate;
service TestService {
rpc Echo(grpc.cpp.test.util.EchoRequest)
returns (grpc.cpp.test.util.EchoResponse);
}

@ -0,0 +1,21 @@
syntax = "proto2";
package grpc.cpp.test.util;
message RequestParams {
optional bool echo_deadline = 1;
}
message EchoRequest {
optional string message = 1;
optional RequestParams param = 2;
}
message ResponseParams {
optional int64 request_deadline = 1;
}
message EchoResponse {
optional string message = 1;
optional ResponseParams param = 2;
}

@ -1,13 +1,13 @@
#!/bin/bash
set -ex
set -x
if [ "x$TEST" == "x" ] ; then
TEST=false
fi
cd `dirname $0`/..
cd `dirname $0`/../..
mako_renderer=tools/buildgen/mako_renderer.py
gen_build_json=test/core/end2end/gen_build_json.py
@ -33,8 +33,6 @@ for dir in . ; do
if [ $TEST == true ] ; then
actual_out=$out
out=`mktemp`
else
g4 open $out || true
fi
$mako_renderer $plugins $data -o $out $file
if [ $TEST == true ] ; then

@ -1,6 +1,9 @@
# Dockerfile for gRPC Ruby
FROM grpc/ruby_base
# Start the daemon that allows access to the protected git-on-borg repos
RUN /var/local/git/gcompute-tools/git-cookie-authdaemon
RUN cd /var/local/git/grpc \
&& git pull --recurse-submodules \
&& git submodule update --init --recursive

@ -333,6 +333,45 @@ grpc_interop_test_args() {
}
}
grpc_update_docker_images_args() {
[[ -n $1 ]] && { # host
host=$1
shift
} || {
echo "$FUNCNAME: missing arg: host" 1>&2
return 1
}
}
# Updates all the known docker images on a host..
#
# call-seq;
# grpc_update_docker_images <server_name>
#
# Updates the GCE docker instance <server_name>
grpc_update_docker_images() {
# declare vars local so that they don't pollute the shell environment
# where they this func is used.
local grpc_zone grpc_project dry_run # set by grpc_set_project_and_zone
# set by grpc_update_docker_images_args
local host
# set the project zone and check that all necessary args are provided
grpc_set_project_and_zone -f grpc_update_docker_images_args "$@" || return 1
gce_has_instance $grpc_project $host || return 1;
local func_lib="/var/local/startup_scripts/shared_startup_funcs.sh"
local cmd="source $func_lib && grpc_docker_pull_known"
local project_opt="--project $grpc_project"
local zone_opt="--zone $grpc_zone"
local ssh_cmd="bash -l -c \"$cmd\""
echo "will run:"
echo " $ssh_cmd"
echo "on $host"
[[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run
gcloud compute $project_opt ssh $zone_opt $host --command "$cmd"
}
grpc_launch_server_args() {
[[ -n $1 ]] && { # host
host=$1

@ -8,7 +8,7 @@ import tempfile
import time
_MAX_JOBS = 3
_DEFAULT_MAX_JOBS = 16 * multiprocessing.cpu_count()
def shuffle_iteratable(it):
@ -103,16 +103,17 @@ class Job(object):
class Jobset(object):
"""Manages one run of jobs."""
def __init__(self, check_cancelled):
def __init__(self, check_cancelled, maxjobs):
self._running = set()
self._check_cancelled = check_cancelled
self._cancelled = False
self._failures = 0
self._completed = 0
self._maxjobs = maxjobs
def start(self, cmdline):
"""Start a job. Return True on success, False on failure."""
while len(self._running) >= _MAX_JOBS:
while len(self._running) >= self._maxjobs:
if self.cancelled(): return False
self.reap()
if self.cancelled(): return False
@ -156,10 +157,10 @@ def _never_cancelled():
return False
def run(cmdlines, check_cancelled=_never_cancelled):
js = Jobset(check_cancelled)
def run(cmdlines, check_cancelled=_never_cancelled, maxjobs=None):
js = Jobset(check_cancelled,
maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS)
for cmdline in shuffle_iteratable(cmdlines):
if not js.start(cmdline):
break
return js.finish()

@ -76,7 +76,7 @@ def _build_and_run(check_cancelled):
'-j', '%d' % (multiprocessing.cpu_count() + 1),
'buildtests_c',
'CONFIG=%s' % cfg]
for cfg in build_configs), check_cancelled):
for cfg in build_configs), check_cancelled, maxjobs=1):
sys.exit(1)
# run all the tests

@ -1,7 +1,6 @@
"""Helper to watch a (set) of directories for modifications."""
import os
import threading
import time
@ -11,7 +10,6 @@ class DirWatcher(object):
def __init__(self, paths):
if isinstance(paths, basestring):
paths = [paths]
self._mu = threading.Lock()
self._done = False
self.paths = list(paths)
self.lastrun = time.time()
@ -35,12 +33,8 @@ class DirWatcher(object):
return most_recent_change
def most_recent_change(self):
self._mu.acquire()
try:
if time.time() - self.lastrun > 1:
self._cache = self._calculate()
self.lastrun = time.time()
return self._cache
finally:
self._mu.release()
if time.time() - self.lastrun > 1:
self._cache = self._calculate()
self.lastrun = time.time()
return self._cache

@ -134,6 +134,7 @@
<ClInclude Include="..\..\src\core\statistics\census_interface.h" />
<ClInclude Include="..\..\src\core\statistics\census_log.h" />
<ClInclude Include="..\..\src\core\statistics\census_rpc_stats.h" />
<ClInclude Include="..\..\src\core\statistics\census_tracing.h" />
<ClInclude Include="..\..\src\core\statistics\hash_table.h" />
<ClInclude Include="..\..\src\core\statistics\window_stats.h" />
<ClInclude Include="..\..\src\core\surface\call.h" />

@ -134,6 +134,7 @@
<ClInclude Include="..\..\src\core\statistics\census_interface.h" />
<ClInclude Include="..\..\src\core\statistics\census_log.h" />
<ClInclude Include="..\..\src\core\statistics\census_rpc_stats.h" />
<ClInclude Include="..\..\src\core\statistics\census_tracing.h" />
<ClInclude Include="..\..\src\core\statistics\hash_table.h" />
<ClInclude Include="..\..\src\core\statistics\window_stats.h" />
<ClInclude Include="..\..\src\core\surface\call.h" />

Loading…
Cancel
Save