Merge branch 'decompression' into compression-interop

# Conflicts:
#	src/core/channel/compress_filter.c
#	src/core/surface/call.c
pull/2533/head
David Garcia Quintas 10 years ago
commit f8efe4dad2
  1. 6
      .gitignore
  2. 3
      .travis.yml
  3. 15
      BUILD
  4. 192
      Makefile
  5. 44
      build.json
  6. 57
      doc/connection-backoff.md
  7. 4
      gRPC.podspec
  8. 62
      include/grpc++/auth_context.h
  9. 4
      include/grpc++/client_context.h
  10. 141
      include/grpc++/impl/call.h
  11. 7
      include/grpc++/server_context.h
  12. 26
      include/grpc++/stream.h
  13. 3
      include/grpc/grpc.h
  14. 13
      include/grpc/grpc_security.h
  15. 2
      include/grpc/support/port_platform.h
  16. 22
      include/grpc/support/time.h
  17. 76
      src/compiler/objective_c_generator.cc
  18. 8
      src/core/channel/census_filter.c
  19. 24
      src/core/channel/compress_filter.c
  20. 4
      src/core/client_config/subchannel.c
  21. 1
      src/core/iomgr/iocp_windows.c
  22. 39
      src/core/iomgr/iomgr.c
  23. 3
      src/core/iomgr/pollset_multipoller_with_epoll.c
  24. 9
      src/core/iomgr/pollset_posix.c
  25. 6
      src/core/iomgr/pollset_windows.c
  26. 35
      src/core/iomgr/socket_windows.c
  27. 10
      src/core/iomgr/tcp_client_posix.c
  28. 3
      src/core/iomgr/tcp_client_windows.c
  29. 80
      src/core/iomgr/tcp_server_windows.c
  30. 24
      src/core/iomgr/tcp_windows.c
  31. 2
      src/core/profiling/timers_preciseclock.h
  32. 18
      src/core/security/client_auth_filter.c
  33. 123
      src/core/security/credentials.c
  34. 112
      src/core/security/credentials.h
  35. 89
      src/core/security/google_default_credentials.c
  36. 54
      src/core/security/json_token.c
  37. 15
      src/core/security/json_token.h
  38. 40
      src/core/security/jwt_verifier.c
  39. 14
      src/core/security/security_context.c
  40. 8
      src/core/security/security_context.h
  41. 4
      src/core/statistics/census_rpc_stats.c
  42. 16
      src/core/statistics/census_tracing.c
  43. 6
      src/core/statistics/window_stats.h
  44. 4
      src/core/support/cancellable.c
  45. 2
      src/core/support/log_linux.c
  46. 2
      src/core/support/log_posix.c
  47. 2
      src/core/support/log_win32.c
  48. 130
      src/core/support/stack_lockfree.c
  49. 50
      src/core/support/stack_lockfree.h
  50. 2
      src/core/support/sync_win32.c
  51. 44
      src/core/support/time_posix.c
  52. 35
      src/core/support/time_win32.c
  53. 61
      src/core/surface/call.c
  54. 1
      src/core/surface/channel.c
  55. 232
      src/core/surface/completion_queue.c
  56. 18
      src/core/surface/completion_queue.h
  57. 2
      src/core/surface/init.c
  58. 207
      src/core/surface/server.c
  59. 41
      src/core/surface/version.c
  60. 5
      src/core/transport/chttp2/parsing.c
  61. 3
      src/core/transport/chttp2/stream_encoder.c
  62. 8
      src/core/transport/chttp2_transport.c
  63. 20
      src/core/transport/metadata.c
  64. 8
      src/cpp/client/client_context.cc
  65. 42
      src/cpp/common/create_auth_context.h
  66. 45
      src/cpp/common/insecure_create_auth_context.cc
  67. 80
      src/cpp/common/secure_auth_context.cc
  68. 62
      src/cpp/common/secure_auth_context.h
  69. 50
      src/cpp/common/secure_create_auth_context.cc
  70. 99
      src/cpp/server/async_server_context.cc
  71. 4
      src/cpp/server/server.cc
  72. 13
      src/cpp/server/server_context.cc
  73. 4
      src/csharp/Grpc.Auth/Grpc.Auth.csproj
  74. 6
      src/csharp/Grpc.Auth/Grpc.Auth.nuspec
  75. 1
      src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
  76. 6
      src/csharp/Grpc.Core.Tests/ClientServerTest.cs
  77. 5
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  78. 17
      src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
  79. 12
      src/csharp/Grpc.Core.Tests/PInvokeTest.cs
  80. 1
      src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
  81. 3
      src/csharp/Grpc.Core.Tests/ServerTest.cs
  82. 16
      src/csharp/Grpc.Core/Calls.cs
  83. 30
      src/csharp/Grpc.Core/Channel.cs
  84. 9
      src/csharp/Grpc.Core/Grpc.Core.csproj
  85. 8
      src/csharp/Grpc.Core/Grpc.Core.nuspec
  86. 110
      src/csharp/Grpc.Core/GrpcEnvironment.cs
  87. 9
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  88. 9
      src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
  89. 30
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  90. 12
      src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
  91. 35
      src/csharp/Grpc.Core/Internal/DebugStats.cs
  92. 8
      src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
  93. 26
      src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
  94. 14
      src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
  95. 1
      src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
  96. 17
      src/csharp/Grpc.Core/Server.cs
  97. 6
      src/csharp/Grpc.Core/Version.cs
  98. 2
      src/csharp/Grpc.Core/packages.config
  99. 7
      src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
  100. 2
      src/csharp/Grpc.Examples.MathClient/MathClient.cs
  101. Some files were not shown because too many files have changed in this diff Show More

6
.gitignore vendored

@ -4,8 +4,8 @@ gens
libs
objs
# Python virtual environment (pre-3.4 only)
python2.7_virtual_environment
# Python virtual environments
python*_virtual_environment
# gcov coverage data
coverage
@ -31,3 +31,5 @@ coverage
# vim temp files
.*.swp
# Makefile's cache
cache.mk

@ -6,7 +6,8 @@ before_install:
- echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
- echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
- sudo apt-get update -qq
- sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv clang-3.5
- sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv python-dev python3-dev clang-3.5
- sudo pip install --upgrade virtualenv
- sudo pip install cpp-coveralls mako simplejson
- sudo apt-get install -qq mono-devel nunit
- wget www.nuget.org/NuGet.exe -O nuget.exe

15
BUILD

@ -47,6 +47,7 @@ cc_library(
"src/core/support/env.h",
"src/core/support/file.h",
"src/core/support/murmur_hash.h",
"src/core/support/stack_lockfree.h",
"src/core/support/string.h",
"src/core/support/string_win32.h",
"src/core/support/thd_internal.h",
@ -73,6 +74,7 @@ cc_library(
"src/core/support/murmur_hash.c",
"src/core/support/slice.c",
"src/core/support/slice_buffer.c",
"src/core/support/stack_lockfree.c",
"src/core/support/string.c",
"src/core/support/string_posix.c",
"src/core/support/string_win32.c",
@ -350,6 +352,7 @@ cc_library(
"src/core/surface/server_chttp2.c",
"src/core/surface/server_create.c",
"src/core/surface/surface_trace.c",
"src/core/surface/version.c",
"src/core/transport/chttp2/alpn.c",
"src/core/transport/chttp2/bin_encoder.c",
"src/core/transport/chttp2/frame_data.c",
@ -582,6 +585,7 @@ cc_library(
"src/core/surface/server_chttp2.c",
"src/core/surface/server_create.c",
"src/core/surface/surface_trace.c",
"src/core/surface/version.c",
"src/core/transport/chttp2/alpn.c",
"src/core/transport/chttp2/bin_encoder.c",
"src/core/transport/chttp2/frame_data.c",
@ -633,11 +637,15 @@ cc_library(
name = "grpc++",
srcs = [
"src/cpp/client/secure_credentials.h",
"src/cpp/common/secure_auth_context.h",
"src/cpp/server/secure_server_credentials.h",
"src/cpp/client/channel.h",
"src/cpp/common/create_auth_context.h",
"src/cpp/server/thread_pool.h",
"src/cpp/client/secure_channel_arguments.cc",
"src/cpp/client/secure_credentials.cc",
"src/cpp/common/secure_auth_context.cc",
"src/cpp/common/secure_create_auth_context.cc",
"src/cpp/server/secure_server_credentials.cc",
"src/cpp/client/channel.cc",
"src/cpp/client/channel_arguments.cc",
@ -667,6 +675,7 @@ cc_library(
hdrs = [
"include/grpc++/async_generic_service.h",
"include/grpc++/async_unary_call.h",
"include/grpc++/auth_context.h",
"include/grpc++/byte_buffer.h",
"include/grpc++/channel_arguments.h",
"include/grpc++/channel_interface.h",
@ -719,7 +728,9 @@ cc_library(
name = "grpc++_unsecure",
srcs = [
"src/cpp/client/channel.h",
"src/cpp/common/create_auth_context.h",
"src/cpp/server/thread_pool.h",
"src/cpp/common/insecure_create_auth_context.cc",
"src/cpp/client/channel.cc",
"src/cpp/client/channel_arguments.cc",
"src/cpp/client/client_context.cc",
@ -748,6 +759,7 @@ cc_library(
hdrs = [
"include/grpc++/async_generic_service.h",
"include/grpc++/async_unary_call.h",
"include/grpc++/auth_context.h",
"include/grpc++/byte_buffer.h",
"include/grpc++/channel_arguments.h",
"include/grpc++/channel_interface.h",
@ -877,6 +889,7 @@ objc_library(
"src/core/support/murmur_hash.c",
"src/core/support/slice.c",
"src/core/support/slice_buffer.c",
"src/core/support/stack_lockfree.c",
"src/core/support/string.c",
"src/core/support/string_posix.c",
"src/core/support/string_win32.c",
@ -924,6 +937,7 @@ objc_library(
"src/core/support/env.h",
"src/core/support/file.h",
"src/core/support/murmur_hash.h",
"src/core/support/stack_lockfree.h",
"src/core/support/string.h",
"src/core/support/string_win32.h",
"src/core/support/thd_internal.h",
@ -1046,6 +1060,7 @@ objc_library(
"src/core/surface/server_chttp2.c",
"src/core/surface/server_create.c",
"src/core/surface/surface_trace.c",
"src/core/surface/version.c",
"src/core/transport/chttp2/alpn.c",
"src/core/transport/chttp2/bin_encoder.c",
"src/core/transport/chttp2/frame_data.c",

File diff suppressed because one or more lines are too long

@ -30,6 +30,7 @@
"public_headers": [
"include/grpc++/async_generic_service.h",
"include/grpc++/async_unary_call.h",
"include/grpc++/auth_context.h",
"include/grpc++/byte_buffer.h",
"include/grpc++/channel_arguments.h",
"include/grpc++/channel_interface.h",
@ -68,6 +69,7 @@
],
"headers": [
"src/cpp/client/channel.h",
"src/cpp/common/create_auth_context.h",
"src/cpp/server/thread_pool.h"
],
"src": [
@ -287,6 +289,7 @@
"src/core/surface/server_chttp2.c",
"src/core/surface/server_create.c",
"src/core/surface/surface_trace.c",
"src/core/surface/version.c",
"src/core/transport/chttp2/alpn.c",
"src/core/transport/chttp2/bin_encoder.c",
"src/core/transport/chttp2/frame_data.c",
@ -375,6 +378,7 @@
"src/core/support/env.h",
"src/core/support/file.h",
"src/core/support/murmur_hash.h",
"src/core/support/stack_lockfree.h",
"src/core/support/string.h",
"src/core/support/string_win32.h",
"src/core/support/thd_internal.h"
@ -403,6 +407,7 @@
"src/core/support/murmur_hash.c",
"src/core/support/slice.c",
"src/core/support/slice_buffer.c",
"src/core/support/stack_lockfree.c",
"src/core/support/string.c",
"src/core/support/string_posix.c",
"src/core/support/string_win32.c",
@ -561,11 +566,14 @@
"language": "c++",
"headers": [
"src/cpp/client/secure_credentials.h",
"src/cpp/common/secure_auth_context.h",
"src/cpp/server/secure_server_credentials.h"
],
"src": [
"src/cpp/client/secure_channel_arguments.cc",
"src/cpp/client/secure_credentials.cc",
"src/cpp/common/secure_auth_context.cc",
"src/cpp/common/secure_create_auth_context.cc",
"src/cpp/server/secure_server_credentials.cc"
],
"deps": [
@ -618,6 +626,9 @@
"name": "grpc++_unsecure",
"build": "all",
"language": "c++",
"src": [
"src/cpp/common/insecure_create_auth_context.cc"
],
"deps": [
"gpr",
"grpc_unsecure"
@ -1162,6 +1173,18 @@
"gpr"
]
},
{
"name": "gpr_stack_lockfree_test",
"build": "test",
"language": "c",
"src": [
"test/core/support/stack_lockfree_test.c"
],
"deps": [
"gpr_test_util",
"gpr"
]
},
{
"name": "gpr_string_test",
"build": "test",
@ -2288,11 +2311,11 @@
]
},
{
"name": "qps_test",
"name": "qps_openloop_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/qps/qps_test.cc"
"test/cpp/qps/qps_openloop_test.cc"
],
"deps": [
"qps",
@ -2306,11 +2329,11 @@
]
},
{
"name": "qps_test_openloop",
"name": "qps_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/qps/qps_test_openloop.cc"
"test/cpp/qps/qps_test.cc"
],
"deps": [
"qps",
@ -2345,6 +2368,19 @@
"grpc++_test_config"
]
},
{
"name": "secure_auth_context_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/common/secure_auth_context_test.cc"
],
"deps": [
"grpc++",
"grpc",
"gpr"
]
},
{
"name": "server_crash_test",
"build": "test",

@ -8,58 +8,39 @@ requests) and instead do some form of exponential backoff.
We have several parameters:
1. INITIAL_BACKOFF (how long to wait after the first failure before retrying)
2. MULTIPLIER (factor with which to multiply backoff after a failed retry)
3. MAX_BACKOFF (Upper bound on backoff)
4. MIN_CONNECTION_TIMEOUT
3. MAX_BACKOFF (upper bound on backoff)
4. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to
complete)
## Proposed Backoff Algorithm
Exponentially back off the start time of connection attempts up to a limit of
MAX_BACKOFF.
MAX_BACKOFF, with jitter.
```
ConnectWithBackoff()
current_backoff = INITIAL_BACKOFF
current_deadline = now() + INITIAL_BACKOFF
while (TryConnect(Max(current_deadline, MIN_CONNECT_TIMEOUT))
while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))
!= SUCCESS)
SleepUntil(current_deadline)
current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
current_deadline = now() + current_backoff
```
## Historical Algorithm in Stubby
Exponentially increase up to a limit of MAX_BACKOFF the intervals between
connection attempts. This is what stubby 2 uses, and is equivalent if
TryConnect() fails instantly.
current_deadline = now() + current_backoff +
UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
```
LegacyConnectWithBackoff()
current_backoff = INITIAL_BACKOFF
while (TryConnect(MIN_CONNECT_TIMEOUT) != SUCCESS)
SleepFor(current_backoff)
current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
```
The grpc C implementation currently uses this approach with an initial backoff
of 1 second, multiplier of 2, and maximum backoff of 120 seconds. (This will
change)
Stubby, or at least rpc2, uses exactly this algorithm with an initial backoff
of 1 second, multiplier of 1.2, and a maximum backoff of 120 seconds.
With specific parameters of
MIN_CONNECT_TIMEOUT = 20 seconds
INITIAL_BACKOFF = 1 second
MULTIPLIER = 1.6
MAX_BACKOFF = 120 seconds
JITTER = 0.2
## Use Cases to Consider
Implementations with pressing concerns (such as minimizing the number of wakeups
on a mobile phone) may wish to use a different algorithm, and in particular
different jitter logic.
* Client tries to connect to a server which is down for multiple hours, eg for
maintenance
* Client tries to connect to a server which is overloaded
* User is bringing up both a client and a server at the same time
* In particular, we would like to avoid a large unnecessary delay if the
client connects to a server which is about to come up
* Client/server are misconfigured such that connection attempts always fail
* We want to make sure these don’t put too much load on the server by
default.
* Server is overloaded and wants to transiently make clients back off
* Application has out of band reason to believe a server is back
* We should consider an out of band mechanism for the client to hint that
we should short circuit the backoff.
Alternate implementations must ensure that connection backoffs started at the
same time disperse, and must not attempt connections substantially more often
than the above algorithm.

@ -64,6 +64,7 @@ Pod::Spec.new do |s|
ss.source_files = 'src/core/support/env.h',
'src/core/support/file.h',
'src/core/support/murmur_hash.h',
'src/core/support/stack_lockfree.h',
'src/core/support/grpc_string.h',
'src/core/support/string_win32.h',
'src/core/support/thd_internal.h',
@ -118,6 +119,7 @@ Pod::Spec.new do |s|
'src/core/support/murmur_hash.c',
'src/core/support/slice.c',
'src/core/support/slice_buffer.c',
'src/core/support/stack_lockfree.c',
'src/core/support/string.c',
'src/core/support/string_posix.c',
'src/core/support/string_win32.c',
@ -359,6 +361,7 @@ Pod::Spec.new do |s|
'src/core/surface/server_chttp2.c',
'src/core/surface/server_create.c',
'src/core/surface/surface_trace.c',
'src/core/surface/version.c',
'src/core/transport/chttp2/alpn.c',
'src/core/transport/chttp2/bin_encoder.c',
'src/core/transport/chttp2/frame_data.c',
@ -391,6 +394,7 @@ Pod::Spec.new do |s|
ss.private_header_files = 'src/core/support/env.h',
'src/core/support/file.h',
'src/core/support/murmur_hash.h',
'src/core/support/stack_lockfree.h',
'src/core/support/string.h',
'src/core/support/string_win32.h',
'src/core/support/thd_internal.h',

@ -0,0 +1,62 @@
/*
*
* 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 GRPCXX_AUTH_CONTEXT_H
#define GRPCXX_AUTH_CONTEXT_H
#include <vector>
#include <grpc++/config.h>
namespace grpc {
class AuthContext {
public:
typedef std::pair<grpc::string, grpc::string> Property;
virtual ~AuthContext() {}
// A peer identity, in general is one or more properties (in which case they
// have the same name).
virtual std::vector<grpc::string> GetPeerIdentity() const = 0;
virtual grpc::string GetPeerIdentityPropertyName() const = 0;
// Returns all the property values with the given name.
virtual std::vector<grpc::string> FindPropertyValues(
const grpc::string& name) const = 0;
};
} // namespace grpc
#endif // GRPCXX_AUTH_CONTEXT_H

@ -41,6 +41,7 @@
#include <grpc/compression.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpc++/auth_context.h>
#include <grpc++/config.h>
#include <grpc++/status.h>
#include <grpc++/time.h>
@ -119,6 +120,8 @@ class ClientContext {
}
void set_compression_algorithm(grpc_compression_algorithm algorithm);
std::shared_ptr<const AuthContext> auth_context() const;
// Get and set census context
void set_census_context(census_context* ccp) { census_context_ = ccp; }
census_context* get_census_context() const { return census_context_; }
@ -170,6 +173,7 @@ class ClientContext {
gpr_timespec deadline_;
grpc::string authority_;
std::shared_ptr<Credentials> creds_;
mutable std::shared_ptr<const AuthContext> auth_context_;
census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
std::multimap<grpc::string, grpc::string> recv_initial_metadata_;

@ -60,6 +60,93 @@ void FillMetadataMap(grpc_metadata_array* arr,
grpc_metadata* FillMetadataArray(
const std::multimap<grpc::string, grpc::string>& metadata);
/// Per-message write options.
class WriteOptions {
public:
WriteOptions() : flags_(0) {}
WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
/// Clear all flags.
inline void Clear() {
flags_ = 0;
}
/// Returns raw flags bitset.
inline gpr_uint32 flags() const {
return flags_;
}
/// Sets flag for the disabling of compression for the next message write.
///
/// \sa GRPC_WRITE_NO_COMPRESS
inline WriteOptions& set_no_compression() {
SetBit(GRPC_WRITE_NO_COMPRESS);
return *this;
}
/// Clears flag for the disabling of compression for the next message write.
///
/// \sa GRPC_WRITE_NO_COMPRESS
inline WriteOptions& clear_no_compression() {
ClearBit(GRPC_WRITE_NO_COMPRESS);
return *this;
}
/// Get value for the flag indicating whether compression for the next
/// message write is forcefully disabled.
///
/// \sa GRPC_WRITE_NO_COMPRESS
inline bool get_no_compression() const {
return GetBit(GRPC_WRITE_NO_COMPRESS);
}
/// Sets flag indicating that the write may be buffered and need not go out on
/// the wire immediately.
///
/// \sa GRPC_WRITE_BUFFER_HINT
inline WriteOptions& set_buffer_hint() {
SetBit(GRPC_WRITE_BUFFER_HINT);
return *this;
}
/// Clears flag indicating that the write may be buffered and need not go out
/// on the wire immediately.
///
/// \sa GRPC_WRITE_BUFFER_HINT
inline WriteOptions& clear_buffer_hint() {
ClearBit(GRPC_WRITE_BUFFER_HINT);
return *this;
}
/// Get value for the flag indicating that the write may be buffered and need
/// not go out on the wire immediately.
///
/// \sa GRPC_WRITE_BUFFER_HINT
inline bool get_buffer_hint() const {
return GetBit(GRPC_WRITE_BUFFER_HINT);
}
WriteOptions& operator=(const WriteOptions& rhs) {
flags_ = rhs.flags_;
return *this;
}
private:
void SetBit(const gpr_int32 mask) {
flags_ |= mask;
}
void ClearBit(const gpr_int32 mask) {
flags_ &= ~mask;
}
bool GetBit(const gpr_int32 mask) const {
return flags_ & mask;
}
gpr_uint32 flags_;
};
/// Default argument for CallOpSet. I is unused by the class, but can be
/// used for generating multiple names for the same thing.
template <int I>
@ -104,6 +191,12 @@ class CallOpSendMessage {
public:
CallOpSendMessage() : send_buf_(nullptr), own_buf_(false) {}
/// Send \a message using \a options for the write. The \a options are cleared
/// after use.
template <class M>
Status SendMessage(const M& message,
const WriteOptions& options) GRPC_MUST_USE_RESULT;
template <class M>
Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
@ -112,8 +205,10 @@ class CallOpSendMessage {
if (send_buf_ == nullptr) return;
grpc_op* op = &ops[(*nops)++];
op->op = GRPC_OP_SEND_MESSAGE;
op->flags = 0;
op->flags = write_options_.flags();
op->data.send_message = send_buf_;
// Flags are per-message: clear them after use.
write_options_.Clear();
}
void FinishOp(bool* status, int max_message_size) {
if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
@ -122,14 +217,22 @@ class CallOpSendMessage {
private:
grpc_byte_buffer* send_buf_;
WriteOptions write_options_;
bool own_buf_;
};
template <class M>
Status CallOpSendMessage::SendMessage(const M& message) {
Status CallOpSendMessage::SendMessage(const M& message,
const WriteOptions& options) {
write_options_ = options;
return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
}
template <class M>
Status CallOpSendMessage::SendMessage(const M& message) {
return SendMessage(message, WriteOptions());
}
template <class R>
class CallOpRecvMessage {
public:
@ -172,17 +275,34 @@ class CallOpRecvMessage {
grpc_byte_buffer* recv_buf_;
};
namespace CallOpGenericRecvMessageHelper {
class DeserializeFunc {
public:
virtual Status Deserialize(grpc_byte_buffer* buf, int max_message_size) = 0;
};
template <class R>
class DeserializeFuncType GRPC_FINAL : public DeserializeFunc {
public:
DeserializeFuncType(R* message) : message_(message) {}
Status Deserialize(grpc_byte_buffer* buf,
int max_message_size) GRPC_OVERRIDE {
return SerializationTraits<R>::Deserialize(buf, message_, max_message_size);
}
private:
R* message_; // Not a managed pointer because management is external to this
};
} // namespace CallOpGenericRecvMessageHelper
class CallOpGenericRecvMessage {
public:
CallOpGenericRecvMessage() : got_message(false) {}
template <class R>
void RecvMessage(R* message) {
deserialize_ = [message](grpc_byte_buffer* buf,
int max_message_size) -> Status {
return SerializationTraits<R>::Deserialize(buf, message,
max_message_size);
};
deserialize_.reset(
new CallOpGenericRecvMessageHelper::DeserializeFuncType<R>(message));
}
bool got_message;
@ -201,7 +321,7 @@ class CallOpGenericRecvMessage {
if (recv_buf_) {
if (*status) {
got_message = true;
*status = deserialize_(recv_buf_, max_message_size).ok();
*status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
} else {
got_message = false;
grpc_byte_buffer_destroy(recv_buf_);
@ -210,12 +330,11 @@ class CallOpGenericRecvMessage {
got_message = false;
*status = false;
}
deserialize_ = DeserializeFunc();
deserialize_.reset();
}
private:
typedef std::function<Status(grpc_byte_buffer*, int)> DeserializeFunc;
DeserializeFunc deserialize_;
std::unique_ptr<CallOpGenericRecvMessageHelper::DeserializeFunc> deserialize_;
grpc_byte_buffer* recv_buf_;
};

@ -35,9 +35,11 @@
#define GRPCXX_SERVER_CONTEXT_H
#include <map>
#include <memory>
#include <grpc/compression.h>
#include <grpc/support/time.h>
#include <grpc++/auth_context.h>
#include <grpc++/config.h>
#include <grpc++/time.h>
@ -112,6 +114,8 @@ class ServerContext {
}
void set_compression_algorithm(grpc_compression_algorithm algorithm);
std::shared_ptr<const AuthContext> auth_context() const;
private:
friend class ::grpc::testing::InteropContextInspector;
friend class ::grpc::Server;
@ -149,12 +153,15 @@ class ServerContext {
ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
size_t metadata_count);
void set_call(grpc_call* call);
CompletionOp* completion_op_;
gpr_timespec deadline_;
grpc_call* call_;
CompletionQueue* cq_;
bool sent_initial_metadata_;
mutable std::shared_ptr<const AuthContext> auth_context_;
std::multimap<grpc::string, grpc::string> client_metadata_;
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;

@ -79,7 +79,11 @@ class WriterInterface {
// Blocking write msg to the stream. Returns true on success.
// Returns false when the stream has been closed.
virtual bool Write(const W& msg) = 0;
virtual bool Write(const W& msg, const WriteOptions& options) = 0;
inline bool Write(const W& msg) {
return Write(msg, WriteOptions());
}
};
template <class R>
@ -168,9 +172,10 @@ class ClientWriter : public ClientWriterInterface<W> {
cq_.Pluck(&ops);
}
bool Write(const W& msg) GRPC_OVERRIDE {
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
CallOpSet<CallOpSendMessage> ops;
if (!ops.SendMessage(msg).ok()) {
if (!ops.SendMessage(msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
@ -246,9 +251,10 @@ class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> {
return cq_.Pluck(&ops) && ops.got_message;
}
bool Write(const W& msg) GRPC_OVERRIDE {
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
CallOpSet<CallOpSendMessage> ops;
if (!ops.SendMessage(msg).ok()) return false;
if (!ops.SendMessage(msg, options).ok()) return false;
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
@ -317,9 +323,10 @@ class ServerWriter GRPC_FINAL : public WriterInterface<W> {
call_->cq()->Pluck(&ops);
}
bool Write(const W& msg) GRPC_OVERRIDE {
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
if (!ops.SendMessage(msg).ok()) {
if (!ops.SendMessage(msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
@ -359,9 +366,10 @@ class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
return call_->cq()->Pluck(&ops) && ops.got_message;
}
bool Write(const W& msg) GRPC_OVERRIDE {
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
if (!ops.SendMessage(msg).ok()) {
if (!ops.SendMessage(msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {

@ -351,6 +351,9 @@ void grpc_init(void);
destroyed. */
void grpc_shutdown(void);
/** Return a string representing the current version of grpc */
const char *grpc_version_string(void);
/** Create a completion queue */
grpc_completion_queue *grpc_completion_queue_create(void);

@ -51,6 +51,11 @@ typedef struct grpc_credentials grpc_credentials;
The creator of the credentials object is responsible for its release. */
void grpc_credentials_release(grpc_credentials *creds);
/* Environment variable that points to the google default application
credentials json key or refresh token. Used in the
grpc_google_default_credentials_create function. */
#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
/* Creates default credentials to connect to a google gRPC service.
WARNING: Do NOT use this credentials to connect to a non-google service as
this could result in an oauth2 token leak. */
@ -248,8 +253,12 @@ const char *grpc_auth_context_peer_identity_property_name(
/* 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. */
const grpc_auth_context *grpc_call_auth_context(grpc_call *call);
/* 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);
#ifdef __cplusplus
}

@ -82,6 +82,7 @@
#define GPR_WIN32_ATOMIC 1
#define GPR_MSVC_TLS 1
#endif
#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(_WIN32) || defined(WIN32)
#define GPR_ARCH_32 1
#define GPR_WIN32 1
@ -94,6 +95,7 @@
#define GPR_WIN32_ATOMIC 1
#define GPR_MSVC_TLS 1
#endif
#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(ANDROID) || defined(__ANDROID__)
#define GPR_ANDROID 1
#define GPR_ARCH_32 1

@ -46,8 +46,8 @@ extern "C" {
#endif
typedef struct gpr_timespec {
time_t tv_sec;
int tv_nsec;
time_t tv_sec;
int tv_nsec;
} gpr_timespec;
/* Time constants. */
@ -62,8 +62,20 @@ extern const gpr_timespec gpr_inf_past; /* The far past. */
#define GPR_NS_PER_US 1000
#define GPR_US_PER_MS 1000
/* Return the current time measured from the system's default epoch. */
gpr_timespec gpr_now(void);
/* The clocks we support. */
typedef enum {
/* Monotonic clock. Epoch undefined. Always moves forwards. */
GPR_CLOCK_MONOTONIC = 0,
/* Realtime clock. May jump forwards or backwards. Settable by
the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */
GPR_CLOCK_REALTIME
} gpr_clock_type;
/* initialize time subsystem */
void gpr_time_init(void);
/* Return the current time measured from the given clocks epoch. */
gpr_timespec gpr_now(gpr_clock_type clock);
/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
respectively. */
@ -100,4 +112,4 @@ double gpr_timespec_to_micros(gpr_timespec t);
}
#endif
#endif /* GRPC_SUPPORT_TIME_H */
#endif /* GRPC_SUPPORT_TIME_H */

@ -57,13 +57,12 @@ void PrintProtoRpcDeclarationAsPragma(Printer *printer,
vars["server_stream"] = method->server_streaming() ? "stream " : "";
printer->Print(vars,
"#pragma mark $method_name$($client_stream$$request_type$)"
" returns ($server_stream$$response_type$)\n\n");
"#pragma mark $method_name$($client_stream$$request_type$)"
" returns ($server_stream$$response_type$)\n\n");
}
void PrintMethodSignature(Printer *printer,
const MethodDescriptor *method,
const map<string, string>& vars) {
void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
const map<string, string> &vars) {
// TODO(jcanizales): Print method comments.
printer->Print(vars, "- ($return_type$)$method_name$With");
@ -75,16 +74,17 @@ void PrintMethodSignature(Printer *printer,
// TODO(jcanizales): Put this on a new line and align colons.
if (method->server_streaming()) {
printer->Print(vars, " eventHandler:(void(^)(BOOL done, "
"$response_class$ *response, NSError *error))eventHandler");
printer->Print(vars,
" eventHandler:(void(^)(BOOL done, "
"$response_class$ *response, NSError *error))eventHandler");
} else {
printer->Print(vars, " handler:(void(^)($response_class$ *response, "
"NSError *error))handler");
printer->Print(vars,
" handler:(void(^)($response_class$ *response, "
"NSError *error))handler");
}
}
void PrintSimpleSignature(Printer *printer,
const MethodDescriptor *method,
void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
map<string, string> vars) {
vars["method_name"] =
grpc_generator::LowercaseFirstLetter(vars["method_name"]);
@ -92,8 +92,7 @@ void PrintSimpleSignature(Printer *printer,
PrintMethodSignature(printer, method, vars);
}
void PrintAdvancedSignature(Printer *printer,
const MethodDescriptor *method,
void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
map<string, string> vars) {
vars["method_name"] = "RPCTo" + vars["method_name"];
vars["return_type"] = "ProtoRPC *";
@ -101,15 +100,16 @@ void PrintAdvancedSignature(Printer *printer,
}
inline map<string, string> GetMethodVars(const MethodDescriptor *method) {
return {{ "method_name", method->name() },
{ "request_type", method->input_type()->name() },
{ "response_type", method->output_type()->name() },
{ "request_class", ClassName(method->input_type()) },
{ "response_class", ClassName(method->output_type()) }};
map<string, string> res;
res["method_name"] = method->name();
res["request_type"] = method->input_type()->name();
res["response_type"] = method->output_type()->name();
res["request_class"] = ClassName(method->input_type());
res["response_class"] = ClassName(method->output_type());
return res;
}
void PrintMethodDeclarations(Printer *printer,
const MethodDescriptor *method) {
void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
map<string, string> vars = GetMethodVars(method);
PrintProtoRpcDeclarationAsPragma(printer, method, vars);
@ -120,8 +120,7 @@ void PrintMethodDeclarations(Printer *printer,
printer->Print(";\n\n\n");
}
void PrintSimpleImplementation(Printer *printer,
const MethodDescriptor *method,
void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
map<string, string> vars) {
printer->Print("{\n");
printer->Print(vars, " [[self RPCTo$method_name$With");
@ -178,7 +177,7 @@ void PrintMethodImplementations(Printer *printer,
PrintAdvancedImplementation(printer, method, vars);
}
} // namespace
} // namespace
string GetHeader(const ServiceDescriptor *service) {
string output;
@ -186,7 +185,7 @@ string GetHeader(const ServiceDescriptor *service) {
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
printer.Print("@protocol GRXWriteable;\n");
printer.Print("@protocol GRXWriter;\n\n");
@ -199,12 +198,15 @@ string GetHeader(const ServiceDescriptor *service) {
}
printer.Print("@end\n\n");
printer.Print("// Basic service implementation, over gRPC, that only does"
printer.Print(
"// Basic service implementation, over gRPC, that only does"
" marshalling and parsing.\n");
printer.Print(vars, "@interface $service_class$ :"
" ProtoService<$service_class$>\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print(vars,
"@interface $service_class$ :"
" ProtoService<$service_class$>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("@end\n");
}
return output;
@ -222,18 +224,20 @@ string GetSource(const ServiceDescriptor *service) {
{"package", service->file()->package()}};
printer.Print(vars,
"static NSString *const kPackageName = @\"$package$\";\n");
printer.Print(vars,
"static NSString *const kServiceName = @\"$service_name$\";\n\n");
"static NSString *const kPackageName = @\"$package$\";\n");
printer.Print(
vars, "static NSString *const kServiceName = @\"$service_name$\";\n\n");
printer.Print(vars, "@implementation $service_class$\n\n");
printer.Print("// Designated initializer\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
printer.Print(" return (self = [super initWithHost:host"
printer.Print(
" return (self = [super initWithHost:host"
" packageName:kPackageName serviceName:kServiceName]);\n");
printer.Print("}\n\n");
printer.Print("// Override superclass initializer to disallow different"
printer.Print(
"// Override superclass initializer to disallow different"
" package and service names.\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
printer.Print(" packageName:(NSString *)packageName\n");
@ -250,4 +254,4 @@ string GetSource(const ServiceDescriptor *service) {
return output;
}
} // namespace grpc_objective_c_generator
} // namespace grpc_objective_c_generator

@ -151,7 +151,7 @@ static void client_init_call_elem(grpc_call_element* elem,
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
d->start_ts = gpr_now();
d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
d->op_id = census_tracing_start_op();
if (initial_op) client_mutate_op(elem, initial_op);
}
@ -169,7 +169,7 @@ static void server_init_call_elem(grpc_call_element* elem,
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
d->start_ts = gpr_now();
d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
d->op_id = census_tracing_start_op();
if (initial_op) server_mutate_op(elem, initial_op);
}
@ -177,8 +177,8 @@ static void server_init_call_elem(grpc_call_element* elem,
static void server_destroy_call_elem(grpc_call_element* elem) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
d->stats.elapsed_time_ms =
gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
d->stats.elapsed_time_ms = gpr_timespec_to_micros(
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), d->start_ts));
census_record_rpc_server_stats(d->op_id, &d->stats);
census_tracing_end_op(d->op_id);
}

@ -110,13 +110,17 @@ static int skip_compression(channel_data *channeld, call_data *calld) {
return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE;
}
/** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying
* the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length,
* flags indicating compression is in effect) and replaces \a send_ops with it.
* */
static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops,
grpc_call_element *elem) {
size_t i;
grpc_stream_op_buffer new_send_ops;
call_data *calld = elem->call_data;
int new_slices_added = 0; /* GPR_FALSE */
grpc_metadata_batch metadata;
grpc_stream_op_buffer new_send_ops;
grpc_sopb_init(&new_send_ops);
for (i = 0; i < send_ops->nops; i++) {
@ -128,6 +132,9 @@ static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops,
sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS);
break;
case GRPC_OP_SLICE:
/* Once we reach the slices section of the original buffer, simply add
* all the new (compressed) slices. We obviously want to do this only
* once, hence the "new_slices_added" guard. */
if (!new_slices_added) {
size_t j;
for (j = 0; j < calld->slices.count; ++j) {
@ -138,8 +145,9 @@ static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops,
}
break;
case GRPC_OP_METADATA:
grpc_sopb_add_metadata(&new_send_ops, sop->data.metadata);
memset(&(sop->data.metadata), 0, sizeof(grpc_metadata_batch));
/* move the metadata to the new buffer. */
grpc_metadata_batch_move(&metadata, &sop->data.metadata);
grpc_sopb_add_metadata(&new_send_ops, metadata);
break;
case GRPC_NO_OP:
break;
@ -156,12 +164,12 @@ static void process_send_ops(grpc_call_element *elem,
size_t i;
int did_compress = 0;
/* buffer up slices until we've processed all the expected ones (as given by
* GRPC_OP_BEGIN_MESSAGE) */
for (i = 0; i < send_ops->nops; ++i) {
grpc_stream_op *sop = &send_ops->ops[i];
switch (sop->type) {
case GRPC_OP_BEGIN_MESSAGE:
/* buffer up slices until we've processed all the expected ones (as
* given by GRPC_OP_BEGIN_MESSAGE) */
calld->remaining_slice_bytes = sop->data.begin_message.length;
if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) {
calld->has_compression_algorithm = 1; /* GPR_TRUE */
@ -192,12 +200,10 @@ static void process_send_ops(grpc_call_element *elem,
case GRPC_OP_SLICE:
if (skip_compression(channeld, calld)) continue;
GPR_ASSERT(calld->remaining_slice_bytes > 0);
/* We need to copy the input because gpr_slice_buffer_add takes
* ownership. However, we don't own sop->data.slice, the caller does. */
/* Increase input ref count, gpr_slice_buffer_add takes ownership. */
gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice));
calld->remaining_slice_bytes -= GPR_SLICE_LENGTH(sop->data.slice);
if (calld->remaining_slice_bytes == 0) {
/* compress */
did_compress =
compress_send_sb(calld->compression_algorithm, &calld->slices);
}

@ -300,7 +300,7 @@ static void continue_connect(grpc_subchannel *c) {
}
static void start_connect(grpc_subchannel *c) {
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
c->next_attempt = now;
c->backoff_delta = gpr_time_from_seconds(1);
@ -585,7 +585,7 @@ static void subchannel_connected(void *arg, int iomgr_success) {
c->have_alarm = 1;
c->next_attempt = gpr_time_add(c->next_attempt, c->backoff_delta);
c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta);
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now());
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now(GPR_CLOCK_REALTIME));
gpr_mu_unlock(&c->mu);
}
}

@ -127,7 +127,6 @@ static void iocp_loop(void *p) {
grpc_maybe_call_delayed_callbacks(NULL, 1);
do_iocp_work();
}
gpr_log(GPR_DEBUG, "iocp_loop is done");
gpr_event_set(&g_iocp_done, (void *)1);
}

@ -59,7 +59,7 @@ static void background_callback_executor(void *ignored) {
while (!g_shutdown) {
gpr_timespec deadline = gpr_inf_future;
gpr_timespec short_deadline =
gpr_time_add(gpr_now(), gpr_time_from_millis(100));
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100));
if (g_cbs_head) {
grpc_iomgr_closure *closure = g_cbs_head;
g_cbs_head = closure->next;
@ -67,7 +67,8 @@ static void background_callback_executor(void *ignored) {
gpr_mu_unlock(&g_mu);
closure->cb(closure->cb_arg, closure->success);
gpr_mu_lock(&g_mu);
} else if (grpc_alarm_check(&g_mu, gpr_now(), &deadline)) {
} else if (grpc_alarm_check(&g_mu, gpr_now(GPR_CLOCK_REALTIME),
&deadline)) {
} else {
gpr_mu_unlock(&g_mu);
gpr_sleep_until(gpr_time_min(short_deadline, deadline));
@ -89,7 +90,7 @@ void grpc_iomgr_init(void) {
gpr_thd_id id;
gpr_mu_init(&g_mu);
gpr_cv_init(&g_rcv);
grpc_alarm_list_init(gpr_now());
grpc_alarm_list_init(gpr_now(GPR_CLOCK_REALTIME));
g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = "root";
grpc_iomgr_platform_init();
@ -110,21 +111,27 @@ void grpc_iomgr_shutdown(void) {
grpc_iomgr_object *obj;
grpc_iomgr_closure *closure;
gpr_timespec shutdown_deadline =
gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10));
gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
gpr_mu_lock(&g_mu);
g_shutdown = 1;
while (g_cbs_head != NULL || g_root_object.next != &g_root_object) {
if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
gpr_log(GPR_DEBUG,
"Waiting for %d iomgr objects to be destroyed and executing "
"final callbacks",
count_objects());
} else if (g_cbs_head != NULL) {
gpr_log(GPR_DEBUG, "Executing final iomgr callbacks");
} else {
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
count_objects());
if (gpr_time_cmp(
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time),
gpr_time_from_seconds(1)) >= 0) {
if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
gpr_log(GPR_DEBUG,
"Waiting for %d iomgr objects to be destroyed and executing "
"final callbacks",
count_objects());
} else if (g_cbs_head != NULL) {
gpr_log(GPR_DEBUG, "Executing final iomgr callbacks");
} else {
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
count_objects());
}
last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
}
if (g_cbs_head) {
do {
@ -145,9 +152,9 @@ void grpc_iomgr_shutdown(void) {
if (g_root_object.next != &g_root_object) {
int timeout = 0;
gpr_timespec short_deadline =
gpr_time_add(gpr_now(), gpr_time_from_millis(100));
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100));
while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
timeout = 1;
break;
}

@ -105,10 +105,11 @@ static void multipoll_with_epoll_pollset_maybe_work(
* here.
*/
timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
pollset->counter += 1;
gpr_mu_unlock(&pollset->mu);
timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
do {
ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms);
if (ep_rv < 0) {

@ -122,7 +122,7 @@ static void finish_shutdown(grpc_pollset *pollset) {
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
/* pollset->mu already held */
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
if (gpr_time_cmp(now, deadline) > 0) {
return 0;
}
@ -187,15 +187,16 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
gpr_mu_destroy(&pollset->mu);
}
int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now) {
int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
gpr_timespec now) {
gpr_timespec timeout;
static const int max_spin_polling_us = 10;
if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
return -1;
}
if (gpr_time_cmp(
deadline,
gpr_time_add(now, gpr_time_from_micros(max_spin_polling_us))) <= 0) {
deadline,
gpr_time_add(now, gpr_time_from_micros(max_spin_polling_us))) <= 0) {
return 0;
}
timeout = gpr_time_sub(deadline, now);

@ -70,7 +70,7 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
gpr_timespec now;
now = gpr_now();
now = gpr_now(GPR_CLOCK_REALTIME);
if (gpr_time_cmp(now, deadline) > 0) {
return 0 /* GPR_FALSE */;
}
@ -86,8 +86,6 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
return 1 /* GPR_TRUE */;
}
void grpc_pollset_kick(grpc_pollset *p) {
gpr_cv_signal(&p->cv);
}
void grpc_pollset_kick(grpc_pollset *p) { gpr_cv_signal(&p->cv); }
#endif /* GPR_WINSOCK_SOCKET */

@ -37,6 +37,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/iomgr/iocp_windows.h"
#include "src/core/iomgr/iomgr_internal.h"
@ -45,11 +46,14 @@
#include "src/core/iomgr/socket_windows.h"
grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) {
char *final_name;
grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket));
memset(r, 0, sizeof(grpc_winsocket));
r->socket = socket;
gpr_mu_init(&r->state_mu);
grpc_iomgr_register_object(&r->iomgr_object, name);
gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
grpc_iomgr_register_object(&r->iomgr_object, final_name);
gpr_free(final_name);
grpc_iocp_add_socket(r);
return r;
}
@ -58,22 +62,27 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) {
operations to abort them. We need to do that this way because of the
various callsites of that function, which happens to be in various
mutex hold states, and that'd be unsafe to call them directly. */
int grpc_winsocket_shutdown(grpc_winsocket *socket) {
int grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
int callbacks_set = 0;
gpr_mu_lock(&socket->state_mu);
if (socket->read_info.cb) {
SOCKET socket;
gpr_mu_lock(&winsocket->state_mu);
socket = winsocket->socket;
if (winsocket->read_info.cb) {
callbacks_set++;
grpc_iomgr_closure_init(&socket->shutdown_closure, socket->read_info.cb,
socket->read_info.opaque);
grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
grpc_iomgr_closure_init(&winsocket->shutdown_closure,
winsocket->read_info.cb,
winsocket->read_info.opaque);
grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
}
if (socket->write_info.cb) {
if (winsocket->write_info.cb) {
callbacks_set++;
grpc_iomgr_closure_init(&socket->shutdown_closure, socket->write_info.cb,
socket->write_info.opaque);
grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
grpc_iomgr_closure_init(&winsocket->shutdown_closure,
winsocket->write_info.cb,
winsocket->write_info.opaque);
grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
}
gpr_mu_unlock(&socket->state_mu);
gpr_mu_unlock(&winsocket->state_mu);
closesocket(socket);
return callbacks_set;
}
@ -84,14 +93,12 @@ int grpc_winsocket_shutdown(grpc_winsocket *socket) {
an "idle" socket which is neither trying to read or write, we'd start leaking
both memory and sockets. */
void grpc_winsocket_orphan(grpc_winsocket *winsocket) {
SOCKET socket = winsocket->socket;
grpc_iomgr_unregister_object(&winsocket->iomgr_object);
if (winsocket->read_info.outstanding || winsocket->write_info.outstanding) {
grpc_iocp_socket_orphan(winsocket);
} else {
grpc_winsocket_destroy(winsocket);
}
closesocket(socket);
}
void grpc_winsocket_destroy(grpc_winsocket *winsocket) {

@ -114,6 +114,7 @@ static void on_writable(void *acp, int success) {
void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
void *cb_arg = ac->cb_arg;
gpr_mu_lock(&ac->mu);
if (success) {
do {
so_error_size = sizeof(so_error);
@ -139,6 +140,7 @@ static void on_writable(void *acp, int success) {
opened too many network connections. The "easy" fix:
don't do that! */
gpr_log(GPR_ERROR, "kernel out of buffers");
gpr_mu_unlock(&ac->mu);
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
return;
} else {
@ -165,10 +167,11 @@ static void on_writable(void *acp, int success) {
abort();
finish:
gpr_mu_lock(&ac->mu);
if (!ep) {
if (ep == NULL) {
grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
} else {
ac->fd = NULL;
}
done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
@ -250,7 +253,8 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
ac->write_closure.cb_arg = ac;
gpr_mu_lock(&ac->mu);
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
gpr_now(GPR_CLOCK_REALTIME));
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
gpr_mu_unlock(&ac->mu);

@ -215,7 +215,8 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
ac->refs = 2;
ac->aborted = 0;
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
gpr_now(GPR_CLOCK_REALTIME));
socket->write_info.outstanding = 1;
grpc_socket_notify_on_write(socket, on_connect, ac);
return;

@ -108,9 +108,10 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s,
size_t i;
gpr_mu_lock(&s->mu);
/* First, shutdown all fd's. This will queue abortion calls for all
of the pending accepts. */
of the pending accepts due to the normal operation mechanism. */
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
sp->shutting_down = 1;
grpc_winsocket_shutdown(sp->socket);
}
/* This happens asynchronously. Wait while that happens. */
@ -242,63 +243,52 @@ static void on_accept(void *arg, int from_iocp) {
SOCKET sock = sp->new_socket;
grpc_winsocket_callback_info *info = &sp->socket->read_info;
grpc_endpoint *ep = NULL;
/* The shutdown sequence is done in two parts. This is the second
part here, acknowledging the IOCP notification, and doing nothing
else, especially not queuing a new accept. */
if (sp->shutting_down) {
GPR_ASSERT(from_iocp);
sp->shutting_down = 0;
sp->socket->read_info.outstanding = 0;
gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) {
gpr_cv_broadcast(&sp->server->cv);
}
gpr_mu_unlock(&sp->server->mu);
return;
}
if (from_iocp) {
/* The IOCP notified us of a completed operation. Let's grab the results,
and act accordingly. */
DWORD transfered_bytes = 0;
DWORD flags;
BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
&transfered_bytes, FALSE, &flags);
if (!wsa_success) {
DWORD transfered_bytes;
DWORD flags;
BOOL wsa_success;
/* The general mechanism for shutting down is to queue abortion calls. While
this is necessary in the read/write case, it's useless for the accept
case. Let's do nothing. */
if (!from_iocp) return;
/* The IOCP notified us of a completed operation. Let's grab the results,
and act accordingly. */
transfered_bytes = 0;
wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
&transfered_bytes, FALSE, &flags);
if (!wsa_success) {
if (sp->shutting_down) {
/* During the shutdown case, we ARE expecting an error. So that's swell,
and we can wake up the shutdown thread. */
sp->shutting_down = 0;
sp->socket->read_info.outstanding = 0;
gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) {
gpr_cv_broadcast(&sp->server->cv);
}
gpr_mu_unlock(&sp->server->mu);
return;
} else {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
gpr_free(utf8_message);
closesocket(sock);
} else {
/* TODO(ctiller): add sockaddr address to label */
ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
}
} else {
/* If we're not notified from the IOCP, it means we are asked to shutdown.
This will initiate that shutdown. Calling closesocket will trigger an
IOCP notification, that will call this function a second time, from
the IOCP thread. Of course, this only works if the socket was, in fact,
listening. If that's not the case, we'd wait indefinitely. That's a bit
of a degenerate case, but it can happen if you create a server, but
don't start it. So let's support that by recursing once. */
sp->shutting_down = 1;
sp->new_socket = INVALID_SOCKET;
if (sock != INVALID_SOCKET) {
closesocket(sock);
} else {
on_accept(sp, 1);
if (!sp->shutting_down) {
/* TODO(ctiller): add sockaddr address to label */
ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
}
return;
}
/* The only time we should call our callback, is where we successfully
managed to accept a connection, and created an endpoint. */
if (ep) sp->server->cb(sp->server->cb_arg, ep);
/* As we were notified from the IOCP of one and exactly one accept,
the former socked we created has now either been destroy or assigned
to the new connection. We need to create a new one for the next
connection. */
the former socked we created has now either been destroy or assigned
to the new connection. We need to create a new one for the next
connection. */
start_accept(sp);
}

@ -148,9 +148,11 @@ static void on_read(void *tcpp, int from_iocp) {
GPR_ASSERT(tcp->socket->read_info.outstanding);
if (socket->read_info.wsa_error != 0) {
char *utf8_message = gpr_format_message(info->wsa_error);
gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
gpr_free(utf8_message);
if (socket->read_info.wsa_error != WSAECONNRESET) {
char *utf8_message = gpr_format_message(info->wsa_error);
gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
gpr_free(utf8_message);
}
status = GRPC_ENDPOINT_CB_ERROR;
} else {
if (info->bytes_transfered != 0) {
@ -259,9 +261,11 @@ static void on_write(void *tcpp, int from_iocp) {
GPR_ASSERT(tcp->socket->write_info.outstanding);
if (info->wsa_error != 0) {
char *utf8_message = gpr_format_message(info->wsa_error);
gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
gpr_free(utf8_message);
if (info->wsa_error != WSAECONNRESET) {
char *utf8_message = gpr_format_message(info->wsa_error);
gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
gpr_free(utf8_message);
}
status = GRPC_ENDPOINT_CB_ERROR;
} else {
GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
@ -325,9 +329,11 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
ret = GRPC_ENDPOINT_WRITE_DONE;
GPR_ASSERT(bytes_sent == tcp->write_slices.length);
} else {
char *utf8_message = gpr_format_message(info->wsa_error);
gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
gpr_free(utf8_message);
if (socket->read_info.wsa_error != WSAECONNRESET) {
char *utf8_message = gpr_format_message(info->wsa_error);
gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
gpr_free(utf8_message);
}
}
if (allocated) gpr_free(allocated);
gpr_slice_buffer_reset_and_unref(&tcp->write_slices);

@ -82,7 +82,7 @@ struct grpc_precise_clock {
gpr_timespec clock;
};
static void grpc_precise_clock_now(grpc_precise_clock* clk) {
clk->clock = gpr_now();
clk->clock = gpr_now(GPR_CLOCK_REALTIME);
}
#define GRPC_PRECISE_CLOCK_FORMAT "%ld.%09d"
#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \

@ -61,6 +61,7 @@ typedef struct {
grpc_transport_stream_op op;
size_t op_md_idx;
int sent_initial_metadata;
gpr_uint8 security_context_set;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
} call_data;
@ -199,8 +200,22 @@ static void auth_start_transport_op(grpc_call_element *elem,
channel_data *chand = elem->channel_data;
grpc_linked_mdelem *l;
size_t i;
grpc_client_security_context* sec_ctx = NULL;
/* TODO(jboeuf): write the call auth context. */
if (calld->security_context_set == 0) {
calld->security_context_set = 1;
GPR_ASSERT(op->context);
if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
op->context[GRPC_CONTEXT_SECURITY].value =
grpc_client_security_context_create();
op->context[GRPC_CONTEXT_SECURITY].destroy =
grpc_client_security_context_destroy;
}
sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
sec_ctx->auth_context = GRPC_AUTH_CONTEXT_REF(
chand->security_connector->base.auth_context, "client_auth_filter");
}
if (op->bind_pollset) {
calld->pollset = op->bind_pollset;
@ -263,6 +278,7 @@ static void init_call_elem(grpc_call_element *elem,
calld->method = NULL;
calld->pollset = NULL;
calld->sent_initial_metadata = 0;
calld->security_context_set = 0;
GPR_ASSERT(!initial_op || !initial_op->send_ops);
}

@ -41,7 +41,6 @@
#include "src/core/json/json.h"
#include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/security/json_token.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
@ -52,12 +51,12 @@
/* -- Common. -- */
typedef struct {
struct grpc_credentials_metadata_request {
grpc_credentials *creds;
grpc_credentials_metadata_cb cb;
grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
void *user_data;
} grpc_credentials_metadata_request;
};
static grpc_credentials_metadata_request *
grpc_credentials_metadata_request_create(grpc_credentials *creds,
@ -152,16 +151,6 @@ grpc_security_status grpc_server_credentials_create_security_connector(
/* -- Ssl credentials. -- */
typedef struct {
grpc_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
static void ssl_destroy(grpc_credentials *creds) {
grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
@ -326,22 +315,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create(
/* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
/* Have a simple cache for now with just 1 entry. We could have a map based on
the service_url for a more sophisticated one. */
gpr_mu cache_mu;
struct {
grpc_credentials_md_store *jwt_md;
char *service_url;
gpr_timespec jwt_expiration;
} cached;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
static void jwt_reset_cache(grpc_jwt_credentials *c) {
if (c->cached.jwt_md != NULL) {
grpc_credentials_md_store_unref(c->cached.jwt_md);
@ -384,7 +357,8 @@ static void jwt_get_request_metadata(grpc_credentials *creds,
if (c->cached.service_url != NULL &&
strcmp(c->cached.service_url, service_url) == 0 &&
c->cached.jwt_md != NULL &&
(gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()),
(gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
gpr_now(GPR_CLOCK_REALTIME)),
refresh_threshold) > 0)) {
jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
}
@ -401,7 +375,8 @@ static void jwt_get_request_metadata(grpc_credentials *creds,
char *md_value;
gpr_asprintf(&md_value, "Bearer %s", jwt);
gpr_free(jwt);
c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime);
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.jwt_md = grpc_credentials_md_store_create(1);
grpc_credentials_md_store_add_cstrings(
@ -424,10 +399,9 @@ static grpc_credentials_vtable jwt_vtable = {
jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
jwt_get_request_metadata, NULL};
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) {
grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime) {
grpc_jwt_credentials *c;
grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
if (!grpc_auth_json_key_is_valid(&key)) {
gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
return NULL;
@ -444,25 +418,13 @@ grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
return &c->base;
}
/* -- Oauth2TokenFetcher credentials -- */
/* This object is a base for credentials that need to acquire an oauth2 token
from an http service. */
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb,
gpr_timespec deadline);
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) {
return grpc_jwt_credentials_create_from_auth_json_key(
grpc_auth_json_key_create_from_string(json_key), token_lifetime);
}
typedef struct {
grpc_credentials base;
gpr_mu mu;
grpc_credentials_md_store *access_token_md;
gpr_timespec token_expiration;
grpc_httpcli_context httpcli_context;
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
/* -- Oauth2TokenFetcher credentials -- */
static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
grpc_oauth2_token_fetcher_credentials *c =
@ -585,7 +547,8 @@ static void on_oauth2_token_fetcher_http_response(
status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
response, &c->access_token_md, &token_lifetime);
if (status == GRPC_CREDENTIALS_OK) {
c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
c->token_expiration =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime);
r->cb(r->user_data, c->access_token_md->entries,
c->access_token_md->num_entries, status);
} else {
@ -607,8 +570,9 @@ static void oauth2_token_fetcher_get_request_metadata(
{
gpr_mu_lock(&c->mu);
if (c->access_token_md != NULL &&
(gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
refresh_threshold) > 0)) {
(gpr_time_cmp(
gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)),
refresh_threshold) > 0)) {
cached_access_token_md =
grpc_credentials_md_store_ref(c->access_token_md);
}
@ -622,7 +586,7 @@ static void oauth2_token_fetcher_get_request_metadata(
c->fetch_func(
grpc_credentials_metadata_request_create(creds, cb, user_data),
&c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
gpr_time_add(gpr_now(), refresh_threshold));
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
}
}
@ -669,13 +633,6 @@ grpc_credentials *grpc_compute_engine_credentials_create(void) {
/* -- ServiceAccount credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_json_key key;
char *scope;
gpr_timespec token_lifetime;
} grpc_service_account_credentials;
static void service_account_destroy(grpc_credentials *creds) {
grpc_service_account_credentials *c =
(grpc_service_account_credentials *)creds;
@ -746,11 +703,6 @@ grpc_credentials *grpc_service_account_credentials_create(
/* -- RefreshToken credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
} grpc_refresh_token_credentials;
static void refresh_token_destroy(grpc_credentials *creds) {
grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
grpc_auth_refresh_token_destruct(&c->refresh_token);
@ -786,12 +738,9 @@ static void refresh_token_fetch_oauth2(
gpr_free(body);
}
grpc_credentials *grpc_refresh_token_credentials_create(
const char *json_refresh_token) {
grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token refresh_token) {
grpc_refresh_token_credentials *c;
grpc_auth_refresh_token refresh_token =
grpc_auth_refresh_token_create_from_string(json_refresh_token);
if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
return NULL;
@ -804,13 +753,13 @@ grpc_credentials *grpc_refresh_token_credentials_create(
return &c->base.base;
}
/* -- Fake Oauth2 credentials. -- */
grpc_credentials *grpc_refresh_token_credentials_create(
const char *json_refresh_token) {
return grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token_create_from_string(json_refresh_token));
}
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
int is_async;
} grpc_fake_oauth2_credentials;
/* -- Fake Oauth2 credentials. -- */
static void fake_oauth2_destroy(grpc_credentials *creds) {
grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
@ -877,11 +826,6 @@ grpc_credentials *grpc_fake_oauth2_credentials_create(
/* -- Oauth2 Access Token credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
} grpc_access_token_credentials;
static void access_token_destroy(grpc_credentials *creds) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
grpc_credentials_md_store_unref(c->access_token_md);
@ -996,12 +940,6 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
/* -- Composite credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials;
typedef struct {
grpc_composite_credentials *composite_creds;
size_t creds_index;
@ -1232,11 +1170,6 @@ grpc_credentials *grpc_credentials_contains_type(
/* -- IAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
} grpc_iam_credentials;
static void iam_destroy(grpc_credentials *creds) {
grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
grpc_credentials_md_store_unref(c->iam_md);

@ -39,6 +39,8 @@
#include <grpc/grpc_security.h>
#include <grpc/support/sync.h>
#include "src/core/httpcli/httpcli.h"
#include "src/core/security/json_token.h"
#include "src/core/security/security_connector.h"
struct grpc_httpcli_response;
@ -178,11 +180,22 @@ grpc_credentials_status
grpc_oauth2_token_fetcher_credentials_parse_server_response(
const struct grpc_httpcli_response *response,
grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
void grpc_flush_cached_google_default_credentials(void);
/* Simulates an oauth2 token fetch with the specified value for testing. */
grpc_credentials *grpc_fake_oauth2_credentials_create(
const char *token_md_value, int is_async);
/* Private constructor for jwt credentials from an already parsed json key.
Takes ownership of the key. */
grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime);
/* Private constructor for refresh token credentials from an already parsed
refresh token. Takes ownership of the refresh token. */
grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token token);
/* --- grpc_server_credentials. --- */
typedef struct {
@ -199,4 +212,103 @@ struct grpc_server_credentials {
grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc);
/* -- Ssl credentials. -- */
typedef struct {
grpc_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
/* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
/* Have a simple cache for now with just 1 entry. We could have a map based on
the service_url for a more sophisticated one. */
gpr_mu cache_mu;
struct {
grpc_credentials_md_store *jwt_md;
char *service_url;
gpr_timespec jwt_expiration;
} cached;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
/* -- Oauth2TokenFetcher credentials --
This object is a base for credentials that need to acquire an oauth2 token
from an http service. */
typedef struct grpc_credentials_metadata_request
grpc_credentials_metadata_request;
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb,
gpr_timespec deadline);
typedef struct {
grpc_credentials base;
gpr_mu mu;
grpc_credentials_md_store *access_token_md;
gpr_timespec token_expiration;
grpc_httpcli_context httpcli_context;
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
/* -- ServiceAccount credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_json_key key;
char *scope;
gpr_timespec token_lifetime;
} grpc_service_account_credentials;
/* -- RefreshToken credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
} grpc_refresh_token_credentials;
/* -- Oauth2 Access Token credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
} grpc_access_token_credentials;
/* -- Fake Oauth2 credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
int is_async;
} grpc_fake_oauth2_credentials;
/* -- IAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
} grpc_iam_credentials;
/* -- Composite credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials;
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */

@ -46,7 +46,6 @@
/* -- Constants. -- */
#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
/* -- Default credentials. -- */
@ -104,9 +103,10 @@ static int is_stack_running_on_compute_engine(void) {
grpc_httpcli_context_init(&context);
grpc_httpcli_get(&context, &detector.pollset, &request,
gpr_time_add(gpr_now(), max_detection_delay),
on_compute_engine_detection_http_response, &detector);
grpc_httpcli_get(
&context, &detector.pollset, &request,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
on_compute_engine_detection_http_response, &detector);
/* Block until we get the response. This is not ideal but this should only be
called once for the lifetime of the process by the default credentials. */
@ -123,36 +123,40 @@ static int is_stack_running_on_compute_engine(void) {
}
/* Takes ownership of creds_path if not NULL. */
static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
static grpc_credentials *create_default_creds_from_path(char *creds_path) {
grpc_json *json = NULL;
grpc_auth_json_key key;
grpc_auth_refresh_token token;
grpc_credentials *result = NULL;
gpr_slice creds_data;
gpr_slice creds_data = gpr_empty_slice();
int file_ok = 0;
if (creds_path == NULL) return NULL;
creds_data = gpr_load_file(creds_path, 1, &file_ok);
gpr_free(creds_path);
if (file_ok) {
result = grpc_jwt_credentials_create(
(const char *)GPR_SLICE_START_PTR(creds_data),
grpc_max_auth_token_lifetime);
gpr_slice_unref(creds_data);
if (creds_path == NULL) goto end;
creds_data = gpr_load_file(creds_path, 0, &file_ok);
if (!file_ok) goto end;
json = grpc_json_parse_string_with_len(
(char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data));
if (json == NULL) goto end;
/* First, try an auth json key. */
key = grpc_auth_json_key_create_from_json(json);
if (grpc_auth_json_key_is_valid(&key)) {
result = grpc_jwt_credentials_create_from_auth_json_key(
key, grpc_max_auth_token_lifetime);
goto end;
}
return result;
}
/* Takes ownership of creds_path if not NULL. */
static grpc_credentials *create_refresh_token_creds_from_path(
char *creds_path) {
grpc_credentials *result = NULL;
gpr_slice creds_data;
int file_ok = 0;
if (creds_path == NULL) return NULL;
creds_data = gpr_load_file(creds_path, 1, &file_ok);
gpr_free(creds_path);
if (file_ok) {
result = grpc_refresh_token_credentials_create(
(const char *)GPR_SLICE_START_PTR(creds_data));
gpr_slice_unref(creds_data);
/* Then try a refresh token if the auth json key was invalid. */
token = grpc_auth_refresh_token_create_from_json(json);
if (grpc_auth_refresh_token_is_valid(&token)) {
result =
grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
goto end;
}
end:
if (creds_path != NULL) gpr_free(creds_path);
gpr_slice_unref(creds_data);
if (json != NULL) grpc_json_destroy(json);
return result;
}
@ -170,12 +174,12 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
}
/* First, try the environment variable. */
result =
create_jwt_creds_from_path(gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
result = create_default_creds_from_path(
gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
if (result != NULL) goto end;
/* Then the well-known file. */
result = create_refresh_token_creds_from_path(
result = create_default_creds_from_path(
grpc_get_well_known_google_credentials_file_path());
if (result != NULL) goto end;
@ -193,11 +197,24 @@ end:
if (!serving_cached_credentials && result != NULL) {
/* Blend with default ssl credentials and add a global reference so that it
can be cached and re-served. */
result = grpc_composite_credentials_create(
grpc_ssl_credentials_create(NULL, NULL), result);
GPR_ASSERT(result != NULL);
default_credentials = grpc_credentials_ref(result);
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
default_credentials = grpc_credentials_ref(grpc_composite_credentials_create(
ssl_creds, result));
GPR_ASSERT(default_credentials != NULL);
grpc_credentials_unref(ssl_creds);
grpc_credentials_unref(result);
result = default_credentials;
}
gpr_mu_unlock(&g_mu);
return result;
}
void grpc_flush_cached_google_default_credentials(void) {
gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_mu);
if (default_credentials != NULL) {
grpc_credentials_unref(default_credentials);
default_credentials = NULL;
}
gpr_mu_unlock(&g_mu);
}

@ -46,17 +46,11 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#include "src/core/json/json.h"
/* --- Constants. --- */
/* 1 hour max. */
const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
#define GRPC_JWT_TYPE "JWT"
@ -66,7 +60,7 @@ static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL;
/* --- grpc_auth_json_key. --- */
static const char *json_get_string_property(grpc_json *json,
static const char *json_get_string_property(const grpc_json *json,
const char *prop_name) {
grpc_json *child;
for (child = json->child; child != NULL; child = child->next) {
@ -79,7 +73,8 @@ static const char *json_get_string_property(grpc_json *json,
return child->value;
}
static int set_json_key_string_property(grpc_json *json, const char *prop_name,
static int set_json_key_string_property(const grpc_json *json,
const char *prop_name,
char **json_key_field) {
const char *prop_value = json_get_string_property(json, prop_name);
if (prop_value == NULL) return 0;
@ -92,11 +87,8 @@ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
}
grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string) {
grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) {
grpc_auth_json_key result;
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
BIO *bio = NULL;
const char *prop_value;
int success = 0;
@ -104,7 +96,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
memset(&result, 0, sizeof(grpc_auth_json_key));
result.type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
gpr_log(GPR_ERROR, "Invalid json.");
goto end;
}
@ -142,8 +134,16 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
end:
if (bio != NULL) BIO_free(bio);
if (json != NULL) grpc_json_destroy(json);
if (!success) grpc_auth_json_key_destruct(&result);
return result;
}
grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string) {
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json);
if (json != NULL) grpc_json_destroy(json);
gpr_free(scratchpad);
return result;
}
@ -207,7 +207,7 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
grpc_json *child = NULL;
char *json_str = NULL;
char *result = NULL;
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
gpr_timespec expiration = gpr_time_add(now, token_lifetime);
char now_str[GPR_LTOA_MIN_BUFSIZE];
char expiration_str[GPR_LTOA_MIN_BUFSIZE];
@ -218,8 +218,8 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
gpr_ltoa(now.tv_sec, now_str);
gpr_ltoa(expiration.tv_sec, expiration_str);
child = create_child(NULL, json, "iss", json_key->client_email,
GRPC_JSON_STRING);
child =
create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING);
if (scope != NULL) {
child = create_child(child, json, "scope", scope, GRPC_JSON_STRING);
} else {
@ -342,18 +342,16 @@ int grpc_auth_refresh_token_is_valid(
strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
}
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
const char *json_string) {
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
const grpc_json *json) {
grpc_auth_refresh_token result;
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
const char *prop_value;
int success = 0;
memset(&result, 0, sizeof(grpc_auth_refresh_token));
result.type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
gpr_log(GPR_ERROR, "Invalid json.");
goto end;
}
@ -374,8 +372,17 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
success = 1;
end:
if (json != NULL) grpc_json_destroy(json);
if (!success) grpc_auth_refresh_token_destruct(&result);
return result;
}
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
const char *json_string) {
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
grpc_auth_refresh_token result =
grpc_auth_refresh_token_create_from_json(json);
if (json != NULL) grpc_json_destroy(json);
gpr_free(scratchpad);
return result;
}
@ -396,4 +403,3 @@ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) {
refresh_token->refresh_token = NULL;
}
}

@ -37,10 +37,16 @@
#include <grpc/support/slice.h>
#include <openssl/rsa.h>
#include "src/core/json/json.h"
/* --- Constants. --- */
#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token"
#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
/* --- auth_json_key parsing. --- */
typedef struct {
@ -59,6 +65,10 @@ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key);
grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string);
/* Creates a json_key object from parsed json. Returns an invalid object if a
parsing error has been encountered. */
grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json);
/* Destructs the object. */
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key);
@ -97,6 +107,11 @@ int grpc_auth_refresh_token_is_valid(
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
const char *json_string);
/* Creates a refresh token object from parsed json. Returns an invalid object if
a parsing error has been encountered. */
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
const grpc_json *json);
/* Destructs the object. */
void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);

@ -189,7 +189,6 @@ struct grpc_jwt_claims {
gpr_slice buffer;
};
void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) {
grpc_json_destroy(claims->json);
gpr_slice_unref(claims->buffer);
@ -286,12 +285,14 @@ grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
GPR_ASSERT(claims != NULL);
skewed_now = gpr_time_add(gpr_now(), grpc_jwt_verifier_clock_skew);
skewed_now =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew);
if (gpr_time_cmp(skewed_now, claims->nbf) < 0) {
gpr_log(GPR_ERROR, "JWT is not valid yet.");
return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
}
skewed_now = gpr_time_sub(gpr_now(), grpc_jwt_verifier_clock_skew);
skewed_now =
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew);
if (gpr_time_cmp(skewed_now, claims->exp) > 0) {
gpr_log(GPR_ERROR, "JWT is expired.");
return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
@ -327,10 +328,10 @@ typedef struct {
/* Takes ownership of the header, claims and signature. */
static verifier_cb_ctx *verifier_cb_ctx_create(
grpc_jwt_verifier *verifier, grpc_pollset *pollset,
jose_header * header, grpc_jwt_claims *claims, const char *audience,
gpr_slice signature, const char *signed_jwt, size_t signed_jwt_len,
void *user_data, grpc_jwt_verification_done_cb cb) {
grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header,
grpc_jwt_claims *claims, const char *audience, gpr_slice signature,
const char *signed_jwt, size_t signed_jwt_len, void *user_data,
grpc_jwt_verification_done_cb cb) {
verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx));
memset(ctx, 0, sizeof(verifier_cb_ctx));
ctx->verifier = verifier;
@ -604,7 +605,7 @@ end:
static void on_openid_config_retrieved(void *user_data,
const grpc_httpcli_response *response) {
const grpc_json* cur;
const grpc_json *cur;
grpc_json *json = json_from_http(response);
verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data;
grpc_httpcli_request req;
@ -632,9 +633,10 @@ static void on_openid_config_retrieved(void *user_data,
} else {
*(req.host + (req.path - jwks_uri)) = '\0';
}
grpc_httpcli_get(&ctx->verifier->http_ctx, ctx->pollset, &req,
gpr_time_add(gpr_now(), grpc_jwt_verifier_max_delay),
on_keys_retrieved, ctx);
grpc_httpcli_get(
&ctx->verifier->http_ctx, ctx->pollset, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
on_keys_retrieved, ctx);
grpc_json_destroy(json);
gpr_free(req.host);
return;
@ -645,8 +647,8 @@ error:
verifier_cb_ctx_destroy(ctx);
}
static email_key_mapping *verifier_get_mapping(
grpc_jwt_verifier *v, const char *email_domain) {
static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v,
const char *email_domain) {
size_t i;
if (v->mappings == NULL) return NULL;
for (i = 0; i < v->num_mappings; i++) {
@ -733,9 +735,10 @@ static void retrieve_key_and_verify(verifier_cb_ctx *ctx) {
http_cb = on_openid_config_retrieved;
}
grpc_httpcli_get(&ctx->verifier->http_ctx, ctx->pollset, &req,
gpr_time_add(gpr_now(), grpc_jwt_verifier_max_delay),
http_cb, ctx);
grpc_httpcli_get(
&ctx->verifier->http_ctx, ctx->pollset, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
http_cb, ctx);
gpr_free(req.host);
gpr_free(req.path);
return;
@ -764,7 +767,7 @@ void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier,
dot = strchr(cur, '.');
if (dot == NULL) goto error;
json = parse_json_part_from_jwt(cur, dot - cur, &header_buffer);
if (json == NULL) goto error;
if (json == NULL) goto error;
header = jose_header_from_json(json, header_buffer);
if (header == NULL) goto error;
@ -772,7 +775,7 @@ void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier,
dot = strchr(cur, '.');
if (dot == NULL) goto error;
json = parse_json_part_from_jwt(cur, dot - cur, &claims_buffer);
if (json == NULL) goto error;
if (json == NULL) goto error;
claims = grpc_jwt_claims_from_json(json, claims_buffer);
if (claims == NULL) goto error;
@ -827,4 +830,3 @@ void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v) {
}
gpr_free(v);
}

@ -69,12 +69,20 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
return GRPC_CALL_OK;
}
const grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
if (sec_ctx == NULL) return NULL;
return grpc_call_is_client(call)
? ((grpc_client_security_context *)sec_ctx)->auth_context
: ((grpc_server_security_context *)sec_ctx)->auth_context;
? GRPC_AUTH_CONTEXT_REF(
((grpc_client_security_context *)sec_ctx)->auth_context,
"grpc_call_auth_context client")
: GRPC_AUTH_CONTEXT_REF(
((grpc_server_security_context *)sec_ctx)->auth_context,
"grpc_call_auth_context server");
}
void grpc_auth_context_release(grpc_auth_context *context) {
GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref");
}
/* --- grpc_client_security_context --- */

@ -36,6 +36,10 @@
#include "src/core/security/credentials.h"
#ifdef __cplusplus
extern "C" {
#endif
/* --- grpc_auth_context ---
High level authentication context object. Can optionally be chained. */
@ -103,5 +107,9 @@ typedef struct {
grpc_server_security_context *grpc_server_security_context_create(void);
void grpc_server_security_context_destroy(void *ctx);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */

@ -157,7 +157,7 @@ static void record_stats(census_ht* store, census_op_id op_id,
key.ptr = gpr_strdup(key.ptr);
census_ht_insert(store, key, (void*)window_stats);
}
census_window_stats_add(window_stats, gpr_now(), stats);
census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats);
} else {
census_internal_unlock_trace_store();
}
@ -185,7 +185,7 @@ static void get_stats(census_ht* store, census_aggregated_rpc_stats* data) {
if (store != NULL) {
size_t n;
unsigned i, j;
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
census_ht_kv* kv = census_ht_get_all_elements(store, &n);
if (kv != NULL) {
data->num_entries = n;

@ -94,7 +94,7 @@ census_op_id census_tracing_start_op(void) {
g_id++;
memcpy(&ret->id, &g_id, sizeof(census_op_id));
ret->rpc_stats.cnt = 1;
ret->ts = gpr_now();
ret->ts = gpr_now(GPR_CLOCK_REALTIME);
census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void*)ret);
gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id);
gpr_mu_unlock(&g_mu);
@ -122,7 +122,7 @@ void census_tracing_print(census_op_id op_id, const char* anno_txt) {
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace != NULL) {
census_trace_annotation* anno = gpr_malloc(sizeof(census_trace_annotation));
anno->ts = gpr_now();
anno->ts = gpr_now(GPR_CLOCK_REALTIME);
{
char* d = anno->txt;
const char* s = anno_txt;
@ -143,8 +143,8 @@ void census_tracing_end_op(census_op_id op_id) {
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace != NULL) {
trace->rpc_stats.elapsed_time_ms =
gpr_timespec_to_micros(gpr_time_sub(gpr_now(), trace->ts));
trace->rpc_stats.elapsed_time_ms = gpr_timespec_to_micros(
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), trace->ts));
gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us",
op_id_2_uint64(&op_id), trace->method,
trace->rpc_stats.elapsed_time_ms);
@ -194,8 +194,8 @@ const char* census_get_trace_method_name(const census_trace_obj* trace) {
static census_trace_annotation* dup_annotation_chain(
census_trace_annotation* from) {
census_trace_annotation *ret = NULL;
census_trace_annotation **to = &ret;
census_trace_annotation* ret = NULL;
census_trace_annotation** to = &ret;
for (; from != NULL; from = from->next) {
*to = gpr_malloc(sizeof(census_trace_annotation));
memcpy(*to, from, sizeof(census_trace_annotation));
@ -223,9 +223,9 @@ census_trace_obj** census_get_active_ops(int* num_active_ops) {
size_t n = 0;
census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n);
*num_active_ops = (int)n;
if (n != 0 ) {
if (n != 0) {
size_t i = 0;
ret = gpr_malloc(sizeof(census_trace_obj *) * n);
ret = gpr_malloc(sizeof(census_trace_obj*) * n);
for (i = 0; i < n; i++) {
ret[i] = trace_obj_dup((census_trace_obj*)all_kvs[i].v);
}

@ -90,11 +90,11 @@
// Record a new event, taking 15.3ms, transferring 1784 bytes.
stat.latency = 0.153;
stat.bytes = 1784;
census_window_stats_add(stats, gpr_now(), &stat);
census_window_stats_add(stats, gpr_now(GPR_CLOCK_REALTIME), &stat);
// Get sums and print them out
result[kMinInterval].statistic = &sums[kMinInterval];
result[kHourInterval].statistic = &sums[kHourInterval];
census_window_stats_get_sums(stats, gpr_now(), result);
census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), result);
printf("%d events/min, average time %gs, average bytes %g\n",
result[kMinInterval].count,
(my_stat*)result[kMinInterval].statistic->latency /
@ -170,4 +170,4 @@ void census_window_stats_get_sums(const struct census_window_stats* wstats,
assertion failure). This function is thread-compatible. */
void census_window_stats_destroy(struct census_window_stats* wstats);
#endif /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */
#endif /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */

@ -121,8 +121,8 @@ void gpr_cancellable_cancel(gpr_cancellable *c) {
} else {
gpr_event ev;
gpr_event_init(&ev);
gpr_event_wait(&ev,
gpr_time_add(gpr_now(), gpr_time_from_micros(1000)));
gpr_event_wait(&ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_micros(1000)));
}
}
} while (failures != 0);

@ -76,7 +76,7 @@ void gpr_default_log(gpr_log_func_args *args) {
char *prefix;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
final_slash = strrchr(args->file, '/');

@ -75,7 +75,7 @@ void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
final_slash = strrchr(args->file, '/');

@ -82,7 +82,7 @@ void gpr_log(const char *file, int line, gpr_log_severity severity,
/* Simple starter implementation */
void gpr_default_log(gpr_log_func_args *args) {
char time_buffer[64];
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
if (localtime_s(&tm, &now.tv_sec)) {

@ -0,0 +1,130 @@
/*
*
* 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/support/stack_lockfree.h"
#include <stdlib.h>
#include <string.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
/* The lockfree node structure is a single architecture-level
word that allows for an atomic CAS to set it up. */
struct lockfree_node_contents {
/* next thing to look at. Actual index for head, next index otherwise */
gpr_uint16 index;
#ifdef GPR_ARCH_64
gpr_uint16 pad;
gpr_uint32 aba_ctr;
#else
#ifdef GPR_ARCH_32
gpr_uint16 aba_ctr;
#else
#error Unsupported bit width architecture
#endif
#endif
};
/* Use a union to make sure that these are in the same bits as an atm word */
typedef union lockfree_node {
gpr_atm atm;
struct lockfree_node_contents contents;
} lockfree_node;
#define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */
#define INVALID_ENTRY_INDEX ((1 << 16) - 1) /* reserve this entry as invalid \
*/
struct gpr_stack_lockfree {
lockfree_node *entries;
lockfree_node head; /* An atomic entry describing curr head */
};
gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
gpr_stack_lockfree *stack;
stack = gpr_malloc(sizeof(*stack));
/* Since we only allocate 16 bits to represent an entry number,
* make sure that we are within the desired range */
/* Reserve the highest entry number as a dummy */
GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]),
ENTRY_ALIGNMENT_BITS);
/* Clear out all entries */
memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
memset(&stack->head, 0, sizeof(stack->head));
/* Point the head at reserved dummy entry */
stack->head.contents.index = INVALID_ENTRY_INDEX;
return stack;
}
void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) {
gpr_free_aligned(stack->entries);
gpr_free(stack);
}
void gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
lockfree_node head;
lockfree_node newhead;
/* First fill in the entry's index and aba ctr for new head */
newhead.contents.index = (gpr_uint16)entry;
/* Also post-increment the aba_ctr */
newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++;
do {
/* Atomically get the existing head value for use */
head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
/* Point to it */
stack->entries[entry].contents.index = head.contents.index;
} while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
/* Use rel_cas above to make sure that entry index is set properly */
}
int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
lockfree_node head;
lockfree_node newhead;
do {
head.atm = gpr_atm_acq_load(&(stack->head.atm));
if (head.contents.index == INVALID_ENTRY_INDEX) {
return -1;
}
newhead.atm =
gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
} while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
return head.contents.index;
}

@ -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_SUPPORT_STACK_LOCKFREE_H
#define GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H
typedef struct gpr_stack_lockfree gpr_stack_lockfree;
/* This stack must specify the maximum number of entries to track.
The current implementation only allows up to 65534 entries */
gpr_stack_lockfree* gpr_stack_lockfree_create(int entries);
void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
/* Pass in a valid entry number for the next stack entry */
void gpr_stack_lockfree_push(gpr_stack_lockfree* stack, int entry);
/* Returns -1 on empty or the actual entry number */
int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);
#endif /* GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H */

@ -86,7 +86,7 @@ int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
SleepConditionVariableCS(cv, &mu->cs, INFINITE);
} else {
gpr_timespec now = gpr_now();
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000;
gpr_int64 deadline_ms =
abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;

@ -55,22 +55,52 @@ static gpr_timespec gpr_from_timespec(struct timespec ts) {
return rv;
}
gpr_timespec gpr_now(void) {
/** maps gpr_clock_type --> clockid_t for clock_gettime */
static clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, CLOCK_REALTIME};
void gpr_time_init(void) {}
gpr_timespec gpr_now(gpr_clock_type clock) {
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
clock_gettime(clockid_for_gpr_clock[clock], &now);
return gpr_from_timespec(now);
}
#else
/* For some reason Apple's OSes haven't implemented clock_gettime. */
#include <sys/time.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
static double g_time_scale;
static uint64_t g_time_start;
void gpr_time_init(void) {
mach_timebase_info_data_t tb = {0, 1};
mach_timebase_info(&tb);
g_time_scale = tb.numer;
g_time_scale /= tb.denom;
g_time_start = mach_absolute_time();
}
gpr_timespec gpr_now(void) {
gpr_timespec gpr_now(gpr_clock_type clock) {
gpr_timespec now;
struct timeval now_tv;
gettimeofday(&now_tv, NULL);
now.tv_sec = now_tv.tv_sec;
now.tv_nsec = now_tv.tv_usec * 1000;
double now_dbl;
switch (clock) {
case GPR_CLOCK_REALTIME:
gettimeofday(&now_tv, NULL);
now.tv_sec = now_tv.tv_sec;
now.tv_nsec = now_tv.tv_usec * 1000;
break;
case GPR_CLOCK_MONOTONIC:
now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale;
now.tv_sec = now_dbl * 1e-9;
now.tv_nsec = now_dbl - now.tv_sec * 1e9;
break;
}
return now;
}
#endif
@ -83,7 +113,7 @@ void gpr_sleep_until(gpr_timespec until) {
for (;;) {
/* We could simplify by using clock_nanosleep instead, but it might be
* slightly less portable. */
now = gpr_now();
now = gpr_now(GPR_CLOCK_REALTIME);
if (gpr_time_cmp(until, now) <= 0) {
return;
}

@ -40,12 +40,34 @@
#include <grpc/support/time.h>
#include <sys/timeb.h>
gpr_timespec gpr_now(void) {
static LARGE_INTEGER g_start_time;
static double g_time_scale;
void gpr_time_init(void) {
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&g_start_time);
g_time_scale = 1.0 / frequency.QuadPart;
}
gpr_timespec gpr_now(gpr_clock_type clock) {
gpr_timespec now_tv;
struct _timeb now_tb;
_ftime_s(&now_tb);
now_tv.tv_sec = now_tb.time;
now_tv.tv_nsec = now_tb.millitm * 1000000;
LARGE_INTEGER timestamp;
double now_dbl;
switch (clock) {
case GPR_CLOCK_REALTIME:
_ftime_s(&now_tb);
now_tv.tv_sec = now_tb.time;
now_tv.tv_nsec = now_tb.millitm * 1000000;
break;
case GPR_CLOCK_MONOTONIC:
QueryPerformanceCounter(&timestamp);
now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
now_tv.tv_sec = (time_t)now_dbl;
now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9);
break;
}
return now_tv;
}
@ -57,13 +79,14 @@ void gpr_sleep_until(gpr_timespec until) {
for (;;) {
/* We could simplify by using clock_nanosleep instead, but it might be
* slightly less portable. */
now = gpr_now();
now = gpr_now(GPR_CLOCK_REALTIME);
if (gpr_time_cmp(until, now) <= 0) {
return;
}
delta = gpr_time_sub(until, now);
sleep_millis = (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
sleep_millis =
(DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
Sleep(sleep_millis);
}
}

@ -50,6 +50,17 @@
#include "src/core/surface/channel.h"
#include "src/core/surface/completion_queue.h"
/** The maximum number of completions possible.
Based upon the maximum number of individually queueable ops in the batch
api:
- initial metadata send
- message send
- status/close send (depending on client/server)
- initial metadata recv
- message recv
- status/close recv (depending on client/server) */
#define MAX_CONCURRENT_COMPLETIONS 6
typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state;
typedef enum {
@ -136,6 +147,7 @@ struct grpc_call {
grpc_mdctx *metadata_context;
/* TODO(ctiller): share with cq if possible? */
gpr_mu mu;
gpr_mu completion_mu;
/* how far through the stream have we read? */
read_state read_state;
@ -163,6 +175,8 @@ struct grpc_call {
gpr_uint8 error_status_set;
/** should the alarm be cancelled */
gpr_uint8 cancel_alarm;
/** bitmask of allocated completion events in completions */
gpr_uint8 allocated_completions;
/* flags with bits corresponding to write states allowing us to determine
what was sent */
@ -251,6 +265,9 @@ struct grpc_call {
grpc_iomgr_closure on_done_recv;
grpc_iomgr_closure on_done_send;
grpc_iomgr_closure on_done_bind;
/** completion events - for completion queue use */
grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS];
};
#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
@ -287,6 +304,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
memset(call, 0, sizeof(grpc_call));
gpr_mu_init(&call->mu);
gpr_mu_init(&call->completion_mu);
call->channel = channel;
call->cq = cq;
if (cq) {
@ -350,6 +368,29 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
return call->cq;
}
static grpc_cq_completion *allocate_completion(grpc_call *call) {
gpr_uint8 i;
gpr_mu_lock(&call->completion_mu);
for (i = 0; i < GPR_ARRAY_SIZE(call->completions); i++) {
if (call->allocated_completions & (1u << i)) {
continue;
}
call->allocated_completions |= 1u << i;
gpr_mu_unlock(&call->completion_mu);
return &call->completions[i];
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
}
static void done_completion(void *call, grpc_cq_completion *completion) {
grpc_call *c = call;
gpr_mu_lock(&c->completion_mu);
c->allocated_completions &= ~(1u << (completion - c->completions));
gpr_mu_unlock(&c->completion_mu);
GRPC_CALL_INTERNAL_UNREF(c, "completion", 1);
}
#ifdef GRPC_CALL_REF_COUNT_DEBUG
void grpc_call_internal_ref(grpc_call *c, const char *reason) {
gpr_log(GPR_DEBUG, "CALL: ref %p %d -> %d [%s]", c,
@ -366,6 +407,7 @@ static void destroy_call(void *call, int ignored_success) {
grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call");
gpr_mu_destroy(&c->mu);
gpr_mu_destroy(&c->completion_mu);
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
if (c->status[i].details) {
GRPC_MDSTR_UNREF(c->status[i].details);
@ -717,6 +759,7 @@ static void finish_message(grpc_call *call) {
/* some aliases for readability */
gpr_slice *slices = call->incoming_message.slices;
const size_t nslices = call->incoming_message.count;
if ((call->incoming_message_flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
(call->compression_algorithm > GRPC_COMPRESS_NONE)) {
byte_buffer = grpc_raw_compressed_byte_buffer_create(
@ -1220,7 +1263,8 @@ static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) {
}
GRPC_CALL_INTERNAL_REF(call, "alarm");
call->have_alarm = 1;
grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now());
grpc_alarm_init(&call->alarm, deadline, call_alarm, call,
gpr_now(GPR_CLOCK_REALTIME));
}
/* we offset status by a small amount when storing it into transport metadata
@ -1343,11 +1387,13 @@ static void set_cancelled_value(grpc_status_code status, void *dest) {
}
static void finish_batch(grpc_call *call, int success, void *tag) {
grpc_cq_end_op(call->cq, tag, call, success);
grpc_cq_end_op(call->cq, tag, success, done_completion, call,
allocate_completion(call));
}
static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
grpc_cq_end_op(call->cq, tag, call, 1);
grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
allocate_completion(call));
}
static int are_write_flags_valid(gpr_uint32 flags) {
@ -1370,8 +1416,10 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
if (nops == 0) {
grpc_cq_begin_op(call->cq, call);
grpc_cq_end_op(call->cq, tag, call, 1);
grpc_cq_begin_op(call->cq);
GRPC_CALL_INTERNAL_REF(call, "completion");
grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
allocate_completion(call));
return GRPC_CALL_OK;
}
@ -1493,7 +1541,8 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
}
}
grpc_cq_begin_op(call->cq, call);
GRPC_CALL_INTERNAL_REF(call, "completion");
grpc_cq_begin_op(call->cq);
return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func, tag);
}

@ -91,6 +91,7 @@ grpc_channel *grpc_channel_create_from_filters(
size_t size =
sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
grpc_channel *channel = gpr_malloc(size);
memset(channel, 0, sizeof(*channel));
GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
channel->is_client = is_client;
/* decremented by grpc_channel_destroy */

@ -45,34 +45,20 @@
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#define NUM_TAG_BUCKETS 31
/* A single event: extends grpc_event to form a linked list with a destruction
function (on_finish) that is hidden from outside this module */
typedef struct event {
grpc_event base;
struct event *queue_next;
struct event *queue_prev;
struct event *bucket_next;
struct event *bucket_prev;
} event;
/* Completion queue structure */
struct grpc_completion_queue {
/* When refs drops to zero, we are in shutdown mode, and will be destroyable
once all queued events are drained */
gpr_refcount refs;
/* Once owning_refs drops to zero, we will destroy the cq */
/** completed events */
grpc_cq_completion completed_head;
grpc_cq_completion *completed_tail;
/** Number of pending events (+1 if we're not shutdown) */
gpr_refcount pending_events;
/** Once owning_refs drops to zero, we will destroy the cq */
gpr_refcount owning_refs;
/* the set of low level i/o things that concern this cq */
/** the set of low level i/o things that concern this cq */
grpc_pollset pollset;
/* 0 initially, 1 once we've begun shutting down */
/** 0 initially, 1 once we've begun shutting down */
int shutdown;
int shutdown_called;
/* Head of a linked list of queued events (prev points to the last element) */
event *queue;
/* Fixed size chained hash table of events for pluck() */
event *buckets[NUM_TAG_BUCKETS];
int is_server_cq;
};
@ -80,19 +66,20 @@ grpc_completion_queue *grpc_completion_queue_create(void) {
grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
memset(cc, 0, sizeof(*cc));
/* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_ref_init(&cc->refs, 1);
gpr_ref_init(&cc->pending_events, 1);
/* One for destroy(), one for pollset_shutdown */
gpr_ref_init(&cc->owning_refs, 2);
grpc_pollset_init(&cc->pollset);
cc->completed_tail = &cc->completed_head;
cc->completed_head.next = (gpr_uintptr)cc->completed_tail;
return cc;
}
#ifdef GRPC_CQ_REF_COUNT_DEBUG
void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
const char *file, int line) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s",
cc, (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1,
reason);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cc,
(int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason);
#else
void grpc_cq_internal_ref(grpc_completion_queue *cc) {
#endif
@ -107,186 +94,135 @@ static void on_pollset_destroy_done(void *arg) {
#ifdef GRPC_CQ_REF_COUNT_DEBUG
void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason,
const char *file, int line) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s",
cc, (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1,
reason);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc,
(int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason);
#else
void grpc_cq_internal_unref(grpc_completion_queue *cc) {
#endif
if (gpr_unref(&cc->owning_refs)) {
GPR_ASSERT(cc->queue == NULL);
GPR_ASSERT(cc->completed_head.next == (gpr_uintptr)&cc->completed_head);
grpc_pollset_destroy(&cc->pollset);
gpr_free(cc);
}
}
/* Create and append an event to the queue. Returns the event so that its data
members can be filled in.
Requires GRPC_POLLSET_MU(&cc->pollset) locked. */
static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type,
void *tag, grpc_call *call) {
event *ev = gpr_malloc(sizeof(event));
gpr_uintptr bucket = ((gpr_uintptr)tag) % NUM_TAG_BUCKETS;
ev->base.type = type;
ev->base.tag = tag;
if (cc->queue == NULL) {
cc->queue = ev->queue_next = ev->queue_prev = ev;
} else {
ev->queue_next = cc->queue;
ev->queue_prev = cc->queue->queue_prev;
ev->queue_next->queue_prev = ev->queue_prev->queue_next = ev;
}
if (cc->buckets[bucket] == NULL) {
cc->buckets[bucket] = ev->bucket_next = ev->bucket_prev = ev;
} else {
ev->bucket_next = cc->buckets[bucket];
ev->bucket_prev = cc->buckets[bucket]->bucket_prev;
ev->bucket_next->bucket_prev = ev->bucket_prev->bucket_next = ev;
}
grpc_pollset_kick(&cc->pollset);
return ev;
}
void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call) {
gpr_ref(&cc->refs);
if (call) GRPC_CALL_INTERNAL_REF(call, "cq");
void grpc_cq_begin_op(grpc_completion_queue *cc) {
gpr_ref(&cc->pending_events);
}
/* Signal the end of an operation - if this is the last waiting-to-be-queued
event, then enter shutdown mode */
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
int success) {
event *ev;
int shutdown = 0;
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
ev = add_locked(cc, GRPC_OP_COMPLETE, tag, call);
ev->base.success = success;
if (gpr_unref(&cc->refs)) {
/* Queue a GRPC_OP_COMPLETED operation */
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
void (*done)(void *done_arg, grpc_cq_completion *storage),
void *done_arg, grpc_cq_completion *storage) {
int shutdown = gpr_unref(&cc->pending_events);
storage->tag = tag;
storage->done = done;
storage->done_arg = done_arg;
storage->next =
((gpr_uintptr)&cc->completed_head) | ((gpr_uintptr)(success != 0));
if (!shutdown) {
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
cc->completed_tail->next =
((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next);
cc->completed_tail = storage;
grpc_pollset_kick(&cc->pollset);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
} else {
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
cc->completed_tail->next =
((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next);
cc->completed_tail = storage;
GPR_ASSERT(!cc->shutdown);
GPR_ASSERT(cc->shutdown_called);
cc->shutdown = 1;
shutdown = 1;
}
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
if (call) GRPC_CALL_INTERNAL_UNREF(call, "cq", 0);
if (shutdown) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
}
}
/* Create a GRPC_QUEUE_SHUTDOWN event without queuing it anywhere */
static event *create_shutdown_event(void) {
event *ev = gpr_malloc(sizeof(event));
ev->base.type = GRPC_QUEUE_SHUTDOWN;
ev->base.tag = NULL;
return ev;
}
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_timespec deadline) {
event *ev = NULL;
grpc_event ret;
GRPC_CQ_INTERNAL_REF(cc, "next");
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
for (;;) {
if (cc->queue != NULL) {
gpr_uintptr bucket;
ev = cc->queue;
bucket = ((gpr_uintptr)ev->base.tag) % NUM_TAG_BUCKETS;
cc->queue = ev->queue_next;
ev->queue_next->queue_prev = ev->queue_prev;
ev->queue_prev->queue_next = ev->queue_next;
ev->bucket_next->bucket_prev = ev->bucket_prev;
ev->bucket_prev->bucket_next = ev->bucket_next;
if (ev == cc->buckets[bucket]) {
cc->buckets[bucket] = ev->bucket_next;
if (ev == cc->buckets[bucket]) {
cc->buckets[bucket] = NULL;
}
}
if (cc->queue == ev) {
cc->queue = NULL;
if (cc->completed_tail != &cc->completed_head) {
grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
cc->completed_head.next = c->next & ~(gpr_uintptr)1;
if (c == cc->completed_tail) {
cc->completed_tail = &cc->completed_head;
}
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
ret.type = GRPC_OP_COMPLETE;
ret.success = c->next & 1u;
ret.tag = c->tag;
c->done(c->done_arg, c);
break;
}
if (cc->shutdown) {
ev = create_shutdown_event();
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_SHUTDOWN;
break;
}
if (!grpc_pollset_work(&cc->pollset, deadline)) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT;
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
GRPC_CQ_INTERNAL_UNREF(cc, "next");
return ret;
break;
}
}
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
ret = ev->base;
gpr_free(ev);
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
GRPC_CQ_INTERNAL_UNREF(cc, "next");
return ret;
}
static event *pluck_event(grpc_completion_queue *cc, void *tag) {
gpr_uintptr bucket = ((gpr_uintptr)tag) % NUM_TAG_BUCKETS;
event *ev = cc->buckets[bucket];
if (ev == NULL) return NULL;
do {
if (ev->base.tag == tag) {
ev->queue_next->queue_prev = ev->queue_prev;
ev->queue_prev->queue_next = ev->queue_next;
ev->bucket_next->bucket_prev = ev->bucket_prev;
ev->bucket_prev->bucket_next = ev->bucket_next;
if (ev == cc->buckets[bucket]) {
cc->buckets[bucket] = ev->bucket_next;
if (ev == cc->buckets[bucket]) {
cc->buckets[bucket] = NULL;
}
}
if (cc->queue == ev) {
cc->queue = ev->queue_next;
if (cc->queue == ev) {
cc->queue = NULL;
}
}
return ev;
}
ev = ev->bucket_next;
} while (ev != cc->buckets[bucket]);
return NULL;
}
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
gpr_timespec deadline) {
event *ev = NULL;
grpc_event ret;
grpc_cq_completion *c;
grpc_cq_completion *prev;
GRPC_CQ_INTERNAL_REF(cc, "pluck");
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
for (;;) {
if ((ev = pluck_event(cc, tag))) {
break;
prev = &cc->completed_head;
while ((c = (grpc_cq_completion *)(prev->next & ~(gpr_uintptr)1)) !=
&cc->completed_head) {
if (c->tag == tag) {
prev->next =
(prev->next & (gpr_uintptr)1) | (c->next & ~(gpr_uintptr)1);
if (c == cc->completed_tail) {
cc->completed_tail = prev;
}
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
ret.type = GRPC_OP_COMPLETE;
ret.success = c->next & 1u;
ret.tag = c->tag;
c->done(c->done_arg, c);
goto done;
}
prev = c;
}
if (cc->shutdown) {
ev = create_shutdown_event();
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_SHUTDOWN;
break;
}
if (!grpc_pollset_work(&cc->pollset, deadline)) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT;
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
return ret;
break;
}
}
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
ret = ev->base;
gpr_free(ev);
done:
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
return ret;
@ -303,7 +239,7 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
cc->shutdown_called = 1;
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
if (gpr_unref(&cc->refs)) {
if (gpr_unref(&cc->pending_events)) {
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
GPR_ASSERT(!cc->shutdown);
cc->shutdown = 1;
@ -324,8 +260,8 @@ grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc) {
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
grpc_pollset_kick(&cc->pollset);
grpc_pollset_work(&cc->pollset,
gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
grpc_pollset_work(&cc->pollset, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(100)));
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
}

@ -39,6 +39,17 @@
#include "src/core/iomgr/pollset.h"
#include <grpc/grpc.h>
typedef struct grpc_cq_completion {
/** user supplied tag */
void *tag;
/** done callback - called when this queue element is no longer
needed by the completion queue */
void (*done)(void *done_arg, struct grpc_cq_completion *c);
void *done_arg;
/** next pointer; low bit is used to indicate success or not */
gpr_uintptr next;
} grpc_cq_completion;
#ifdef GRPC_CQ_REF_COUNT_DEBUG
void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
const char *file, int line);
@ -57,11 +68,12 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc);
/* Flag that an operation is beginning: the completion channel will not finish
shutdown until a corrensponding grpc_cq_end_* call is made */
void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call);
void grpc_cq_begin_op(grpc_completion_queue *cc);
/* Queue a GRPC_OP_COMPLETED operation */
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
int success);
void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
void (*done)(void *done_arg, grpc_cq_completion *storage),
void *done_arg, grpc_cq_completion *storage);
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);

@ -35,6 +35,7 @@
#include <grpc/census.h>
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/resolver_registry.h"
#include "src/core/client_config/resolvers/dns_resolver.h"
@ -64,6 +65,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
grpc_resolver_registry_init("dns:///");
grpc_register_resolver_type("dns", grpc_dns_resolver_factory_create());
#ifdef GPR_POSIX_SOCKET

@ -72,12 +72,14 @@ typedef struct {
typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
typedef struct {
typedef struct requested_call {
requested_call_type type;
struct requested_call *next;
void *tag;
grpc_completion_queue *cq_bound_to_call;
grpc_completion_queue *cq_for_notification;
grpc_call **call;
grpc_cq_completion completion;
union {
struct {
grpc_call_details *details;
@ -92,17 +94,11 @@ typedef struct {
} data;
} requested_call;
typedef struct {
requested_call *calls;
size_t count;
size_t capacity;
} requested_call_array;
struct registered_method {
char *method;
char *host;
call_data *pending;
requested_call_array requested;
requested_call *requests;
registered_method *next;
};
@ -131,6 +127,7 @@ struct channel_data {
typedef struct shutdown_tag {
void *tag;
grpc_completion_queue *cq;
grpc_cq_completion completion;
} shutdown_tag;
struct grpc_server {
@ -153,7 +150,7 @@ struct grpc_server {
gpr_mu mu_call; /* mutex for call-specific state */
registered_method *registered_methods;
requested_call_array requested_calls;
requested_call *requests;
gpr_uint8 shutdown;
gpr_uint8 shutdown_published;
@ -166,6 +163,9 @@ struct grpc_server {
listener *listeners;
int listeners_destroyed;
gpr_refcount internal_refcount;
/** when did we print the last shutdown progress message */
gpr_timespec last_shutdown_message_time;
};
typedef enum {
@ -270,7 +270,8 @@ static void send_shutdown(grpc_channel *channel, int send_goaway,
}
static void channel_broadcaster_shutdown(channel_broadcaster *cb,
int send_goaway, int force_disconnect) {
int send_goaway,
int force_disconnect) {
size_t i;
for (i = 0; i < cb->num_channels; i++) {
@ -329,22 +330,6 @@ static int call_list_remove(call_data *call, call_list list) {
return 1;
}
static void requested_call_array_destroy(requested_call_array *array) {
gpr_free(array->calls);
}
static requested_call *requested_call_array_add(requested_call_array *array) {
requested_call *rc;
if (array->count == array->capacity) {
array->capacity = GPR_MAX(array->capacity + 8, array->capacity * 2);
array->calls =
gpr_realloc(array->calls, sizeof(requested_call) * array->capacity);
}
rc = &array->calls[array->count++];
memset(rc, 0, sizeof(*rc));
return rc;
}
static void server_ref(grpc_server *server) {
gpr_ref(&server->internal_refcount);
}
@ -356,12 +341,10 @@ static void server_delete(grpc_server *server) {
gpr_mu_destroy(&server->mu_global);
gpr_mu_destroy(&server->mu_call);
gpr_free(server->channel_filters);
requested_call_array_destroy(&server->requested_calls);
while ((rm = server->registered_methods) != NULL) {
server->registered_methods = rm->next;
gpr_free(rm->method);
gpr_free(rm->host);
requested_call_array_destroy(&rm->requested);
gpr_free(rm);
}
for (i = 0; i < server->cq_count; i++) {
@ -409,23 +392,24 @@ static void destroy_channel(channel_data *chand) {
static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
call_data **pending_root,
requested_call_array *array) {
requested_call rc;
requested_call **requests) {
requested_call *rc;
call_data *calld = elem->call_data;
gpr_mu_lock(&server->mu_call);
if (array->count == 0) {
rc = *requests;
if (rc == NULL) {
gpr_mu_lock(&calld->mu_state);
calld->state = PENDING;
gpr_mu_unlock(&calld->mu_state);
call_list_join(pending_root, calld, PENDING_START);
gpr_mu_unlock(&server->mu_call);
} else {
rc = array->calls[--array->count];
*requests = rc->next;
gpr_mu_lock(&calld->mu_state);
calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state);
gpr_mu_unlock(&server->mu_call);
begin_call(server, calld, &rc);
begin_call(server, calld, rc);
}
}
@ -441,14 +425,14 @@ static void start_new_rpc(grpc_call_element *elem) {
/* TODO(ctiller): unify these two searches */
/* check for an exact match with host */
hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash);
for (i = 0; i < chand->registered_method_max_probes; i++) {
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
if (!rm) break;
if (rm->host != calld->host) continue;
if (rm->method != calld->path) continue;
finish_start_new_rpc(server, elem, &rm->server_registered_method->pending,
&rm->server_registered_method->requested);
&rm->server_registered_method->requests);
return;
}
/* check for a wildcard method definition (no host set) */
@ -460,12 +444,12 @@ static void start_new_rpc(grpc_call_element *elem) {
if (rm->host != NULL) continue;
if (rm->method != calld->path) continue;
finish_start_new_rpc(server, elem, &rm->server_registered_method->pending,
&rm->server_registered_method->requested);
&rm->server_registered_method->requests);
return;
}
}
finish_start_new_rpc(server, elem, &server->lists[PENDING_START],
&server->requested_calls);
&server->requests);
}
static void kill_zombie(void *elem, int success) {
@ -481,26 +465,47 @@ static int num_listeners(grpc_server *server) {
return n;
}
static void done_shutdown_event(void *server, grpc_cq_completion *completion) {
server_unref(server);
}
static int num_channels(grpc_server *server) {
channel_data *chand;
int n = 0;
for (chand = server->root_channel_data.next;
chand != &server->root_channel_data; chand = chand->next) {
n++;
}
return n;
}
static void maybe_finish_shutdown(grpc_server *server) {
size_t i;
if (!server->shutdown || server->shutdown_published) {
return;
}
if (server->root_channel_data.next != &server->root_channel_data) {
gpr_log(GPR_DEBUG,
"Waiting for all channels to close before destroying server");
return;
}
if (server->listeners_destroyed < num_listeners(server)) {
gpr_log(GPR_DEBUG, "Waiting for all listeners to be destroyed (@ %d/%d)",
server->listeners_destroyed, num_listeners(server));
if (server->root_channel_data.next != &server->root_channel_data ||
server->listeners_destroyed < num_listeners(server)) {
if (gpr_time_cmp(
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), server->last_shutdown_message_time),
gpr_time_from_seconds(1)) >= 0) {
server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
gpr_log(GPR_DEBUG,
"Waiting for %d channels and %d/%d listeners to be destroyed"
" before shutting down server",
num_channels(server),
num_listeners(server) - server->listeners_destroyed,
num_listeners(server));
}
return;
}
server->shutdown_published = 1;
for (i = 0; i < server->num_shutdown_tags; i++) {
grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag,
NULL, 1);
server_ref(server);
grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag, 1,
done_shutdown_event, server,
&server->shutdown_tags[i].completion);
}
}
@ -924,15 +929,14 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
void grpc_server_shutdown_and_notify(grpc_server *server,
grpc_completion_queue *cq, void *tag) {
listener *l;
requested_call_array requested_calls;
size_t i;
requested_call *requests = NULL;
registered_method *rm;
shutdown_tag *sdt;
channel_broadcaster broadcaster;
/* lock, and gather up some stuff to do */
gpr_mu_lock(&server->mu_global);
grpc_cq_begin_op(cq, NULL);
grpc_cq_begin_op(cq);
server->shutdown_tags =
gpr_realloc(server->shutdown_tags,
sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
@ -944,27 +948,21 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
return;
}
server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
channel_broadcaster_init(server, &broadcaster);
/* collect all unregistered then registered calls */
gpr_mu_lock(&server->mu_call);
requested_calls = server->requested_calls;
memset(&server->requested_calls, 0, sizeof(server->requested_calls));
requests = server->requests;
server->requests = NULL;
for (rm = server->registered_methods; rm; rm = rm->next) {
if (requested_calls.count + rm->requested.count >
requested_calls.capacity) {
requested_calls.capacity =
GPR_MAX(requested_calls.count + rm->requested.count,
2 * requested_calls.capacity);
requested_calls.calls =
gpr_realloc(requested_calls.calls, sizeof(*requested_calls.calls) *
requested_calls.capacity);
while (rm->requests != NULL) {
requested_call *c = rm->requests;
rm->requests = c->next;
c->next = requests;
requests = c;
}
memcpy(requested_calls.calls + requested_calls.count, rm->requested.calls,
sizeof(*requested_calls.calls) * rm->requested.count);
requested_calls.count += rm->requested.count;
gpr_free(rm->requested.calls);
memset(&rm->requested, 0, sizeof(rm->requested));
}
gpr_mu_unlock(&server->mu_call);
@ -973,10 +971,11 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
gpr_mu_unlock(&server->mu_global);
/* terminate all the requested calls */
for (i = 0; i < requested_calls.count; i++) {
fail_call(server, &requested_calls.calls[i]);
while (requests != NULL) {
requested_call *next = requests->next;
fail_call(server, requests);
requests = next;
}
gpr_free(requested_calls.calls);
/* Shutdown listeners */
for (l = server->listeners; l; l = l->next) {
@ -1038,7 +1037,7 @@ void grpc_server_add_listener(grpc_server *server, void *arg,
static grpc_call_error queue_call_request(grpc_server *server,
requested_call *rc) {
call_data *calld = NULL;
requested_call_array *requested_calls = NULL;
requested_call **requests = NULL;
gpr_mu_lock(&server->mu_call);
if (server->shutdown) {
gpr_mu_unlock(&server->mu_call);
@ -1049,12 +1048,12 @@ static grpc_call_error queue_call_request(grpc_server *server,
case BATCH_CALL:
calld =
call_list_remove_head(&server->lists[PENDING_START], PENDING_START);
requested_calls = &server->requested_calls;
requests = &server->requests;
break;
case REGISTERED_CALL:
calld = call_list_remove_head(
&rc->data.registered.registered_method->pending, PENDING_START);
requested_calls = &rc->data.registered.registered_method->requested;
requests = &rc->data.registered.registered_method->requests;
break;
}
if (calld != NULL) {
@ -1066,7 +1065,8 @@ static grpc_call_error queue_call_request(grpc_server *server,
begin_call(server, calld, rc);
return GRPC_CALL_OK;
} else {
*requested_call_array_add(requested_calls) = *rc;
rc->next = *requests;
*requests = rc;
gpr_mu_unlock(&server->mu_call);
return GRPC_CALL_OK;
}
@ -1077,22 +1077,23 @@ grpc_call_error grpc_server_request_call(
grpc_metadata_array *initial_metadata,
grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification, void *tag) {
requested_call rc;
requested_call *rc = gpr_malloc(sizeof(*rc));
GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details,
initial_metadata, cq_bound_to_call,
cq_for_notification, tag);
if (!grpc_cq_is_server_cq(cq_for_notification)) {
gpr_free(rc);
return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
}
grpc_cq_begin_op(cq_for_notification, NULL);
rc.type = BATCH_CALL;
rc.tag = tag;
rc.cq_bound_to_call = cq_bound_to_call;
rc.cq_for_notification = cq_for_notification;
rc.call = call;
rc.data.batch.details = details;
rc.data.batch.initial_metadata = initial_metadata;
return queue_call_request(server, &rc);
grpc_cq_begin_op(cq_for_notification);
rc->type = BATCH_CALL;
rc->tag = tag;
rc->cq_bound_to_call = cq_bound_to_call;
rc->cq_for_notification = cq_for_notification;
rc->call = call;
rc->data.batch.details = details;
rc->data.batch.initial_metadata = initial_metadata;
return queue_call_request(server, rc);
}
grpc_call_error grpc_server_request_registered_call(
@ -1100,22 +1101,23 @@ grpc_call_error grpc_server_request_registered_call(
grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload,
grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification, void *tag) {
requested_call rc;
requested_call *rc = gpr_malloc(sizeof(*rc));
registered_method *registered_method = rm;
if (!grpc_cq_is_server_cq(cq_for_notification)) {
gpr_free(rc);
return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
}
grpc_cq_begin_op(cq_for_notification, NULL);
rc.type = REGISTERED_CALL;
rc.tag = tag;
rc.cq_bound_to_call = cq_bound_to_call;
rc.cq_for_notification = cq_for_notification;
rc.call = call;
rc.data.registered.registered_method = registered_method;
rc.data.registered.deadline = deadline;
rc.data.registered.initial_metadata = initial_metadata;
rc.data.registered.optional_payload = optional_payload;
return queue_call_request(server, &rc);
grpc_cq_begin_op(cq_for_notification);
rc->type = REGISTERED_CALL;
rc->tag = tag;
rc->cq_bound_to_call = cq_bound_to_call;
rc->cq_for_notification = cq_for_notification;
rc->call = call;
rc->data.registered.registered_method = registered_method;
rc->data.registered.deadline = deadline;
rc->data.registered.initial_metadata = initial_metadata;
rc->data.registered.optional_payload = optional_payload;
return queue_call_request(server, rc);
}
static void publish_registered_or_batch(grpc_call *call, int success,
@ -1182,8 +1184,11 @@ static void begin_call(grpc_server *server, call_data *calld,
}
GRPC_CALL_INTERNAL_REF(calld->call, "server");
grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish,
rc->tag);
grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc);
}
static void done_request_event(void *req, grpc_cq_completion *c) {
gpr_free(req);
}
static void fail_call(grpc_server *server, requested_call *rc) {
@ -1196,15 +1201,19 @@ static void fail_call(grpc_server *server, requested_call *rc) {
rc->data.registered.initial_metadata->count = 0;
break;
}
grpc_cq_end_op(rc->cq_for_notification, rc->tag, NULL, 0);
grpc_cq_end_op(rc->cq_for_notification, rc->tag, 0, done_request_event, rc,
&rc->completion);
}
static void publish_registered_or_batch(grpc_call *call, int success,
void *tag) {
void *prc) {
grpc_call_element *elem =
grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
requested_call *rc = prc;
call_data *calld = elem->call_data;
grpc_cq_end_op(calld->cq_new, tag, call, success);
grpc_cq_end_op(calld->cq_new, rc->tag, success, done_request_event, rc,
&rc->completion);
GRPC_CALL_INTERNAL_UNREF(call, "server", 0);
}
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {

@ -0,0 +1,41 @@
/*
*
* 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.
*
*/
/* This file is autogenerated from:
templates/src/core/surface/version.c.template */
#include <grpc/grpc.h>
const char *grpc_version_string(void) {
return "0.10.0.0";
}

@ -205,7 +205,8 @@ void grpc_chttp2_publish_reads(
}
if (stream_parsing->saw_rst_stream) {
stream_global->cancelled = 1;
stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(stream_parsing->rst_stream_reason);
stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(
stream_parsing->rst_stream_reason);
if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) {
stream_global->published_cancelled = 1;
}
@ -599,7 +600,7 @@ static void on_header(void *tp, grpc_mdelem *md) {
}
grpc_chttp2_incoming_metadata_buffer_set_deadline(
&stream_parsing->incoming_metadata,
gpr_time_add(gpr_now(), *cached_timeout));
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), *cached_timeout));
GRPC_MDELEM_UNREF(md);
} else {
grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata,

@ -437,7 +437,8 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
framer_state *st) {
char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
grpc_mdelem *mdelem;
grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
grpc_chttp2_encode_timeout(
gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME)), 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));

@ -876,11 +876,19 @@ static void update_global_window(void *args, gpr_uint32 id, void *stream) {
grpc_chttp2_stream *s = stream;
grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_stream_global *stream_global = &s->global;
int was_zero;
int is_zero;
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global,
outgoing_window,
t->parsing.initial_window_update);
was_zero = stream_global->outgoing_window <= 0;
stream_global->outgoing_window += t->parsing.initial_window_update;
is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
}
}
static void read_error_locked(grpc_chttp2_transport *t) {

@ -87,6 +87,7 @@ typedef struct internal_metadata {
gpr_atm refcnt;
/* private only data */
gpr_mu mu_user_data;
void *user_data;
void (*destroy_user_data)(void *user_data);
@ -183,7 +184,7 @@ 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_now().tv_nsec);
return grpc_mdctx_create_with_seed(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
}
static void discard_metadata(grpc_mdctx *ctx) {
@ -200,6 +201,7 @@ static void discard_metadata(grpc_mdctx *ctx) {
if (cur->user_data) {
cur->destroy_user_data(cur->user_data);
}
gpr_mu_destroy(&cur->mu_user_data);
gpr_free(cur);
cur = next;
ctx->mdtab_free--;
@ -467,6 +469,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
md->user_data = NULL;
md->destroy_user_data = NULL;
md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
gpr_mu_init(&md->mu_user_data);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md,
gpr_atm_no_barrier_load(&md->refcnt),
@ -581,18 +584,29 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) {
void *grpc_mdelem_get_user_data(grpc_mdelem *md,
void (*if_destroy_func)(void *)) {
internal_metadata *im = (internal_metadata *)md;
return im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
void *result;
gpr_mu_lock(&im->mu_user_data);
result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
gpr_mu_unlock(&im->mu_user_data);
return result;
}
void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
void *user_data) {
internal_metadata *im = (internal_metadata *)md;
GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
gpr_mu_lock(&im->mu_user_data);
if (im->destroy_user_data) {
im->destroy_user_data(im->user_data);
/* user data can only be set once */
gpr_mu_unlock(&im->mu_user_data);
if (destroy_func != NULL) {
destroy_func(user_data);
}
return;
}
im->destroy_user_data = destroy_func;
im->user_data = user_data;
gpr_mu_unlock(&im->mu_user_data);
}
gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {

@ -39,6 +39,7 @@
#include <grpc++/time.h>
#include "src/core/channel/compress_filter.h"
#include "src/cpp/common/create_auth_context.h"
namespace grpc {
@ -96,6 +97,13 @@ void ClientContext::set_compression_algorithm(
AddMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
}
std::shared_ptr<const AuthContext> ClientContext::auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = CreateAuthContext(call_);
}
return auth_context_;
}
void ClientContext::TryCancel() {
if (call_) {
grpc_call_cancel(call_);

@ -0,0 +1,42 @@
/*
*
* 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 <memory>
#include <grpc/grpc.h>
#include <grpc++/auth_context.h>
namespace grpc {
std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call);
} // namespace grpc

@ -0,0 +1,45 @@
/*
*
* 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 <memory>
#include <grpc/grpc.h>
#include <grpc++/auth_context.h>
namespace grpc {
std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call) {
(void)call;
return std::shared_ptr<const AuthContext>();
}
} // namespace grpc

@ -0,0 +1,80 @@
/*
*
* 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/cpp/common/secure_auth_context.h"
#include <grpc/grpc_security.h>
namespace grpc {
SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx) : ctx_(ctx) {}
SecureAuthContext::~SecureAuthContext() { grpc_auth_context_release(ctx_); }
std::vector<grpc::string> SecureAuthContext::GetPeerIdentity() const {
if (!ctx_) {
return std::vector<grpc::string>();
}
grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_);
std::vector<grpc::string> identity;
const grpc_auth_property* property = nullptr;
while ((property = grpc_auth_property_iterator_next(&iter))) {
identity.push_back(grpc::string(property->value, property->value_length));
}
return identity;
}
grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const {
if (!ctx_) {
return "";
}
const char* name = grpc_auth_context_peer_identity_property_name(ctx_);
return name == nullptr ? "" : name;
}
std::vector<grpc::string> SecureAuthContext::FindPropertyValues(
const grpc::string& name) const {
if (!ctx_) {
return std::vector<grpc::string>();
}
grpc_auth_property_iterator iter =
grpc_auth_context_find_properties_by_name(ctx_, name.c_str());
const grpc_auth_property* property = nullptr;
std::vector<grpc::string> values;
while ((property = grpc_auth_property_iterator_next(&iter))) {
values.push_back(grpc::string(property->value, property->value_length));
}
return values;
}
} // namespace grpc

@ -0,0 +1,62 @@
/*
*
* 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_CPP_COMMON_SECURE_AUTH_CONTEXT_H
#define GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
#include <grpc++/auth_context.h>
struct grpc_auth_context;
namespace grpc {
class SecureAuthContext GRPC_FINAL : public AuthContext {
public:
SecureAuthContext(grpc_auth_context* ctx);
~SecureAuthContext() GRPC_OVERRIDE;
std::vector<grpc::string> GetPeerIdentity() const GRPC_OVERRIDE;
grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE;
std::vector<grpc::string> FindPropertyValues(const grpc::string& name) const
GRPC_OVERRIDE;
private:
grpc_auth_context* ctx_;
};
} // namespace grpc
#endif // GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H

@ -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.
*
*/
#include <memory>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc++/auth_context.h>
#include "src/cpp/common/secure_auth_context.h"
namespace grpc {
std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call) {
if (call == nullptr) {
return std::shared_ptr<const AuthContext>();
}
return std::shared_ptr<const AuthContext>(
new SecureAuthContext(grpc_call_auth_context(call)));
}
} // namespace grpc

@ -1,99 +0,0 @@
/*
*
* 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++/async_server_context.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include "src/cpp/proto/proto_utils.h"
#include <grpc++/config.h>
#include <grpc++/status.h>
namespace grpc {
AsyncServerContext::AsyncServerContext(
grpc_call* call, const grpc::string& method, const grpc::string& host,
system_clock::time_point absolute_deadline)
: method_(method),
host_(host),
absolute_deadline_(absolute_deadline),
request_(nullptr),
call_(call) {}
AsyncServerContext::~AsyncServerContext() { grpc_call_destroy(call_); }
void AsyncServerContext::Accept(grpc_completion_queue* cq) {
GPR_ASSERT(grpc_call_server_accept_old(call_, cq, this) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_server_end_initial_metadata_old(
call_, GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
}
bool AsyncServerContext::StartRead(grpc::protobuf::Message* request) {
GPR_ASSERT(request);
request_ = request;
grpc_call_error err = grpc_call_start_read_old(call_, this);
return err == GRPC_CALL_OK;
}
bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response,
int flags) {
grpc_byte_buffer* buffer = nullptr;
GRPC_TIMER_MARK(SER_PROTO_BEGIN, call_->call());
if (!SerializeProto(response, &buffer)) {
return false;
}
GRPC_TIMER_MARK(SER_PROTO_END, call_->call());
grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags);
grpc_byte_buffer_destroy(buffer);
return err == GRPC_CALL_OK;
}
bool AsyncServerContext::StartWriteStatus(const Status& status) {
grpc_call_error err = grpc_call_start_write_status_old(
call_, static_cast<grpc_status_code>(status.code()),
status.details().empty() ? nullptr
: const_cast<char*>(status.details().c_str()),
this);
return err == GRPC_CALL_OK;
}
bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
GPR_ASSERT(request_);
GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_->call());
bool success = DeserializeProto(read_buffer, request_);
GRPC_TIMER_MARK(DESER_PROTO_END, call_->call());
request_ = nullptr;
return success;
}
} // namespace grpc

@ -118,7 +118,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
has_request_payload_(mrd->has_request_payload_),
request_payload_(mrd->request_payload_),
method_(mrd->method_) {
ctx_.call_ = mrd->call_;
ctx_.set_call(mrd->call_);
ctx_.cq_ = &cq_;
GPR_ASSERT(mrd->in_flight_);
mrd->in_flight_ = false;
@ -326,7 +326,7 @@ bool Server::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) {
}
}
grpc_metadata_array_destroy(&initial_metadata_array_);
context_->call_ = call_;
context_->set_call(call_);
context_->cq_ = call_cq_;
Call call(call_, server_, call_cq_, server_->max_message_size_);
if (*status && call_) {

@ -40,6 +40,7 @@
#include <grpc++/time.h>
#include "src/core/channel/compress_filter.h"
#include "src/cpp/common/create_auth_context.h"
namespace grpc {
@ -166,4 +167,16 @@ void ServerContext::set_compression_algorithm(
AddInitialMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
}
void ServerContext::set_call(grpc_call* call) {
call_ = call;
auth_context_ = CreateAuthContext(call);
}
std::shared_ptr<const AuthContext> ServerContext::auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = CreateAuthContext(call_);
}
return auth_context_;
}
} // namespace grpc

@ -68,6 +68,9 @@
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GoogleCredential.cs" />
<Compile Include="OAuth2InterceptorFactory.cs" />
@ -81,6 +84,7 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="Grpc.Auth.nuspec" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />

@ -5,19 +5,19 @@
<title>gRPC C# Auth</title>
<summary>Auth library for C# implementation of gRPC - an RPC library and framework</summary>
<description>Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
<version>0.5.1</version>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
<releaseNotes>Release $version$ of gRPC C#</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
<dependencies>
<dependency id="BouncyCastle" version="1.7.0" />
<dependency id="Google.Apis.Auth" version="1.9.1" />
<dependency id="Grpc.Core" version="0.5.1" />
<dependency id="Grpc.Core" version="$version$" />
</dependencies>
</metadata>
<files>

@ -9,6 +9,5 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("0.5.*")]
[assembly: InternalsVisibleTo("Grpc.Auth.Tests")]

@ -73,12 +73,6 @@ namespace Grpc.Core.Tests
Server server;
Channel channel;
[TestFixtureSetUp]
public void InitClass()
{
GrpcEnvironment.Initialize();
}
[SetUp]
public void Init()
{

@ -37,6 +37,9 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ClientServerTest.cs" />
<Compile Include="ServerTest.cs" />
@ -63,4 +66,4 @@
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup />
</Project>
</Project>

@ -43,16 +43,17 @@ namespace Grpc.Core.Tests
[Test]
public void InitializeAndShutdownGrpcEnvironment()
{
GrpcEnvironment.Initialize();
Assert.IsNotNull(GrpcEnvironment.ThreadPool.CompletionQueue);
var env = GrpcEnvironment.GetInstance();
Assert.IsNotNull(env.CompletionQueue);
GrpcEnvironment.Shutdown();
}
[Test]
public void SubsequentInvocations()
{
GrpcEnvironment.Initialize();
GrpcEnvironment.Initialize();
var env1 = GrpcEnvironment.GetInstance();
var env2 = GrpcEnvironment.GetInstance();
Assert.IsTrue(object.ReferenceEquals(env1, env2));
GrpcEnvironment.Shutdown();
GrpcEnvironment.Shutdown();
}
@ -60,15 +61,13 @@ namespace Grpc.Core.Tests
[Test]
public void InitializeAfterShutdown()
{
GrpcEnvironment.Initialize();
var tp1 = GrpcEnvironment.ThreadPool;
var env1 = GrpcEnvironment.GetInstance();
GrpcEnvironment.Shutdown();
GrpcEnvironment.Initialize();
var tp2 = GrpcEnvironment.ThreadPool;
var env2 = GrpcEnvironment.GetInstance();
GrpcEnvironment.Shutdown();
Assert.IsFalse(object.ReferenceEquals(tp1, tp2));
Assert.IsFalse(object.ReferenceEquals(env1, env2));
}
}
}

@ -53,18 +53,6 @@ namespace Grpc.Core.Tests
[DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
[TestFixtureSetUp]
public void Init()
{
GrpcEnvironment.Initialize();
}
[TestFixtureTearDown]
public void Cleanup()
{
GrpcEnvironment.Shutdown();
}
/// <summary>
/// (~1.26us .NET Windows)
/// </summary>

@ -9,4 +9,3 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("0.5.*")]

@ -44,13 +44,10 @@ namespace Grpc.Core.Tests
[Test]
public void StartAndShutdownServer()
{
GrpcEnvironment.Initialize();
Server server = new Server();
server.AddListeningPort("localhost", Server.PickUnusedPort);
server.Start();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
}

@ -58,7 +58,7 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers);
RegisterCancellationCallback(asyncCall, token);
return await asyncResult;
@ -69,7 +69,7 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
asyncCall.StartServerStreamingCall(req, call.Headers);
RegisterCancellationCallback(asyncCall, token);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
@ -81,7 +81,7 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers);
RegisterCancellationCallback(asyncCall, token);
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@ -93,7 +93,7 @@ namespace Grpc.Core
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
asyncCall.StartDuplexStreamingCall(call.Headers);
RegisterCancellationCallback(asyncCall, token);
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@ -108,13 +108,5 @@ namespace Grpc.Core
token.Register(() => asyncCall.Cancel());
}
}
/// <summary>
/// Gets shared completion queue used for async calls.
/// </summary>
private static CompletionQueueSafeHandle GetCompletionQueue()
{
return GrpcEnvironment.ThreadPool.CompletionQueue;
}
}
}

@ -42,8 +42,10 @@ namespace Grpc.Core
/// </summary>
public class Channel : IDisposable
{
readonly GrpcEnvironment environment;
readonly ChannelSafeHandle handle;
readonly string target;
bool disposed;
/// <summary>
/// Creates a channel that connects to a specific host.
@ -54,6 +56,7 @@ namespace Grpc.Core
/// <param name="options">Channel options.</param>
public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
{
this.environment = GrpcEnvironment.GetInstance();
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options))
{
if (credentials != null)
@ -105,10 +108,35 @@ namespace Grpc.Core
}
}
internal CompletionQueueSafeHandle CompletionQueue
{
get
{
return this.environment.CompletionQueue;
}
}
internal CompletionRegistry CompletionRegistry
{
get
{
return this.environment.CompletionRegistry;
}
}
internal GrpcEnvironment Environment
{
get
{
return this.environment;
}
}
protected virtual void Dispose(bool disposing)
{
if (handle != null && !handle.IsInvalid)
if (disposing && handle != null && !disposed)
{
disposed = true;
handle.Dispose();
}
}

@ -33,8 +33,9 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable">
<HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
<Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
@ -48,6 +49,7 @@
<Compile Include="IAsyncStreamWriter.cs" />
<Compile Include="IAsyncStreamReader.cs" />
<Compile Include="Internal\GrpcLog.cs" />
<Compile Include="Version.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RpcException.cs" />
<Compile Include="Calls.cs" />
@ -103,6 +105,7 @@
<Compile Include="ChannelOptions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />
<None Include="packages.config" />
</ItemGroup>
<Choose>
@ -130,4 +133,4 @@
</Target>
<Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
<Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
</Project>
</Project>

@ -5,19 +5,19 @@
<title>gRPC C# Core</title>
<summary>Core C# implementation of gRPC - an RPC library and framework</summary>
<description>Core C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
<version>0.5.1</version>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
<releaseNotes>Release $version$ of gRPC C#</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="Microsoft.Bcl.Immutable" version="1.0.34" />
<dependency id="System.Collections.Immutable" version="1.1.36" />
<dependency id="Ix-Async" version="1.2.3" />
<dependency id="grpc.native.csharp_ext" version="0.9.1" />
<dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
</dependencies>
</metadata>
<files>

@ -33,7 +33,9 @@
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
@ -51,20 +53,18 @@ namespace Grpc.Core
static extern void grpcsharp_shutdown();
static object staticLock = new object();
static volatile GrpcEnvironment instance;
static GrpcEnvironment instance;
readonly GrpcThreadPool threadPool;
readonly CompletionRegistry completionRegistry;
readonly DebugStats debugStats = new DebugStats();
bool isClosed;
/// <summary>
/// Makes sure GRPC environment is initialized. Subsequent invocations don't have any
/// effect unless you call Shutdown first.
/// Although normal use cases assume you will call this just once in your application's
/// lifetime (and call Shutdown once you're done), for the sake of easier testing it's
/// allowed to initialize the environment again after it has been successfully shutdown.
/// Returns an instance of initialized gRPC environment.
/// Subsequent invocations return the same instance unless Shutdown has been called first.
/// </summary>
public static void Initialize()
internal static GrpcEnvironment GetInstance()
{
lock (staticLock)
{
@ -72,12 +72,13 @@ namespace Grpc.Core
{
instance = new GrpcEnvironment();
}
return instance;
}
}
/// <summary>
/// Shuts down the GRPC environment if it was initialized before.
/// Repeated invocations have no effect.
/// Shuts down the gRPC environment if it was initialized before.
/// Blocks until the environment has been fully shutdown.
/// </summary>
public static void Shutdown()
{
@ -87,50 +88,55 @@ namespace Grpc.Core
{
instance.Close();
instance = null;
CheckDebugStats();
}
}
}
internal static GrpcThreadPool ThreadPool
/// <summary>
/// Creates gRPC environment.
/// </summary>
private GrpcEnvironment()
{
GrpcLog.RedirectNativeLogs(Console.Error);
grpcsharp_init();
completionRegistry = new CompletionRegistry(this);
threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
threadPool.Start();
// TODO: use proper logging here
Console.WriteLine("GRPC initialized.");
}
/// <summary>
/// Gets the completion registry used by this gRPC environment.
/// </summary>
internal CompletionRegistry CompletionRegistry
{
get
{
var inst = instance;
if (inst == null)
{
throw new InvalidOperationException("GRPC environment not initialized");
}
return inst.threadPool;
return this.completionRegistry;
}
}
internal static CompletionRegistry CompletionRegistry
/// <summary>
/// Gets the completion queue used by this gRPC environment.
/// </summary>
internal CompletionQueueSafeHandle CompletionQueue
{
get
{
var inst = instance;
if (inst == null)
{
throw new InvalidOperationException("GRPC environment not initialized");
}
return inst.completionRegistry;
return this.threadPool.CompletionQueue;
}
}
/// <summary>
/// Creates gRPC environment.
/// Gets the completion queue used by this gRPC environment.
/// </summary>
private GrpcEnvironment()
internal DebugStats DebugStats
{
GrpcLog.RedirectNativeLogs(Console.Error);
grpcsharp_init();
completionRegistry = new CompletionRegistry();
threadPool = new GrpcThreadPool(THREAD_POOL_SIZE);
threadPool.Start();
// TODO: use proper logging here
Console.WriteLine("GRPC initialized.");
get
{
return this.debugStats;
}
}
/// <summary>
@ -146,32 +152,28 @@ namespace Grpc.Core
grpcsharp_shutdown();
isClosed = true;
debugStats.CheckOK();
// TODO: use proper logging here
Console.WriteLine("GRPC shutdown.");
}
private static void CheckDebugStats()
/// <summary>
/// Shuts down this environment asynchronously.
/// </summary>
private Task CloseAsync()
{
var remainingClientCalls = DebugStats.ActiveClientCalls.Count;
if (remainingClientCalls != 0)
{
DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
}
var remainingServerCalls = DebugStats.ActiveServerCalls.Count;
if (remainingServerCalls != 0)
{
DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
}
var pendingBatchCompletions = DebugStats.PendingBatchCompletions.Count;
if (pendingBatchCompletions != 0)
return Task.Run(() =>
{
DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
}
}
private static void DebugWarning(string message)
{
throw new Exception("Shutdown check: " + message);
try
{
Close();
}
catch (Exception e)
{
Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e);
}
});
}
}
}

@ -47,6 +47,8 @@ namespace Grpc.Core.Internal
/// </summary>
internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
{
Channel channel;
// Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs;
@ -61,8 +63,9 @@ namespace Grpc.Core.Internal
public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
{
var call = CallSafeHandle.Create(channel.Handle, cq, methodName, channel.Target, Timespec.InfFuture);
DebugStats.ActiveClientCalls.Increment();
this.channel = channel;
var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture);
channel.Environment.DebugStats.ActiveClientCalls.Increment();
InitializeInternal(call);
}
@ -277,7 +280,7 @@ namespace Grpc.Core.Internal
protected override void OnReleaseResources()
{
DebugStats.ActiveClientCalls.Decrement();
channel.Environment.DebugStats.ActiveClientCalls.Decrement();
}
/// <summary>

@ -48,14 +48,17 @@ namespace Grpc.Core.Internal
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
{
readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
readonly GrpcEnvironment environment;
public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer) : base(serializer, deserializer)
public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
{
this.environment = Preconditions.CheckNotNull(environment);
}
public void Initialize(CallSafeHandle call)
{
DebugStats.ActiveServerCalls.Increment();
call.SetCompletionRegistry(environment.CompletionRegistry);
environment.DebugStats.ActiveServerCalls.Increment();
InitializeInternal(call);
}
@ -114,7 +117,7 @@ namespace Grpc.Core.Internal
protected override void OnReleaseResources()
{
DebugStats.ActiveServerCalls.Decrement();
environment.DebugStats.ActiveServerCalls.Decrement();
}
/// <summary>

@ -43,6 +43,7 @@ namespace Grpc.Core.Internal
internal class CallSafeHandle : SafeHandleZeroIsInvalid
{
const uint GRPC_WRITE_BUFFER_HINT = 1;
CompletionRegistry completionRegistry;
[DllImport("grpc_csharp_ext.dll")]
static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
@ -97,15 +98,22 @@ namespace Grpc.Core.Internal
{
}
public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
{
return grpcsharp_channel_create_call(channel, cq, method, host, deadline);
var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline);
result.SetCompletionRegistry(registry);
return result;
}
public void SetCompletionRegistry(CompletionRegistry completionRegistry)
{
this.completionRegistry = completionRegistry;
}
public void StartUnary(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray)
.CheckOk();
}
@ -119,56 +127,56 @@ namespace Grpc.Core.Internal
public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
}
public void StartServerStreaming(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray).CheckOk();
}
public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
}
public void StartSendMessage(byte[] payload, BatchCompletionDelegate callback)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length)).CheckOk();
}
public void StartSendCloseFromClient(BatchCompletionDelegate callback)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
}
public void StartSendStatusFromServer(Status status, BatchCompletionDelegate callback)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail).CheckOk();
}
public void StartReceiveMessage(BatchCompletionDelegate callback)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_recv_message(this, ctx).CheckOk();
}
public void StartServerSide(BatchCompletionDelegate callback)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
completionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_call_start_serverside(this, ctx).CheckOk();
}

@ -45,11 +45,17 @@ namespace Grpc.Core.Internal
internal class CompletionRegistry
{
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
readonly GrpcEnvironment environment;
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
public CompletionRegistry(GrpcEnvironment environment)
{
this.environment = environment;
}
public void Register(IntPtr key, OpCompletionDelegate callback)
{
DebugStats.PendingBatchCompletions.Increment();
environment.DebugStats.PendingBatchCompletions.Increment();
Preconditions.CheckState(dict.TryAdd(key, callback));
}
@ -63,7 +69,7 @@ namespace Grpc.Core.Internal
{
OpCompletionDelegate value;
Preconditions.CheckState(dict.TryRemove(key, out value));
DebugStats.PendingBatchCompletions.Decrement();
environment.DebugStats.PendingBatchCompletions.Decrement();
return value;
}

@ -36,12 +36,39 @@ using System.Threading;
namespace Grpc.Core.Internal
{
internal static class DebugStats
internal class DebugStats
{
public static readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
public readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
public static readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
public readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
public static readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
public readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
/// <summary>
/// Checks the debug stats and take action for any inconsistency found.
/// </summary>
public void CheckOK()
{
var remainingClientCalls = ActiveClientCalls.Count;
if (remainingClientCalls != 0)
{
DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
}
var remainingServerCalls = ActiveServerCalls.Count;
if (remainingServerCalls != 0)
{
DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
}
var pendingBatchCompletions = PendingBatchCompletions.Count;
if (pendingBatchCompletions != 0)
{
DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
}
}
private void DebugWarning(string message)
{
throw new Exception("Shutdown check: " + message);
}
}
}

@ -45,14 +45,16 @@ namespace Grpc.Core.Internal
/// </summary>
internal class GrpcThreadPool
{
readonly GrpcEnvironment environment;
readonly object myLock = new object();
readonly List<Thread> threads = new List<Thread>();
readonly int poolSize;
CompletionQueueSafeHandle cq;
public GrpcThreadPool(int poolSize)
public GrpcThreadPool(GrpcEnvironment environment, int poolSize)
{
this.environment = environment;
this.poolSize = poolSize;
}
@ -80,7 +82,7 @@ namespace Grpc.Core.Internal
{
cq.Shutdown();
Console.WriteLine("Waiting for GPRC threads to finish.");
Console.WriteLine("Waiting for GRPC threads to finish.");
foreach (var thread in threads)
{
thread.Join();
@ -122,7 +124,7 @@ namespace Grpc.Core.Internal
IntPtr tag = ev.tag;
try
{
var callback = GrpcEnvironment.CompletionRegistry.Extract(tag);
var callback = environment.CompletionRegistry.Extract(tag);
callback(success);
}
catch (Exception e)

@ -42,7 +42,7 @@ namespace Grpc.Core.Internal
{
internal interface IServerCallHandler
{
Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq);
Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment);
}
internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@ -58,11 +58,12 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer);
method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync();
@ -110,11 +111,12 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer);
method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync();
@ -163,11 +165,12 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer);
method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync();
@ -219,11 +222,12 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer);
method.RequestMarshaller.Deserializer,
environment);
asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync();
@ -255,11 +259,11 @@ namespace Grpc.Core.Internal
internal class NoSuchMethodCallHandler : IServerCallHandler
{
public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
{
// We don't care about the payload type here.
var asyncCall = new AsyncCallServer<byte[], byte[]>(
(payload) => payload, (payload) => payload);
(payload) => payload, (payload) => payload, environment);
asyncCall.Initialize(call);
var finishedTask = asyncCall.ServerSideCallAsync();

@ -91,19 +91,19 @@ namespace Grpc.Core.Internal
{
grpcsharp_server_start(this);
}
public void ShutdownAndNotify(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
public void ShutdownAndNotify(BatchCompletionDelegate callback, GrpcEnvironment environment)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_server_shutdown_and_notify_callback(this, cq, ctx);
environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_server_shutdown_and_notify_callback(this, environment.CompletionQueue, ctx);
}
public void RequestCall(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
public void RequestCall(BatchCompletionDelegate callback, GrpcEnvironment environment)
{
var ctx = BatchContextSafeHandle.Create();
GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_server_request_call(this, cq, ctx).CheckOk();
environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
grpcsharp_server_request_call(this, environment.CompletionQueue, ctx).CheckOk();
}
protected override bool ReleaseHandle()

@ -9,6 +9,5 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("0.5.*")]
[assembly: InternalsVisibleTo("Grpc.Core.Tests")]

@ -52,6 +52,7 @@ namespace Grpc.Core
/// </summary>
public const int PickUnusedPort = 0;
readonly GrpcEnvironment environment;
readonly ServerSafeHandle handle;
readonly object myLock = new object();
@ -67,9 +68,10 @@ namespace Grpc.Core
/// <param name="options">Channel options.</param>
public Server(IEnumerable<ChannelOption> options = null)
{
this.environment = GrpcEnvironment.GetInstance();
using (var channelArgs = ChannelOptions.CreateChannelArgs(options))
{
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), channelArgs);
this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
}
}
@ -144,7 +146,7 @@ namespace Grpc.Core
shutdownRequested = true;
}
handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
handle.ShutdownAndNotify(HandleServerShutdown, environment);
await shutdownTcs.Task;
handle.Dispose();
}
@ -173,7 +175,7 @@ namespace Grpc.Core
shutdownRequested = true;
}
handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
handle.ShutdownAndNotify(HandleServerShutdown, environment);
handle.CancelAllCalls();
await shutdownTcs.Task;
handle.Dispose();
@ -208,7 +210,7 @@ namespace Grpc.Core
{
if (!shutdownRequested)
{
handle.RequestCall(GetCompletionQueue(), HandleNewServerRpc);
handle.RequestCall(HandleNewServerRpc, environment);
}
}
}
@ -225,7 +227,7 @@ namespace Grpc.Core
{
callHandler = new NoSuchMethodCallHandler();
}
await callHandler.HandleCall(method, call, GetCompletionQueue());
await callHandler.HandleCall(method, call, environment);
}
catch (Exception e)
{
@ -259,10 +261,5 @@ namespace Grpc.Core
{
shutdownTcs.SetResult(null);
}
private static CompletionQueueSafeHandle GetCompletionQueue()
{
return GrpcEnvironment.ThreadPool.CompletionQueue;
}
}
}

@ -0,0 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// The current version of gRPC C#.
[assembly: AssemblyVersion("0.6.0.*")]

@ -3,5 +3,5 @@
<package id="grpc.dependencies.openssl.redist" version="1.0.2.2" targetFramework="net45" />
<package id="grpc.dependencies.zlib.redist" version="1.2.8.9" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
</packages>

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?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>
@ -35,6 +35,9 @@
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MathClient.cs" />
</ItemGroup>
@ -49,4 +52,4 @@
<Name>Grpc.Examples</Name>
</ProjectReference>
</ItemGroup>
</Project>
</Project>

@ -39,8 +39,6 @@ namespace math
{
public static void Main(string[] args)
{
GrpcEnvironment.Initialize();
using (Channel channel = new Channel("127.0.0.1", 23456))
{
Math.IMathClient stub = new Math.MathClient(channel);

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

Loading…
Cancel
Save