merge with head and resolve conflict

pull/4175/head
yang-g 9 years ago
commit d88e1d8f4e
  1. 1
      .gitignore
  2. 22
      BUILD
  3. 561
      Makefile
  4. 4
      binding.gyp
  5. 75
      build.yaml
  6. 289
      doc/grpc-auth-support.md
  7. 2
      examples/objective-c/auth_sample/AuthTestService.podspec
  8. 2
      examples/objective-c/helloworld/HelloWorld.podspec
  9. 2
      examples/objective-c/route_guide/RouteGuide.podspec
  10. 15
      gRPC.podspec
  11. 23
      include/grpc++/impl/thd_no_cxx11.h
  12. 16
      include/grpc++/security/credentials.h
  13. 11
      include/grpc/grpc.h
  14. 177
      include/grpc/grpc_security.h
  15. 91
      include/grpc/support/avl.h
  16. 3
      include/grpc/support/slice.h
  17. 2
      package.json
  18. 141
      reports/interop_html_report.template
  19. 20
      src/core/census/grpc_filter.c
  20. 2
      src/core/channel/channel_stack.c
  21. 2
      src/core/channel/channel_stack.h
  22. 3
      src/core/channel/client_channel.c
  23. 10
      src/core/channel/client_uchannel.c
  24. 78
      src/core/channel/compress_filter.c
  25. 102
      src/core/channel/http_client_filter.c
  26. 104
      src/core/channel/http_server_filter.c
  27. 2
      src/core/client_config/connector.h
  28. 39
      src/core/client_config/default_initial_connect_string.c
  29. 53
      src/core/client_config/initial_connect_string.c
  30. 50
      src/core/client_config/initial_connect_string.h
  31. 18
      src/core/client_config/subchannel.c
  32. 11
      src/core/client_config/subchannel.h
  33. 50
      src/core/compression/algorithm.c
  34. 53
      src/core/compression/algorithm_metadata.h
  35. 17
      src/core/iomgr/fd_posix.c
  36. 4
      src/core/iomgr/fd_posix.h
  37. 5
      src/core/iomgr/pollset_posix.c
  38. 3
      src/core/iomgr/pollset_windows.c
  39. 4
      src/core/iomgr/tcp_client_posix.c
  40. 16
      src/core/iomgr/tcp_posix.c
  41. 6
      src/core/iomgr/tcp_posix.h
  42. 19
      src/core/iomgr/tcp_server.h
  43. 151
      src/core/iomgr/tcp_server_posix.c
  44. 121
      src/core/iomgr/tcp_server_windows.c
  45. 2
      src/core/iomgr/udp_server.c
  46. 2
      src/core/iomgr/workqueue_posix.c
  47. 185
      src/core/profiling/basic_timers.c
  48. 2
      src/core/profiling/timers.h
  49. 85
      src/core/security/client_auth_filter.c
  50. 72
      src/core/security/credentials.c
  51. 16
      src/core/security/credentials.h
  52. 3
      src/core/security/google_default_credentials.c
  53. 6
      src/core/security/security_connector.c
  54. 2
      src/core/security/security_connector.h
  55. 2
      src/core/security/server_auth_filter.c
  56. 15
      src/core/security/server_secure_chttp2.c
  57. 288
      src/core/support/avl.c
  58. 15
      src/core/support/slice.c
  59. 9
      src/core/support/thd_posix.c
  60. 1
      src/core/surface/byte_buffer_reader.c
  61. 62
      src/core/surface/call.c
  62. 115
      src/core/surface/channel.c
  63. 11
      src/core/surface/channel.h
  64. 39
      src/core/surface/channel_create.c
  65. 2
      src/core/surface/init.c
  66. 12
      src/core/surface/lame_client.c
  67. 44
      src/core/surface/secure_channel_create.c
  68. 21
      src/core/surface/server.c
  69. 2
      src/core/surface/server.h
  70. 13
      src/core/surface/server_chttp2.c
  71. 123
      src/core/transport/chttp2/hpack_encoder.c
  72. 32
      src/core/transport/chttp2/hpack_encoder.h
  73. 100
      src/core/transport/chttp2/hpack_parser.c
  74. 3
      src/core/transport/chttp2/hpack_parser.h
  75. 122
      src/core/transport/chttp2/hpack_table.c
  76. 35
      src/core/transport/chttp2/hpack_table.h
  77. 13
      src/core/transport/chttp2/internal.h
  78. 24
      src/core/transport/chttp2/parsing.c
  79. 11
      src/core/transport/chttp2/writing.c
  80. 98
      src/core/transport/chttp2_transport.c
  81. 2
      src/core/transport/chttp2_transport.h
  82. 580
      src/core/transport/metadata.c
  83. 42
      src/core/transport/metadata.h
  84. 157
      src/core/transport/static_metadata.c
  85. 402
      src/core/transport/static_metadata.h
  86. 4
      src/cpp/client/insecure_credentials.cc
  87. 25
      src/cpp/client/secure_credentials.cc
  88. 5
      src/cpp/client/secure_credentials.h
  89. 2
      src/csharp/Grpc.Core/Profiling/IProfiler.cs
  90. 3
      src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs
  91. 13
      src/csharp/Grpc.Core/Profiling/Profilers.cs
  92. 2
      src/csharp/Grpc.Core/VersionInfo.cs
  93. 3
      src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore
  94. 60
      src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
  95. 46
      src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs
  96. 11
      src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs
  97. 76
      src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
  98. 153
      src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
  99. 2362
      src/csharp/Grpc.IntegrationTesting/Control.cs
  100. 67
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -38,6 +38,7 @@ cache.mk
# Temporary test reports
report.xml
latency_trace.txt
latency_trace.*.txt
# port server log
portlog.txt

22
BUILD

@ -57,6 +57,7 @@ cc_library(
"src/core/profiling/basic_timers.c",
"src/core/profiling/stap_timers.c",
"src/core/support/alloc.c",
"src/core/support/avl.c",
"src/core/support/cmdline.c",
"src/core/support/cpu_iphone.c",
"src/core/support/cpu_linux.c",
@ -101,6 +102,7 @@ cc_library(
"include/grpc/support/atm_gcc_atomic.h",
"include/grpc/support/atm_gcc_sync.h",
"include/grpc/support/atm_win32.h",
"include/grpc/support/avl.h",
"include/grpc/support/cmdline.h",
"include/grpc/support/cpu.h",
"include/grpc/support/histogram.h",
@ -163,6 +165,7 @@ cc_library(
"src/core/channel/subchannel_call_holder.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/initial_connect_string.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h",
@ -178,6 +181,7 @@ cc_library(
"src/core/client_config/subchannel_factory_decorators/add_channel_arg.h",
"src/core/client_config/subchannel_factory_decorators/merge_channel_args.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/algorithm_metadata.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/httpcli/format_request.h",
@ -260,6 +264,7 @@ cc_library(
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/metadata_batch.h",
"src/core/transport/static_metadata.h",
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/aggregation.h",
@ -300,6 +305,8 @@ cc_library(
"src/core/channel/subchannel_call_holder.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/default_initial_connect_string.c",
"src/core/client_config/initial_connect_string.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policy.c",
@ -408,6 +415,7 @@ cc_library(
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/metadata_batch.c",
"src/core/transport/static_metadata.c",
"src/core/transport/transport.c",
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
@ -453,6 +461,7 @@ cc_library(
"src/core/channel/subchannel_call_holder.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/initial_connect_string.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h",
@ -468,6 +477,7 @@ cc_library(
"src/core/client_config/subchannel_factory_decorators/add_channel_arg.h",
"src/core/client_config/subchannel_factory_decorators/merge_channel_args.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/algorithm_metadata.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/httpcli/format_request.h",
@ -550,6 +560,7 @@ cc_library(
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/metadata_batch.h",
"src/core/transport/static_metadata.h",
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/aggregation.h",
@ -570,6 +581,8 @@ cc_library(
"src/core/channel/subchannel_call_holder.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/default_initial_connect_string.c",
"src/core/client_config/initial_connect_string.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policy.c",
@ -678,6 +691,7 @@ cc_library(
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/metadata_batch.c",
"src/core/transport/static_metadata.c",
"src/core/transport/transport.c",
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
@ -975,6 +989,7 @@ objc_library(
"src/core/profiling/basic_timers.c",
"src/core/profiling/stap_timers.c",
"src/core/support/alloc.c",
"src/core/support/avl.c",
"src/core/support/cmdline.c",
"src/core/support/cpu_iphone.c",
"src/core/support/cpu_linux.c",
@ -1019,6 +1034,7 @@ objc_library(
"include/grpc/support/atm_gcc_atomic.h",
"include/grpc/support/atm_gcc_sync.h",
"include/grpc/support/atm_win32.h",
"include/grpc/support/avl.h",
"include/grpc/support/cmdline.h",
"include/grpc/support/cpu.h",
"include/grpc/support/histogram.h",
@ -1099,6 +1115,8 @@ objc_library(
"src/core/channel/subchannel_call_holder.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/default_initial_connect_string.c",
"src/core/client_config/initial_connect_string.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policy.c",
@ -1207,6 +1225,7 @@ objc_library(
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/metadata_batch.c",
"src/core/transport/static_metadata.c",
"src/core/transport/transport.c",
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
@ -1249,6 +1268,7 @@ objc_library(
"src/core/channel/subchannel_call_holder.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/initial_connect_string.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h",
@ -1264,6 +1284,7 @@ objc_library(
"src/core/client_config/subchannel_factory_decorators/add_channel_arg.h",
"src/core/client_config/subchannel_factory_decorators/merge_channel_args.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/algorithm_metadata.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/httpcli/format_request.h",
@ -1346,6 +1367,7 @@ objc_library(
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/metadata_batch.h",
"src/core/transport/static_metadata.h",
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/aggregation.h",

File diff suppressed because one or more lines are too long

@ -97,6 +97,7 @@
'src/core/profiling/basic_timers.c',
'src/core/profiling/stap_timers.c',
'src/core/support/alloc.c',
'src/core/support/avl.c',
'src/core/support/cmdline.c',
'src/core/support/cpu_iphone.c',
'src/core/support/cpu_linux.c',
@ -186,6 +187,8 @@
'src/core/channel/subchannel_call_holder.c',
'src/core/client_config/client_config.c',
'src/core/client_config/connector.c',
'src/core/client_config/default_initial_connect_string.c',
'src/core/client_config/initial_connect_string.c',
'src/core/client_config/lb_policies/pick_first.c',
'src/core/client_config/lb_policies/round_robin.c',
'src/core/client_config/lb_policy.c',
@ -294,6 +297,7 @@
'src/core/transport/connectivity_state.c',
'src/core/transport/metadata.c',
'src/core/transport/metadata_batch.c',
'src/core/transport/static_metadata.c',
'src/core/transport/transport.c',
'src/core/transport/transport_op_string.c',
'src/core/census/context.c',

@ -119,6 +119,7 @@ filegroups:
- src/core/channel/subchannel_call_holder.h
- src/core/client_config/client_config.h
- src/core/client_config/connector.h
- src/core/client_config/initial_connect_string.h
- src/core/client_config/lb_policies/pick_first.h
- src/core/client_config/lb_policies/round_robin.h
- src/core/client_config/lb_policy.h
@ -134,6 +135,7 @@ filegroups:
- src/core/client_config/subchannel_factory_decorators/add_channel_arg.h
- src/core/client_config/subchannel_factory_decorators/merge_channel_args.h
- src/core/client_config/uri_parser.h
- src/core/compression/algorithm_metadata.h
- src/core/compression/message_compress.h
- src/core/debug/trace.h
- src/core/httpcli/format_request.h
@ -216,6 +218,7 @@ filegroups:
- src/core/transport/connectivity_state.h
- src/core/transport/metadata.h
- src/core/transport/metadata_batch.h
- src/core/transport/static_metadata.h
- src/core/transport/transport.h
- src/core/transport/transport_impl.h
src:
@ -233,6 +236,8 @@ filegroups:
- src/core/channel/subchannel_call_holder.c
- src/core/client_config/client_config.c
- src/core/client_config/connector.c
- src/core/client_config/default_initial_connect_string.c
- src/core/client_config/initial_connect_string.c
- src/core/client_config/lb_policies/pick_first.c
- src/core/client_config/lb_policies/round_robin.c
- src/core/client_config/lb_policy.c
@ -341,6 +346,7 @@ filegroups:
- src/core/transport/connectivity_state.c
- src/core/transport/metadata.c
- src/core/transport/metadata_batch.c
- src/core/transport/static_metadata.c
- src/core/transport/transport.c
- src/core/transport/transport_op_string.c
- name: grpc_test_util_base
@ -373,6 +379,7 @@ libs:
- include/grpc/support/atm_gcc_atomic.h
- include/grpc/support/atm_gcc_sync.h
- include/grpc/support/atm_win32.h
- include/grpc/support/avl.h
- include/grpc/support/cmdline.h
- include/grpc/support/cpu.h
- include/grpc/support/histogram.h
@ -410,6 +417,7 @@ libs:
- src/core/profiling/basic_timers.c
- src/core/profiling/stap_timers.c
- src/core/support/alloc.c
- src/core/support/avl.c
- src/core/support/cmdline.c
- src/core/support/cpu_iphone.c
- src/core/support/cpu_linux.c
@ -579,6 +587,19 @@ libs:
src:
- test/core/util/reconnect_server.c
deps:
- test_tcp_server
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: test_tcp_server
build: private
language: c
headers:
- test/core/util/test_tcp_server.h
src:
- test/core/util/test_tcp_server.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
@ -969,6 +990,14 @@ targets:
src:
- tools/codegen/core/gen_legal_metadata_characters.c
deps: []
- name: gpr_avl_test
build: test
language: c
src:
- test/core/support/avl_test.c
deps:
- gpr_test_util
- gpr
- name: gpr_cmdline_test
build: test
language: c
@ -1426,6 +1455,17 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: set_initial_connect_string_test
build: test
language: c
src:
- test/core/client_config/set_initial_connect_string_test.c
deps:
- test_tcp_server
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: sockaddr_utils_test
build: test
language: c
@ -1887,6 +1927,20 @@ targets:
- mac
- linux
- posix
- name: metrics_client
build: test
run: false
language: c++
headers:
- test/cpp/util/metrics_server.h
src:
- test/proto/metrics.proto
- test/cpp/interop/metrics_client.cc
deps:
- grpc++
- grpc
- gpr
- grpc++_test_config
- name: mock_test
build: test
language: c++
@ -2015,6 +2069,7 @@ targets:
- test/cpp/interop/reconnect_interop_server.cc
deps:
- reconnect_server
- test_tcp_server
- grpc++_test_util
- grpc_test_util
- grpc++
@ -2127,13 +2182,16 @@ targets:
- test/cpp/interop/client_helper.h
- test/cpp/interop/interop_client.h
- test/cpp/interop/stress_interop_client.h
- test/cpp/util/metrics_server.h
src:
- test/proto/empty.proto
- test/proto/messages.proto
- test/proto/metrics.proto
- test/proto/test.proto
- test/cpp/interop/interop_client.cc
- test/cpp/interop/stress_interop_client.cc
- test/cpp/interop/stress_test.cc
- test/cpp/util/metrics_server.cc
deps:
- grpc++_test_util
- grpc_test_util
@ -2228,6 +2286,23 @@ node_modules:
- deps:
- grpc
- gpr
headers:
- src/node/ext/byte_buffer.h
- src/node/ext/call.h
- src/node/ext/call_credentials.h
- src/node/ext/channel.h
- src/node/ext/channel_credentials.h
- src/node/ext/completion_queue_async_worker.h
- src/node/ext/server.h
- src/node/ext/server_credentials.h
- src/node/ext/timeval.h
js:
- src/node/index.js
- src/node/src/client.js
- src/node/src/common.js
- src/node/src/credentials.js
- src/node/src/metadata.js
- src/node/src/server.js
name: grpc_node
src:
- src/node/ext/byte_buffer.cc

@ -1,289 +0,0 @@
#gRPC Authentication support
gRPC is designed to plug-in a number of authentication mechanisms. This document
provides a quick overview of the various auth mechanisms supported, discusses
the API with some examples, and concludes with a discussion of extensibility.
More documentation and examples are coming soon!
## Supported auth mechanisms
###SSL/TLS
gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the
server, and encrypt all the data exchanged between the client and the server.
Optional mechanisms are available for clients to provide certificates to
accomplish mutual authentication.
###OAuth 2.0
gRPC provides a generic mechanism (described below) to attach metadata to
requests and responses. This mechanism can be used to attach OAuth 2.0 Access
Tokens to RPCs being made at a client. Additional support for acquiring Access
Tokens while accessing Google APIs through gRPC is provided for certain auth
flows, demonstrated through code examples below.
## API
To reduce complexity and minimize API clutter, gRPC works with a unified concept
of a Credentials object. Users construct gRPC credentials using corresponding
bootstrap credentials (e.g., SSL client certs or Service Account Keys), and use
the credentials while creating a gRPC channel to any server. Depending on the
type of credential supplied, the channel uses the credentials during the initial
SSL/TLS handshake with the server, or uses the credential to generate and
attach Access Tokens to each request being made on the channel.
###SSL/TLS for server authentication and encryption
This is the simplest authentication scenario, where a client just wants to
authenticate the server and encrypt all data.
```cpp
SslCredentialsOptions ssl_opts; // Options to override SSL params, empty by default
// Create the credentials object by providing service account key in constructor
std::shared_ptr<ChannelCredentials> creds = SslCredentials(ssl_opts);
// Create a channel using the credentials created in the previous step
std::shared_ptr<Channel> channel = CreateChannel(server_name, creds);
// Create a stub on the channel
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
// Make actual RPC calls on the stub.
grpc::Status s = stub->sayHello(&context, *request, response);
```
For advanced use cases such as modifying the root CA or using client certs,
the corresponding options can be set in the SslCredentialsOptions parameter
passed to the factory method.
###Authenticating with Google
gRPC applications can use a simple API to create a credential that works in various deployment scenarios.
```cpp
std::shared_ptr<ChannelCredentials> creds = GoogleDefaultCredentials();
// Create a channel, stub and make RPC calls (same as in the previous example)
std::shared_ptr<Channel> channel = CreateChannel(server_name, creds);
std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
grpc::Status s = stub->sayHello(&context, *request, response);
```
This credential works for applications using Service Accounts as well as for
applications running in [Google Compute Engine (GCE)](https://cloud.google.com/compute/). In the former case, the
service account’s private keys are loaded from the file named in the environment
variable `GOOGLE_APPLICATION_CREDENTIALS`. The
keys are used to generate bearer tokens that are attached to each outgoing RPC
on the corresponding channel.
For applications running in GCE, a default service account and corresponding
OAuth scopes can be configured during VM setup. At run-time, this credential
handles communication with the authentication systems to obtain OAuth2 access
tokens and attaches them to each outgoing RPC on the corresponding channel.
Extending gRPC to support other authentication mechanisms
The gRPC protocol is designed with a general mechanism for sending metadata
associated with RPC. Clients can send metadata at the beginning of an RPC and
servers can send back metadata at the beginning and end of the RPC. This
provides a natural mechanism to support OAuth2 and other authentication
mechanisms that need attach bearer tokens to individual request.
In the simplest case, there is a single line of code required on the client
to add a specific token as metadata to an RPC and a corresponding access on
the server to retrieve this piece of metadata. The generation of the token
on the client side and its verification at the server can be done separately.
A deeper integration can be achieved by plugging in a gRPC credentials implementation for any custom authentication mechanism that needs to attach per-request tokens. gRPC internals also allow switching out SSL/TLS with other encryption mechanisms.
## Examples
These authentication mechanisms will be available in all gRPC's supported languages.
The following sections demonstrate how authentication and authorization features described above appear in each language: more languages are coming soon.
###SSL/TLS for server authentication and encryption (Ruby)
```ruby
# Base case - No encryption
stub = Helloworld::Greeter::Stub.new('localhost:50051')
...
# With server authentication SSL/TLS
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file
stub = Helloworld::Greeter::Stub.new('localhost:50051', creds: creds)
```
###SSL/TLS for server authentication and encryption (C#)
```csharp
// Base case - No encryption
var channel = new Channel("localhost:50051");
var client = new Greeter.GreeterClient(channel);
...
// With server authentication SSL/TLS
var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file
var channel = new Channel("localhost:50051", credentials);
var client = new Greeter.GreeterClient(channel);
```
###SSL/TLS for server authentication and encryption (Objective-C)
The default for Objective-C is to use SSL/TLS, as that's the most common use case when accessing
remote APIs.
```objective-c
// Base case - With server authentication SSL/TLS
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"localhost:50051"];
// Same as using @"https://localhost:50051".
...
// No encryption
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"http://localhost:50051"];
// Specifying the HTTP scheme explicitly forces no encryption.
```
###SSL/TLS for server authentication and encryption (Python)
```python
# Base case - No encryption
stub = early_adopter_create_GreeterService_stub('localhost', 50051)
...
# With server authentication SSL/TLS
stub = early_adopter_create_GreeterService_stub(
'localhost', 50051, secure=True, root_certificates=open('ca.pem').read())
...
```
n.b.: the beta API will look different
###Authenticating with Google (Ruby)
```ruby
# Base case - No encryption/authorization
stub = Helloworld::Greeter::Stub.new('localhost:50051')
...
# Authenticating with Google
require 'googleauth' # from http://www.rubydoc.info/gems/googleauth/0.1.0
...
creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file
scope = 'https://www.googleapis.com/auth/grpc-testing'
authorization = Google::Auth.get_application_default(scope)
stub = Helloworld::Greeter::Stub.new('localhost:50051',
creds: creds,
update_metadata: authorization.updater_proc)
```
###Authenticating with Google (Node.js)
```node
// Base case - No encryption/authorization
var stub = new helloworld.Greeter('localhost:50051');
...
// Authenticating with Google
var GoogleAuth = require('google-auth-library'); // from https://www.npmjs.com/package/google-auth-library
...
var creds = grpc.Credentials.createSsl(load_certs); // load_certs typically loads a CA roots file
var scope = 'https://www.googleapis.com/auth/grpc-testing';
(new GoogleAuth()).getApplicationDefault(function(err, auth) {
if (auth.createScopeRequired()) {
auth = auth.createScoped(scope);
}
var stub = new helloworld.Greeter('localhost:50051',
{credentials: creds},
grpc.getGoogleAuthDelegate(auth));
});
```
###Authenticating with Google (C#)
```csharp
// Base case - No encryption/authorization
var channel = new Channel("localhost:50051");
var client = new Greeter.GreeterClient(channel);
...
// Authenticating with Google
using Grpc.Auth; // from Grpc.Auth NuGet package
...
var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file
var channel = new Channel("localhost:50051", credentials);
string scope = "https://www.googleapis.com/auth/grpc-testing";
var authorization = GoogleCredential.GetApplicationDefault();
if (authorization.IsCreateScopedRequired)
{
authorization = credential.CreateScoped(new[] { scope });
}
var client = new Greeter.GreeterClient(channel,
new StubConfiguration(OAuth2InterceptorFactory.Create(credential)));
```
###Authenticating with Google (PHP)
```php
// Base case - No encryption/authorization
$client = new helloworld\GreeterClient(
new Grpc\BaseStub('localhost:50051', []));
...
// Authenticating with Google
// the environment variable "GOOGLE_APPLICATION_CREDENTIALS" needs to be set
$scope = "https://www.googleapis.com/auth/grpc-testing";
$auth = Google\Auth\ApplicationDefaultCredentials::getCredentials($scope);
$opts = [
'credentials' => Grpc\Credentials::createSsl(file_get_contents('ca.pem'));
'update_metadata' => $auth->getUpdateMetadataFunc(),
];
$client = new helloworld\GreeterClient(
new Grpc\BaseStub('localhost:50051', $opts));
```
###Authenticating with Google (Objective-C)
This example uses the [Google iOS Sign-In library](https://developers.google.com/identity/sign-in/ios/),
but it's easily extrapolated to any other OAuth2 library.
```objective-c
// Base case - No authentication
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
...
}];
...
// Authenticating with Google
// When signing the user in, ask her for the relevant scopes.
GIDSignIn.sharedInstance.scopes = @[@"https://www.googleapis.com/auth/grpc-testing"];
...
#import <ProtoRPC/ProtoRPC.h>
// Create a not-yet-started RPC. We want to set the request headers on this object before starting
// it.
ProtoRPC *call =
[client RPCToSayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
...
}];
// Set the access token to be used.
NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]}];
// Start the RPC.
[call start];
```
You can see a working example app, with a more detailed explanation, [here](examples/objective-c/auth_sample).
### Authenticating with Google (Python)
```python
# Base case - No encryption
stub = early_adopter_create_GreeterService_stub('localhost', 50051)
...
# With server authentication SSL/TLS
import oauth2client.client
credentials = oauth2client.GoogleCredentials.get_application_default()
scope = 'https://www.googleapis.com/auth/grpc-testing'
scoped_credentials = credentials.create_scoped([scope])
access_token = scoped_credentials.get_access_token().access_token
metadata_transformer = (
lambda x: [('Authorization', 'Bearer {}'.format(access_token))])
stub = early_adopter_create_GreeterService_stub(
'localhost', 50051, secure=True, root_certificates=open('ca.pem').read(),
metadata_transformer=metadata_transformer)
...
```
n.b.: the beta API will look different

@ -29,7 +29,7 @@ Pod::Spec.new do |s|
ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
ss.header_mappings_dir = dir
ss.requires_arc = true
ss.dependency "gRPC", "~> 0.11"
ss.dependency "gRPC", "~> 0.12"
ss.dependency "#{s.name}/Messages"
end
end

@ -29,7 +29,7 @@ Pod::Spec.new do |s|
ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
ss.header_mappings_dir = dir
ss.requires_arc = true
ss.dependency "gRPC", "~> 0.11"
ss.dependency "gRPC", "~> 0.12"
ss.dependency "#{s.name}/Messages"
end
end

@ -29,7 +29,7 @@ Pod::Spec.new do |s|
ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
ss.header_mappings_dir = dir
ss.requires_arc = true
ss.dependency "gRPC", "~> 0.11"
ss.dependency "gRPC", "~> 0.12"
ss.dependency "#{s.name}/Messages"
end
end

@ -36,7 +36,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
version = '0.11.2'
version = '0.12.0'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'http://www.grpc.io'
@ -78,6 +78,7 @@ Pod::Spec.new do |s|
'include/grpc/support/atm_gcc_atomic.h',
'include/grpc/support/atm_gcc_sync.h',
'include/grpc/support/atm_win32.h',
'include/grpc/support/avl.h',
'include/grpc/support/cmdline.h',
'include/grpc/support/cpu.h',
'include/grpc/support/histogram.h',
@ -103,6 +104,7 @@ Pod::Spec.new do |s|
'src/core/profiling/basic_timers.c',
'src/core/profiling/stap_timers.c',
'src/core/support/alloc.c',
'src/core/support/avl.c',
'src/core/support/cmdline.c',
'src/core/support/cpu_iphone.c',
'src/core/support/cpu_linux.c',
@ -167,6 +169,7 @@ Pod::Spec.new do |s|
'src/core/channel/subchannel_call_holder.h',
'src/core/client_config/client_config.h',
'src/core/client_config/connector.h',
'src/core/client_config/initial_connect_string.h',
'src/core/client_config/lb_policies/pick_first.h',
'src/core/client_config/lb_policies/round_robin.h',
'src/core/client_config/lb_policy.h',
@ -182,6 +185,7 @@ Pod::Spec.new do |s|
'src/core/client_config/subchannel_factory_decorators/add_channel_arg.h',
'src/core/client_config/subchannel_factory_decorators/merge_channel_args.h',
'src/core/client_config/uri_parser.h',
'src/core/compression/algorithm_metadata.h',
'src/core/compression/message_compress.h',
'src/core/debug/trace.h',
'src/core/httpcli/format_request.h',
@ -264,6 +268,7 @@ Pod::Spec.new do |s|
'src/core/transport/connectivity_state.h',
'src/core/transport/metadata.h',
'src/core/transport/metadata_batch.h',
'src/core/transport/static_metadata.h',
'src/core/transport/transport.h',
'src/core/transport/transport_impl.h',
'src/core/census/aggregation.h',
@ -311,6 +316,8 @@ Pod::Spec.new do |s|
'src/core/channel/subchannel_call_holder.c',
'src/core/client_config/client_config.c',
'src/core/client_config/connector.c',
'src/core/client_config/default_initial_connect_string.c',
'src/core/client_config/initial_connect_string.c',
'src/core/client_config/lb_policies/pick_first.c',
'src/core/client_config/lb_policies/round_robin.c',
'src/core/client_config/lb_policy.c',
@ -419,6 +426,7 @@ Pod::Spec.new do |s|
'src/core/transport/connectivity_state.c',
'src/core/transport/metadata.c',
'src/core/transport/metadata_batch.c',
'src/core/transport/static_metadata.c',
'src/core/transport/transport.c',
'src/core/transport/transport_op_string.c',
'src/core/census/context.c',
@ -463,6 +471,7 @@ Pod::Spec.new do |s|
'src/core/channel/subchannel_call_holder.h',
'src/core/client_config/client_config.h',
'src/core/client_config/connector.h',
'src/core/client_config/initial_connect_string.h',
'src/core/client_config/lb_policies/pick_first.h',
'src/core/client_config/lb_policies/round_robin.h',
'src/core/client_config/lb_policy.h',
@ -478,6 +487,7 @@ Pod::Spec.new do |s|
'src/core/client_config/subchannel_factory_decorators/add_channel_arg.h',
'src/core/client_config/subchannel_factory_decorators/merge_channel_args.h',
'src/core/client_config/uri_parser.h',
'src/core/compression/algorithm_metadata.h',
'src/core/compression/message_compress.h',
'src/core/debug/trace.h',
'src/core/httpcli/format_request.h',
@ -560,6 +570,7 @@ Pod::Spec.new do |s|
'src/core/transport/connectivity_state.h',
'src/core/transport/metadata.h',
'src/core/transport/metadata_batch.h',
'src/core/transport/static_metadata.h',
'src/core/transport/transport.h',
'src/core/transport/transport_impl.h',
'src/core/census/aggregation.h',
@ -578,7 +589,7 @@ Pod::Spec.new do |s|
ss.requires_arc = false
ss.libraries = 'z'
ss.dependency 'OpenSSL', '~> 1.0.200'
ss.dependency 'OpenSSL', '~> 1.0.204.1'
# ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
end

@ -46,10 +46,21 @@ class thread {
joined_ = false;
start();
}
template <class T, class U>
thread(void (T::*fptr)(U arg), T *obj, U arg) {
func_ = new thread_function_arg<T, U>(fptr, obj, arg);
joined_ = false;
start();
}
~thread() {
if (!joined_) std::terminate();
delete func_;
}
thread(thread &&other)
: func_(other.func_), thd_(other.thd_), joined_(other.joined_) {
other.joined_ = true;
other.func_ = NULL;
}
void join() {
gpr_thd_join(thd_);
joined_ = true;
@ -80,6 +91,18 @@ class thread {
void (T::*fptr_)();
T *obj_;
};
template <class T, class U>
class thread_function_arg : public thread_function_base {
public:
thread_function_arg(void (T::*fptr)(U arg), T *obj, U arg)
: fptr_(fptr), obj_(obj), arg_(arg) {}
virtual void call() { (obj_->*fptr_)(arg_); }
private:
void (T::*fptr_)(U arg);
T *obj_;
U arg_;
};
thread_function_base *func_;
gpr_thd_id thd_;
bool joined_;

@ -38,6 +38,7 @@
#include <memory>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/security/auth_context.h>
#include <grpc++/support/config.h>
#include <grpc++/support/status.h>
#include <grpc++/support/string_ref.h>
@ -186,9 +187,8 @@ std::shared_ptr<CallCredentials> GoogleIAMCredentials(
/// Combines a channel credentials and a call credentials into a composite
/// channel credentials.
std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
/// Combines two call credentials objects into a composite call credentials.
std::shared_ptr<CallCredentials> CompositeCallCredentials(
@ -207,9 +207,17 @@ class MetadataCredentialsPlugin {
// a different thread from the one processing the call.
virtual bool IsBlocking() const { return true; }
// Type of credentials this plugin is implementing.
virtual const char* GetType() const { return ""; }
// Gets the auth metatada produced by this plugin.
// The fully qualified method name is:
// service_url + "/" + method_name.
// The channel_auth_context contains (among other things), the identity of
// the server.
virtual Status GetMetadata(
grpc::string_ref service_url,
grpc::string_ref service_url, grpc::string_ref method_name,
const AuthContext& channel_auth_context,
std::multimap<grpc::string, grpc::string>* metadata) = 0;
};

@ -127,6 +127,17 @@ typedef struct {
/** Initial sequence number for http2 transports */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"
/** Amount to read ahead on individual streams. Defaults to 64kb, larger
values can help throughput on high-latency connections.
NOTE: at some point we'd like to auto-tune this, and this parameter
will become a no-op. */
#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
/** How much memory to use for hpack decoding */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
"grpc.http2.hpack_table_size.decoder"
/** How much memory to use for hpack encoding */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
"grpc.http2.hpack_table_size.encoder"
/** Default authority to pass if none specified on call construction */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
/** Primary user agent: goes at the start of the user-agent metadata

@ -41,6 +41,81 @@
extern "C" {
#endif
/* --- Authentication Context. --- */
#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type"
#define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
#define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
#define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
typedef struct grpc_auth_context grpc_auth_context;
typedef struct grpc_auth_property_iterator {
const grpc_auth_context *ctx;
size_t index;
const char *name;
} grpc_auth_property_iterator;
/* value, if not NULL, is guaranteed to be NULL terminated. */
typedef struct grpc_auth_property {
char *name;
char *value;
size_t value_length;
} grpc_auth_property;
/* Returns NULL when the iterator is at the end. */
const grpc_auth_property *grpc_auth_property_iterator_next(
grpc_auth_property_iterator *it);
/* Iterates over the auth context. */
grpc_auth_property_iterator grpc_auth_context_property_iterator(
const grpc_auth_context *ctx);
/* Gets the peer identity. Returns an empty iterator (first _next will return
NULL) if the peer is not authenticated. */
grpc_auth_property_iterator grpc_auth_context_peer_identity(
const grpc_auth_context *ctx);
/* Finds a property in the context. May return an empty iterator (first _next
will return NULL) if no property with this name was found in the context. */
grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
const grpc_auth_context *ctx, const char *name);
/* Gets the name of the property that indicates the peer identity. Will return
NULL if the peer is not authenticated. */
const char *grpc_auth_context_peer_identity_property_name(
const grpc_auth_context *ctx);
/* Returns 1 if the peer is authenticated, 0 otherwise. */
int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx);
/* Gets the auth context from the call. Caller needs to call
grpc_auth_context_release on the returned context. */
grpc_auth_context *grpc_call_auth_context(grpc_call *call);
/* Releases the auth context returned from grpc_call_auth_context. */
void grpc_auth_context_release(grpc_auth_context *context);
/* --
The following auth context methods should only be called by a server metadata
processor to set properties extracted from auth metadata.
-- */
/* Add a property. */
void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name,
const char *value, size_t value_length);
/* Add a C string property. */
void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
const char *name,
const char *value);
/* Sets the property name. Returns 1 if successful or 0 in case of failure
(which means that no property with this name exists). */
int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
const char *name);
/* --- grpc_channel_credentials object. ---
A channel credentials object represents a way to authenticate a client on a
@ -165,6 +240,24 @@ typedef void (*grpc_credentials_plugin_metadata_cb)(
void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
grpc_status_code status, const char *error_details);
/* Context that can be used by metadata credentials plugin in order to create
auth related metadata. */
typedef struct {
/* The fully qualifed service url. */
const char *service_url;
/* The method name of the RPC being called (not fully qualified).
The fully qualified method name can be built from the service_url:
full_qualified_method_name = ctx->service_url + '/' + ctx->method_name. */
const char *method_name;
/* The auth_context of the channel which gives the server's identity. */
const grpc_auth_context *channel_auth_context;
/* Reserved for future use. */
void *reserved;
} grpc_auth_metadata_context;
/* grpc_metadata_credentials plugin is an API user provided structure used to
create grpc_credentials objects that can be set on a channel (composed) or
a call. See grpc_credentials_metadata_create_from_plugin below.
@ -172,11 +265,11 @@ typedef void (*grpc_credentials_plugin_metadata_cb)(
every call in scope for the credentials created from it. */
typedef struct {
/* The implementation of this method has to be non-blocking.
- service_url is the fully qualified URL that the client stack is
connecting to.
- context is the information that can be used by the plugin to create auth
metadata.
- cb is the callback that needs to be called when the metadata is ready.
- user_data needs to be passed as the first parameter of the callback. */
void (*get_metadata)(void *state, const char *service_url,
void (*get_metadata)(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data);
/* Destroys the plugin state. */
@ -184,6 +277,9 @@ typedef struct {
/* State that will be set as the first parameter of the methods above. */
void *state;
/* Type of credentials that this plugin is implementing. */
const char *type;
} grpc_metadata_credentials_plugin;
/* Creates a credentials object from a plugin. */
@ -239,81 +335,6 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_call_error grpc_call_set_credentials(grpc_call *call,
grpc_call_credentials *creds);
/* --- Authentication Context. --- */
#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type"
#define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
#define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
#define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
typedef struct grpc_auth_context grpc_auth_context;
typedef struct grpc_auth_property_iterator {
const grpc_auth_context *ctx;
size_t index;
const char *name;
} grpc_auth_property_iterator;
/* value, if not NULL, is guaranteed to be NULL terminated. */
typedef struct grpc_auth_property {
char *name;
char *value;
size_t value_length;
} grpc_auth_property;
/* Returns NULL when the iterator is at the end. */
const grpc_auth_property *grpc_auth_property_iterator_next(
grpc_auth_property_iterator *it);
/* Iterates over the auth context. */
grpc_auth_property_iterator grpc_auth_context_property_iterator(
const grpc_auth_context *ctx);
/* Gets the peer identity. Returns an empty iterator (first _next will return
NULL) if the peer is not authenticated. */
grpc_auth_property_iterator grpc_auth_context_peer_identity(
const grpc_auth_context *ctx);
/* Finds a property in the context. May return an empty iterator (first _next
will return NULL) if no property with this name was found in the context. */
grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
const grpc_auth_context *ctx, const char *name);
/* Gets the name of the property that indicates the peer identity. Will return
NULL if the peer is not authenticated. */
const char *grpc_auth_context_peer_identity_property_name(
const grpc_auth_context *ctx);
/* Returns 1 if the peer is authenticated, 0 otherwise. */
int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx);
/* Gets the auth context from the call. Caller needs to call
grpc_auth_context_release on the returned context. */
grpc_auth_context *grpc_call_auth_context(grpc_call *call);
/* Releases the auth context returned from grpc_call_auth_context. */
void grpc_auth_context_release(grpc_auth_context *context);
/* --
The following auth context methods should only be called by a server metadata
processor to set properties extracted from auth metadata.
-- */
/* Add a property. */
void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name,
const char *value, size_t value_length);
/* Add a C string property. */
void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
const char *name,
const char *value);
/* Sets the property name. Returns 1 if successful or 0 in case of failure
(which means that no property with this name exists). */
int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
const char *name);
/* --- Auth Metadata Processing --- */
/* Callback function that is called when the metadata processing is done.

@ -0,0 +1,91 @@
/*
*
* Copyright 2015, 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_SUPPORT_AVL_H
#define GRPC_SUPPORT_AVL_H
#include <grpc/support/sync.h>
/** internal node of an AVL tree */
typedef struct gpr_avl_node {
gpr_refcount refs;
void *key;
void *value;
struct gpr_avl_node *left;
struct gpr_avl_node *right;
long height;
} gpr_avl_node;
typedef struct gpr_avl_vtable {
/** destroy a key */
void (*destroy_key)(void *key);
/** copy a key, returning new value */
void *(*copy_key)(void *key);
/** compare key1, key2; return <0 if key1 < key2,
>0 if key1 > key2, 0 if key1 == key2 */
long (*compare_keys)(void *key1, void *key2);
/** destroy a value */
void (*destroy_value)(void *value);
/** copy a value */
void *(*copy_value)(void *value);
} gpr_avl_vtable;
/** "pointer" to an AVL tree - this is a reference
counted object - use gpr_avl_ref to add a reference,
gpr_avl_unref when done with a reference */
typedef struct gpr_avl {
const gpr_avl_vtable *vtable;
gpr_avl_node *root;
} gpr_avl;
/** create an immutable AVL tree */
gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable);
/** add a reference to an existing tree - returns
the tree as a convenience */
gpr_avl gpr_avl_ref(gpr_avl avl);
/** remove a reference to a tree - destroying it if there
are no references left */
void gpr_avl_unref(gpr_avl avl);
/** return a new tree with (key, value) added to avl.
implicitly unrefs avl to allow easy chaining.
if key exists in avl, the new tree's key entry updated
(i.e. a duplicate is not created) */
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value);
/** return a new tree with key deleted */
gpr_avl gpr_avl_remove(gpr_avl avl, void *key);
/** lookup key, and return the associated value.
does not mutate avl.
returns NULL if key is not found. */
void *gpr_avl_get(gpr_avl avl, void *key);
#endif

@ -144,6 +144,9 @@ gpr_slice gpr_slice_from_copied_string(const char *source);
memcpy(slice->data, source, len); */
gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len);
/* Create a slice pointing to constant memory */
gpr_slice gpr_slice_from_static_string(const char *source);
/* Return a result slice derived from s, which shares a ref count with s, where
result.data==s.data+begin, and result.length==end-begin.
The ref count of s is increased by one.

@ -1,6 +1,6 @@
{
"name": "grpc",
"version": "0.11.1",
"version": "0.12.0",
"author": "Google Inc.",
"description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/",

@ -0,0 +1,141 @@
<!DOCTYPE html>
<html lang="en">
<head><title>Interop Test Result</title></head>
<body>
<%def name="fill_one_test_result(shortname, resultset)">
% if shortname in resultset:
## Because interop tests does not have runs_per_test flag, each test is
## run once. So there should only be one element for each result.
<% result = resultset[shortname][0] %>
% if result.state == 'PASSED':
<td bgcolor="green">PASS</td>
% else:
<%
tooltip = ''
if result.returncode > 0 or result.message:
if result.returncode > 0:
tooltip = 'returncode: %d ' % result.returncode
if result.message:
tooltip = '%smessage: %s' % (tooltip, result.message)
%>
% if result.state == 'FAILED':
<td bgcolor="red">
% if tooltip:
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">FAIL</a></td>
% else:
FAIL</td>
% endif
% elif result.state == 'TIMEOUT':
<td bgcolor="yellow">
% if tooltip:
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">TIMEOUT</a></td>
% else:
TIMEOUT</td>
% endif
% endif
% endif
% else:
<td bgcolor="magenta">Not implemented</td>
% endif
</%def>
% if num_failures > 1:
<p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
% elif num_failures:
<p><h2><font color="red">${num_failures} test failed!</font></h2></p>
% else:
<p><h2><font color="green">All tests passed!</font></h2></p>
% endif
% if cloud_to_prod:
## Each column header is the client language.
<h2>Cloud to Prod</h2>
<table style="width:100%" border="1">
<tr bgcolor="#00BFFF">
<th>Client languages &#9658;<br/>Test Cases &#9660;</th>
% for client_lang in client_langs:
<th>${client_lang}</th>
% endfor
</tr>
% for test_case in test_cases + auth_test_cases:
<tr><td><b>${test_case}</b></td>
% for client_lang in client_langs:
<%
if test_case in auth_test_cases:
shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case)
else:
shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case)
%>
${fill_one_test_result(shortname, resultset)}
% endfor
</tr>
% endfor
</table>
% endif
% if http2_interop:
## Each column header is the server language.
<h2>HTTP/2 Interop</h2>
<table style="width:100%" border="1">
<tr bgcolor="#00BFFF">
<th>Servers &#9658;<br/>Test Cases &#9660;</th>
% for server_lang in server_langs:
<th>${server_lang}</th>
% endfor
% if cloud_to_prod:
<th>prod</th>
% endif
</tr>
% for test_case in http2_cases:
<tr><td><b>${test_case}</b></td>
## Fill up the cells with test result.
% for server_lang in server_langs:
<%
shortname = 'cloud_to_cloud:http2:%s_server:%s' % (
server_lang, test_case)
%>
${fill_one_test_result(shortname, resultset)}
% endfor
% if cloud_to_prod:
<% shortname = 'cloud_to_prod:http2:%s' % test_case %>
${fill_one_test_result(shortname, resultset)}
% endif
</tr>
% endfor
</table>
% endif
% if server_langs:
% for test_case in test_cases:
## Each column header is the client language.
<h2>${test_case}</h2>
<table style="width:100%" border="1">
<tr bgcolor="#00BFFF">
<th>Client languages &#9658;<br/>Server languages &#9660;</th>
% for client_lang in client_langs:
<th>${client_lang}</th>
% endfor
</tr>
## Each row head is the server language.
% for server_lang in server_langs:
<tr>
<td><b>${server_lang}</b></td>
% for client_lang in client_langs:
<%
shortname = 'cloud_to_cloud:%s:%s_server:%s' % (
client_lang, server_lang, test_case)
%>
${fill_one_test_result(shortname, resultset)}
% endfor
</tr>
% endfor
</table>
% endfor
% endif
<script>
$(document).ready(function(){$('[data-toggle="tooltip"]').tooltip();});
</script>
</body>
</html>

@ -36,16 +36,18 @@
#include <stdio.h>
#include <string.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/noop_filter.h"
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_rpc_stats.h"
#include <grpc/census.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/noop_filter.h"
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/transport/static_metadata.h"
typedef struct call_data {
census_op_id op_id;
census_context *ctxt;
@ -58,16 +60,14 @@ typedef struct call_data {
grpc_closure finish_recv;
} call_data;
typedef struct channel_data {
grpc_mdstr *path_str; /* pointer to meta data str with key == ":path" */
} channel_data;
typedef struct channel_data { gpr_uint8 unused; } channel_data;
static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
call_data *calld,
channel_data *chand) {
grpc_linked_mdelem *m;
for (m = md->list.head; m != NULL; m = m->next) {
if (m->md->key == chand->path_str) {
if (m->md->key == GRPC_MDSTR_PATH) {
gpr_log(GPR_DEBUG, "%s",
(const char *)GPR_SLICE_START_PTR(m->md->value->slice));
/* Add method tag here */
@ -161,16 +161,12 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element_args *args) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(chand != NULL);
chand->path_str = grpc_mdstr_from_string(args->metadata_context, ":path");
}
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
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 = {

@ -105,7 +105,6 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
const grpc_channel_filter **filters,
size_t filter_count, grpc_channel *master,
const grpc_channel_args *channel_args,
grpc_mdctx *metadata_context,
grpc_channel_stack *stack) {
size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
@ -125,7 +124,6 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
for (i = 0; i < filter_count; i++) {
args.master = master;
args.channel_args = channel_args;
args.metadata_context = metadata_context;
args.is_first = i == 0;
args.is_last = i == (filter_count - 1);
elems[i].filter = filters[i];

@ -54,7 +54,6 @@ typedef struct grpc_call_element grpc_call_element;
typedef struct {
grpc_channel *master;
const grpc_channel_args *channel_args;
grpc_mdctx *metadata_context;
int is_first;
int is_last;
} grpc_channel_element_args;
@ -180,7 +179,6 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
const grpc_channel_filter **filters,
size_t filter_count, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context,
grpc_channel_stack *stack);
/* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,

@ -55,8 +55,6 @@
typedef grpc_subchannel_call_holder call_data;
typedef struct client_channel_channel_data {
/** metadata context for this channel */
grpc_mdctx *mdctx;
/** resolver for this channel */
grpc_resolver *resolver;
/** have we started resolving this channel */
@ -387,7 +385,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
gpr_mu_init(&chand->mu_config);
chand->mdctx = args->metadata_context;
chand->master = args->master;
grpc_pollset_set_init(&chand->pollset_set);
grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);

@ -54,9 +54,6 @@
* load-balancing mechanisms meant for communication from within the core. */
typedef struct client_uchannel_channel_data {
/** metadata context for this channel */
grpc_mdctx *mdctx;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
@ -161,7 +158,6 @@ static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand);
GPR_ASSERT(args->is_last);
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
chand->mdctx = args->metadata_context;
chand->master = args->master;
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_uchannel");
@ -252,13 +248,11 @@ grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
grpc_channel *channel = NULL;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
grpc_mdctx *mdctx = grpc_subchannel_get_mdctx(subchannel);
grpc_channel *master = grpc_subchannel_get_master(subchannel);
char *target = grpc_channel_get_target(master);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
size_t n = 0;
grpc_mdctx_ref(mdctx);
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
}
@ -266,8 +260,8 @@ grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
filters[n++] = &grpc_client_uchannel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
args, mdctx, 1);
channel =
grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
gpr_free(target);
return channel;

@ -39,11 +39,13 @@
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include "src/core/channel/compress_filter.h"
#include "src/core/channel/channel_args.h"
#include "src/core/profiling/timers.h"
#include "src/core/channel/compress_filter.h"
#include "src/core/compression/algorithm_metadata.h"
#include "src/core/compression/message_compress.h"
#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
#include "src/core/transport/static_metadata.h"
typedef struct call_data {
gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
@ -67,20 +69,12 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
/** Metadata key for the incoming (requested) compression algorithm */
grpc_mdstr *mdstr_request_compression_algorithm_key;
/** Metadata key for the outgoing (used) compression algorithm */
grpc_mdstr *mdstr_outgoing_compression_algorithm_key;
/** Metadata key for the accepted encodings */
grpc_mdstr *mdstr_compression_capabilities_key;
/** Precomputed metadata elements for all available compression algorithms */
grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT];
/** Precomputed metadata elements for the accepted encodings */
grpc_mdelem *mdelem_accept_encoding;
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
/** Compression options for the channel */
grpc_compression_options compression_options;
/** Supported compression algorithms */
gpr_uint32 supported_compression_algorithms;
} channel_data;
/** For each \a md element from the incoming metadata, filter out the entry for
@ -91,7 +85,7 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
if (md->key == channeld->mdstr_request_compression_algorithm_key) {
if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
&calld->compression_algorithm)) {
@ -147,14 +141,13 @@ static void process_send_initial_metadata(
/* hint compression algorithm */
grpc_metadata_batch_add_tail(
initial_metadata, &calld->compression_algorithm_storage,
GRPC_MDELEM_REF(
channeld
->mdelem_compression_algorithms[calld->compression_algorithm]));
grpc_compression_encoding_mdelem(calld->compression_algorithm));
/* convey supported compression algorithms */
grpc_metadata_batch_add_tail(
initial_metadata, &calld->accept_encoding_storage,
GRPC_MDELEM_REF(channeld->mdelem_accept_encoding));
grpc_metadata_batch_add_tail(initial_metadata,
&calld->accept_encoding_storage,
GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(
channeld->supported_compression_algorithms));
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
@ -266,10 +259,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element_args *args) {
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1];
size_t supported_algorithms_idx = 0;
char *accept_encoding_str;
size_t accept_encoding_str_len;
grpc_compression_options_init(&channeld->compression_options);
channeld->compression_options.enabled_algorithms_bitset =
@ -284,61 +273,22 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
channeld->compression_options.default_compression_algorithm =
channeld->default_compression_algorithm;
channeld->mdstr_request_compression_algorithm_key = grpc_mdstr_from_string(
args->metadata_context, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY);
channeld->mdstr_outgoing_compression_algorithm_key =
grpc_mdstr_from_string(args->metadata_context, "grpc-encoding");
channeld->mdstr_compression_capabilities_key =
grpc_mdstr_from_string(args->metadata_context, "grpc-accept-encoding");
channeld->supported_compression_algorithms = 0;
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
char *algorithm_name;
/* skip disabled algorithms */
if (grpc_compression_options_is_algorithm_enabled(
&channeld->compression_options, algo_idx) == 0) {
continue;
}
GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
channeld->mdelem_compression_algorithms[algo_idx] =
grpc_mdelem_from_metadata_strings(
args->metadata_context,
GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key),
grpc_mdstr_from_string(args->metadata_context, algorithm_name));
if (algo_idx > 0) {
supported_algorithms_names[supported_algorithms_idx++] = algorithm_name;
}
channeld->supported_compression_algorithms |= 1u << algo_idx;
}
/* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated
* arrays, as to avoid the heap allocs */
accept_encoding_str =
gpr_strjoin_sep(supported_algorithms_names, supported_algorithms_idx, ",",
&accept_encoding_str_len);
channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings(
args->metadata_context,
GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key),
grpc_mdstr_from_string(args->metadata_context, accept_encoding_str));
gpr_free(accept_encoding_str);
GPR_ASSERT(!args->is_last);
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key);
GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key);
GRPC_MDSTR_UNREF(channeld->mdstr_compression_capabilities_key);
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]);
}
GRPC_MDELEM_UNREF(channeld->mdelem_accept_encoding);
}
const grpc_channel_filter grpc_compress_filter = {

@ -31,12 +31,13 @@
*/
#include "src/core/channel/http_client_filter.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/support/string.h"
#include <string.h>
#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
#include "src/core/transport/static_metadata.h"
typedef struct call_data {
grpc_linked_mdelem method;
@ -57,12 +58,7 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
grpc_mdelem *te_trailers;
grpc_mdelem *method;
grpc_mdelem *scheme;
grpc_mdelem *content_type;
grpc_mdelem *status;
/** complete user agent mdelem */
grpc_mdelem *static_scheme;
grpc_mdelem *user_agent;
} channel_data;
@ -73,14 +69,12 @@ typedef struct {
static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
client_recv_filter_args *a = user_data;
grpc_call_element *elem = a->elem;
channel_data *channeld = elem->channel_data;
if (md == channeld->status) {
if (md == GRPC_MDELEM_STATUS_200) {
return NULL;
} else if (md->key == channeld->status->key) {
grpc_call_element_send_cancel(a->exec_ctx, elem);
} else if (md->key == GRPC_MDSTR_STATUS) {
grpc_call_element_send_cancel(a->exec_ctx, a->elem);
return NULL;
} else if (md->key == channeld->content_type->key) {
} else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
return NULL;
}
return md;
@ -98,14 +92,12 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
}
static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
channel_data *channeld = elem->channel_data;
/* eat the things we'd like to set ourselves */
if (md->key == channeld->method->key) return NULL;
if (md->key == channeld->scheme->key) return NULL;
if (md->key == channeld->te_trailers->key) return NULL;
if (md->key == channeld->content_type->key) return NULL;
if (md->key == channeld->user_agent->key) return NULL;
if (md->key == GRPC_MDSTR_METHOD) return NULL;
if (md->key == GRPC_MDSTR_SCHEME) return NULL;
if (md->key == GRPC_MDSTR_TE) return NULL;
if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL;
if (md->key == GRPC_MDSTR_USER_AGENT) return NULL;
return md;
}
@ -120,14 +112,14 @@ static void hc_mutate_op(grpc_call_element *elem,
/* Send : prefixed headers, which have to be before any application
layer headers. */
grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
GRPC_MDELEM_REF(channeld->method));
GRPC_MDELEM_METHOD_POST);
grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
GRPC_MDELEM_REF(channeld->scheme));
channeld->static_scheme);
grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
GRPC_MDELEM_REF(channeld->te_trailers));
grpc_metadata_batch_add_tail(op->send_initial_metadata,
&calld->content_type,
GRPC_MDELEM_REF(channeld->content_type));
GRPC_MDELEM_TE_TRAILERS);
grpc_metadata_batch_add_tail(
op->send_initial_metadata, &calld->content_type,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent,
GRPC_MDELEM_REF(channeld->user_agent));
}
@ -162,21 +154,28 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
static const char *scheme_from_args(const grpc_channel_args *args) {
static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
unsigned i;
size_t j;
grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
GRPC_MDELEM_SCHEME_HTTPS};
if (args != NULL) {
for (i = 0; i < args->num_args; ++i) {
if (args->args[i].type == GRPC_ARG_STRING &&
strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
return args->args[i].value.string;
for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) {
if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value),
args->args[i].value.string)) {
return valid_schemes[j];
}
}
}
}
}
return "http";
return GRPC_MDELEM_SCHEME_HTTP;
}
static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
const grpc_channel_args *args) {
static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
gpr_strvec v;
size_t i;
int is_first = 1;
@ -218,7 +217,7 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
tmp = gpr_strvec_flatten(&v, NULL);
gpr_strvec_destroy(&v);
result = grpc_mdstr_from_string(mdctx, tmp);
result = grpc_mdstr_from_string(tmp);
gpr_free(tmp);
return result;
@ -228,43 +227,18 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
channel_data *chand = elem->channel_data;
GPR_ASSERT(!args->is_last);
/* initialize members */
channeld->te_trailers =
grpc_mdelem_from_strings(args->metadata_context, "te", "trailers");
channeld->method =
grpc_mdelem_from_strings(args->metadata_context, ":method", "POST");
channeld->scheme = grpc_mdelem_from_strings(
args->metadata_context, ":scheme", scheme_from_args(args->channel_args));
channeld->content_type = grpc_mdelem_from_strings(
args->metadata_context, "content-type", "application/grpc");
channeld->status =
grpc_mdelem_from_strings(args->metadata_context, ":status", "200");
channeld->user_agent = grpc_mdelem_from_metadata_strings(
args->metadata_context,
grpc_mdstr_from_string(args->metadata_context, "user-agent"),
user_agent_from_args(args->metadata_context, args->channel_args));
chand->static_scheme = scheme_from_args(args->channel_args);
chand->user_agent = grpc_mdelem_from_metadata_strings(
GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
GRPC_MDELEM_UNREF(channeld->te_trailers);
GRPC_MDELEM_UNREF(channeld->method);
GRPC_MDELEM_UNREF(channeld->scheme);
GRPC_MDELEM_UNREF(channeld->content_type);
GRPC_MDELEM_UNREF(channeld->status);
GRPC_MDELEM_UNREF(channeld->user_agent);
channel_data *chand = elem->channel_data;
GRPC_MDELEM_UNREF(chand->user_agent);
}
const grpc_channel_filter grpc_http_client_filter = {

@ -33,10 +33,11 @@
#include "src/core/channel/http_server_filter.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <string.h>
#include "src/core/profiling/timers.h"
#include "src/core/transport/static_metadata.h"
typedef struct call_data {
gpr_uint8 seen_path;
@ -57,22 +58,7 @@ typedef struct call_data {
grpc_closure hs_on_recv;
} call_data;
typedef struct channel_data {
grpc_mdelem *te_trailers;
grpc_mdelem *method_post;
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_ok;
grpc_mdelem *status_not_found;
grpc_mdstr *path_key;
grpc_mdstr *authority_key;
grpc_mdstr *host_key;
grpc_mdctx *mdctx;
} channel_data;
typedef struct channel_data { gpr_uint8 unused; } channel_data;
typedef struct {
grpc_call_element *elem;
@ -82,25 +68,24 @@ typedef struct {
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
server_filter_args *a = user_data;
grpc_call_element *elem = a->elem;
channel_data *channeld = elem->channel_data;
call_data *calld = elem->call_data;
/* Check if it is one of the headers we care about. */
if (md == channeld->te_trailers || md == channeld->method_post ||
md == channeld->http_scheme || md == channeld->https_scheme ||
md == channeld->grpc_scheme || md == channeld->content_type) {
if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
/* swallow it */
if (md == channeld->method_post) {
if (md == GRPC_MDELEM_METHOD_POST) {
calld->seen_post = 1;
} else if (md->key == channeld->http_scheme->key) {
} else if (md->key == GRPC_MDSTR_SCHEME) {
calld->seen_scheme = 1;
} else if (md == channeld->te_trailers) {
} else if (md == GRPC_MDELEM_TE_TRAILERS) {
calld->seen_te_trailers = 1;
}
/* TODO(klempner): Track that we've seen all the headers we should
require */
return NULL;
} else if (md->key == channeld->content_type->key) {
} else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
0) {
/* Although the C implementation doesn't (currently) generate them,
@ -112,12 +97,11 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
/* 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_mdstr_as_c_string(md->value));
}
return NULL;
} else if (md->key == channeld->te_trailers->key ||
md->key == channeld->method_post->key ||
md->key == channeld->http_scheme->key) {
} else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
md->key == GRPC_MDSTR_SCHEME) {
gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
/* swallow it and error everything out. */
@ -125,22 +109,21 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
on the wire here. */
grpc_call_element_send_cancel(a->exec_ctx, elem);
return NULL;
} else if (md->key == channeld->path_key) {
} else if (md->key == GRPC_MDSTR_PATH) {
if (calld->seen_path) {
gpr_log(GPR_ERROR, "Received :path twice");
return NULL;
}
calld->seen_path = 1;
return md;
} else if (md->key == channeld->authority_key) {
} else if (md->key == GRPC_MDSTR_AUTHORITY) {
calld->seen_authority = 1;
return md;
} else if (md->key == channeld->host_key) {
} else if (md->key == GRPC_MDSTR_HOST) {
/* translate host to :authority since :authority may be
omitted */
grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
channeld->mdctx, GRPC_MDSTR_REF(channeld->authority_key),
GRPC_MDSTR_REF(md->value));
GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
GRPC_MDELEM_UNREF(md);
calld->seen_authority = 1;
return authority;
@ -191,15 +174,14 @@ static void hs_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
if (op->send_initial_metadata != NULL && !calld->sent_status) {
calld->sent_status = 1;
grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status,
GRPC_MDELEM_REF(channeld->status_ok));
grpc_metadata_batch_add_tail(op->send_initial_metadata,
&calld->content_type,
GRPC_MDELEM_REF(channeld->content_type));
GRPC_MDELEM_STATUS_200);
grpc_metadata_batch_add_tail(
op->send_initial_metadata, &calld->content_type,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
}
if (op->recv_initial_metadata) {
@ -238,56 +220,12 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!args->is_last);
/* initialize members */
channeld->te_trailers =
grpc_mdelem_from_strings(args->metadata_context, "te", "trailers");
channeld->status_ok =
grpc_mdelem_from_strings(args->metadata_context, ":status", "200");
channeld->status_not_found =
grpc_mdelem_from_strings(args->metadata_context, ":status", "404");
channeld->method_post =
grpc_mdelem_from_strings(args->metadata_context, ":method", "POST");
channeld->http_scheme =
grpc_mdelem_from_strings(args->metadata_context, ":scheme", "http");
channeld->https_scheme =
grpc_mdelem_from_strings(args->metadata_context, ":scheme", "https");
channeld->grpc_scheme =
grpc_mdelem_from_strings(args->metadata_context, ":scheme", "grpc");
channeld->path_key = grpc_mdstr_from_string(args->metadata_context, ":path");
channeld->authority_key =
grpc_mdstr_from_string(args->metadata_context, ":authority");
channeld->host_key = grpc_mdstr_from_string(args->metadata_context, "host");
channeld->content_type = grpc_mdelem_from_strings(
args->metadata_context, "content-type", "application/grpc");
channeld->mdctx = args->metadata_context;
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
GRPC_MDELEM_UNREF(channeld->te_trailers);
GRPC_MDELEM_UNREF(channeld->status_ok);
GRPC_MDELEM_UNREF(channeld->status_not_found);
GRPC_MDELEM_UNREF(channeld->method_post);
GRPC_MDELEM_UNREF(channeld->http_scheme);
GRPC_MDELEM_UNREF(channeld->https_scheme);
GRPC_MDELEM_UNREF(channeld->grpc_scheme);
GRPC_MDELEM_UNREF(channeld->content_type);
GRPC_MDSTR_UNREF(channeld->path_key);
GRPC_MDSTR_UNREF(channeld->authority_key);
GRPC_MDSTR_UNREF(channeld->host_key);
}
const grpc_channel_filter grpc_http_server_filter = {

@ -51,6 +51,8 @@ typedef struct {
/** address to connect to */
const struct sockaddr *addr;
size_t addr_len;
/** initial connect string to send */
gpr_slice initial_connect_string;
/** deadline for connection */
gpr_timespec deadline;
/** channel arguments (to be passed to transport) */

@ -0,0 +1,39 @@
/*
*
* Copyright 2015, 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/support/slice.h>
#include "src/core/iomgr/sockaddr.h"
void grpc_set_default_initial_connect_string(struct sockaddr **addr,
size_t *addr_len,
gpr_slice *initial_str) {}

@ -0,0 +1,53 @@
/*
*
* Copyright 2015, 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 "src/core/client_config/initial_connect_string.h"
#include <stddef.h>
extern void grpc_set_default_initial_connect_string(struct sockaddr **addr,
size_t *addr_len,
gpr_slice *initial_str);
static grpc_set_initial_connect_string_func g_set_initial_connect_string_func =
grpc_set_default_initial_connect_string;
void grpc_test_set_initial_connect_string_function(
grpc_set_initial_connect_string_func func) {
g_set_initial_connect_string_func = func;
}
void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
gpr_slice *initial_str) {
g_set_initial_connect_string_func(addr, addr_len, initial_str);
}

@ -0,0 +1,50 @@
/*
*
* Copyright 2015, 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_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
#include <grpc/support/slice.h>
#include "src/core/iomgr/sockaddr.h"
typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr,
size_t *addr_len,
gpr_slice *initial_str);
void grpc_test_set_initial_connect_string_function(
grpc_set_initial_connect_string_func func);
/** Set a string to be sent once connected. Optionally reset addr. */
void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
gpr_slice *connect_string);
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */

@ -40,6 +40,7 @@
#include "src/core/channel/channel_args.h"
#include "src/core/channel/client_channel.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/client_config/initial_connect_string.h"
#include "src/core/iomgr/timer.h"
#include "src/core/profiling/timers.h"
#include "src/core/surface/channel.h"
@ -87,8 +88,8 @@ struct grpc_subchannel {
/** address to connect to */
struct sockaddr *addr;
size_t addr_len;
/** metadata context */
grpc_mdctx *mdctx;
/** initial string to send to peer */
gpr_slice initial_connect_string;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
@ -267,7 +268,7 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
gpr_free((void *)c->filters);
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
grpc_mdctx_unref(c->mdctx);
gpr_slice_unref(c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector);
gpr_free(c);
@ -305,12 +306,12 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
c->addr = gpr_malloc(args->addr_len);
memcpy(c->addr, args->addr, args->addr_len);
c->addr_len = args->addr_len;
grpc_set_initial_connect_string(&c->addr, &c->addr_len,
&c->initial_connect_string);
c->args = grpc_channel_args_copy(args->args);
c->mdctx = args->mdctx;
c->master = args->master;
c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem);
c->random = random_seed();
grpc_mdctx_ref(c->mdctx);
grpc_closure_init(&c->connected, subchannel_connected, c);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel");
@ -380,6 +381,7 @@ static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c);
args.channel_args = c->args;
args.initial_connect_string = c->initial_connect_string;
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
&c->connected);
@ -624,7 +626,7 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
con->refs = 0;
con->subchannel = c;
grpc_channel_stack_init(exec_ctx, filters, num_filters, c->master, c->args,
c->mdctx, stk);
stk);
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
gpr_free((void *)c->connecting_result.filters);
memset(&c->connecting_result, 0, sizeof(c->connecting_result));
@ -871,10 +873,6 @@ static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx,
return call;
}
grpc_mdctx *grpc_subchannel_get_mdctx(grpc_subchannel *subchannel) {
return subchannel->mdctx;
}
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel) {
return subchannel->master;
}

@ -77,10 +77,10 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call (possibly asynchronously).
*
* If the returned status is 1, the call will return immediately and \a target
* will point to a connected \a subchannel_call instance. Note that \a notify
* If the returned status is 1, the call will return immediately and \a target
* will point to a connected \a subchannel_call instance. Note that \a notify
* will \em not be invoked in this case.
* Otherwise, if the returned status is 0, the subchannel call will be created
* Otherwise, if the returned status is 0, the subchannel call will be created
* asynchronously, invoking the \a notify callback upon completion. */
int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
@ -147,8 +147,6 @@ struct grpc_subchannel_args {
/** Address to connect to */
struct sockaddr *addr;
size_t addr_len;
/** metadata context to use */
grpc_mdctx *mdctx;
/** master channel */
grpc_channel *master;
};
@ -157,9 +155,6 @@ struct grpc_subchannel_args {
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args);
/** Return the metadata context associated with the subchannel */
grpc_mdctx *grpc_subchannel_get_mdctx(grpc_subchannel *subchannel);
/** Return the master channel associated with the subchannel */
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel);

@ -37,7 +37,9 @@
#include <grpc/compression.h>
#include <grpc/support/useful.h>
#include "src/core/compression/algorithm_metadata.h"
#include "src/core/surface/api_trace.h"
#include "src/core/transport/static_metadata.h"
int grpc_compression_algorithm_parse(const char *name, size_t name_length,
grpc_compression_algorithm *algorithm) {
@ -72,17 +74,55 @@ int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
switch (algorithm) {
case GRPC_COMPRESS_NONE:
*name = "identity";
break;
return 1;
case GRPC_COMPRESS_DEFLATE:
*name = "deflate";
break;
return 1;
case GRPC_COMPRESS_GZIP:
*name = "gzip";
break;
default:
return 1;
case GRPC_COMPRESS_ALGORITHMS_COUNT:
return 0;
}
return 1;
return 0;
}
grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
grpc_mdstr *str) {
if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE;
if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE;
if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP;
return GRPC_COMPRESS_ALGORITHMS_COUNT;
}
grpc_mdstr *grpc_compression_algorithm_mdstr(
grpc_compression_algorithm algorithm) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
return GRPC_MDSTR_IDENTITY;
case GRPC_COMPRESS_DEFLATE:
return GRPC_MDSTR_DEFLATE;
case GRPC_COMPRESS_GZIP:
return GRPC_MDSTR_GZIP;
case GRPC_COMPRESS_ALGORITHMS_COUNT:
return NULL;
}
return NULL;
}
grpc_mdelem *grpc_compression_encoding_mdelem(
grpc_compression_algorithm algorithm) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
return GRPC_MDELEM_GRPC_ENCODING_IDENTITY;
case GRPC_COMPRESS_DEFLATE:
return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
case GRPC_COMPRESS_GZIP:
return GRPC_MDELEM_GRPC_ENCODING_GZIP;
case GRPC_COMPRESS_ALGORITHMS_COUNT:
return NULL;
}
return NULL;
}
/* TODO(dgq): Add the ability to specify parameters to the individual

@ -0,0 +1,53 @@
/*
*
* Copyright 2015, 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_CORE_COMPRESSION_ALGORITHM_METADATA_H
#define GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H
#include <grpc/compression.h>
#include "src/core/transport/metadata.h"
/** Return compression algorithm based metadata value */
grpc_mdstr *grpc_compression_algorithm_mdstr(
grpc_compression_algorithm algorithm);
/** Return compression algorithm based metadata element (grpc-encoding: xxx) */
grpc_mdelem *grpc_compression_encoding_mdelem(
grpc_compression_algorithm algorithm);
/** Find compression algorithm based on passed in mdstr - returns
* GRPC_COMPRESS_ALGORITHM_COUNT on failure */
grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
grpc_mdstr *str);
#endif /* GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H */

@ -207,14 +207,21 @@ static int has_watchers(grpc_fd *fd) {
}
void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
const char *reason) {
int *release_fd, const char *reason) {
fd->on_done_closure = on_done;
shutdown(fd->fd, SHUT_RDWR);
fd->released = release_fd != NULL;
if (!fd->released) {
shutdown(fd->fd, SHUT_RDWR);
} else {
*release_fd = fd->fd;
}
gpr_mu_lock(&fd->mu);
REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
if (!has_watchers(fd)) {
fd->closed = 1;
close(fd->fd);
if (!fd->released) {
close(fd->fd);
}
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
} else {
wake_all_watchers_locked(fd);
@ -406,7 +413,9 @@ void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
}
if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) {
fd->closed = 1;
close(fd->fd);
if (!fd->released) {
close(fd->fd);
}
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
}
gpr_mu_unlock(&fd->mu);

@ -62,6 +62,7 @@ struct grpc_fd {
gpr_mu mu;
int shutdown;
int closed;
int released;
/* The watcher list.
@ -107,11 +108,12 @@ grpc_fd *grpc_fd_create(int fd, const char *name);
/* Releases fd to be asynchronously destroyed.
on_done is called when the underlying file descriptor is definitely close()d.
If on_done is NULL, no callback will be made.
If release_fd is not NULL, it's set to fd and fd will not be closed.
Requires: *fd initialized; no outstanding notify_on_read or
notify_on_write.
MUST NOT be called with a pollset lock taken */
void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
const char *reason);
int *release_fd, const char *reason);
/* Begin polling on an fd.
Registers that the given pollset is interested in this fd - so that if read

@ -194,6 +194,7 @@ void grpc_pollset_init(grpc_pollset *pollset) {
pollset->in_flight_cbs = 0;
pollset->shutting_down = 0;
pollset->called_shutdown = 0;
pollset->kicked_without_pollers = 0;
pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL;
pollset->local_wakeup_cache = NULL;
pollset->kicked_without_pollers = 0;
@ -612,7 +613,9 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
GPR_TIMER_END("poll", 0);
if (r < 0) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
}
if (fd) {
grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
}

@ -126,7 +126,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {}
void grpc_pollset_reset(grpc_pollset *pollset) {
GPR_ASSERT(pollset->shutting_down);
GPR_ASSERT(!has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
GPR_ASSERT(
!has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
pollset->shutting_down = 0;
pollset->is_iocp_worker = 0;
pollset->kicked_without_pollers = 0;

@ -196,7 +196,7 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, int success) {
finish:
if (fd != NULL) {
grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
grpc_fd_orphan(exec_ctx, fd, NULL, "tcp_client_orphan");
grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan");
fd = NULL;
}
done = (--ac->refs == 0);
@ -265,7 +265,7 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
grpc_fd_orphan(exec_ctx, fdobj, NULL, "tcp_client_connect_error");
grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
goto done;
}

@ -90,6 +90,8 @@ typedef struct {
grpc_closure *read_cb;
grpc_closure *write_cb;
grpc_closure *release_fd_cb;
int *release_fd;
grpc_closure read_closure;
grpc_closure write_closure;
@ -108,7 +110,8 @@ static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
}
static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
grpc_fd_orphan(exec_ctx, tcp->em_fd, NULL, "tcp_unref_orphan");
grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
"tcp_unref_orphan");
gpr_slice_buffer_destroy(&tcp->last_read_buffer);
gpr_free(tcp->peer_string);
gpr_free(tcp);
@ -452,6 +455,8 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
tcp->fd = em_fd->fd;
tcp->read_cb = NULL;
tcp->write_cb = NULL;
tcp->release_fd_cb = NULL;
tcp->release_fd = NULL;
tcp->incoming_buffer = NULL;
tcp->slice_size = slice_size;
tcp->iov_size = 1;
@ -468,4 +473,13 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
return &tcp->base;
}
void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
int *fd, grpc_closure *done) {
grpc_tcp *tcp = (grpc_tcp *)ep;
GPR_ASSERT(ep->vtable == &vtable);
tcp->release_fd = fd;
tcp->release_fd_cb = done;
TCP_UNREF(exec_ctx, tcp, "destroy");
}
#endif

@ -56,4 +56,10 @@ extern int grpc_tcp_trace;
grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
const char *peer_string);
/* Destroy the tcp endpoint without closing its fd. *fd will be set and done
* will be called when the endpoint is destroyed.
* Requires: ep must be a tcp endpoint and fd must not be NULL. */
void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
int *fd, grpc_closure *done);
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */

@ -39,6 +39,9 @@
/* Forward decl of grpc_tcp_server */
typedef struct grpc_tcp_server grpc_tcp_server;
/* Forward decl of grpc_tcp_listener */
typedef struct grpc_tcp_listener grpc_tcp_listener;
/* Called for newly connected TCP connections. */
typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *ep);
@ -51,19 +54,17 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
grpc_pollset **pollsets, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb, void *cb_arg);
/* Add a port to the server, returning port number on success, or negative
on failure.
/* Add a port to the server, returning the newly created listener on success,
or a null pointer on failure.
The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
both IPv4 and IPv6 connections, but :: is the preferred style. This usually
creates one socket, but possibly two on systems which support IPv6,
but not dualstack sockets.
For raw access to the underlying sockets, see grpc_tcp_server_get_fd(). */
but not dualstack sockets. */
/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
all of the multiple socket port matching logic in one place */
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
size_t addr_len);
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
const void *addr, size_t addr_len);
/* Returns the file descriptor of the Nth listening socket on this server,
or -1 if the index is out of bounds.
@ -75,4 +76,8 @@ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index);
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
grpc_closure *closure);
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener);
void grpc_tcp_listener_ref(grpc_tcp_listener *listener);
void grpc_tcp_listener_unref(grpc_tcp_listener *listener);
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */

@ -67,14 +67,13 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#define INIT_PORT_CAP 2
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
static gpr_once s_init_max_accept_queue_size;
static int s_max_accept_queue_size;
/* one listening port */
typedef struct {
struct grpc_tcp_listener {
int fd;
grpc_fd *emfd;
grpc_tcp_server *server;
@ -84,9 +83,18 @@ typedef struct {
struct sockaddr_un un;
} addr;
size_t addr_len;
int port;
grpc_closure read_closure;
grpc_closure destroyed_closure;
} server_port;
gpr_refcount refs;
struct grpc_tcp_listener *next;
/* When we add a listener, more than one can be created, mainly because of
IPv6. A sibling will still be in the normal list, but will be flagged
as such. Any action, such as ref or unref, will affect all of the
siblings in the list. */
struct grpc_tcp_listener *sibling;
int is_sibling;
};
static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
struct stat st;
@ -112,10 +120,9 @@ struct grpc_tcp_server {
/* is this server shutting down? (boolean) */
int shutdown;
/* all listening ports */
server_port *ports;
size_t nports;
size_t port_capacity;
/* linked list of server ports */
grpc_tcp_listener *head;
unsigned nports;
/* shutdown callback */
grpc_closure *shutdown_complete;
@ -134,9 +141,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
s->shutdown = 0;
s->on_accept_cb = NULL;
s->on_accept_cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
s->head = NULL;
s->nports = 0;
s->port_capacity = INIT_PORT_CAP;
return s;
}
@ -145,7 +151,12 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
gpr_mu_destroy(&s->mu);
gpr_free(s->ports);
while (s->head) {
grpc_tcp_listener *sp = s->head;
s->head = sp->next;
grpc_tcp_listener_unref(sp);
}
gpr_free(s);
}
@ -166,8 +177,6 @@ static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, int success) {
events will be received on them - at this point it's safe to destroy
things */
static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
size_t i;
/* delete ALL the things */
gpr_mu_lock(&s->mu);
@ -176,15 +185,15 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
return;
}
if (s->nports) {
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
if (s->head) {
grpc_tcp_listener *sp;
for (sp = s->head; sp; sp = sp->next) {
if (sp->addr.sockaddr.sa_family == AF_UNIX) {
unlink_if_unix_domain_socket(&sp->addr.un);
}
sp->destroyed_closure.cb = destroyed_port;
sp->destroyed_closure.cb_arg = s;
grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure,
grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
"tcp_listener_shutdown");
}
gpr_mu_unlock(&s->mu);
@ -196,7 +205,6 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_closure *closure) {
size_t i;
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->shutdown);
@ -206,8 +214,9 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
/* shutdown all fd's */
if (s->active_ports) {
for (i = 0; i < s->nports; i++) {
grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
grpc_tcp_listener *sp;
for (sp = s->head; sp; sp = sp->next) {
grpc_fd_shutdown(exec_ctx, sp->emfd);
}
gpr_mu_unlock(&s->mu);
} else {
@ -298,7 +307,7 @@ error:
/* event manager callback when reads are ready */
static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
server_port *sp = arg;
grpc_tcp_listener *sp = arg;
grpc_fd *fdobj;
size_t i;
@ -364,9 +373,10 @@ error:
}
}
static int add_socket_to_server(grpc_tcp_server *s, int fd,
const struct sockaddr *addr, size_t addr_len) {
server_port *sp;
static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
const struct sockaddr *addr,
size_t addr_len) {
grpc_tcp_listener *sp = NULL;
int port;
char *addr_str;
char *name;
@ -376,32 +386,34 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu);
s->nports++;
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
/* append it to the list under a lock */
if (s->nports == s->port_capacity) {
s->port_capacity *= 2;
s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
}
sp = &s->ports[s->nports++];
sp = gpr_malloc(sizeof(grpc_tcp_listener));
sp->next = s->head;
s->head = sp;
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd, name);
memcpy(sp->addr.untyped, addr, addr_len);
sp->addr_len = addr_len;
sp->port = port;
sp->is_sibling = 0;
sp->sibling = NULL;
gpr_ref_init(&sp->refs, 1);
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
gpr_free(addr_str);
gpr_free(name);
}
return port;
return sp;
}
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
size_t addr_len) {
int allocated_port1 = -1;
int allocated_port2 = -1;
unsigned i;
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
const void *addr, size_t addr_len) {
int allocated_port = -1;
grpc_tcp_listener *sp;
grpc_tcp_listener *sp2 = NULL;
int fd;
grpc_dualstack_mode dsmode;
struct sockaddr_in6 addr6_v4mapped;
@ -420,9 +432,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
for (i = 0; i < s->nports; i++) {
for (sp = s->head; sp; sp = sp->next) {
sockname_len = sizeof(sockname_temp);
if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp,
&sockname_len)) {
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
if (port > 0) {
@ -436,6 +448,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
}
}
sp = NULL;
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
addr = (const struct sockaddr *)&addr6_v4mapped;
addr_len = sizeof(addr6_v4mapped);
@ -449,14 +463,16 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
addr = (struct sockaddr *)&wild6;
addr_len = sizeof(wild6);
fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
allocated_port1 = add_socket_to_server(s, fd, addr, addr_len);
sp = add_socket_to_server(s, fd, addr, addr_len);
allocated_port = sp->port;
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
}
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
if (port == 0 && allocated_port1 > 0) {
grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
if (port == 0 && allocated_port > 0) {
grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port);
sp2 = sp;
}
addr = (struct sockaddr *)&wild4;
addr_len = sizeof(wild4);
@ -471,22 +487,32 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
addr = (struct sockaddr *)&addr4_copy;
addr_len = sizeof(addr4_copy);
}
allocated_port2 = add_socket_to_server(s, fd, addr, addr_len);
sp = add_socket_to_server(s, fd, addr, addr_len);
sp->sibling = sp2;
if (sp2) sp2->is_sibling = 1;
done:
gpr_free(allocated_addr);
return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
return sp;
}
int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) {
return (port_index < s->nports) ? s->ports[port_index].fd : -1;
grpc_tcp_listener *sp;
for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--)
;
if (port_index == 0 && sp) {
return sp->fd;
} else {
return -1;
}
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_pollset **pollsets, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,
void *on_accept_cb_arg) {
size_t i, j;
size_t i;
grpc_tcp_listener *sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb);
@ -495,17 +521,40 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
s->on_accept_cb_arg = on_accept_cb_arg;
s->pollsets = pollsets;
s->pollset_count = pollset_count;
for (i = 0; i < s->nports; i++) {
for (j = 0; j < pollset_count; j++) {
grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
for (sp = s->head; sp; sp = sp->next) {
for (i = 0; i < pollset_count; i++) {
grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
}
s->ports[i].read_closure.cb = on_read;
s->ports[i].read_closure.cb_arg = &s->ports[i];
grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
&s->ports[i].read_closure);
sp->read_closure.cb = on_read;
sp->read_closure.cb_arg = sp;
grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
}
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
grpc_tcp_listener *sp = listener;
return sp->port;
}
void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
grpc_tcp_listener *sp = listener;
gpr_ref(&sp->refs);
}
void grpc_tcp_listener_unref(grpc_tcp_listener *listener) {
grpc_tcp_listener *sp = listener;
if (sp->is_sibling) return;
if (gpr_unref(&sp->refs)) {
grpc_tcp_listener *sibling = sp->sibling;
while (sibling) {
sp = sibling;
sibling = sp->sibling;
gpr_free(sp);
}
gpr_free(listener);
}
}
#endif

@ -35,7 +35,8 @@
#ifdef GPR_WINSOCK_SOCKET
#define _GNU_SOURCE
#include <io.h>
#include "src/core/iomgr/sockaddr_utils.h"
#include <grpc/support/alloc.h>
@ -51,25 +52,29 @@
#include "src/core/iomgr/tcp_server.h"
#include "src/core/iomgr/tcp_windows.h"
#define INIT_PORT_CAP 2
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
/* one listening port */
typedef struct server_port {
struct grpc_tcp_listener {
/* This seemingly magic number comes from AcceptEx's documentation. each
address buffer needs to have at least 16 more bytes at their end. */
gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
/* This will hold the socket for the next accept. */
SOCKET new_socket;
/* The listener winsocked. */
/* The listener winsocket. */
grpc_winsocket *socket;
/* The actual TCP port number. */
int port;
grpc_tcp_server *server;
/* The cached AcceptEx for that port. */
LPFN_ACCEPTEX AcceptEx;
int shutting_down;
/* closure for socket notification of accept being ready */
grpc_closure on_accept;
} server_port;
gpr_refcount refs;
/* linked list */
struct grpc_tcp_listener *next;
};
/* the overall server */
struct grpc_tcp_server {
@ -82,10 +87,8 @@ struct grpc_tcp_server {
/* active port count: how many ports are actually still listening */
int active_ports;
/* all listening ports */
server_port *ports;
size_t nports;
size_t port_capacity;
/* linked list of server ports */
grpc_tcp_listener *head;
/* shutdown callback */
grpc_closure *shutdown_complete;
@ -99,9 +102,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
s->active_ports = 0;
s->on_accept_cb = NULL;
s->on_accept_cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
s->nports = 0;
s->port_capacity = INIT_PORT_CAP;
s->head = NULL;
s->shutdown_complete = NULL;
return s;
}
@ -109,26 +110,26 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
static void dont_care_about_shutdown_completion(void *arg) {}
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
size_t i;
grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1);
/* Now that the accepts have been aborted, we can destroy the sockets.
The IOCP won't get notified on these, so we can flag them as already
closed by the system. */
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
while (s->head) {
grpc_tcp_listener *sp = s->head;
s->head = sp->next;
sp->next = NULL;
grpc_winsocket_destroy(sp->socket);
grpc_tcp_listener_unref(sp);
}
gpr_free(s->ports);
gpr_free(s);
}
/* Public function. Stops and destroys a grpc_tcp_server. */
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_closure *shutdown_complete) {
size_t i;
int immediately_done = 0;
grpc_tcp_listener *sp;
gpr_mu_lock(&s->mu);
s->shutdown_complete = shutdown_complete;
@ -138,8 +139,7 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
if (s->active_ports == 0) {
immediately_done = 1;
}
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
for (sp = s->head; sp; sp = sp->next) {
sp->shutting_down = 1;
grpc_winsocket_shutdown(sp->socket);
}
@ -199,7 +199,7 @@ error:
}
static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
server_port *sp) {
grpc_tcp_listener *sp) {
int notify = 0;
sp->shutting_down = 0;
gpr_mu_lock(&sp->server->mu);
@ -216,7 +216,7 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
/* In order to do an async accept, we need to create a socket first which
will be the one assigned to the new incoming connection. */
static void start_accept(grpc_exec_ctx *exec_ctx, server_port *port) {
static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
SOCKET sock = INVALID_SOCKET;
char *message;
char *utf8_message;
@ -276,7 +276,7 @@ failure:
/* Event manager callback when reads are ready. */
static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
server_port *sp = arg;
grpc_tcp_listener *sp = arg;
SOCKET sock = sp->new_socket;
grpc_winsocket_callback_info *info = &sp->socket->read_info;
grpc_endpoint *ep = NULL;
@ -351,16 +351,17 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
start_accept(exec_ctx, sp);
}
static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
const struct sockaddr *addr, size_t addr_len) {
server_port *sp;
static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
const struct sockaddr *addr,
size_t addr_len) {
grpc_tcp_listener *sp = NULL;
int port;
int status;
GUID guid = WSAID_ACCEPTEX;
DWORD ioctl_num_bytes;
LPFN_ACCEPTEX AcceptEx;
if (sock == INVALID_SOCKET) return -1;
if (sock == INVALID_SOCKET) return NULL;
/* We need to grab the AcceptEx pointer for that port, as it may be
interface-dependent. We'll cache it to avoid doing that again. */
@ -373,37 +374,34 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
gpr_free(utf8_message);
closesocket(sock);
return -1;
return NULL;
}
port = prepare_socket(sock, addr, addr_len);
if (port >= 0) {
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
/* append it to the list under a lock */
if (s->nports == s->port_capacity) {
/* too many ports, and we need to store their address in a closure */
/* TODO(ctiller): make server_port a linked list */
abort();
}
sp = &s->ports[s->nports++];
sp = gpr_malloc(sizeof(grpc_tcp_listener));
sp->next = s->head;
s->head = sp;
sp->server = s;
sp->socket = grpc_winsocket_create(sock, "listener");
sp->shutting_down = 0;
sp->AcceptEx = AcceptEx;
sp->new_socket = INVALID_SOCKET;
sp->port = port;
gpr_ref_init(&sp->refs, 1);
grpc_closure_init(&sp->on_accept, on_accept, sp);
GPR_ASSERT(sp->socket);
gpr_mu_unlock(&s->mu);
}
return port;
return sp;
}
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
size_t addr_len) {
int allocated_port = -1;
unsigned i;
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
const void *addr, size_t addr_len) {
grpc_tcp_listener *sp;
SOCKET sock;
struct sockaddr_in6 addr6_v4mapped;
struct sockaddr_in6 wildcard;
@ -415,9 +413,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
for (i = 0; i < s->nports; i++) {
for (sp = s->head; sp; sp = sp->next) {
sockname_len = sizeof(sockname_temp);
if (0 == getsockname(s->ports[i].socket->socket,
if (0 == getsockname(sp->socket->socket,
(struct sockaddr *)&sockname_temp, &sockname_len)) {
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
if (port > 0) {
@ -452,33 +450,56 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
gpr_free(utf8_message);
}
allocated_port = add_socket_to_server(s, sock, addr, addr_len);
sp = add_socket_to_server(s, sock, addr, addr_len);
gpr_free(allocated_addr);
return allocated_port;
return sp;
}
SOCKET
grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) {
grpc_tcp_listener *sp;
for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--)
;
if (port_index == 0 && sp) {
return _open_osfhandle(sp->socket->socket, 0);
} else {
return -1;
}
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
grpc_pollset **pollset, size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,
void *on_accept_cb_arg) {
size_t i;
grpc_tcp_listener *sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb);
GPR_ASSERT(s->active_ports == 0);
s->on_accept_cb = on_accept_cb;
s->on_accept_cb_arg = on_accept_cb_arg;
for (i = 0; i < s->nports; i++) {
start_accept(exec_ctx, s->ports + i);
for (sp = s->head; sp; sp = sp->next) {
start_accept(exec_ctx, sp);
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
}
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
grpc_tcp_listener *sp = listener;
return sp->port;
}
void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
grpc_tcp_listener *sp = listener;
gpr_ref(&sp->refs);
}
void grpc_tcp_listener_unref(grpc_tcp_listener *listener) {
grpc_tcp_listener *sp = listener;
if (gpr_unref(&sp->refs)) {
gpr_free(listener);
}
}
#endif /* GPR_WINSOCK_SOCKET */

@ -179,7 +179,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
}
sp->destroyed_closure.cb = destroyed_port;
sp->destroyed_closure.cb_arg = s;
grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure,
grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
"udp_listener_shutdown");
}
gpr_mu_unlock(&s->mu);

@ -115,7 +115,7 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, int success) {
/* HACK: let wakeup_fd code know that we stole the fd */
workqueue->wakeup_fd.read_fd = 0;
grpc_wakeup_fd_destroy(&workqueue->wakeup_fd);
grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, "destroy");
grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy");
gpr_free(workqueue);
} else {
gpr_mu_lock(&workqueue->mu);

@ -53,50 +53,186 @@ typedef struct gpr_timer_entry {
short line;
char type;
gpr_uint8 important;
int thd;
} gpr_timer_entry;
#define MAX_COUNT (5 * 1024 * 1024 / sizeof(gpr_timer_entry))
#define MAX_COUNT 1000000
static __thread gpr_timer_entry g_log[MAX_COUNT];
static __thread int g_count;
typedef struct gpr_timer_log {
size_t num_entries;
struct gpr_timer_log *next;
struct gpr_timer_log *prev;
gpr_timer_entry log[MAX_COUNT];
} gpr_timer_log;
typedef struct gpr_timer_log_list {
gpr_timer_log *head;
/* valid iff head!=NULL */
gpr_timer_log *tail;
} gpr_timer_log_list;
static __thread gpr_timer_log *g_thread_log;
static gpr_once g_once_init = GPR_ONCE_INIT;
static FILE *output_file;
static const char *output_filename = "latency_trace.txt";
static pthread_mutex_t g_mu;
static pthread_cond_t g_cv;
static gpr_timer_log_list g_in_progress_logs;
static gpr_timer_log_list g_done_logs;
static int g_shutdown;
static gpr_thd_id g_writing_thread;
static __thread int g_thread_id;
static int g_next_thread_id;
static void close_output() { fclose(output_file); }
static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) {
if (list->head == NULL) {
list->head = list->tail = log;
log->next = log->prev = NULL;
return 1;
} else {
log->prev = list->tail;
log->next = NULL;
list->tail->next = log;
list->tail = log;
return 0;
}
}
static void init_output() {
output_file = fopen("latency_trace.txt", "w");
GPR_ASSERT(output_file);
atexit(close_output);
static gpr_timer_log *timer_log_pop_front(gpr_timer_log_list *list) {
gpr_timer_log *out = list->head;
if (out != NULL) {
list->head = out->next;
if (list->head != NULL) {
list->head->prev = NULL;
} else {
list->tail = NULL;
}
}
return out;
}
static void log_report() {
int i;
gpr_once_init(&g_once_init, init_output);
for (i = 0; i < g_count; i++) {
gpr_timer_entry *entry = &(g_log[i]);
static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) {
if (log->prev == NULL) {
list->head = log->next;
if (list->head != NULL) {
list->head->prev = NULL;
}
} else {
log->prev->next = log->next;
}
if (log->next == NULL) {
list->tail = log->prev;
if (list->tail != NULL) {
list->tail->next = NULL;
}
} else {
log->next->prev = log->prev;
}
}
static void write_log(gpr_timer_log *log) {
size_t i;
if (output_file == NULL) {
output_file = fopen(output_filename, "w");
}
for (i = 0; i < log->num_entries; i++) {
gpr_timer_entry *entry = &(log->log[i]);
if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) {
entry->tm = gpr_time_0(entry->tm.clock_type);
}
fprintf(output_file,
"{\"t\": %ld.%09d, \"thd\": \"%p\", \"type\": \"%c\", \"tag\": "
"{\"t\": %ld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
"\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
entry->tm.tv_sec, entry->tm.tv_nsec,
(void *)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tagstr,
entry->file, entry->line, entry->important);
entry->tm.tv_sec, entry->tm.tv_nsec, entry->thd, entry->type,
entry->tagstr, entry->file, entry->line, entry->important);
}
}
static void writing_thread(void *unused) {
gpr_timer_log *log;
pthread_mutex_lock(&g_mu);
for (;;) {
while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) {
pthread_cond_wait(&g_cv, &g_mu);
}
if (log != NULL) {
pthread_mutex_unlock(&g_mu);
write_log(log);
free(log);
pthread_mutex_lock(&g_mu);
}
if (g_shutdown) {
pthread_mutex_unlock(&g_mu);
return;
}
}
}
/* Now clear out the log */
g_count = 0;
static void flush_logs(gpr_timer_log_list *list) {
gpr_timer_log *log;
while ((log = timer_log_pop_front(list)) != NULL) {
write_log(log);
free(log);
}
}
static void finish_writing() {
pthread_mutex_lock(&g_mu);
g_shutdown = 1;
pthread_cond_signal(&g_cv);
pthread_mutex_unlock(&g_mu);
gpr_thd_join(g_writing_thread);
gpr_log(GPR_INFO, "flushing logs");
pthread_mutex_lock(&g_mu);
flush_logs(&g_done_logs);
flush_logs(&g_in_progress_logs);
pthread_mutex_unlock(&g_mu);
if (output_file) {
fclose(output_file);
}
}
void gpr_timers_set_log_filename(const char *filename) {
output_filename = filename;
}
static void init_output() {
gpr_thd_options options = gpr_thd_options_default();
gpr_thd_options_set_joinable(&options);
gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options);
atexit(finish_writing);
}
static void rotate_log() {
gpr_timer_log *new = malloc(sizeof(*new));
gpr_once_init(&g_once_init, init_output);
new->num_entries = 0;
pthread_mutex_lock(&g_mu);
if (g_thread_log != NULL) {
timer_log_remove(&g_in_progress_logs, g_thread_log);
if (timer_log_push_back(&g_done_logs, g_thread_log)) {
pthread_cond_signal(&g_cv);
}
} else {
g_thread_id = g_next_thread_id++;
}
timer_log_push_back(&g_in_progress_logs, new);
pthread_mutex_unlock(&g_mu);
g_thread_log = new;
}
static void gpr_timers_log_add(const char *tagstr, marker_type type,
int important, const char *file, int line) {
gpr_timer_entry *entry;
/* TODO (vpai) : Improve concurrency */
if (g_count == MAX_COUNT) {
log_report();
if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
rotate_log();
}
entry = &g_log[g_count++];
entry = &g_thread_log->log[g_thread_log->num_entries++];
entry->tm = gpr_now(GPR_CLOCK_PRECISE);
entry->tagstr = tagstr;
@ -104,6 +240,7 @@ static void gpr_timers_log_add(const char *tagstr, marker_type type,
entry->file = file;
entry->line = (short)line;
entry->important = important != 0;
entry->thd = g_thread_id;
}
/* Latency profiler API implementation. */
@ -131,4 +268,6 @@ void gpr_timers_global_destroy(void) {}
void gpr_timers_global_init(void) {}
void gpr_timers_global_destroy(void) {}
void gpr_timers_set_log_filename(const char *filename) {}
#endif /* GRPC_BASIC_PROFILER */

@ -48,6 +48,8 @@ void gpr_timer_begin(const char *tagstr, int important, const char *file,
void gpr_timer_end(const char *tagstr, int important, const char *file,
int line);
void gpr_timers_set_log_filename(const char *filename);
#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
/* No profiling. No-op all the things. */
#define GPR_TIMER_MARK(tag, important) \

@ -39,12 +39,13 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/support/string.h"
#include "src/core/channel/channel_stack.h"
#include "src/core/security/security_context.h"
#include "src/core/security/security_connector.h"
#include "src/core/security/credentials.h"
#include "src/core/security/security_connector.h"
#include "src/core/security/security_context.h"
#include "src/core/support/string.h"
#include "src/core/surface/call.h"
#include "src/core/transport/static_metadata.h"
#define MAX_CREDENTIALS_METADATA_COUNT 4
@ -61,24 +62,28 @@ typedef struct {
grpc_transport_stream_op op;
gpr_uint8 security_context_set;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
char *service_url;
grpc_auth_metadata_context auth_md_context;
} call_data;
/* We can have a per-channel credentials. */
typedef struct {
grpc_channel_security_connector *security_connector;
grpc_mdctx *md_ctx;
grpc_mdstr *authority_string;
grpc_mdstr *path_string;
grpc_mdstr *error_msg_key;
grpc_mdstr *status_key;
} channel_data;
static void reset_service_url(call_data *calld) {
if (calld->service_url != NULL) {
gpr_free(calld->service_url);
calld->service_url = NULL;
static void reset_auth_metadata_context(
grpc_auth_metadata_context *auth_md_context) {
if (auth_md_context->service_url != NULL) {
gpr_free((char *)auth_md_context->service_url);
auth_md_context->service_url = NULL;
}
if (auth_md_context->method_name != NULL) {
gpr_free((char *)auth_md_context->method_name);
auth_md_context->method_name = NULL;
}
GRPC_AUTH_CONTEXT_UNREF(
(grpc_auth_context *)auth_md_context->channel_auth_context,
"grpc_auth_metadata_context");
auth_md_context->channel_auth_context = NULL;
}
static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
@ -95,11 +100,10 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_credentials_status status) {
grpc_call_element *elem = (grpc_call_element *)user_data;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_stream_op *op = &calld->op;
grpc_metadata_batch *mdb;
size_t i;
reset_service_url(calld);
reset_auth_metadata_context(&calld->auth_md_context);
if (status != GRPC_CREDENTIALS_OK) {
bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED,
"Credentials failed to get metadata.");
@ -111,15 +115,19 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
for (i = 0; i < num_md; i++) {
grpc_metadata_batch_add_tail(
mdb, &calld->md_links[i],
grpc_mdelem_from_slices(chand->md_ctx, gpr_slice_ref(md_elems[i].key),
grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key),
gpr_slice_ref(md_elems[i].value)));
}
grpc_call_next_op(exec_ctx, elem, op);
}
void build_service_url(const char *url_scheme, call_data *calld) {
void build_auth_metadata_context(grpc_security_connector *sc,
call_data *calld) {
char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
char *last_slash = strrchr(service, '/');
char *method_name = NULL;
char *service_url = NULL;
reset_auth_metadata_context(&calld->auth_md_context);
if (last_slash == NULL) {
gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
service[0] = '\0';
@ -128,11 +136,16 @@ void build_service_url(const char *url_scheme, call_data *calld) {
service[1] = '\0';
} else {
*last_slash = '\0';
method_name = gpr_strdup(last_slash + 1);
}
if (url_scheme == NULL) url_scheme = "";
reset_service_url(calld);
gpr_asprintf(&calld->service_url, "%s://%s%s", url_scheme,
if (method_name == NULL) method_name = gpr_strdup("");
gpr_asprintf(&service_url, "%s://%s%s",
sc->url_scheme == NULL ? "" : sc->url_scheme,
grpc_mdstr_as_c_string(calld->host), service);
calld->auth_md_context.service_url = service_url;
calld->auth_md_context.method_name = method_name;
calld->auth_md_context.channel_auth_context =
GRPC_AUTH_CONTEXT_REF(sc->auth_context, "grpc_auth_metadata_context");
gpr_free(service);
}
@ -166,12 +179,12 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx,
call_creds_has_md ? ctx->creds : channel_call_creds);
}
build_service_url(chand->security_connector->base.url_scheme, calld);
build_auth_metadata_context(&chand->security_connector->base, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */
GPR_ASSERT(calld->pollset);
grpc_call_credentials_get_request_metadata(exec_ctx, calld->creds,
calld->pollset, calld->service_url,
on_credentials_metadata, elem);
grpc_call_credentials_get_request_metadata(
exec_ctx, calld->creds, calld->pollset, calld->auth_md_context,
on_credentials_metadata, elem);
}
static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
@ -225,10 +238,10 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_mdelem *md = l->md;
/* Pointer comparison is OK for md_elems created from the same context.
*/
if (md->key == chand->authority_string) {
if (md->key == GRPC_MDSTR_AUTHORITY) {
if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
calld->host = GRPC_MDSTR_REF(md->value);
} else if (md->key == chand->path_string) {
} else if (md->key == GRPC_MDSTR_PATH) {
if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
calld->method = GRPC_MDSTR_REF(md->value);
}
@ -285,7 +298,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
if (calld->method != NULL) {
GRPC_MDSTR_UNREF(calld->method);
}
reset_service_url(calld);
reset_auth_metadata_context(&calld->auth_md_context);
}
/* Constructor for channel_data */
@ -308,11 +321,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
chand->security_connector =
(grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
sc, "client_auth_filter");
chand->md_ctx = args->metadata_context;
chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
}
/* Destructor for channel data */
@ -321,19 +329,8 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
grpc_channel_security_connector *ctx = chand->security_connector;
if (ctx != NULL)
if (ctx != NULL) {
GRPC_SECURITY_CONNECTOR_UNREF(&ctx->base, "client_auth_filter");
if (chand->authority_string != NULL) {
GRPC_MDSTR_UNREF(chand->authority_string);
}
if (chand->error_msg_key != NULL) {
GRPC_MDSTR_UNREF(chand->error_msg_key);
}
if (chand->status_key != NULL) {
GRPC_MDSTR_UNREF(chand->status_key);
}
if (chand->path_string != NULL) {
GRPC_MDSTR_UNREF(chand->path_string);
}
}

@ -33,16 +33,16 @@
#include "src/core/security/credentials.h"
#include <string.h>
#include <stdio.h>
#include <string.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/http_client_filter.h"
#include "src/core/json/json.h"
#include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/surface/api_trace.h"
#include "src/core/json/json.h"
#include "src/core/support/string.h"
#include "src/core/surface/api_trace.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@ -117,15 +117,16 @@ void grpc_call_credentials_release(grpc_call_credentials *creds) {
}
void grpc_call_credentials_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
grpc_pollset *pollset, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
if (cb != NULL) {
cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
}
return;
}
creds->vtable->get_request_metadata(exec_ctx, creds, pollset, service_url, cb,
creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb,
user_data);
}
@ -423,9 +424,12 @@ static void jwt_destruct(grpc_call_credentials *creds) {
gpr_mu_destroy(&c->cache_mu);
}
static void jwt_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
grpc_pollset *pollset,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_service_account_jwt_access_credentials *c =
(grpc_service_account_jwt_access_credentials *)creds;
gpr_timespec refresh_threshold = gpr_time_from_seconds(
@ -436,7 +440,7 @@ static void jwt_get_request_metadata(
{
gpr_mu_lock(&c->cache_mu);
if (c->cached.service_url != NULL &&
strcmp(c->cached.service_url, service_url) == 0 &&
strcmp(c->cached.service_url, context.service_url) == 0 &&
c->cached.jwt_md != NULL &&
(gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
gpr_now(GPR_CLOCK_REALTIME)),
@ -451,14 +455,15 @@ static void jwt_get_request_metadata(
/* Generate a new jwt. */
gpr_mu_lock(&c->cache_mu);
jwt_reset_cache(c);
jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL);
jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url,
c->jwt_lifetime, NULL);
if (jwt != NULL) {
char *md_value;
gpr_asprintf(&md_value, "Bearer %s", jwt);
gpr_free(jwt);
c->cached.jwt_expiration =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
c->cached.service_url = gpr_strdup(service_url);
c->cached.service_url = gpr_strdup(context.service_url);
c->cached.jwt_md = grpc_credentials_md_store_create(1);
grpc_credentials_md_store_add_cstrings(
c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
@ -643,7 +648,7 @@ static void on_oauth2_token_fetcher_http_response(
static void oauth2_token_fetcher_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
grpc_pollset *pollset, const char *service_url,
grpc_pollset *pollset, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds;
@ -799,8 +804,9 @@ static void on_simulated_token_fetch_done(void *user_data) {
}
static void md_only_test_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
grpc_pollset *pollset, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
if (c->is_async) {
@ -838,8 +844,9 @@ static void access_token_destruct(grpc_call_credentials *creds) {
}
static void access_token_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
grpc_pollset *pollset, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
}
@ -920,7 +927,7 @@ typedef struct {
grpc_composite_call_credentials *composite_creds;
size_t creds_index;
grpc_credentials_md_store *md_elems;
char *service_url;
grpc_auth_metadata_context auth_md_context;
void *user_data;
grpc_pollset *pollset;
grpc_credentials_metadata_cb cb;
@ -938,7 +945,6 @@ static void composite_call_destruct(grpc_call_credentials *creds) {
static void composite_call_md_context_destroy(
grpc_composite_call_credentials_metadata_context *ctx) {
grpc_credentials_md_store_unref(ctx->md_elems);
if (ctx->service_url != NULL) gpr_free(ctx->service_url);
gpr_free(ctx);
}
@ -966,9 +972,9 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
grpc_call_credentials *inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
grpc_call_credentials_get_request_metadata(exec_ctx, inner_creds,
ctx->pollset, ctx->service_url,
composite_call_metadata_cb, ctx);
grpc_call_credentials_get_request_metadata(
exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context,
composite_call_metadata_cb, ctx);
return;
}
@ -979,22 +985,23 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
}
static void composite_call_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
grpc_composite_call_credentials_metadata_context *ctx;
ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
ctx->service_url = gpr_strdup(service_url);
ctx->auth_md_context = auth_md_context;
ctx->user_data = user_data;
ctx->cb = cb;
ctx->composite_creds = c;
ctx->pollset = pollset;
ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
grpc_call_credentials_get_request_metadata(
exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset, service_url,
composite_call_metadata_cb, ctx);
exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset,
auth_md_context, composite_call_metadata_cb, ctx);
}
static grpc_call_credentials_vtable composite_call_credentials_vtable = {
@ -1088,7 +1095,7 @@ static void iam_destruct(grpc_call_credentials *creds) {
static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
grpc_pollset *pollset,
const char *service_url,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
@ -1097,7 +1104,7 @@ static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
}
static grpc_call_credentials_vtable iam_vtable = {iam_destruct,
iam_get_request_metadata};
iam_get_request_metadata};
grpc_call_credentials *grpc_google_iam_credentials_create(
const char *token, const char *authority_selector, void *reserved) {
@ -1177,7 +1184,7 @@ static void plugin_md_request_metadata_ready(void *request,
static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
grpc_pollset *pollset,
const char *service_url,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
@ -1186,7 +1193,7 @@ static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
memset(request, 0, sizeof(*request));
request->user_data = user_data;
request->cb = cb;
c->plugin.get_metadata(c->plugin.state, service_url,
c->plugin.get_metadata(c->plugin.state, context,
plugin_md_request_metadata_ready, request);
} else {
cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
@ -1203,7 +1210,7 @@ grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
(reserved));
GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(*c));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN;
c->base.type = plugin.type;
c->base.vtable = &plugin_vtable;
gpr_ref_init(&c->base.refcount, 1);
c->plugin = plugin;
@ -1265,4 +1272,3 @@ grpc_channel_credentials *grpc_composite_channel_credentials_create(
c->call_creds = grpc_call_credentials_ref(call_creds);
return &c->base;
}

@ -59,7 +59,6 @@ typedef enum {
"FakeTransportSecurity"
#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
#define GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin"
#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt"
#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam"
#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite"
@ -162,7 +161,7 @@ typedef struct {
void (*destruct)(grpc_call_credentials *c);
void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *c, grpc_pollset *pollset,
const char *service_url,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data);
} grpc_call_credentials_vtable;
@ -175,19 +174,18 @@ struct grpc_call_credentials {
grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
void grpc_call_credentials_unref(grpc_call_credentials *creds);
void grpc_call_credentials_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
grpc_pollset *pollset,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data);
void grpc_call_credentials_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
grpc_pollset *pollset, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data);
typedef struct {
grpc_call_credentials **creds_array;
size_t num_creds;
} grpc_call_credentials_array;
const grpc_call_credentials_array *grpc_composite_call_credentials_get_credentials(
const grpc_call_credentials_array *
grpc_composite_call_credentials_get_credentials(
grpc_call_credentials *composite_creds);
/* Returns creds if creds is of the specified type or the inner creds of the

@ -214,7 +214,8 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) {
end:
if (result == NULL) {
if (call_creds != NULL) {
/* Blend with default ssl credentials and add a global reference so that it
/* Blend with default ssl credentials and add a global reference so that
it
can be cached and re-served. */
grpc_channel_credentials *ssl_creds =
grpc_ssl_credentials_create(NULL, NULL, NULL);

@ -591,9 +591,9 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
}
grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config,
const char *target_name, const char *overridden_target_name,
grpc_channel_security_connector **sc) {
grpc_call_credentials *request_metadata_creds,
const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);

@ -91,8 +91,10 @@ struct grpc_security_connector {
const char *url_scheme;
grpc_auth_context *auth_context; /* Populated after the peer is checked. */
/* Used on server side only. */
/* TODO(yangg) maybe create a grpc_server_security_connector with these */
gpr_mu mu;
grpc_security_connector_handshake_list *handshaking_handshakes;
const grpc_channel_args *channel_args;
};
/* Refcounting. */

@ -58,7 +58,6 @@ typedef struct call_data {
typedef struct channel_data {
grpc_auth_context *auth_context;
grpc_server_credentials *creds;
grpc_mdctx *mdctx;
} channel_data;
static grpc_metadata_array metadata_batch_to_md_array(
@ -247,7 +246,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
chand->auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
chand->creds = grpc_server_credentials_ref(creds);
chand->mdctx = args->metadata_context;
}
/* Destructor for channel data */

@ -81,7 +81,7 @@ static void state_unref(grpc_server_secure_state *state) {
}
static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
grpc_transport *transport, grpc_mdctx *mdctx) {
grpc_transport *transport) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_server_auth_filter, &grpc_http_server_filter};
grpc_server_secure_state *state = statep;
@ -93,7 +93,7 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
grpc_server_get_channel_args(state->server), args_to_add,
GPR_ARRAY_SIZE(args_to_add));
grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy);
GPR_ARRAY_SIZE(extra_filters), args_copy);
grpc_channel_args_destroy(args_copy);
}
@ -102,16 +102,14 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
grpc_endpoint *secure_endpoint) {
grpc_server_secure_state *state = statep;
grpc_transport *transport;
grpc_mdctx *mdctx;
if (status == GRPC_SECURITY_OK) {
if (secure_endpoint) {
gpr_mu_lock(&state->mu);
if (!state->is_shutdown) {
mdctx = grpc_mdctx_create();
transport = grpc_create_chttp2_transport(
exec_ctx, grpc_server_get_channel_args(state->server),
secure_endpoint, mdctx, 0);
setup_transport(exec_ctx, state, transport, mdctx);
secure_endpoint, 0);
setup_transport(exec_ctx, state, transport);
grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
} else {
/* We need to consume this here, because the server may already have
@ -192,6 +190,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
creds->type);
goto error;
}
sc->channel_args = grpc_server_get_channel_args(server);
/* resolve address */
resolved = grpc_blocking_resolve_address(addr, "https");
@ -205,9 +204,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
}
for (i = 0; i < resolved->naddrs; i++) {
port_temp = grpc_tcp_server_add_port(
grpc_tcp_listener *listener;
listener = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len);
port_temp = grpc_tcp_listener_get_port(listener);
if (port_temp >= 0) {
if (port_num == -1) {
port_num = port_temp;

@ -0,0 +1,288 @@
/*
*
* Copyright 2015, 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/support/avl.h>
#include <assert.h>
#include <stdlib.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) {
gpr_avl out;
out.vtable = vtable;
out.root = NULL;
return out;
}
static gpr_avl_node *ref_node(gpr_avl_node *node) {
if (node) {
gpr_ref(&node->refs);
}
return node;
}
static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) {
if (node == NULL) {
return;
}
if (gpr_unref(&node->refs)) {
vtable->destroy_key(node->key);
vtable->destroy_value(node->value);
unref_node(vtable, node->left);
unref_node(vtable, node->right);
gpr_free(node);
}
}
static long node_height(gpr_avl_node *node) {
return node == NULL ? 0 : node->height;
}
#ifndef NDEBUG
static long calculate_height(gpr_avl_node *node) {
return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left),
calculate_height(node->right));
}
static gpr_avl_node *assert_invariants(gpr_avl_node *n) {
if (n == NULL) return NULL;
assert_invariants(n->left);
assert_invariants(n->right);
assert(calculate_height(n) == n->height);
assert(labs(node_height(n->left) - node_height(n->right)) <= 1);
return n;
}
#else
static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; }
#endif
gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *node = gpr_malloc(sizeof(*node));
gpr_ref_init(&node->refs, 1);
node->key = key;
node->value = value;
node->left = assert_invariants(left);
node->right = assert_invariants(right);
node->height = 1 + GPR_MAX(node_height(left), node_height(right));
return node;
}
static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node,
void *key) {
long cmp;
if (node == NULL) {
return NULL;
}
cmp = vtable->compare_keys(node->key, key);
if (cmp == 0) {
return node;
} else if (cmp > 0) {
return get(vtable, node->left, key);
} else {
return get(vtable, node->right, key);
}
}
void *gpr_avl_get(gpr_avl avl, void *key) {
gpr_avl_node *node = get(avl.vtable, avl.root, key);
return node ? node->value : NULL;
}
static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *n =
new_node(vtable->copy_key(right->key), vtable->copy_value(right->value),
new_node(key, value, left, ref_node(right->left)),
ref_node(right->right));
unref_node(vtable, right);
return n;
}
static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *n = new_node(
vtable->copy_key(left->key), vtable->copy_value(left->value),
ref_node(left->left), new_node(key, value, ref_node(left->right), right));
unref_node(vtable, left);
return n;
}
static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
/* rotate_right(..., rotate_left(left), right) */
gpr_avl_node *n = new_node(
vtable->copy_key(left->right->key),
vtable->copy_value(left->right->value),
new_node(vtable->copy_key(left->key), vtable->copy_value(left->value),
ref_node(left->left), ref_node(left->right->left)),
new_node(key, value, ref_node(left->right->right), right));
unref_node(vtable, left);
return n;
}
static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
/* rotate_left(..., left, rotate_right(right)) */
gpr_avl_node *n = new_node(
vtable->copy_key(right->left->key),
vtable->copy_value(right->left->value),
new_node(key, value, left, ref_node(right->left->left)),
new_node(vtable->copy_key(right->key), vtable->copy_key(right->value),
ref_node(right->left->right), ref_node(right->right)));
unref_node(vtable, right);
return n;
}
static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
switch (node_height(left) - node_height(right)) {
case 2:
if (node_height(left->left) - node_height(left->right) == -1) {
return assert_invariants(
rotate_left_right(vtable, key, value, left, right));
} else {
return assert_invariants(rotate_right(vtable, key, value, left, right));
}
case -2:
if (node_height(right->left) - node_height(right->right) == 1) {
return assert_invariants(
rotate_right_left(vtable, key, value, left, right));
} else {
return assert_invariants(rotate_left(vtable, key, value, left, right));
}
default:
return assert_invariants(new_node(key, value, left, right));
}
}
static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node,
void *key, void *value) {
long cmp;
if (node == NULL) {
return new_node(key, value, NULL, NULL);
}
cmp = vtable->compare_keys(node->key, key);
if (cmp == 0) {
return new_node(key, value, ref_node(node->left), ref_node(node->right));
} else if (cmp > 0) {
return rebalance(
vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
add(vtable, node->left, key, value), ref_node(node->right));
} else {
return rebalance(vtable, vtable->copy_key(node->key),
vtable->copy_value(node->value), ref_node(node->left),
add(vtable, node->right, key, value));
}
}
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) {
gpr_avl_node *old_root = avl.root;
avl.root = add(avl.vtable, avl.root, key, value);
assert_invariants(avl.root);
unref_node(avl.vtable, old_root);
return avl;
}
static gpr_avl_node *in_order_head(gpr_avl_node *node) {
while (node->left != NULL) {
node = node->left;
}
return node;
}
static gpr_avl_node *in_order_tail(gpr_avl_node *node) {
while (node->right != NULL) {
node = node->right;
}
return node;
}
static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node,
void *key) {
long cmp;
if (node == NULL) {
return NULL;
}
cmp = vtable->compare_keys(node->key, key);
if (cmp == 0) {
if (node->left == NULL) {
return ref_node(node->right);
} else if (node->right == NULL) {
return ref_node(node->left);
} else if (node->left->height < node->right->height) {
gpr_avl_node *h = in_order_head(node->right);
return rebalance(vtable, vtable->copy_key(h->key),
vtable->copy_value(h->value), ref_node(node->left),
remove(vtable, node->right, h->key));
} else {
gpr_avl_node *h = in_order_tail(node->left);
return rebalance(
vtable, vtable->copy_key(h->key), vtable->copy_value(h->value),
remove(vtable, node->left, h->key), ref_node(node->right));
}
} else if (cmp > 0) {
return rebalance(vtable, vtable->copy_key(node->key),
vtable->copy_value(node->value),
remove(vtable, node->left, key), ref_node(node->right));
} else {
return rebalance(vtable, vtable->copy_key(node->key),
vtable->copy_value(node->value), ref_node(node->left),
remove(vtable, node->right, key));
}
}
gpr_avl gpr_avl_remove(gpr_avl avl, void *key) {
gpr_avl_node *old_root = avl.root;
avl.root = remove(avl.vtable, avl.root, key);
assert_invariants(avl.root);
unref_node(avl.vtable, old_root);
return avl;
}
gpr_avl gpr_avl_ref(gpr_avl avl) {
ref_node(avl.root);
return avl;
}
void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); }

@ -57,6 +57,21 @@ void gpr_slice_unref(gpr_slice slice) {
}
}
/* gpr_slice_from_static_string support structure - a refcount that does
nothing */
static void noop_ref_or_unref(void *unused) {}
static gpr_slice_refcount noop_refcount = {noop_ref_or_unref,
noop_ref_or_unref};
gpr_slice gpr_slice_from_static_string(const char *s) {
gpr_slice slice;
slice.refcount = &noop_refcount;
slice.data.refcounted.bytes = (gpr_uint8 *)s;
slice.data.refcounted.length = strlen(s);
return slice;
}
/* gpr_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
typedef struct new_slice_refcount {

@ -53,7 +53,7 @@ struct thd_arg {
/* Body of every thread started via gpr_thd_new. */
static void *thread_body(void *v) {
struct thd_arg a = *(struct thd_arg *)v;
gpr_free(v);
free(v);
(*a.body)(a.arg);
return NULL;
}
@ -63,7 +63,10 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
int thread_started;
pthread_attr_t attr;
pthread_t p;
struct thd_arg *a = gpr_malloc(sizeof(*a));
/* don't use gpr_malloc as we may cause an infinite recursion with
* the profiling code */
struct thd_arg *a = malloc(sizeof(*a));
GPR_ASSERT(a != NULL);
a->body = thd_body;
a->arg = arg;
@ -78,7 +81,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
if (!thread_started) {
gpr_free(a);
free(a);
}
*t = (gpr_thd_id)p;
return thread_started;

@ -121,4 +121,3 @@ gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
}
return out_slice;
}

@ -43,6 +43,7 @@
#include <grpc/support/useful.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/compression/algorithm_metadata.h"
#include "src/core/iomgr/timer.h"
#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
@ -50,6 +51,7 @@
#include "src/core/surface/call.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/completion_queue.h"
#include "src/core/transport/static_metadata.h"
/** The maximum number of concurrent batches possible.
Based upon the maximum number of individually queueable ops in the batch
@ -135,7 +137,6 @@ struct grpc_call {
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
grpc_mdctx *metadata_context;
/* TODO(ctiller): share with cq if possible? */
gpr_mu mu;
@ -267,7 +268,6 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
}
call->send_deadline = send_deadline;
GRPC_CHANNEL_INTERNAL_REF(channel, "call");
call->metadata_context = grpc_channel_get_metadata_context(channel);
/* initial refcount dropped by grpc_call_destroy */
grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
call->context, server_transport_data,
@ -567,9 +567,8 @@ static int prepare_application_metadata(grpc_call *call, int count,
grpc_metadata *md = &metadata[i];
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key,
(const gpr_uint8 *)md->value,
md->value_length);
l->md = grpc_mdelem_from_string_and_buffer(
md->key, (const gpr_uint8 *)md->value, md->value_length);
if (!grpc_mdstr_is_legal_header(l->md->key)) {
gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
grpc_mdstr_as_c_string(l->md->key));
@ -712,8 +711,7 @@ static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description) {
grpc_mdstr *details =
description ? grpc_mdstr_from_string(c->metadata_context, description)
: NULL;
description ? grpc_mdstr_from_string(description) : NULL;
cancel_closure *cc = gpr_malloc(sizeof(*cc));
GPR_ASSERT(status != GRPC_STATUS_OK);
@ -788,8 +786,12 @@ static void destroy_status(void *ignored) {}
static gpr_uint32 decode_status(grpc_mdelem *md) {
gpr_uint32 status;
void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data) {
void *user_data;
if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0;
if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1;
if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2;
user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data != NULL) {
status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
} else {
if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
@ -803,38 +805,23 @@ static gpr_uint32 decode_status(grpc_mdelem *md) {
return status;
}
/* just as for status above, we need to offset: metadata userdata can't hold a
* zero (null), which in this case is used to signal no compression */
#define COMPRESS_OFFSET 1
static void destroy_compression(void *ignored) {}
static gpr_uint32 decode_compression(grpc_mdelem *md) {
grpc_compression_algorithm algorithm;
void *user_data = grpc_mdelem_get_user_data(md, destroy_compression);
if (user_data) {
algorithm =
((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET;
} else {
grpc_compression_algorithm algorithm =
grpc_compression_algorithm_from_mdstr(md->value);
if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
&algorithm)) {
gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
assert(0);
}
grpc_mdelem_set_user_data(
md, destroy_compression,
(void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET));
gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
}
return algorithm;
}
static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) {
if (elem->key == grpc_channel_get_status_string(call->channel)) {
if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
GPR_TIMER_BEGIN("status", 0);
set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
GPR_TIMER_END("status", 0);
return NULL;
} else if (elem->key == grpc_channel_get_message_string(call->channel)) {
} else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
GPR_TIMER_BEGIN("status-details", 0);
set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value));
GPR_TIMER_END("status-details", 0);
@ -867,14 +854,12 @@ static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
elem = recv_common_filter(call, elem);
if (elem == NULL) {
return NULL;
} else if (elem->key ==
grpc_channel_get_compression_algorithm_string(call->channel)) {
} else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
GPR_TIMER_BEGIN("compression_algorithm", 0);
set_compression_algorithm(call, decode_compression(elem));
GPR_TIMER_END("compression_algorithm", 0);
return NULL;
} else if (elem->key == grpc_channel_get_encodings_accepted_by_peer_string(
call->channel)) {
} else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
set_encodings_accepted_by_peer(call, elem);
GPR_TIMER_END("encodings_accepted_by_peer", 0);
@ -922,11 +907,12 @@ static batch_control *allocate_batch_control(grpc_call *call) {
size_t i;
for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
if ((call->used_batches & (1 << i)) == 0) {
call->used_batches |= (gpr_uint8)(1 << i);
call->used_batches =
(gpr_uint8)(call->used_batches | (gpr_uint8)(1 << i));
return &call->active_batches[i];
}
}
GPR_UNREACHABLE_CODE(return NULL);
return NULL;
}
static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
@ -1240,10 +1226,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->channel, op->data.send_status_from_server.status);
if (op->data.send_status_from_server.status_details != NULL) {
call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
call->metadata_context,
GRPC_MDSTR_REF(grpc_channel_get_message_string(call->channel)),
GRPC_MDSTR_GRPC_MESSAGE,
grpc_mdstr_from_string(
call->metadata_context,
op->data.send_status_from_server.status_details));
call->send_extra_metadata_count++;
set_status_details(

@ -46,6 +46,7 @@
#include "src/core/surface/api_trace.h"
#include "src/core/surface/call.h"
#include "src/core/surface/init.h"
#include "src/core/transport/static_metadata.h"
/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
* Avoids needing to take a metadata context lock for sending status
@ -64,17 +65,7 @@ struct grpc_channel {
int is_client;
gpr_refcount refs;
gpr_uint32 max_message_length;
grpc_mdctx *metadata_context;
/** mdstr for the grpc-status key */
grpc_mdstr *grpc_status_string;
grpc_mdstr *grpc_compression_algorithm_string;
grpc_mdstr *grpc_encodings_accepted_by_peer_string;
grpc_mdstr *grpc_message_string;
grpc_mdstr *path_string;
grpc_mdstr *authority_string;
grpc_mdelem *default_authority;
/** mdelem for grpc-status: 0 thru grpc-status: 2 */
grpc_mdelem *grpc_status_elem[NUM_CACHED_STATUS_ELEMS];
gpr_mu registered_call_mu;
registered_call *registered_calls;
@ -93,7 +84,7 @@ struct grpc_channel {
grpc_channel *grpc_channel_create_from_filters(
grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_filter **filters, size_t num_filters,
const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) {
const grpc_channel_args *args, int is_client) {
size_t i;
size_t size =
sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
@ -104,22 +95,6 @@ grpc_channel *grpc_channel_create_from_filters(
channel->is_client = is_client;
/* decremented by grpc_channel_destroy */
gpr_ref_init(&channel->refs, 1);
channel->metadata_context = mdctx;
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
channel->grpc_compression_algorithm_string =
grpc_mdstr_from_string(mdctx, "grpc-encoding");
channel->grpc_encodings_accepted_by_peer_string =
grpc_mdstr_from_string(mdctx, "grpc-accept-encoding");
channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
char buf[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa((long)i, buf);
channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings(
mdctx, GRPC_MDSTR_REF(channel->grpc_status_string),
grpc_mdstr_from_string(mdctx, buf));
}
channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
@ -146,7 +121,7 @@ grpc_channel *grpc_channel_create_from_filters(
GRPC_MDELEM_UNREF(channel->default_authority);
}
channel->default_authority = grpc_mdelem_from_strings(
mdctx, ":authority", args->args[i].value.string);
":authority", args->args[i].value.string);
}
} else if (0 ==
strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
@ -160,7 +135,7 @@ grpc_channel *grpc_channel_create_from_filters(
GRPC_ARG_DEFAULT_AUTHORITY);
} else {
channel->default_authority = grpc_mdelem_from_strings(
mdctx, ":authority", args->args[i].value.string);
":authority", args->args[i].value.string);
}
}
}
@ -171,14 +146,13 @@ grpc_channel *grpc_channel_create_from_filters(
target != NULL) {
char *default_authority = grpc_get_default_authority(target);
if (default_authority) {
channel->default_authority = grpc_mdelem_from_strings(
channel->metadata_context, ":authority", default_authority);
channel->default_authority =
grpc_mdelem_from_strings(":authority", default_authority);
}
gpr_free(default_authority);
}
grpc_channel_stack_init(exec_ctx, filters, num_filters, channel, args,
channel->metadata_context,
CHANNEL_STACK_FROM_CHANNEL(channel));
return channel;
@ -227,13 +201,10 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, cq,
grpc_mdelem_from_metadata_strings(
channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
grpc_mdstr_from_string(channel->metadata_context, method)),
host ? grpc_mdelem_from_metadata_strings(
channel->metadata_context,
GRPC_MDSTR_REF(channel->authority_string),
grpc_mdstr_from_string(channel->metadata_context, host))
grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
grpc_mdstr_from_string(method)),
host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
grpc_mdstr_from_string(host))
: NULL,
deadline);
}
@ -245,15 +216,11 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
"grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
4, (channel, method, host, reserved));
GPR_ASSERT(!reserved);
rc->path = grpc_mdelem_from_metadata_strings(
channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
grpc_mdstr_from_string(channel->metadata_context, method));
rc->authority =
host ? grpc_mdelem_from_metadata_strings(
channel->metadata_context,
GRPC_MDSTR_REF(channel->authority_string),
grpc_mdstr_from_string(channel->metadata_context, host))
: NULL;
rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
grpc_mdstr_from_string(method));
rc->authority = host ? grpc_mdelem_from_metadata_strings(
GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host))
: NULL;
gpr_mu_lock(&channel->registered_call_mu);
rc->next = channel->registered_calls;
channel->registered_calls = rc;
@ -293,17 +260,7 @@ void grpc_channel_internal_ref(grpc_channel *c) {
}
static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
size_t i;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
GRPC_MDELEM_UNREF(channel->grpc_status_elem[i]);
}
GRPC_MDSTR_UNREF(channel->grpc_status_string);
GRPC_MDSTR_UNREF(channel->grpc_compression_algorithm_string);
GRPC_MDSTR_UNREF(channel->grpc_encodings_accepted_by_peer_string);
GRPC_MDSTR_UNREF(channel->grpc_message_string);
GRPC_MDSTR_UNREF(channel->path_string);
GRPC_MDSTR_UNREF(channel->authority_string);
while (channel->registered_calls) {
registered_call *rc = channel->registered_calls;
channel->registered_calls = rc->next;
@ -316,7 +273,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
if (channel->default_authority != NULL) {
GRPC_MDELEM_UNREF(channel->default_authority);
}
grpc_mdctx_unref(channel->metadata_context);
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
@ -355,38 +311,19 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel) {
return channel->metadata_context;
}
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) {
return channel->grpc_status_string;
}
grpc_mdstr *grpc_channel_get_compression_algorithm_string(
grpc_channel *channel) {
return channel->grpc_compression_algorithm_string;
}
grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string(
grpc_channel *channel) {
return channel->grpc_encodings_accepted_by_peer_string;
}
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
return GRPC_MDELEM_REF(channel->grpc_status_elem[i]);
} else {
char tmp[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(i, tmp);
return grpc_mdelem_from_metadata_strings(
channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string),
grpc_mdstr_from_string(channel->metadata_context, tmp));
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
case 0:
return GRPC_MDELEM_GRPC_STATUS_0;
case 1:
return GRPC_MDELEM_GRPC_STATUS_1;
case 2:
return GRPC_MDELEM_GRPC_STATUS_2;
}
}
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) {
return channel->grpc_message_string;
gpr_ltoa(i, tmp);
return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS,
grpc_mdstr_from_string(tmp));
}
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel) {

@ -40,26 +40,17 @@
grpc_channel *grpc_channel_create_from_filters(
grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_filter **filters, size_t count,
const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client);
const grpc_channel_args *args, int is_client);
/** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
/** Get a (borrowed) pointer to the channel wide metadata context */
grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
status_code.
The returned elem is owned by the caller. */
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
int status_code);
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_compression_algorithm_string(
grpc_channel *channel);
grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string(
grpc_channel *channel);
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG

@ -37,6 +37,8 @@
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/slice.h>
#include <grpc/support/slice_buffer.h>
#include "src/core/census/grpc_filter.h"
#include "src/core/channel/channel_args.h"
@ -56,11 +58,11 @@ typedef struct {
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
grpc_closure initial_string_sent;
gpr_slice_buffer initial_string_buffer;
grpc_endpoint *tcp;
grpc_mdctx *mdctx;
grpc_closure connected;
} connector;
@ -72,18 +74,33 @@ static void connector_ref(grpc_connector *con) {
static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
grpc_mdctx_unref(c->mdctx);
/* c->initial_string_buffer does not need to be destroyed */
gpr_free(c);
}
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
int success) {
connector_unref(exec_ctx, arg);
}
static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
connector *c = arg;
grpc_closure *notify;
grpc_endpoint *tcp = c->tcp;
if (tcp != NULL) {
c->result->transport = grpc_create_chttp2_transport(
exec_ctx, c->args.channel_args, tcp, c->mdctx, 1);
if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
c);
gpr_slice_buffer_init(&c->initial_string_buffer);
gpr_slice_buffer_add(&c->initial_string_buffer,
c->args.initial_connect_string);
connector_ref(arg);
grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
&c->initial_string_sent);
}
c->result->transport =
grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
GPR_ASSERT(c->result->transport);
@ -123,7 +140,6 @@ static const grpc_connector_vtable connector_vtable = {
typedef struct {
grpc_subchannel_factory base;
gpr_refcount refs;
grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel *master;
} subchannel_factory;
@ -139,7 +155,6 @@ static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
if (gpr_unref(&f->refs)) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
grpc_mdctx_unref(f->mdctx);
gpr_free(f);
}
}
@ -154,10 +169,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
grpc_subchannel *s;
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
c->mdctx = f->mdctx;
grpc_mdctx_ref(c->mdctx);
gpr_ref_init(&c->refs, 1);
args->mdctx = f->mdctx;
args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args);
@ -182,7 +194,6 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
const grpc_channel_filter *filters[MAX_FILTERS];
grpc_resolver *resolver;
subchannel_factory *f;
grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
size_t n = 0;
GRPC_API_TRACE(
@ -196,14 +207,12 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
args, mdctx, 1);
channel =
grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
grpc_mdctx_ref(mdctx);
f->mdctx = mdctx;
f->merge_args = grpc_channel_args_copy(args);
f->master = channel;
GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");

@ -93,6 +93,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
grpc_mdctx_global_init();
grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
@ -147,6 +148,7 @@ void grpc_shutdown(void) {
g_all_of_the_plugins[i].destroy();
}
}
grpc_mdctx_global_shutdown();
}
gpr_mu_unlock(&g_init_mu);
}

@ -49,7 +49,6 @@ typedef struct {
} call_data;
typedef struct {
grpc_mdctx *mdctx;
grpc_channel *master;
grpc_status_code error_code;
const char *error_message;
@ -60,9 +59,9 @@ static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) {
channel_data *chand = elem->channel_data;
char tmp[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(chand->error_code, tmp);
calld->status.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-status", tmp);
calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message",
chand->error_message);
calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp);
calld->details.md =
grpc_mdelem_from_strings("grpc-message", chand->error_message);
calld->status.prev = calld->details.next = NULL;
calld->status.next = &calld->details;
calld->details.prev = &calld->status;
@ -115,7 +114,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
channel_data *chand = elem->channel_data;
GPR_ASSERT(args->is_first);
GPR_ASSERT(args->is_last);
chand->mdctx = args->metadata_context;
chand->master = args->master;
}
@ -139,8 +137,8 @@ grpc_channel *grpc_lame_client_channel_create(const char *target,
channel_data *chand;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
static const grpc_channel_filter *filters[] = {&lame_filter};
channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, 1,
NULL, grpc_mdctx_create(), 1);
channel =
grpc_channel_create_from_filters(&exec_ctx, target, filters, 1, NULL, 1);
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
GRPC_API_TRACE(
"grpc_lame_client_channel_create(target=%s, error_code=%d, "

@ -37,6 +37,8 @@
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/slice.h>
#include <grpc/support/slice_buffer.h>
#include "src/core/census/grpc_filter.h"
#include "src/core/channel/channel_args.h"
@ -61,14 +63,14 @@ typedef struct {
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
grpc_closure initial_string_sent;
gpr_slice_buffer initial_string_buffer;
gpr_mu mu;
grpc_endpoint *connecting_endpoint;
grpc_endpoint *newly_connecting_endpoint;
grpc_closure connected_closure;
grpc_mdctx *mdctx;
} connector;
static void connector_ref(grpc_connector *con) {
@ -79,7 +81,7 @@ static void connector_ref(grpc_connector *con) {
static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
grpc_mdctx_unref(c->mdctx);
/* c->initial_string_buffer does not need to be destroyed */
gpr_free(c);
}
}
@ -102,7 +104,7 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
c->result->transport = grpc_create_chttp2_transport(
exec_ctx, c->args.channel_args, secure_endpoint, c->mdctx, 1);
exec_ctx, c->args.channel_args, secure_endpoint, 1);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2);
@ -115,6 +117,14 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
notify->cb(exec_ctx, notify->cb_arg, 1);
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
int success) {
connector *c = arg;
grpc_security_connector_do_handshake(exec_ctx, &c->security_connector->base,
c->connecting_endpoint,
on_secure_handshake_done, c);
}
static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
connector *c = arg;
grpc_closure *notify;
@ -124,8 +134,19 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
GPR_ASSERT(c->connecting_endpoint == NULL);
c->connecting_endpoint = tcp;
gpr_mu_unlock(&c->mu);
grpc_security_connector_do_handshake(exec_ctx, &c->security_connector->base,
tcp, on_secure_handshake_done, c);
if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
c);
gpr_slice_buffer_init(&c->initial_string_buffer);
gpr_slice_buffer_add(&c->initial_string_buffer,
c->args.initial_connect_string);
grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
&c->initial_string_sent);
} else {
grpc_security_connector_do_handshake(exec_ctx,
&c->security_connector->base, tcp,
on_secure_handshake_done, c);
}
} else {
memset(c->result, 0, sizeof(*c->result));
notify = c->notify;
@ -171,7 +192,6 @@ static const grpc_connector_vtable connector_vtable = {
typedef struct {
grpc_subchannel_factory base;
gpr_refcount refs;
grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel_security_connector *security_connector;
grpc_channel *master;
@ -190,7 +210,6 @@ static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
"subchannel_factory");
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
grpc_mdctx_unref(f->mdctx);
gpr_free(f);
}
}
@ -206,13 +225,10 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
c->security_connector = f->security_connector;
c->mdctx = f->mdctx;
gpr_mu_init(&c->mu);
grpc_mdctx_ref(c->mdctx);
gpr_ref_init(&c->refs, 1);
args->args = final_args;
args->master = f->master;
args->mdctx = f->mdctx;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args);
@ -236,7 +252,6 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
grpc_channel_args *args_copy;
grpc_channel_args *new_args_from_connector;
grpc_channel_security_connector *security_connector;
grpc_mdctx *mdctx;
grpc_resolver *resolver;
subchannel_factory *f;
#define MAX_FILTERS 3
@ -266,7 +281,6 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
target, GRPC_STATUS_INVALID_ARGUMENT,
"Failed to create security connector.");
}
mdctx = grpc_mdctx_create();
connector_arg = grpc_security_connector_to_arg(&security_connector->base);
args_copy = grpc_channel_args_copy_and_add(
@ -280,13 +294,11 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
args_copy, mdctx, 1);
args_copy, 1);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
grpc_mdctx_ref(mdctx);
f->mdctx = mdctx;
GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, "subchannel_factory");
f->security_connector = security_connector;
f->merge_args = grpc_channel_args_copy(args_copy);

@ -54,6 +54,7 @@
#include "src/core/surface/completion_queue.h"
#include "src/core/surface/init.h"
#include "src/core/transport/metadata.h"
#include "src/core/transport/static_metadata.h"
typedef struct listener {
void *arg;
@ -108,8 +109,6 @@ struct channel_data {
grpc_server *server;
grpc_connectivity_state connectivity_state;
grpc_channel *channel;
grpc_mdstr *path_key;
grpc_mdstr *authority_key;
/* linked list of all channels on a server */
channel_data *next;
channel_data *prev;
@ -558,12 +557,11 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
if (md->key == chand->path_key) {
if (md->key == GRPC_MDSTR_PATH) {
calld->path = GRPC_MDSTR_REF(md->value);
return NULL;
} else if (md->key == chand->authority_key) {
} else if (md->key == GRPC_MDSTR_AUTHORITY) {
calld->host = GRPC_MDSTR_REF(md->value);
return NULL;
}
@ -718,9 +716,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(!args->is_last);
chand->server = NULL;
chand->channel = NULL;
chand->path_key = grpc_mdstr_from_string(args->metadata_context, ":path");
chand->authority_key =
grpc_mdstr_from_string(args->metadata_context, ":authority");
chand->next = chand->prev = chand;
chand->registered_methods = NULL;
chand->connectivity_state = GRPC_CHANNEL_IDLE;
@ -750,8 +745,6 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
chand->next = chand->prev = chand;
maybe_finish_shutdown(exec_ctx, chand->server);
gpr_mu_unlock(&chand->server->mu_global);
GRPC_MDSTR_UNREF(chand->path_key);
GRPC_MDSTR_UNREF(chand->authority_key);
server_unref(exec_ctx, chand->server);
}
}
@ -894,7 +887,7 @@ void grpc_server_start(grpc_server *server) {
void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
grpc_transport *transport,
grpc_channel_filter const **extra_filters,
size_t num_extra_filters, grpc_mdctx *mdctx,
size_t num_extra_filters,
const grpc_channel_args *args) {
size_t num_filters = s->channel_filter_count + num_extra_filters + 1;
grpc_channel_filter const **filters =
@ -929,7 +922,7 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
}
channel = grpc_channel_create_from_filters(exec_ctx, NULL, filters,
num_filters, args, mdctx, 0);
num_filters, args, 0);
chand = (channel_data *)grpc_channel_stack_element(
grpc_channel_get_channel_stack(channel), 0)->channel_data;
chand->server = s;
@ -948,8 +941,8 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
chand->registered_methods = gpr_malloc(alloc);
memset(chand->registered_methods, 0, alloc);
for (rm = s->registered_methods; rm; rm = rm->next) {
host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host) : NULL;
method = grpc_mdstr_from_string(mdctx, rm->method);
host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL;
method = grpc_mdstr_from_string(rm->method);
hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
.server_registered_method != NULL;

@ -57,7 +57,7 @@ void grpc_server_add_listener(
void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server,
grpc_transport *transport,
grpc_channel_filter const **extra_filters,
size_t num_extra_filters, grpc_mdctx *mdctx,
size_t num_extra_filters,
const grpc_channel_args *args);
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);

@ -44,11 +44,11 @@
#include <grpc/support/useful.h>
static void setup_transport(grpc_exec_ctx *exec_ctx, void *server,
grpc_transport *transport, grpc_mdctx *mdctx) {
grpc_transport *transport) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_http_server_filter};
grpc_server_setup_transport(exec_ctx, server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx,
GPR_ARRAY_SIZE(extra_filters),
grpc_server_get_channel_args(server));
}
@ -61,10 +61,9 @@ static void new_transport(grpc_exec_ctx *exec_ctx, void *server,
* (as in server_secure_chttp2.c) needs to add synchronization to avoid this
* case.
*/
grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_transport *transport = grpc_create_chttp2_transport(
exec_ctx, grpc_server_get_channel_args(server), tcp, mdctx, 0);
setup_transport(exec_ctx, server, transport, mdctx);
exec_ctx, grpc_server_get_channel_args(server), tcp, 0);
setup_transport(exec_ctx, server, transport);
grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
}
@ -107,9 +106,11 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
}
for (i = 0; i < resolved->naddrs; i++) {
port_temp = grpc_tcp_server_add_port(
grpc_tcp_listener *listener;
listener = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len);
port_temp = grpc_tcp_listener_get_port(listener);
if (port_temp >= 0) {
if (port_num == -1) {
port_num = port_temp;

@ -36,12 +36,15 @@
#include <assert.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
#include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/transport/chttp2/hpack_table.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
#include "src/core/transport/chttp2/varint.h"
#include "src/core/transport/static_metadata.h"
#define HASH_FRAGMENT_1(x) ((x)&255)
#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
@ -154,6 +157,18 @@ static gpr_uint8 *add_tiny_header_data(framer_state *st, size_t len) {
return gpr_slice_buffer_tiny_add(st->output, len);
}
static void evict_entry(grpc_chttp2_hpack_compressor *c) {
c->tail_remote_index++;
GPR_ASSERT(c->tail_remote_index > 0);
GPR_ASSERT(c->table_size >=
c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
GPR_ASSERT(c->table_elems > 0);
c->table_size = (gpr_uint16)(
c->table_size -
c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
c->table_elems--;
}
/* add an element to the decoder table */
static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
gpr_uint32 key_hash = elem->key->hash;
@ -164,26 +179,21 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
GPR_ASSERT(elem_size < 65536);
if (elem_size > c->max_table_size) {
while (c->table_size > 0) {
evict_entry(c);
}
return;
}
/* Reserve space for this element in the remote table: if this overflows
the current table, drop elements until it fits, matching the decompressor
algorithm */
/* TODO(ctiller): constant */
while (c->table_size + elem_size > 4096) {
c->tail_remote_index++;
GPR_ASSERT(c->tail_remote_index > 0);
GPR_ASSERT(c->table_size >=
c->table_elem_size[c->tail_remote_index %
GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
GPR_ASSERT(c->table_elems > 0);
c->table_size =
(gpr_uint16)(c->table_size -
c->table_elem_size[c->tail_remote_index %
GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
c->table_elems--;
while (c->table_size + elem_size > c->max_table_size) {
evict_entry(c);
}
GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS);
c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] =
(gpr_uint16)elem_size;
GPR_ASSERT(c->table_elems < c->max_table_size);
c->table_elem_size[new_index % c->cap_table_elems] = (gpr_uint16)elem_size;
c->table_size = (gpr_uint16)(c->table_size + elem_size);
c->table_elems++;
@ -329,6 +339,14 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
add_header_data(st, gpr_slice_ref(value_slice));
}
static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
framer_state *st) {
gpr_uint32 len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3);
GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20,
add_tiny_header_data(st, len), len);
c->advertise_table_size_change = 0;
}
static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c,
gpr_uint32 elem_index) {
return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
@ -435,8 +453,7 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
grpc_chttp2_encode_timeout(
gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
mdelem = grpc_mdelem_from_metadata_strings(
c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str),
grpc_mdstr_from_string(c->mdctx, timeout_str));
GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
hpack_enc(c, mdelem, st);
GRPC_MDELEM_UNREF(mdelem);
}
@ -447,11 +464,20 @@ gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
return slice;
}
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
grpc_mdctx *ctx) {
static gpr_uint32 elems_for_bytes(gpr_uint32 bytes) {
return (bytes + 31) / 32;
}
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) {
memset(c, 0, sizeof(*c));
c->mdctx = ctx;
c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
c->cap_table_elems = elems_for_bytes(c->max_table_size);
c->max_table_elems = c->cap_table_elems;
c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
c->table_elem_size =
gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
memset(c->table_elem_size, 0,
sizeof(*c->table_elem_size) * c->cap_table_elems);
}
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
@ -460,7 +486,55 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]);
if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]);
}
GRPC_MDSTR_UNREF(c->timeout_key_str);
gpr_free(c->table_elem_size);
}
void grpc_chttp2_hpack_compressor_set_max_usable_size(
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) {
c->max_usable_size = max_table_size;
grpc_chttp2_hpack_compressor_set_max_table_size(
c, GPR_MIN(c->max_table_size, max_table_size));
}
static void rebuild_elems(grpc_chttp2_hpack_compressor *c, gpr_uint32 new_cap) {
gpr_uint16 *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap);
gpr_uint32 i;
memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
GPR_ASSERT(c->table_elems <= new_cap);
for (i = 0; i < c->table_elems; i++) {
gpr_uint32 ofs = c->tail_remote_index + i + 1;
table_elem_size[ofs % new_cap] =
c->table_elem_size[ofs % c->cap_table_elems];
}
c->cap_table_elems = new_cap;
gpr_free(c->table_elem_size);
c->table_elem_size = table_elem_size;
}
void grpc_chttp2_hpack_compressor_set_max_table_size(
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) {
max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
if (max_table_size == c->max_table_size) {
return;
}
while (c->table_size > 0 && c->table_size > max_table_size) {
evict_entry(c);
}
c->max_table_size = max_table_size;
c->max_table_elems = elems_for_bytes(max_table_size);
if (c->max_table_elems > c->cap_table_elems) {
rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
} else if (c->max_table_elems < c->cap_table_elems / 3) {
gpr_uint32 new_cap = GPR_MAX(c->max_table_elems, 16);
if (new_cap != c->cap_table_elems) {
rebuild_elems(c, new_cap);
}
}
c->advertise_table_size_change = 1;
gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
}
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
@ -483,6 +557,9 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
updated). After this loop, we'll do a batch unref of elements. */
begin_frame(&st);
if (c->advertise_table_size_change != 0) {
emit_advertise_table_size_change(c, &st);
}
grpc_metadata_batch_assert_ok(metadata);
for (l = metadata->list.head; l; l = l->next) {
hpack_enc(c, l->md, &st);

@ -43,14 +43,26 @@
#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256
#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256
#define GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS (4096 / 32)
/* initial table size, per spec */
#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096
/* maximum table size we'll actually use */
#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024)
typedef struct {
gpr_uint32 filter_elems_sum;
gpr_uint32 max_table_size;
gpr_uint32 max_table_elems;
gpr_uint32 cap_table_elems;
/** if non-zero, advertise to the decoder that we'll start using a table
of this size */
gpr_uint8 advertise_table_size_change;
/** maximum number of bytes we'll use for the decode table (to guard against
peers ooming us by setting decode table size high) */
gpr_uint32 max_usable_size;
/* one before the lowest usable table index */
gpr_uint32 tail_remote_index;
gpr_uint16 table_size;
gpr_uint16 table_elems;
gpr_uint32 table_size;
gpr_uint32 table_elems;
/* filter tables for elems: this tables provides an approximate
popularity count for particular hashes, and are used to determine whether
@ -59,11 +71,6 @@ typedef struct {
been seen. When that count reaches max (255), all values are halved. */
gpr_uint8 filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS];
/* metadata context */
grpc_mdctx *mdctx;
/* the string 'grpc-timeout' */
grpc_mdstr *timeout_key_str;
/* entry tables for keys & elems: these tables track values that have been
seen and *may* be in the decompressor table */
grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
@ -71,12 +78,15 @@ typedef struct {
gpr_uint32 indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
gpr_uint32 indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
gpr_uint16 table_elem_size[GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS];
gpr_uint16 *table_elem_size;
} grpc_chttp2_hpack_compressor;
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
grpc_mdctx *mdctx);
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c);
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
void grpc_chttp2_hpack_compressor_set_max_table_size(
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size);
void grpc_chttp2_hpack_compressor_set_max_usable_size(
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size);
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, gpr_uint32 id,
grpc_metadata_batch *metadata, int is_eof,

@ -74,6 +74,8 @@ static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end);
static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end);
static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end);
static int parse_string_prefix(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end);
@ -156,7 +158,7 @@ static const grpc_chttp2_hpack_parser_state first_byte_action[] = {
parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx,
parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx,
parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size,
parse_max_tbl_size_x, parse_error};
parse_max_tbl_size_x, parse_illegal_op};
/* indexes the first byte to a parse state function - generated by
gen_hpack_tables.c */
@ -169,7 +171,7 @@ static const gpr_uint8 first_byte_lut[256] = {
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X,
ILLEGAL, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
@ -622,19 +624,20 @@ static const gpr_uint8 inverse_base64[256] = {
};
/* emission helpers */
static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
int add_to_table) {
static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
int add_to_table) {
if (add_to_table) {
GRPC_MDELEM_REF(md);
grpc_chttp2_hptbl_add(&p->table, md);
if (!grpc_chttp2_hptbl_add(&p->table, md)) {
return 0;
}
}
p->on_header(p->on_header_user_data, md);
return 1;
}
static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
grpc_chttp2_hpack_parser_string *str) {
grpc_mdstr *s = grpc_mdstr_from_buffer(p->table.mdctx, (gpr_uint8 *)str->str,
str->length);
grpc_mdstr *s = grpc_mdstr_from_buffer((gpr_uint8 *)str->str, str->length);
str->length = 0;
return s;
}
@ -714,9 +717,12 @@ static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
if (md == NULL) {
gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
return 0;
}
GRPC_MDELEM_REF(md);
on_hdr(p, md, 0);
return parse_begin(p, cur, end);
return on_hdr(p, md, 0) && parse_begin(p, cur, end);
}
/* parse an indexed field with index < 127 */
@ -742,21 +748,19 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)),
1);
return parse_begin(p, cur, end);
return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)),
1) &&
parse_begin(p, cur, end);
}
/* finish a literal header with incremental indexing with no index */
static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
take_string(p, &p->key),
take_string(p, &p->value)),
1);
return parse_begin(p, cur, end);
return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
take_string(p, &p->value)),
1) &&
parse_begin(p, cur, end);
}
/* parse a literal header with incremental indexing; index < 63 */
@ -795,21 +799,19 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)),
0);
return parse_begin(p, cur, end);
return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)),
0) &&
parse_begin(p, cur, end);
}
/* finish a literal header without incremental indexing with index = 0 */
static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
take_string(p, &p->key),
take_string(p, &p->value)),
0);
return parse_begin(p, cur, end);
return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
take_string(p, &p->value)),
0) &&
parse_begin(p, cur, end);
}
/* parse a literal header without incremental indexing; index < 15 */
@ -848,21 +850,19 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)),
0);
return parse_begin(p, cur, end);
return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
take_string(p, &p->value)),
0) &&
parse_begin(p, cur, end);
}
/* finish a literal header that is never indexed with an extra value */
static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
take_string(p, &p->key),
take_string(p, &p->value)),
0);
return parse_begin(p, cur, end);
return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
take_string(p, &p->value)),
0) &&
parse_begin(p, cur, end);
}
/* parse a literal header that is never indexed; index < 15 */
@ -901,14 +901,14 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
abort(); /* not implemented */
return parse_begin(p, cur, end);
return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
parse_begin(p, cur, end);
}
/* parse a max table size change, max size < 15 */
static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end) {
p->index = (*cur) & 0xf;
p->index = (*cur) & 0x1f;
return finish_max_tbl_size(p, cur + 1, end);
}
@ -918,7 +918,7 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_max_tbl_size};
p->next_state = and_then;
p->index = 0xf;
p->index = 0x1f;
p->parsing.value = &p->index;
return parse_value0(p, cur + 1, end);
}
@ -930,6 +930,13 @@ static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
return 0;
}
static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end) {
GPR_ASSERT(cur != end);
gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
return parse_error(p, cur, end);
}
/* parse the 1st byte of a varint into p->parsing.value
no overflow is possible */
static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
@ -1342,8 +1349,7 @@ static void on_header_not_set(void *user_data, grpc_mdelem *md) {
abort();
}
void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
grpc_mdctx *mdctx) {
void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
p->on_header = on_header_not_set;
p->on_header_user_data = NULL;
p->state = parse_begin;
@ -1353,7 +1359,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
p->value.str = NULL;
p->value.capacity = 0;
p->value.length = 0;
grpc_chttp2_hptbl_init(&p->table, mdctx);
grpc_chttp2_hptbl_init(&p->table);
}
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {

@ -95,8 +95,7 @@ struct grpc_chttp2_hpack_parser {
grpc_chttp2_hptbl table;
};
void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
grpc_mdctx *mdctx);
void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);

@ -36,7 +36,9 @@
#include <assert.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/support/murmur_hash.h"
static struct {
@ -169,15 +171,24 @@ static struct {
{"www-authenticate", ""},
};
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
static gpr_uint32 entries_for_bytes(gpr_uint32 bytes) {
return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) /
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
}
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) {
size_t i;
memset(tbl, 0, sizeof(*tbl));
tbl->mdctx = mdctx;
tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
tbl->current_table_bytes = tbl->max_bytes =
GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
tbl->max_entries = tbl->cap_entries =
entries_for_bytes(tbl->current_table_bytes);
tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
mdctx, static_table[i].key, static_table[i].value);
tbl->static_ents[i - 1] =
grpc_mdelem_from_strings(static_table[i].key, static_table[i].value);
}
}
@ -187,9 +198,9 @@ void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
GRPC_MDELEM_UNREF(tbl->static_ents[i]);
}
for (i = 0; i < tbl->num_ents; i++) {
GRPC_MDELEM_UNREF(
tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
}
gpr_free(tbl->ents);
}
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
@ -201,8 +212,8 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
/* Otherwise, find the value in the list of valid entries */
tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
if (tbl_index < tbl->num_ents) {
gpr_uint32 offset = (tbl->num_ents - 1u - tbl_index + tbl->first_ent) %
GRPC_CHTTP2_MAX_TABLE_COUNT;
gpr_uint32 offset =
(tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries;
return tbl->ents[offset];
}
/* Invalid entry: return error */
@ -216,21 +227,81 @@ static void evict1(grpc_chttp2_hptbl *tbl) {
GPR_SLICE_LENGTH(first_ent->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
GPR_ASSERT(elem_bytes <= tbl->mem_used);
tbl->mem_used = (gpr_uint16)(tbl->mem_used - elem_bytes);
tbl->first_ent =
(gpr_uint16)((tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
tbl->mem_used -= (gpr_uint32)elem_bytes;
tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
tbl->num_ents--;
GRPC_MDELEM_UNREF(first_ent);
}
void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
static void rebuild_ents(grpc_chttp2_hptbl *tbl, gpr_uint32 new_cap) {
grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
gpr_uint32 i;
for (i = 0; i < tbl->num_ents; i++) {
ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
}
gpr_free(tbl->ents);
tbl->ents = ents;
tbl->cap_entries = new_cap;
tbl->first_ent = 0;
}
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
gpr_uint32 max_bytes) {
if (tbl->max_bytes == max_bytes) {
return;
}
gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
while (tbl->mem_used > max_bytes) {
evict1(tbl);
}
tbl->max_bytes = max_bytes;
}
int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
gpr_uint32 bytes) {
if (tbl->current_table_bytes == bytes) {
return 1;
}
if (bytes > tbl->max_bytes) {
gpr_log(GPR_ERROR,
"Attempt to make hpack table %d bytes when max is %d bytes", bytes,
tbl->max_bytes);
return 0;
}
gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
while (tbl->mem_used > bytes) {
evict1(tbl);
}
tbl->current_table_bytes = bytes;
tbl->max_entries = entries_for_bytes(bytes);
if (tbl->max_entries > tbl->cap_entries) {
rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries));
} else if (tbl->max_entries < tbl->cap_entries / 3) {
gpr_uint32 new_cap = GPR_MAX(tbl->max_entries, 16u);
if (new_cap != tbl->cap_entries) {
rebuild_ents(tbl, new_cap);
}
}
return 1;
}
int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
GPR_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) {
gpr_log(GPR_ERROR,
"HPACK max table size reduced to %d but not reflected by hpack "
"stream (still at %d)",
tbl->max_bytes, tbl->current_table_bytes);
return 0;
}
/* we can't add elements bigger than the max table size */
if (elem_bytes > tbl->max_bytes) {
if (elem_bytes > tbl->current_table_bytes) {
/* HPACK draft 10 section 4.4 states:
* If the size of the new entry is less than or equal to the maximum
* size, that entry is added to the table. It is not an error to
@ -243,44 +314,43 @@ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
while (tbl->num_ents) {
evict1(tbl);
}
return;
return 1;
}
/* evict entries to ensure no overflow */
while (elem_bytes > (size_t)tbl->max_bytes - tbl->mem_used) {
while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
evict1(tbl);
}
/* copy the finalized entry in */
tbl->ents[tbl->last_ent] = md;
tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] =
GRPC_MDELEM_REF(md);
/* update accounting values */
tbl->last_ent =
(gpr_uint16)((tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
tbl->num_ents++;
tbl->mem_used = (gpr_uint16)(tbl->mem_used + elem_bytes);
tbl->mem_used += (gpr_uint32)elem_bytes;
return 1;
}
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
grpc_chttp2_hptbl_find_result r = {0, 0};
gpr_uint16 i;
gpr_uint32 i;
/* See if the string is in the static table */
for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
grpc_mdelem *ent = tbl->static_ents[i];
if (md->key != ent->key) continue;
r.index = (gpr_uint16)(i + 1);
r.index = i + 1u;
r.has_value = md->value == ent->value;
if (r.has_value) return r;
}
/* Scan the dynamic table */
for (i = 0; i < tbl->num_ents; i++) {
gpr_uint16 idx =
(gpr_uint16)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
grpc_mdelem *ent =
tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT];
gpr_uint32 idx =
(gpr_uint32)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
if (md->key != ent->key) continue;
r.index = idx;
r.has_value = md->value == ent->value;

@ -49,47 +49,58 @@
#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE
/* Per entry overhead bytes as per the spec */
#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32
#if 0
/* Maximum number of entries we could possibly fit in the table, given defined
overheads */
#define GRPC_CHTTP2_MAX_TABLE_COUNT \
((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD)
#endif
/* hpack decoder table */
typedef struct {
grpc_mdctx *mdctx;
/* the first used entry in ents */
gpr_uint16 first_ent;
/* the last used entry in ents */
gpr_uint16 last_ent;
gpr_uint32 first_ent;
/* how many entries are in the table */
gpr_uint16 num_ents;
gpr_uint32 num_ents;
/* the amount of memory used by the table, according to the hpack algorithm */
gpr_uint16 mem_used;
gpr_uint32 mem_used;
/* the max memory allowed to be used by the table, according to the hpack
algorithm */
gpr_uint16 max_bytes;
gpr_uint32 max_bytes;
/* the currently agreed size of the table, according to the hpack algorithm */
gpr_uint32 current_table_bytes;
/* Maximum number of entries we could possibly fit in the table, given defined
overheads */
gpr_uint32 max_entries;
/* Number of entries allocated in ents */
gpr_uint32 cap_entries;
/* a circular buffer of headers - this is stored in the opposite order to
what hpack specifies, in order to simplify table management a little...
meaning lookups need to SUBTRACT from the end position */
grpc_mdelem *ents[GRPC_CHTTP2_MAX_TABLE_COUNT];
grpc_mdelem **ents;
grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
} grpc_chttp2_hptbl;
/* initialize a hpack table */
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx);
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
gpr_uint32 max_bytes);
int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
gpr_uint32 bytes);
/* lookup a table entry based on its hpack index */
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
gpr_uint32 index);
/* add a table entry to the index */
void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
grpc_mdelem *md) GRPC_MUST_USE_RESULT;
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {
gpr_uint16 index;
gpr_uint8 has_value;
gpr_uint32 index;
int has_value;
} grpc_chttp2_hptbl_find_result;
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);

@ -191,6 +191,9 @@ typedef struct {
copied to next_stream_id in parsing when parsing commences */
gpr_uint32 next_stream_id;
/** how far to lookahead in a stream? */
gpr_uint32 stream_lookahead;
/** last received stream id */
gpr_uint32 last_incoming_stream_id;
@ -227,14 +230,14 @@ struct grpc_chttp2_transport_parsing {
/** was a goaway frame received? */
gpr_uint8 goaway_received;
/** the last sent max_table_size setting */
gpr_uint32 last_sent_max_table_size;
/** initial window change */
gpr_int64 initial_window_update;
/** data to write later - after parsing */
gpr_slice_buffer qbuf;
/* metadata object cache */
grpc_mdstr *str_grpc_timeout;
grpc_mdelem *elem_grpc_status_ok;
/** parser for headers */
grpc_chttp2_hpack_parser hpack_parser;
/** simple one shot parsers */
@ -288,7 +291,6 @@ struct grpc_chttp2_transport_parsing {
struct grpc_chttp2_transport {
grpc_transport base; /* must be first */
grpc_endpoint *ep;
grpc_mdctx *metadata_context;
gpr_refcount refs;
char *peer_string;
@ -483,7 +485,8 @@ struct grpc_chttp2_stream {
/** Someone is unlocking the transport mutex: check to see if writes
are required, and schedule them if so */
int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global,
grpc_chttp2_transport_writing *writing);
grpc_chttp2_transport_writing *writing,
int is_parsing);
void grpc_chttp2_perform_writes(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
grpc_endpoint *endpoint);

@ -35,14 +35,15 @@
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/profiling/timers.h"
#include "src/core/transport/chttp2/http2_errors.h"
#include "src/core/transport/chttp2/status_conversion.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/transport/static_metadata.h"
static int init_frame_parser(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *transport_parsing);
@ -78,6 +79,9 @@ void grpc_chttp2_prepare_to_read(
GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
transport_parsing->next_stream_id = transport_global->next_stream_id;
transport_parsing->last_sent_max_table_size =
transport_global->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE];
/* update the parsing view of incoming window */
while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
@ -127,6 +131,7 @@ void grpc_chttp2_publish_reads(
transport_global->settings[GRPC_SENT_SETTINGS],
GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
transport_parsing->settings_ack_received = 0;
transport_global->sent_local_settings = 0;
}
/* move goaway to the global state if we received one (it will be
@ -588,13 +593,12 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
transport_parsing->is_client ? "CLI" : "SVR",
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
if (md->key == transport_parsing->elem_grpc_status_ok->key &&
md != transport_parsing->elem_grpc_status_ok) {
if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
/* TODO(ctiller): check for a status like " 0" */
stream_parsing->seen_error = 1;
}
if (md->key == transport_parsing->str_grpc_timeout) {
if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) {
gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
if (!cached_timeout) {
/* not already parsed: parse it now, and store the result away */
@ -635,8 +639,7 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
transport_parsing->is_client ? "CLI" : "SVR",
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
if (md->key == transport_parsing->elem_grpc_status_ok->key &&
md != transport_parsing->elem_grpc_status_ok) {
if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
/* TODO(ctiller): check for a status like " 0" */
stream_parsing->seen_error = 1;
}
@ -819,6 +822,9 @@ static int init_settings_frame_parser(
}
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
transport_parsing->settings_ack_received = 1;
grpc_chttp2_hptbl_set_max_bytes(
&transport_parsing->hpack_parser.table,
transport_parsing->last_sent_max_table_size);
}
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.settings;

@ -45,7 +45,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
int grpc_chttp2_unlocking_check_writes(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_transport_writing *transport_writing) {
grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
grpc_chttp2_stream_global *stream_global;
grpc_chttp2_stream_writing *stream_writing;
@ -55,8 +55,13 @@ int grpc_chttp2_unlocking_check_writes(
gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
GPR_ASSERT(transport_global->qbuf.count == 0);
grpc_chttp2_hpack_compressor_set_max_table_size(
&transport_writing->hpack_compressor,
transport_global->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
if (transport_global->dirtied_local_settings &&
!transport_global->sent_local_settings) {
!transport_global->sent_local_settings && !is_parsing) {
gpr_slice_buffer_add(
&transport_writing->outbuf,
grpc_chttp2_settings_create(
@ -315,6 +320,8 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
}
}
GPR_TIMER_END("finalize_outbuf", 0);
}
void grpc_chttp2_cleanup_writing(

@ -49,10 +49,10 @@
#include "src/core/transport/chttp2/internal.h"
#include "src/core/transport/chttp2/status_conversion.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
#include "src/core/transport/static_metadata.h"
#include "src/core/transport/transport_impl.h"
#define DEFAULT_WINDOW 65535
#define GRPC_CHTTP2_STREAM_LOOKAHEAD DEFAULT_WINDOW
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu
@ -156,9 +156,6 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout);
GRPC_MDELEM_UNREF(t->parsing.elem_grpc_status_ok);
for (i = 0; i < STREAM_LIST_COUNT; i++) {
GPR_ASSERT(t->lists[i].head == NULL);
GPR_ASSERT(t->lists[i].tail == NULL);
@ -184,8 +181,6 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
gpr_free(ping);
}
grpc_mdctx_unref(t->metadata_context);
gpr_free(t->peer_string);
gpr_free(t);
}
@ -220,8 +215,7 @@ static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
const grpc_channel_args *channel_args,
grpc_endpoint *ep, grpc_mdctx *mdctx,
gpr_uint8 is_client) {
grpc_endpoint *ep, gpr_uint8 is_client) {
size_t i;
int j;
@ -237,22 +231,17 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* ref is dropped at transport close() */
gpr_ref_init(&t->shutdown_ep_refs, 1);
gpr_mu_init(&t->mu);
grpc_mdctx_ref(mdctx);
t->peer_string = grpc_endpoint_get_peer(ep);
t->metadata_context = mdctx;
t->endpoint_reading = 1;
t->global.next_stream_id = is_client ? 1 : 2;
t->global.is_client = is_client;
t->writing.outgoing_window = DEFAULT_WINDOW;
t->parsing.incoming_window = DEFAULT_WINDOW;
t->global.stream_lookahead = DEFAULT_WINDOW;
t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
t->global.ping_counter = 1;
t->global.pings.next = t->global.pings.prev = &t->global.pings;
t->parsing.is_client = is_client;
t->parsing.str_grpc_timeout =
grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
t->parsing.elem_grpc_status_ok =
grpc_mdelem_from_strings(t->metadata_context, "grpc-status", "0");
t->parsing.deframe_state =
is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
t->writing.is_client = is_client;
@ -263,12 +252,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_slice_buffer_init(&t->global.qbuf);
gpr_slice_buffer_init(&t->writing.outbuf);
grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
grpc_closure_init(&t->writing_action, writing_action, t);
gpr_slice_buffer_init(&t->parsing.qbuf);
grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);
grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser);
grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
&t->writing);
@ -338,6 +327,43 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->global.next_stream_id =
(gpr_uint32)channel_args->args[i].value.integer;
}
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
gpr_log(GPR_ERROR, "%s: must be an integer",
GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
} else if (channel_args->args[i].value.integer <= 5) {
gpr_log(GPR_ERROR, "%s: must be at least 5",
GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
} else {
t->global.stream_lookahead =
(gpr_uint32)channel_args->args[i].value.integer;
}
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
gpr_log(GPR_ERROR, "%s: must be an integer",
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
} else if (channel_args->args[i].value.integer < 0) {
gpr_log(GPR_DEBUG, "%s: must be non-negative",
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
} else {
push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
(gpr_uint32)channel_args->args[i].value.integer);
}
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
gpr_log(GPR_ERROR, "%s: must be an integer",
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
} else if (channel_args->args[i].value.integer < 0) {
gpr_log(GPR_DEBUG, "%s: must be non-negative",
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
} else {
grpc_chttp2_hpack_compressor_set_max_usable_size(
&t->writing.hpack_compressor,
(gpr_uint32)channel_args->args[i].value.integer);
}
}
}
}
@ -563,7 +589,8 @@ static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
GPR_TIMER_BEGIN("unlock", 0);
if (!t->writing_active && !t->closed &&
grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
grpc_chttp2_unlocking_check_writes(&t->global, &t->writing,
t->parsing_active)) {
t->writing_active = 1;
REF_TRANSPORT(t, "writing");
grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, 1);
@ -724,17 +751,18 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
static int contains_non_ok_status(
grpc_chttp2_transport_global *transport_global,
grpc_metadata_batch *batch) {
grpc_mdelem *ok_elem =
TRANSPORT_FROM_GLOBAL(transport_global)->parsing.elem_grpc_status_ok;
grpc_linked_mdelem *l;
for (l = batch->list.head; l; l = l->next) {
if (l->md->key == ok_elem->key && l->md != ok_elem) {
if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
l->md != GRPC_MDELEM_GRPC_STATUS_0) {
return 1;
}
}
return 0;
}
static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {}
static void perform_stream_op_locked(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
@ -743,6 +771,9 @@ static void perform_stream_op_locked(
GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
on_complete = op->on_complete;
if (on_complete == NULL) {
on_complete = grpc_closure_create(do_nothing, NULL);
}
/* use final_data as a barrier until enqueue time; the inital counter is
dropped at the end of this function */
on_complete->final_data = 2;
@ -806,7 +837,7 @@ static void perform_stream_op_locked(
}
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_trailing_metadata_finished,
exec_ctx, &stream_global->send_trailing_metadata_finished,
grpc_metadata_batch_is_empty(op->send_trailing_metadata));
} else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
@ -1033,20 +1064,20 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
to the upper layers - drop what we've got, and then publish
what we want - which is safe because we haven't told anyone
about the metadata yet */
if (!stream_global->published_trailing_metadata || stream_global->recv_trailing_metadata_finished != NULL) {
grpc_mdctx *mdctx =
TRANSPORT_FROM_GLOBAL(transport_global)->metadata_context;
if (!stream_global->published_trailing_metadata ||
stream_global->recv_trailing_metadata_finished != NULL) {
char status_string[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, status_string);
grpc_chttp2_incoming_metadata_buffer_add(
&stream_global->received_trailing_metadata,
grpc_mdelem_from_strings(mdctx, "grpc-status", status_string));
grpc_mdelem_from_metadata_strings(
GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
if (slice) {
grpc_chttp2_incoming_metadata_buffer_add(
&stream_global->received_trailing_metadata,
grpc_mdelem_from_metadata_strings(
mdctx, grpc_mdstr_from_string(mdctx, "grpc-message"),
grpc_mdstr_from_slice(mdctx, gpr_slice_ref(*slice))));
GRPC_MDSTR_GRPC_MESSAGE,
grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
}
stream_global->published_trailing_metadata = 1;
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
@ -1372,8 +1403,8 @@ static void incoming_byte_stream_update_flow_control(
gpr_uint32 max_recv_bytes;
/* clamp max recv hint to an allowable size */
if (max_size_hint >= GPR_UINT32_MAX - GRPC_CHTTP2_STREAM_LOOKAHEAD) {
max_recv_bytes = GPR_UINT32_MAX - GRPC_CHTTP2_STREAM_LOOKAHEAD;
if (max_size_hint >= GPR_UINT32_MAX - transport_global->stream_lookahead) {
max_recv_bytes = GPR_UINT32_MAX - transport_global->stream_lookahead;
} else {
max_recv_bytes = (gpr_uint32)max_size_hint;
}
@ -1386,8 +1417,9 @@ static void incoming_byte_stream_update_flow_control(
}
/* add some small lookahead to keep pipelines flowing */
GPR_ASSERT(max_recv_bytes <= GPR_UINT32_MAX - GRPC_CHTTP2_STREAM_LOOKAHEAD);
max_recv_bytes += GRPC_CHTTP2_STREAM_LOOKAHEAD;
GPR_ASSERT(max_recv_bytes <=
GPR_UINT32_MAX - transport_global->stream_lookahead);
max_recv_bytes += transport_global->stream_lookahead;
if (stream_global->max_recv_bytes < max_recv_bytes) {
gpr_uint32 add_max_recv_bytes =
max_recv_bytes - stream_global->max_recv_bytes;
@ -1596,9 +1628,9 @@ static const grpc_transport_vtable vtable = {
grpc_transport *grpc_create_chttp2_transport(
grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
grpc_endpoint *ep, grpc_mdctx *mdctx, int is_client) {
grpc_endpoint *ep, int is_client) {
grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
init_transport(exec_ctx, t, channel_args, ep, mdctx, is_client != 0);
init_transport(exec_ctx, t, channel_args, ep, is_client != 0);
return &t->base;
}

@ -42,7 +42,7 @@ extern int grpc_flowctl_trace;
grpc_transport *grpc_create_chttp2_transport(
grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
grpc_endpoint *ep, grpc_mdctx *metadata_context, int is_client);
grpc_endpoint *ep, int is_client);
void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,

@ -31,20 +31,32 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include "src/core/transport/metadata.h"
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <grpc/compression.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/profiling/timers.h"
#include "src/core/support/murmur_hash.h"
#include "src/core/support/string.h"
#include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/transport/static_metadata.h"
/* There are two kinds of mdelem and mdstr instances.
* Static instances are declared in static_metadata.{h,c} and
* are initialized by grpc_mdctx_global_init().
* Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
* by internal_string and internal_element structures.
* Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
* used to determine which kind of element a pointer refers to.
*/
#define INITIAL_STRTAB_CAPACITY 4
#define INITIAL_MDTAB_CAPACITY 4
@ -52,107 +64,188 @@
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
#define DEBUG_ARGS , const char *file, int line
#define FWD_DEBUG_ARGS , file, line
#define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__)
#define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__)
#define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__)
#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
#else
#define DEBUG_ARGS
#define FWD_DEBUG_ARGS
#define INTERNAL_STRING_REF(s) internal_string_ref((s))
#define INTERNAL_STRING_UNREF(s) internal_string_unref((s))
#define REF_MD_LOCKED(s) ref_md_locked((s))
#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
#endif
#define TABLE_IDX(hash, log2_shards, capacity) \
(((hash) >> (log2_shards)) % (capacity))
#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
typedef void (*destroy_user_data_func)(void *user_data);
/* Shadow structure for grpc_mdstr for non-static values */
typedef struct internal_string {
/* must be byte compatible with grpc_mdstr */
gpr_slice slice;
gpr_uint32 hash;
/* private only data */
gpr_uint32 refs;
gpr_atm refcnt;
gpr_uint8 has_base64_and_huffman_encoded;
gpr_slice_refcount refcount;
gpr_slice base64_and_huffman;
grpc_mdctx *context;
struct internal_string *bucket_next;
} internal_string;
/* Shadow structure for grpc_mdelem for non-static elements */
typedef struct internal_metadata {
/* must be byte compatible with grpc_mdelem */
internal_string *key;
internal_string *value;
/* private only data */
gpr_atm refcnt;
/* private only data */
gpr_mu mu_user_data;
gpr_atm destroy_user_data;
gpr_atm user_data;
grpc_mdctx *context;
struct internal_metadata *bucket_next;
} internal_metadata;
struct grpc_mdctx {
gpr_uint32 hash_seed;
int refs;
typedef struct strtab_shard {
gpr_mu mu;
internal_string **strs;
size_t count;
size_t capacity;
} strtab_shard;
internal_string **strtab;
size_t strtab_count;
size_t strtab_capacity;
typedef struct mdtab_shard {
gpr_mu mu;
internal_metadata **elems;
size_t count;
size_t capacity;
size_t free;
} mdtab_shard;
#define LOG2_STRTAB_SHARD_COUNT 5
#define LOG2_MDTAB_SHARD_COUNT 4
#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
/* hash seed: decided at initialization time */
static gpr_uint32 g_hash_seed;
/* linearly probed hash tables for static element lookup */
static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
static size_t g_static_strtab_maxprobe;
static size_t g_static_mdtab_maxprobe;
static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
static void gc_mdtab(mdtab_shard *shard);
void grpc_mdctx_global_init(void) {
size_t i, j;
g_hash_seed = (gpr_uint32)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
g_static_strtab_maxprobe = 0;
g_static_mdtab_maxprobe = 0;
/* build static tables */
memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
memset(g_static_strtab, 0, sizeof(g_static_strtab));
for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
grpc_mdstr *elem = &grpc_static_mdstr_table[i];
const char *str = grpc_static_metadata_strings[i];
gpr_uint32 hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
*(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
*(gpr_uint32 *)&elem->hash = hash;
for (j = 0;; j++) {
size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
if (g_static_strtab[idx] == NULL) {
g_static_strtab[idx] = &grpc_static_mdstr_table[i];
break;
}
}
if (j > g_static_strtab_maxprobe) {
g_static_strtab_maxprobe = j;
}
}
for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
grpc_mdelem *elem = &grpc_static_mdelem_table[i];
grpc_mdstr *key =
&grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
grpc_mdstr *value =
&grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
gpr_uint32 hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
*(grpc_mdstr **)&elem->key = key;
*(grpc_mdstr **)&elem->value = value;
for (j = 0;; j++) {
size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
if (g_static_mdtab[idx] == NULL) {
g_static_mdtab[idx] = elem;
break;
}
}
if (j > g_static_mdtab_maxprobe) {
g_static_mdtab_maxprobe = j;
}
}
/* initialize shards */
for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
strtab_shard *shard = &g_strtab_shard[i];
gpr_mu_init(&shard->mu);
shard->count = 0;
shard->capacity = INITIAL_STRTAB_CAPACITY;
shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
}
for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
mdtab_shard *shard = &g_mdtab_shard[i];
gpr_mu_init(&shard->mu);
shard->count = 0;
shard->free = 0;
shard->capacity = INITIAL_MDTAB_CAPACITY;
shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
}
}
internal_metadata **mdtab;
size_t mdtab_count;
size_t mdtab_free;
size_t mdtab_capacity;
};
static void internal_string_ref(internal_string *s DEBUG_ARGS);
static void internal_string_unref(internal_string *s DEBUG_ARGS);
static void discard_metadata(grpc_mdctx *ctx);
static void gc_mdtab(grpc_mdctx *ctx);
static void metadata_context_destroy_locked(grpc_mdctx *ctx);
static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
static void unlock(grpc_mdctx *ctx) {
/* If the context has been orphaned we'd like to delete it soon. We check
conditions in unlock as it signals the end of mutations on a context.
We need to ensure all grpc_mdelem and grpc_mdstr elements have been deleted
first. This is equivalent to saying that both tables have zero counts,
which is equivalent to saying that strtab_count is zero (as mdelem's MUST
reference an mdstr for their key and value slots).
To encourage that to happen, we start discarding zero reference count
mdelems on every unlock (instead of the usual 'I'm too loaded' trigger
case), since otherwise we can be stuck waiting for a garbage collection
that will never happen. */
if (ctx->refs == 0) {
/* uncomment if you're having trouble diagnosing an mdelem leak to make
things clearer (slows down destruction a lot, however) */
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gc_mdtab(ctx);
#endif
if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
discard_metadata(ctx);
void grpc_mdctx_global_shutdown(void) {
size_t i;
for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
mdtab_shard *shard = &g_mdtab_shard[i];
gpr_mu_destroy(&shard->mu);
gc_mdtab(shard);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
shard->count);
}
if (ctx->strtab_count == 0) {
metadata_context_destroy_locked(ctx);
return;
gpr_free(shard->elems);
}
for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
strtab_shard *shard = &g_strtab_shard[i];
gpr_mu_destroy(&shard->mu);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
shard->count);
}
gpr_free(shard->strs);
}
gpr_mu_unlock(&ctx->mu);
}
static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
static int is_mdstr_static(grpc_mdstr *s) {
return s >= &grpc_static_mdstr_table[0] &&
s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
}
static int is_mdelem_static(grpc_mdelem *e) {
return e >= &grpc_static_mdelem_table[0] &&
e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
}
static void ref_md_locked(mdtab_shard *shard,
internal_metadata *md DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%d->%d: '%s' = '%s'", md,
@ -162,96 +255,14 @@ static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
md->context->mdtab_free--;
shard->free--;
} else {
GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
}
}
grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));
ctx->refs = 1;
ctx->hash_seed = seed;
gpr_mu_init(&ctx->mu);
ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY);
memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY);
ctx->strtab_count = 0;
ctx->strtab_capacity = INITIAL_STRTAB_CAPACITY;
ctx->mdtab = gpr_malloc(sizeof(internal_metadata *) * INITIAL_MDTAB_CAPACITY);
memset(ctx->mdtab, 0, sizeof(grpc_mdelem *) * INITIAL_MDTAB_CAPACITY);
ctx->mdtab_count = 0;
ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY;
ctx->mdtab_free = 0;
return ctx;
}
grpc_mdctx *grpc_mdctx_create(void) {
/* This seed is used to prevent remote connections from controlling hash table
* collisions. It needs to be somewhat unpredictable to a remote connection.
*/
return grpc_mdctx_create_with_seed(
(gpr_uint32)gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
}
static void discard_metadata(grpc_mdctx *ctx) {
size_t i;
internal_metadata *next, *cur;
for (i = 0; i < ctx->mdtab_capacity; i++) {
cur = ctx->mdtab[i];
while (cur) {
void *user_data = (void *)gpr_atm_no_barrier_load(&cur->user_data);
GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0);
next = cur->bucket_next;
INTERNAL_STRING_UNREF(cur->key);
INTERNAL_STRING_UNREF(cur->value);
if (user_data != NULL) {
((destroy_user_data_func)gpr_atm_no_barrier_load(
&cur->destroy_user_data))(user_data);
}
gpr_mu_destroy(&cur->mu_user_data);
gpr_free(cur);
cur = next;
ctx->mdtab_free--;
ctx->mdtab_count--;
}
ctx->mdtab[i] = NULL;
}
}
static void metadata_context_destroy_locked(grpc_mdctx *ctx) {
GPR_ASSERT(ctx->strtab_count == 0);
GPR_ASSERT(ctx->mdtab_count == 0);
GPR_ASSERT(ctx->mdtab_free == 0);
gpr_free(ctx->strtab);
gpr_free(ctx->mdtab);
gpr_mu_unlock(&ctx->mu);
gpr_mu_destroy(&ctx->mu);
gpr_free(ctx);
}
void grpc_mdctx_ref(grpc_mdctx *ctx) {
GPR_TIMER_BEGIN("grpc_mdctx_ref", 0);
lock(ctx);
GPR_ASSERT(ctx->refs > 0);
ctx->refs++;
unlock(ctx);
GPR_TIMER_END("grpc_mdctx_ref", 0);
}
void grpc_mdctx_unref(grpc_mdctx *ctx) {
GPR_TIMER_BEGIN("grpc_mdctx_unref", 0);
lock(ctx);
GPR_ASSERT(ctx->refs > 0);
ctx->refs--;
unlock(ctx);
GPR_TIMER_END("grpc_mdctx_unref", 0);
}
static void grow_strtab(grpc_mdctx *ctx) {
size_t capacity = ctx->strtab_capacity * 2;
static void grow_strtab(strtab_shard *shard) {
size_t capacity = shard->capacity * 2;
size_t i;
internal_string **strtab;
internal_string *s, *next;
@ -261,105 +272,95 @@ static void grow_strtab(grpc_mdctx *ctx) {
strtab = gpr_malloc(sizeof(internal_string *) * capacity);
memset(strtab, 0, sizeof(internal_string *) * capacity);
for (i = 0; i < ctx->strtab_capacity; i++) {
for (s = ctx->strtab[i]; s; s = next) {
for (i = 0; i < shard->capacity; i++) {
for (s = shard->strs[i]; s; s = next) {
size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
next = s->bucket_next;
s->bucket_next = strtab[s->hash % capacity];
strtab[s->hash % capacity] = s;
s->bucket_next = strtab[idx];
strtab[idx] = s;
}
}
gpr_free(ctx->strtab);
ctx->strtab = strtab;
ctx->strtab_capacity = capacity;
gpr_free(shard->strs);
shard->strs = strtab;
shard->capacity = capacity;
GPR_TIMER_END("grow_strtab", 0);
}
static void internal_destroy_string(internal_string *is) {
static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
internal_string **prev_next;
internal_string *cur;
grpc_mdctx *ctx = is->context;
GPR_TIMER_BEGIN("internal_destroy_string", 0);
if (is->has_base64_and_huffman_encoded) {
gpr_slice_unref(is->base64_and_huffman);
}
for (prev_next = &ctx->strtab[is->hash % ctx->strtab_capacity],
for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
shard->capacity)],
cur = *prev_next;
cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
;
*prev_next = cur->bucket_next;
ctx->strtab_count--;
shard->count--;
gpr_free(is);
GPR_TIMER_END("internal_destroy_string", 0);
}
static void internal_string_ref(internal_string *s DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%d->%d: '%s'", s,
s->refs, s->refs + 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
#endif
++s->refs;
}
static void internal_string_unref(internal_string *s DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%d->%d: '%s'", s,
s->refs, s->refs - 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
#endif
GPR_ASSERT(s->refs > 0);
if (0 == --s->refs) {
internal_destroy_string(s);
}
}
static void slice_ref(void *p) {
internal_string *is =
(internal_string *)((char *)p - offsetof(internal_string, refcount));
grpc_mdctx *ctx = is->context;
GPR_TIMER_BEGIN("slice_ref", 0);
lock(ctx);
INTERNAL_STRING_REF(is);
unlock(ctx);
GPR_TIMER_END("slice_ref", 0);
GRPC_MDSTR_REF((grpc_mdstr *)(is));
}
static void slice_unref(void *p) {
internal_string *is =
(internal_string *)((char *)p - offsetof(internal_string, refcount));
grpc_mdctx *ctx = is->context;
GPR_TIMER_BEGIN("slice_unref", 0);
lock(ctx);
INTERNAL_STRING_UNREF(is);
unlock(ctx);
GPR_TIMER_END("slice_unref", 0);
GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
}
grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
grpc_mdstr *grpc_mdstr_from_string(const char *str) {
return grpc_mdstr_from_buffer((const gpr_uint8 *)str, strlen(str));
}
grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice) {
grpc_mdstr *result = grpc_mdstr_from_buffer(ctx, GPR_SLICE_START_PTR(slice),
grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
GPR_SLICE_LENGTH(slice));
gpr_slice_unref(slice);
return result;
}
grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
size_t length) {
gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed);
grpc_mdstr *grpc_mdstr_from_buffer(const gpr_uint8 *buf, size_t length) {
gpr_uint32 hash = gpr_murmur_hash3(buf, length, g_hash_seed);
internal_string *s;
strtab_shard *shard =
&g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
size_t i;
size_t idx;
GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
lock(ctx);
/* search for a static string */
for (i = 0; i <= g_static_strtab_maxprobe; i++) {
grpc_mdstr *ss;
idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
ss = g_static_strtab[idx];
if (ss == NULL) break;
if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length &&
0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) {
GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
return ss;
}
}
gpr_mu_lock(&shard->mu);
/* search for an existing string */
for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) {
idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
for (s = shard->strs[idx]; s; s = s->bucket_next) {
if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
INTERNAL_STRING_REF(s);
unlock(ctx);
GRPC_MDSTR_REF((grpc_mdstr *)s);
gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
return (grpc_mdstr *)s;
}
@ -369,7 +370,7 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
if (length + 1 < GPR_SLICE_INLINED_SIZE) {
/* string data goes directly into the slice */
s = gpr_malloc(sizeof(internal_string));
s->refs = 1;
gpr_atm_rel_store(&s->refcnt, 2);
s->slice.refcount = NULL;
memcpy(s->slice.data.inlined.bytes, buf, length);
s->slice.data.inlined.bytes[length] = 0;
@ -378,7 +379,7 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
/* string data goes after the internal_string header, and we +1 for null
terminator */
s = gpr_malloc(sizeof(internal_string) + length + 1);
s->refs = 1;
gpr_atm_rel_store(&s->refcnt, 2);
s->refcount.ref = slice_ref;
s->refcount.unref = slice_unref;
s->slice.refcount = &s->refcount;
@ -390,44 +391,43 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
}
s->has_base64_and_huffman_encoded = 0;
s->hash = hash;
s->context = ctx;
s->bucket_next = ctx->strtab[hash % ctx->strtab_capacity];
ctx->strtab[hash % ctx->strtab_capacity] = s;
s->bucket_next = shard->strs[idx];
shard->strs[idx] = s;
ctx->strtab_count++;
shard->count++;
if (ctx->strtab_count > ctx->strtab_capacity * 2) {
grow_strtab(ctx);
if (shard->count > shard->capacity * 2) {
grow_strtab(shard);
}
unlock(ctx);
gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
return (grpc_mdstr *)s;
}
static void gc_mdtab(grpc_mdctx *ctx) {
static void gc_mdtab(mdtab_shard *shard) {
size_t i;
internal_metadata **prev_next;
internal_metadata *md, *next;
GPR_TIMER_BEGIN("gc_mdtab", 0);
for (i = 0; i < ctx->mdtab_capacity; i++) {
prev_next = &ctx->mdtab[i];
for (md = ctx->mdtab[i]; md; md = next) {
for (i = 0; i < shard->capacity; i++) {
prev_next = &shard->elems[i];
for (md = shard->elems[i]; md; md = next) {
void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
next = md->bucket_next;
if (gpr_atm_acq_load(&md->refcnt) == 0) {
INTERNAL_STRING_UNREF(md->key);
INTERNAL_STRING_UNREF(md->value);
GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
if (md->user_data) {
((destroy_user_data_func)gpr_atm_no_barrier_load(
&md->destroy_user_data))(user_data);
}
gpr_free(md);
*prev_next = next;
ctx->mdtab_free--;
ctx->mdtab_count--;
shard->free--;
shard->count--;
} else {
prev_next = &md->bucket_next;
}
@ -436,8 +436,8 @@ static void gc_mdtab(grpc_mdctx *ctx) {
GPR_TIMER_END("gc_mdtab", 0);
}
static void grow_mdtab(grpc_mdctx *ctx) {
size_t capacity = ctx->mdtab_capacity * 2;
static void grow_mdtab(mdtab_shard *shard) {
size_t capacity = shard->capacity * 2;
size_t i;
internal_metadata **mdtab;
internal_metadata *md, *next;
@ -448,52 +448,67 @@ static void grow_mdtab(grpc_mdctx *ctx) {
mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
for (i = 0; i < ctx->mdtab_capacity; i++) {
for (md = ctx->mdtab[i]; md; md = next) {
for (i = 0; i < shard->capacity; i++) {
for (md = shard->elems[i]; md; md = next) {
size_t idx;
hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
next = md->bucket_next;
md->bucket_next = mdtab[hash % capacity];
mdtab[hash % capacity] = md;
idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
md->bucket_next = mdtab[idx];
mdtab[idx] = md;
}
}
gpr_free(ctx->mdtab);
ctx->mdtab = mdtab;
ctx->mdtab_capacity = capacity;
gpr_free(shard->elems);
shard->elems = mdtab;
shard->capacity = capacity;
GPR_TIMER_END("grow_mdtab", 0);
}
static void rehash_mdtab(grpc_mdctx *ctx) {
if (ctx->mdtab_free > ctx->mdtab_capacity / 4) {
gc_mdtab(ctx);
static void rehash_mdtab(mdtab_shard *shard) {
if (shard->free > shard->capacity / 4) {
gc_mdtab(shard);
} else {
grow_mdtab(ctx);
grow_mdtab(shard);
}
}
grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
grpc_mdstr *mkey,
grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
grpc_mdstr *mvalue) {
internal_string *key = (internal_string *)mkey;
internal_string *value = (internal_string *)mvalue;
gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
internal_metadata *md;
GPR_ASSERT(key->context == ctx);
GPR_ASSERT(value->context == ctx);
mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
size_t i;
size_t idx;
GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
lock(ctx);
if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
grpc_mdelem *smd;
idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
smd = g_static_mdtab[idx];
if (smd == NULL) break;
if (smd->key == mkey && smd->value == mvalue) {
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
return smd;
}
}
}
gpr_mu_lock(&shard->mu);
idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
/* search for an existing pair */
for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
for (md = shard->elems[idx]; md; md = md->bucket_next) {
if (md->key == key && md->value == value) {
REF_MD_LOCKED(md);
INTERNAL_STRING_UNREF(key);
INTERNAL_STRING_UNREF(value);
unlock(ctx);
REF_MD_LOCKED(shard, md);
GRPC_MDSTR_UNREF((grpc_mdstr *)key);
GRPC_MDSTR_UNREF((grpc_mdstr *)value);
gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
return (grpc_mdelem *)md;
}
@ -502,12 +517,12 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
/* not found: create a new pair */
md = gpr_malloc(sizeof(internal_metadata));
gpr_atm_rel_store(&md->refcnt, 2);
md->context = ctx;
md->key = key;
md->value = value;
md->user_data = 0;
md->destroy_user_data = 0;
md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
md->bucket_next = shard->elems[idx];
shard->elems[idx] = md;
gpr_mu_init(&md->mu_user_data);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md,
@ -515,44 +530,39 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
ctx->mdtab[hash % ctx->mdtab_capacity] = md;
ctx->mdtab_count++;
shard->count++;
if (ctx->mdtab_count > ctx->mdtab_capacity * 2) {
rehash_mdtab(ctx);
if (shard->count > shard->capacity * 2) {
rehash_mdtab(shard);
}
unlock(ctx);
gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
return (grpc_mdelem *)md;
}
grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
const char *value) {
return grpc_mdelem_from_metadata_strings(ctx,
grpc_mdstr_from_string(ctx, key),
grpc_mdstr_from_string(ctx, value));
grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
grpc_mdstr_from_string(value));
}
grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
gpr_slice value) {
return grpc_mdelem_from_metadata_strings(ctx, grpc_mdstr_from_slice(ctx, key),
grpc_mdstr_from_slice(ctx, value));
grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
grpc_mdstr_from_slice(value));
}
grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
const char *key,
grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
const gpr_uint8 *value,
size_t value_length) {
return grpc_mdelem_from_metadata_strings(
ctx, grpc_mdstr_from_string(ctx, key),
grpc_mdstr_from_buffer(ctx, value, value_length));
grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
}
grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
if (is_mdelem_static(gmd)) return gmd;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%d->%d: '%s' = '%s'", md,
@ -573,6 +583,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
if (!md) return;
if (is_mdelem_static(gmd)) return;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
@ -582,14 +593,16 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
grpc_mdctx *ctx = md->context;
gpr_uint32 hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
mdtab_shard *shard =
&g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
lock(ctx);
gpr_mu_lock(&shard->mu);
if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
ctx->mdtab_free++;
shard->free++;
gpr_atm_no_barrier_store(&md->refcnt, 0);
}
unlock(ctx);
gpr_mu_unlock(&shard->mu);
GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
}
}
@ -600,36 +613,31 @@ const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
grpc_mdctx *ctx = s->context;
lock(ctx);
internal_string_ref(s FWD_DEBUG_ARGS);
unlock(ctx);
if (is_mdstr_static(gs)) return gs;
GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
return gs;
}
void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
grpc_mdctx *ctx = s->context;
lock(ctx);
internal_string_unref(s FWD_DEBUG_ARGS);
unlock(ctx);
}
size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *ctx) {
return ctx->mdtab_capacity;
}
size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *ctx) {
return ctx->mdtab_count;
}
size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) {
return ctx->mdtab_free;
if (is_mdstr_static(gs)) return;
if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
strtab_shard *shard =
&g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
gpr_mu_lock(&shard->mu);
if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
internal_destroy_string(shard, s);
}
gpr_mu_unlock(&shard->mu);
}
}
void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
internal_metadata *im = (internal_metadata *)md;
void *result;
if (is_mdelem_static(md)) {
return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
}
if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
return (void *)gpr_atm_no_barrier_load(&im->user_data);
} else {
@ -641,6 +649,7 @@ void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
void *user_data) {
internal_metadata *im = (internal_metadata *)md;
GPR_ASSERT(!is_mdelem_static(md));
GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
gpr_mu_lock(&im->mu_user_data);
if (gpr_atm_no_barrier_load(&im->destroy_user_data)) {
@ -659,15 +668,16 @@ void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
internal_string *s = (internal_string *)gs;
gpr_slice slice;
grpc_mdctx *ctx = s->context;
lock(ctx);
strtab_shard *shard =
&g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
gpr_mu_lock(&shard->mu);
if (!s->has_base64_and_huffman_encoded) {
s->base64_and_huffman =
grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
s->has_base64_and_huffman_encoded = 1;
}
slice = s->base64_and_huffman;
unlock(ctx);
gpr_mu_unlock(&shard->mu);
return slice;
}

@ -59,10 +59,15 @@
grpc_mdelem instances MAY live longer than their refcount implies, and are
garbage collected periodically, meaning cached data can easily outlive a
single request. */
single request.
STATIC METADATA: in static_metadata.h we declare a set of static metadata.
These mdelems and mdstrs are available via pre-declared code generated macros
and are available to code anywhere between grpc_init() and grpc_shutdown().
They are not refcounted, but can be passed to _ref and _unref functions
declared here - in which case those functions are effectively no-ops. */
/* Forward declarations */
typedef struct grpc_mdctx grpc_mdctx;
typedef struct grpc_mdstr grpc_mdstr;
typedef struct grpc_mdelem grpc_mdelem;
@ -81,25 +86,18 @@ struct grpc_mdelem {
/* there is a private part to this in metadata.c */
};
/* Create/orphan a metadata context */
grpc_mdctx *grpc_mdctx_create(void);
grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed);
void grpc_mdctx_ref(grpc_mdctx *mdctx);
void grpc_mdctx_unref(grpc_mdctx *mdctx);
/* Test only accessors to internal state - only for testing this code - do not
rely on it outside of metadata_test.c */
size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *mdctx);
size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *mdctx);
size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx);
size_t grpc_mdctx_get_mdtab_capacity_test_only(void);
size_t grpc_mdctx_get_mdtab_count_test_only(void);
size_t grpc_mdctx_get_mdtab_free_test_only(void);
/* Constructors for grpc_mdstr instances; take a variety of data types that
clients may have handy */
grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str);
grpc_mdstr *grpc_mdstr_from_string(const char *str);
/* Unrefs the slice. */
grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice);
grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str,
size_t length);
grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice);
grpc_mdstr *grpc_mdstr_from_buffer(const gpr_uint8 *str, size_t length);
/* Returns a borrowed slice from the mdstr with its contents base64 encoded
and huffman compressed */
@ -107,15 +105,12 @@ gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str);
/* Constructors for grpc_mdelem instances; take a variety of data types that
clients may have handy */
grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdstr *key,
grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key,
grpc_mdstr *value);
grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
const char *value);
grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value);
/* Unrefs the slices. */
grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
gpr_slice value);
grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
const char *key,
grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value);
grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
const gpr_uint8 *value,
size_t value_length);
@ -157,4 +152,7 @@ int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s);
#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
void grpc_mdctx_global_init(void);
void grpc_mdctx_global_shutdown(void);
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */

@ -0,0 +1,157 @@
/*
* Copyright 2015, 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.
*/
/*
* WARNING: Auto-generated code.
*
* To make changes to this file, change
* tools/codegen/core/gen_static_metadata.py,
* and then re-run it.
*
* See metadata.h for an explanation of the interface here, and metadata.c for
* an
* explanation of what's going on.
*/
#include "src/core/transport/static_metadata.h"
grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
gpr_uintptr grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 3, 7, 5, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const gpr_uint8
grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] = {
11, 33, 10, 33, 12, 33, 12, 47, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33,
28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31,
40, 32, 40, 46, 40, 51, 40, 52, 40, 53, 40, 54, 41, 31, 41, 46, 41, 51,
44, 0, 44, 1, 44, 2, 48, 33, 55, 33, 56, 33, 57, 33, 58, 33, 59, 33,
60, 33, 61, 33, 62, 33, 63, 33, 64, 38, 64, 66, 65, 76, 65, 77, 67, 33,
68, 33, 69, 33, 70, 33, 71, 33, 72, 33, 73, 39, 73, 49, 73, 50, 74, 33,
75, 33, 78, 3, 78, 4, 78, 5, 78, 6, 78, 7, 78, 8, 78, 9, 79, 33,
80, 81, 82, 33, 83, 33, 84, 33, 85, 33, 86, 33};
const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
"0",
"1",
"2",
"200",
"204",
"206",
"304",
"400",
"404",
"500",
"accept",
"accept-charset",
"accept-encoding",
"accept-language",
"accept-ranges",
"access-control-allow-origin",
"age",
"allow",
"application/grpc",
":authority",
"authorization",
"cache-control",
"content-disposition",
"content-encoding",
"content-language",
"content-length",
"content-location",
"content-range",
"content-type",
"cookie",
"date",
"deflate",
"deflate,gzip",
"",
"etag",
"expect",
"expires",
"from",
"GET",
"grpc",
"grpc-accept-encoding",
"grpc-encoding",
"grpc-internal-encoding-request",
"grpc-message",
"grpc-status",
"grpc-timeout",
"gzip",
"gzip, deflate",
"host",
"http",
"https",
"identity",
"identity,deflate",
"identity,deflate,gzip",
"identity,gzip",
"if-match",
"if-modified-since",
"if-none-match",
"if-range",
"if-unmodified-since",
"last-modified",
"link",
"location",
"max-forwards",
":method",
":path",
"POST",
"proxy-authenticate",
"proxy-authorization",
"range",
"referer",
"refresh",
"retry-after",
":scheme",
"server",
"set-cookie",
"/",
"/index.html",
":status",
"strict-transport-security",
"te",
"trailers",
"transfer-encoding",
"user-agent",
"vary",
"via",
"www-authenticate"};
const gpr_uint8 grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30,
28, 32, 27, 31};

@ -0,0 +1,402 @@
/*
* Copyright 2015, 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.
*/
/*
* WARNING: Auto-generated code.
*
* To make changes to this file, change
* tools/codegen/core/gen_static_metadata.py,
* and then re-run it.
*
* See metadata.h for an explanation of the interface here, and metadata.c for
* an
* explanation of what's going on.
*/
#ifndef GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H
#define GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H
#include "src/core/transport/metadata.h"
#define GRPC_STATIC_MDSTR_COUNT 87
extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
/* "0" */
#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
/* "1" */
#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1])
/* "2" */
#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2])
/* "200" */
#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3])
/* "204" */
#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4])
/* "206" */
#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5])
/* "304" */
#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6])
/* "400" */
#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7])
/* "404" */
#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8])
/* "500" */
#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9])
/* "accept" */
#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10])
/* "accept-charset" */
#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11])
/* "accept-encoding" */
#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12])
/* "accept-language" */
#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13])
/* "accept-ranges" */
#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14])
/* "access-control-allow-origin" */
#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15])
/* "age" */
#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16])
/* "allow" */
#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17])
/* "application/grpc" */
#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18])
/* ":authority" */
#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19])
/* "authorization" */
#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
/* "cache-control" */
#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
/* "content-disposition" */
#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[22])
/* "content-encoding" */
#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[23])
/* "content-language" */
#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[24])
/* "content-length" */
#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[25])
/* "content-location" */
#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[26])
/* "content-range" */
#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[27])
/* "content-type" */
#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[28])
/* "cookie" */
#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[29])
/* "date" */
#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[30])
/* "deflate" */
#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[31])
/* "deflate,gzip" */
#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[32])
/* "" */
#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[33])
/* "etag" */
#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[34])
/* "expect" */
#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[35])
/* "expires" */
#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[36])
/* "from" */
#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[37])
/* "GET" */
#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[38])
/* "grpc" */
#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[39])
/* "grpc-accept-encoding" */
#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[40])
/* "grpc-encoding" */
#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[41])
/* "grpc-internal-encoding-request" */
#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[42])
/* "grpc-message" */
#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[43])
/* "grpc-status" */
#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[44])
/* "grpc-timeout" */
#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[45])
/* "gzip" */
#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[46])
/* "gzip, deflate" */
#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[47])
/* "host" */
#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[48])
/* "http" */
#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[49])
/* "https" */
#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[50])
/* "identity" */
#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[51])
/* "identity,deflate" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[52])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(&grpc_static_mdstr_table[53])
/* "identity,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[54])
/* "if-match" */
#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[55])
/* "if-modified-since" */
#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[56])
/* "if-none-match" */
#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[57])
/* "if-range" */
#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[58])
/* "if-unmodified-since" */
#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[59])
/* "last-modified" */
#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[60])
/* "link" */
#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[61])
/* "location" */
#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[62])
/* "max-forwards" */
#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[63])
/* ":method" */
#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[64])
/* ":path" */
#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[65])
/* "POST" */
#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[66])
/* "proxy-authenticate" */
#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[67])
/* "proxy-authorization" */
#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[68])
/* "range" */
#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[69])
/* "referer" */
#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[70])
/* "refresh" */
#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[71])
/* "retry-after" */
#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[72])
/* ":scheme" */
#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[73])
/* "server" */
#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[74])
/* "set-cookie" */
#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[75])
/* "/" */
#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[76])
/* "/index.html" */
#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[77])
/* ":status" */
#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[78])
/* "strict-transport-security" */
#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[79])
/* "te" */
#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[80])
/* "trailers" */
#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[81])
/* "transfer-encoding" */
#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[82])
/* "user-agent" */
#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[83])
/* "vary" */
#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[84])
/* "via" */
#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[85])
/* "www-authenticate" */
#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[86])
#define GRPC_STATIC_MDELEM_COUNT 78
extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern gpr_uintptr grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
/* "accept-charset": "" */
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0])
/* "accept": "" */
#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1])
/* "accept-encoding": "" */
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2])
/* "accept-encoding": "gzip, deflate" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
(&grpc_static_mdelem_table[3])
/* "accept-language": "" */
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4])
/* "accept-ranges": "" */
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5])
/* "access-control-allow-origin": "" */
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
(&grpc_static_mdelem_table[6])
/* "age": "" */
#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7])
/* "allow": "" */
#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8])
/* ":authority": "" */
#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9])
/* "authorization": "" */
#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10])
/* "cache-control": "" */
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11])
/* "content-disposition": "" */
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12])
/* "content-encoding": "" */
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13])
/* "content-language": "" */
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14])
/* "content-length": "" */
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15])
/* "content-location": "" */
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16])
/* "content-range": "" */
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17])
/* "content-type": "application/grpc" */
#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
(&grpc_static_mdelem_table[18])
/* "content-type": "" */
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19])
/* "cookie": "" */
#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20])
/* "date": "" */
#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21])
/* "etag": "" */
#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22])
/* "expect": "" */
#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23])
/* "expires": "" */
#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24])
/* "from": "" */
#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25])
/* "grpc-accept-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26])
/* "grpc-accept-encoding": "deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
(&grpc_static_mdelem_table[27])
/* "grpc-accept-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28])
/* "grpc-accept-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
(&grpc_static_mdelem_table[29])
/* "grpc-accept-encoding": "identity,deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
(&grpc_static_mdelem_table[30])
/* "grpc-accept-encoding": "identity,deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(&grpc_static_mdelem_table[31])
/* "grpc-accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(&grpc_static_mdelem_table[32])
/* "grpc-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33])
/* "grpc-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34])
/* "grpc-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35])
/* "grpc-status": "0" */
#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36])
/* "grpc-status": "1" */
#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37])
/* "grpc-status": "2" */
#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38])
/* "host": "" */
#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39])
/* "if-match": "" */
#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40])
/* "if-modified-since": "" */
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41])
/* "if-none-match": "" */
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42])
/* "if-range": "" */
#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43])
/* "if-unmodified-since": "" */
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44])
/* "last-modified": "" */
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45])
/* "link": "" */
#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46])
/* "location": "" */
#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[47])
/* "max-forwards": "" */
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[48])
/* ":method": "GET" */
#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49])
/* ":method": "POST" */
#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50])
/* ":path": "/" */
#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51])
/* ":path": "/index.html" */
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52])
/* "proxy-authenticate": "" */
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53])
/* "proxy-authorization": "" */
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54])
/* "range": "" */
#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55])
/* "referer": "" */
#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56])
/* "refresh": "" */
#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57])
/* "retry-after": "" */
#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58])
/* ":scheme": "grpc" */
#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59])
/* ":scheme": "http" */
#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60])
/* ":scheme": "https" */
#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61])
/* "server": "" */
#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62])
/* "set-cookie": "" */
#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63])
/* ":status": "200" */
#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64])
/* ":status": "204" */
#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65])
/* ":status": "206" */
#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66])
/* ":status": "304" */
#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67])
/* ":status": "400" */
#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68])
/* ":status": "404" */
#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69])
/* ":status": "500" */
#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70])
/* "strict-transport-security": "" */
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
(&grpc_static_mdelem_table[71])
/* "te": "trailers" */
#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72])
/* "transfer-encoding": "" */
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73])
/* "user-agent": "" */
#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74])
/* "vary": "" */
#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75])
/* "via": "" */
#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76])
/* "www-authenticate": "" */
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77])
extern const gpr_uint8
grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT];
extern const gpr_uint8 grpc_static_accept_encoding_metadata[8];
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]])
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H */

@ -54,7 +54,9 @@ class InsecureChannelCredentialsImpl GRPC_FINAL : public ChannelCredentials {
grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr));
}
SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; }
SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE {
return nullptr;
}
};
} // namespace

@ -31,12 +31,13 @@
*
*/
#include <grpc/support/log.h>
#include <grpc++/channel.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/channel_arguments.h>
#include <grpc/support/log.h>
#include "src/cpp/client/create_channel_internal.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/cpp/common/secure_auth_context.h"
namespace grpc {
@ -160,7 +161,7 @@ void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
}
void MetadataCredentialsPluginWrapper::GetMetadata(
void* wrapper, const char* service_url,
void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data) {
GPR_ASSERT(wrapper);
MetadataCredentialsPluginWrapper* w =
@ -171,18 +172,25 @@ void MetadataCredentialsPluginWrapper::GetMetadata(
}
if (w->plugin_->IsBlocking()) {
w->thread_pool_->Add(
std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w,
service_url, cb, user_data));
std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w, context,
cb, user_data));
} else {
w->InvokePlugin(service_url, cb, user_data);
w->InvokePlugin(context, cb, user_data);
}
}
void MetadataCredentialsPluginWrapper::InvokePlugin(
const char* service_url, grpc_credentials_plugin_metadata_cb cb,
grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb,
void* user_data) {
std::multimap<grpc::string, grpc::string> metadata;
Status status = plugin_->GetMetadata(service_url, &metadata);
// const_cast is safe since the SecureAuthContext does not take owndership and
// the object is passed as a const ref to plugin_->GetMetadata.
SecureAuthContext cpp_channel_auth_context(
const_cast<grpc_auth_context*>(context.channel_auth_context), false);
Status status = plugin_->GetMetadata(context.service_url, context.method_name,
cpp_channel_auth_context, &metadata);
std::vector<grpc_metadata> md;
for (auto it = metadata.begin(); it != metadata.end(); ++it) {
grpc_metadata md_entry;
@ -204,11 +212,12 @@ MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin) {
GrpcLibrary init; // To call grpc_init().
const char* type = plugin->GetType();
MetadataCredentialsPluginWrapper* wrapper =
new MetadataCredentialsPluginWrapper(std::move(plugin));
grpc_metadata_credentials_plugin c_plugin = {
MetadataCredentialsPluginWrapper::GetMetadata,
MetadataCredentialsPluginWrapper::Destroy, wrapper};
MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
return WrapCallCredentials(
grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
}

@ -76,11 +76,10 @@ class SecureCallCredentials GRPC_FINAL : public CallCredentials {
grpc_call_credentials* const c_creds_;
};
class MetadataCredentialsPluginWrapper GRPC_FINAL {
public:
static void Destroy(void* wrapper);
static void GetMetadata(void* wrapper, const char* service_url,
static void GetMetadata(void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void* user_data);
@ -88,7 +87,7 @@ class MetadataCredentialsPluginWrapper GRPC_FINAL {
std::unique_ptr<MetadataCredentialsPlugin> plugin);
private:
void InvokePlugin(const char* service_url,
void InvokePlugin(grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data);
std::unique_ptr<ThreadPoolInterface> thread_pool_;
std::unique_ptr<MetadataCredentialsPlugin> plugin_;

@ -41,7 +41,9 @@ namespace Grpc.Core.Profiling
internal interface IProfiler
{
void Begin(string tag);
void End(string tag);
void Mark(string tag);
}
}

@ -40,7 +40,8 @@ namespace Grpc.Core.Profiling
{
internal struct ProfilerEntry
{
public enum Type {
public enum Type
{
BEGIN,
END,
MARK

@ -40,12 +40,12 @@ namespace Grpc.Core.Profiling
{
internal static class Profilers
{
static readonly NopProfiler defaultProfiler = new NopProfiler();
static readonly NopProfiler DefaultProfiler = new NopProfiler();
static readonly ThreadLocal<IProfiler> profilers = new ThreadLocal<IProfiler>();
public static IProfiler ForCurrentThread()
{
return profilers.Value ?? defaultProfiler;
return profilers.Value ?? DefaultProfiler;
}
public static void SetForCurrentThread(IProfiler profiler)
@ -89,15 +89,18 @@ namespace Grpc.Core.Profiling
this.entries = new ProfilerEntry[capacity];
}
public void Begin(string tag) {
public void Begin(string tag)
{
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag));
}
public void End(string tag) {
public void End(string tag)
{
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag));
}
public void Mark(string tag) {
public void Mark(string tag)
{
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag));
}

@ -41,6 +41,6 @@ namespace Grpc.Core
/// <summary>
/// Current version of gRPC C#
/// </summary>
public const string CurrentVersion = "0.7.1";
public const string CurrentVersion = "0.12.0";
}
}

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
<AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\ReleaseSigned</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
<Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
<Name>Grpc.IntegrationTesting</Name>
</ProjectReference>
</ItemGroup>
</Project>

@ -0,0 +1,46 @@
#region Copyright notice and license
// Copyright 2015, 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.
#endregion
using System;
using Grpc.IntegrationTesting;
namespace Grpc.IntegrationTesting
{
class Program
{
public static void Main(string[] args)
{
QpsWorker.Run(args);
}
}
}

@ -0,0 +1,11 @@
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("Grpc.IntegrationTesting.QpsWorker")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

@ -0,0 +1,76 @@
#region Copyright notice and license
// Copyright 2015, 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.
#endregion
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Utils;
namespace Grpc.Testing
{
/// <summary>
/// Implementation of BenchmarkService server
/// </summary>
public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService
{
private readonly int responseSize;
public BenchmarkServiceImpl(int responseSize)
{
this.responseSize = responseSize;
}
public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
return Task.FromResult(response);
}
public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context)
{
await requestStream.ForEachAsync(async request =>
{
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
await responseStream.WriteAsync(response);
});
}
private static Payload CreateZerosPayload(int size)
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
}
}

@ -0,0 +1,153 @@
#region Copyright notice and license
// Copyright 2015, 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.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
using Grpc.Testing;
namespace Grpc.IntegrationTesting
{
/// <summary>
/// Helper methods to start client runners for performance testing.
/// </summary>
public static class ClientRunners
{
/// <summary>
/// Creates a started client runner.
/// </summary>
public static IClientRunner CreateStarted(ClientConfig config)
{
string target = config.ServerTargets.Single();
Grpc.Core.Utils.Preconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop);
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
var channel = new Channel(target, credentials);
switch (config.RpcType)
{
case RpcType.UNARY:
return new SyncUnaryClientRunner(channel,
config.PayloadConfig.SimpleParams.ReqSize,
config.HistogramParams);
case RpcType.STREAMING:
default:
throw new ArgumentException("Unsupported RpcType.");
}
}
}
/// <summary>
/// Client that starts synchronous unary calls in a closed loop.
/// </summary>
public class SyncUnaryClientRunner : IClientRunner
{
const double SecondsToNanos = 1e9;
readonly Channel channel;
readonly int payloadSize;
readonly Histogram histogram;
readonly BenchmarkService.IBenchmarkServiceClient client;
readonly Task runnerTask;
readonly CancellationTokenSource stoppedCts;
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams)
{
this.channel = Grpc.Core.Utils.Preconditions.CheckNotNull(channel);
this.payloadSize = payloadSize;
this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible);
this.stoppedCts = new CancellationTokenSource();
this.client = BenchmarkService.NewClient(channel);
this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
}
public ClientStats GetStats(bool reset)
{
var histogramData = histogram.GetSnapshot(reset);
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
// TODO: populate user time and system time
return new ClientStats
{
Latencies = histogramData,
TimeElapsed = secondsElapsed,
TimeUser = 0,
TimeSystem = 0
};
}
public async Task StopAsync()
{
stoppedCts.Cancel();
await runnerTask;
await channel.ShutdownAsync();
}
private void Run()
{
var request = new SimpleRequest
{
Payload = CreateZerosPayload(payloadSize)
};
var stopwatch = new Stopwatch();
while (!stoppedCts.Token.IsCancellationRequested)
{
stopwatch.Restart();
client.UnaryCall(request);
stopwatch.Stop();
// spec requires data point in nanoseconds.
histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
}
}
private static Payload CreateZerosPayload(int size)
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
}
}

File diff suppressed because it is too large Load Diff

@ -38,55 +38,46 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="CommandLine">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="BouncyCastle.Crypto">
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Google.Apis.Auth.PlatformServices">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Google.Apis.Core">
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Google.Protobuf">
<HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@ -104,6 +95,22 @@
<Compile Include="TestGrpc.cs" />
<Compile Include="SslCredentialsTest.cs" />
<Compile Include="Test.cs" />
<Compile Include="IClientRunner.cs" />
<Compile Include="ClientRunners.cs" />
<Compile Include="IServerRunner.cs" />
<Compile Include="ServerRunners.cs" />
<Compile Include="RunnerClientServerTest.cs" />
<Compile Include="Control.cs" />
<Compile Include="Payloads.cs" />
<Compile Include="Services.cs" />
<Compile Include="ServicesGrpc.cs" />
<Compile Include="Stats.cs" />
<Compile Include="BenchmarkServiceImpl.cs" />
<Compile Include="Histogram.cs" />
<Compile Include="HistogramTest.cs" />
<Compile Include="WorkerServiceImpl.cs" />
<Compile Include="QpsWorker.cs" />
<Compile Include="WallClockStopwatch.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save