Merge branch 'master' into poisson

pull/1948/head
vjpai 10 years ago
commit afc3ee89ee
  1. 40
      BUILD
  2. 350
      Makefile
  3. 177
      build.json
  4. 25
      gRPC.podspec
  5. 6
      include/grpc++/impl/sync_no_cxx11.h
  6. 4
      include/grpc++/impl/thd_no_cxx11.h
  7. 4
      include/grpc++/server_context.h
  8. 95
      include/grpc/census.h
  9. 12
      include/grpc/grpc.h
  10. 71
      src/core/census/README.md
  11. 32
      src/core/census/context.c
  12. 26
      src/core/census/context.h
  13. 24
      src/core/census/grpc_context.c
  14. 12
      src/core/census/grpc_context.h
  15. 29
      src/core/census/initialize.c
  16. 11
      src/core/channel/child_channel.c
  17. 3
      src/core/iomgr/endpoint_pair.h
  18. 17
      src/core/iomgr/endpoint_pair_posix.c
  19. 6
      src/core/iomgr/endpoint_pair_windows.c
  20. 60
      src/core/iomgr/fd_posix.c
  21. 16
      src/core/iomgr/fd_posix.h
  22. 125
      src/core/iomgr/iomgr.c
  23. 37
      src/core/iomgr/iomgr.h
  24. 14
      src/core/iomgr/iomgr_internal.h
  25. 7
      src/core/iomgr/pollset_posix.c
  26. 10
      src/core/iomgr/pollset_windows.c
  27. 9
      src/core/iomgr/resolve_address_posix.c
  28. 8
      src/core/iomgr/resolve_address_windows.c
  29. 17
      src/core/iomgr/socket_windows.c
  30. 9
      src/core/iomgr/socket_windows.h
  31. 22
      src/core/iomgr/tcp_client_posix.c
  32. 2
      src/core/iomgr/tcp_client_windows.c
  33. 7
      src/core/iomgr/tcp_posix.c
  34. 23
      src/core/iomgr/tcp_server_posix.c
  35. 5
      src/core/iomgr/tcp_server_windows.c
  36. 12
      src/core/security/credentials.c
  37. 15
      src/core/surface/byte_buffer_reader.c
  38. 43
      src/core/surface/call.c
  39. 5
      src/core/surface/channel.c
  40. 3
      src/core/surface/channel_create.c
  41. 6
      src/core/surface/init.c
  42. 3
      src/core/surface/secure_channel_create.c
  43. 49
      src/core/surface/server.c
  44. 6
      src/core/transport/chttp2/gen_hpack_tables.c
  45. 11
      src/cpp/proto/proto_utils.cc
  46. 5
      src/cpp/server/thread_pool.cc
  47. 2
      src/cpp/server/thread_pool.h
  48. 7
      src/cpp/util/byte_buffer.cc
  49. 4
      src/csharp/.nuget/packages.config
  50. 6
      src/csharp/Grpc.Auth/Grpc.Auth.nuspec
  51. 6
      src/csharp/Grpc.Core/Grpc.Core.nuspec
  52. 4
      src/csharp/Grpc.Tools.nuspec
  53. 6
      src/csharp/Grpc.nuspec
  54. 62
      src/csharp/Grpc.sln
  55. 6
      src/csharp/buildall.bat
  56. 8
      src/csharp/ext/grpc_csharp_ext.c
  57. 6
      src/node/ext/byte_buffer.cc
  58. 13
      src/objective-c/GRPCClient/private/NSData+GRPC.m
  59. 86
      src/objective-c/GRPCClient/private/NSDictionary+GRPC.m
  60. 6
      src/php/ext/grpc/byte_buffer.c
  61. 86
      src/python/src/grpc/_adapter/_c.c
  62. 61
      src/python/src/grpc/_adapter/_c/module.c
  63. 60
      src/python/src/grpc/_adapter/_c/types.c
  64. 271
      src/python/src/grpc/_adapter/_c/types.h
  65. 163
      src/python/src/grpc/_adapter/_c/types/call.c
  66. 134
      src/python/src/grpc/_adapter/_c/types/channel.c
  67. 286
      src/python/src/grpc/_adapter/_c/types/client_credentials.c
  68. 124
      src/python/src/grpc/_adapter/_c/types/completion_queue.c
  69. 183
      src/python/src/grpc/_adapter/_c/types/server.c
  70. 146
      src/python/src/grpc/_adapter/_c/types/server_credentials.c
  71. 461
      src/python/src/grpc/_adapter/_c/utility.c
  72. 188
      src/python/src/grpc/_adapter/_c_test.py
  73. 438
      src/python/src/grpc/_adapter/_call.c
  74. 135
      src/python/src/grpc/_adapter/_channel.c
  75. 121
      src/python/src/grpc/_adapter/_client_credentials.c
  76. 653
      src/python/src/grpc/_adapter/_completion_queue.c
  77. 86
      src/python/src/grpc/_adapter/_datatypes.py
  78. 79
      src/python/src/grpc/_adapter/_error.c
  79. 258
      src/python/src/grpc/_adapter/_intermediary_low.py
  80. 421
      src/python/src/grpc/_adapter/_intermediary_low_test.py
  81. 104
      src/python/src/grpc/_adapter/_low.py
  82. 485
      src/python/src/grpc/_adapter/_low_test.py
  83. 202
      src/python/src/grpc/_adapter/_server.c
  84. 152
      src/python/src/grpc/_adapter/_server_credentials.c
  85. 49
      src/python/src/grpc/_adapter/_server_credentials.h
  86. 65
      src/python/src/grpc/_adapter/_tag.c
  87. 70
      src/python/src/grpc/_adapter/_tag.h
  88. 368
      src/python/src/grpc/_adapter/_types.py
  89. 4
      src/python/src/grpc/_adapter/fore.py
  90. 4
      src/python/src/grpc/_adapter/rear.py
  91. 18
      src/python/src/setup.py
  92. 4
      src/ruby/bin/interop/interop_client.rb
  93. 7
      src/ruby/ext/grpc/rb_byte_buffer.c
  94. 11
      src/ruby/lib/grpc/generic/active_call.rb
  95. 64
      src/ruby/lib/grpc/generic/bidi_call.rb
  96. 4
      templates/Makefile.template
  97. 2
      test/core/bad_client/bad_client.c
  98. 2
      test/core/end2end/fixtures/chttp2_socket_pair.c
  99. 2
      test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c
  100. 2
      test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c
  101. Some files were not shown because too many files have changed in this diff Show More

40
BUILD

@ -143,7 +143,7 @@ cc_library(
"src/core/tsi/ssl_transport_security.h",
"src/core/tsi/transport_security.h",
"src/core/tsi/transport_security_interface.h",
"src/core/channel/census_filter.h",
"src/core/census/grpc_context.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
@ -192,12 +192,6 @@ cc_library(
"src/core/json/json_writer.h",
"src/core/profiling/timers.h",
"src/core/profiling/timers_preciseclock.h",
"src/core/statistics/census_interface.h",
"src/core/statistics/census_log.h",
"src/core/statistics/census_rpc_stats.h",
"src/core/statistics/census_tracing.h",
"src/core/statistics/hash_table.h",
"src/core/statistics/window_stats.h",
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
@ -230,6 +224,7 @@ cc_library(
"src/core/transport/stream_op.h",
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/context.h",
"src/core/httpcli/format_request.c",
"src/core/httpcli/httpcli.c",
"src/core/httpcli/httpcli_security_connector.c",
@ -253,7 +248,7 @@ cc_library(
"src/core/tsi/fake_transport_security.c",
"src/core/tsi/ssl_transport_security.c",
"src/core/tsi/transport_security.c",
"src/core/channel/census_filter.c",
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
@ -305,12 +300,6 @@ cc_library(
"src/core/json/json_writer.c",
"src/core/profiling/basic_timers.c",
"src/core/profiling/stap_timers.c",
"src/core/statistics/census_init.c",
"src/core/statistics/census_log.c",
"src/core/statistics/census_rpc_stats.c",
"src/core/statistics/census_tracing.c",
"src/core/statistics/hash_table.c",
"src/core/statistics/window_stats.c",
"src/core/surface/byte_buffer.c",
"src/core/surface/byte_buffer_queue.c",
"src/core/surface/byte_buffer_reader.c",
@ -350,6 +339,8 @@ cc_library(
"src/core/transport/stream_op.c",
"src/core/transport/transport.c",
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
"src/core/census/initialize.c",
],
hdrs = [
"include/grpc/grpc_security.h",
@ -357,6 +348,7 @@ cc_library(
"include/grpc/byte_buffer_reader.h",
"include/grpc/grpc.h",
"include/grpc/status.h",
"include/grpc/census.h",
],
includes = [
"include",
@ -372,7 +364,7 @@ cc_library(
cc_library(
name = "grpc_unsecure",
srcs = [
"src/core/channel/census_filter.h",
"src/core/census/grpc_context.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
@ -421,12 +413,6 @@ cc_library(
"src/core/json/json_writer.h",
"src/core/profiling/timers.h",
"src/core/profiling/timers_preciseclock.h",
"src/core/statistics/census_interface.h",
"src/core/statistics/census_log.h",
"src/core/statistics/census_rpc_stats.h",
"src/core/statistics/census_tracing.h",
"src/core/statistics/hash_table.h",
"src/core/statistics/window_stats.h",
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
@ -459,8 +445,9 @@ cc_library(
"src/core/transport/stream_op.h",
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/context.h",
"src/core/surface/init_unsecure.c",
"src/core/channel/census_filter.c",
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
@ -512,12 +499,6 @@ cc_library(
"src/core/json/json_writer.c",
"src/core/profiling/basic_timers.c",
"src/core/profiling/stap_timers.c",
"src/core/statistics/census_init.c",
"src/core/statistics/census_log.c",
"src/core/statistics/census_rpc_stats.c",
"src/core/statistics/census_tracing.c",
"src/core/statistics/hash_table.c",
"src/core/statistics/window_stats.c",
"src/core/surface/byte_buffer.c",
"src/core/surface/byte_buffer_queue.c",
"src/core/surface/byte_buffer_reader.c",
@ -557,12 +538,15 @@ cc_library(
"src/core/transport/stream_op.c",
"src/core/transport/transport.c",
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
"src/core/census/initialize.c",
],
hdrs = [
"include/grpc/byte_buffer.h",
"include/grpc/byte_buffer_reader.h",
"include/grpc/grpc.h",
"include/grpc/status.h",
"include/grpc/census.h",
],
includes = [
"include",

File diff suppressed because one or more lines are too long

@ -12,6 +12,19 @@
}
},
"filegroups": [
{
"name": "census",
"public_headers": [
"include/grpc/census.h"
],
"headers": [
"src/core/census/context.h"
],
"src": [
"src/core/census/context.c",
"src/core/census/initialize.c"
]
},
{
"name": "grpc++_base",
"public_headers": [
@ -91,7 +104,7 @@
"include/grpc/status.h"
],
"headers": [
"src/core/channel/census_filter.h",
"src/core/census/grpc_context.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
@ -140,12 +153,6 @@
"src/core/json/json_writer.h",
"src/core/profiling/timers.h",
"src/core/profiling/timers_preciseclock.h",
"src/core/statistics/census_interface.h",
"src/core/statistics/census_log.h",
"src/core/statistics/census_rpc_stats.h",
"src/core/statistics/census_tracing.h",
"src/core/statistics/hash_table.h",
"src/core/statistics/window_stats.h",
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
@ -180,7 +187,7 @@
"src/core/transport/transport_impl.h"
],
"src": [
"src/core/channel/census_filter.c",
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
@ -232,12 +239,6 @@
"src/core/json/json_writer.c",
"src/core/profiling/basic_timers.c",
"src/core/profiling/stap_timers.c",
"src/core/statistics/census_init.c",
"src/core/statistics/census_log.c",
"src/core/statistics/census_rpc_stats.c",
"src/core/statistics/census_tracing.c",
"src/core/statistics/hash_table.c",
"src/core/statistics/window_stats.c",
"src/core/surface/byte_buffer.c",
"src/core/surface/byte_buffer_queue.c",
"src/core/surface/byte_buffer_reader.c",
@ -284,7 +285,6 @@
"src": [
"test/core/end2end/cq_verifier.c",
"test/core/iomgr/endpoint_tests.c",
"test/core/statistics/census_log_tests.c",
"test/core/util/grpc_profiler.c",
"test/core/util/parse_hexstring.c",
"test/core/util/port_posix.c",
@ -448,7 +448,8 @@
],
"baselib": true,
"filegroups": [
"grpc_base"
"grpc_base",
"census"
],
"secure": "yes",
"vs_project_guid": "{29D16885-7228-4C31-81ED-5F9187C7F2A9}"
@ -499,7 +500,8 @@
],
"baselib": true,
"filegroups": [
"grpc_base"
"grpc_base",
"census"
],
"secure": "no",
"vs_project_guid": "{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}"
@ -802,147 +804,6 @@
"gpr"
]
},
{
"name": "census_hash_table_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/hash_table_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_statistics_multiple_writers_circular_buffer_test",
"flaky": true,
"build": "test",
"language": "c",
"src": [
"test/core/statistics/multiple_writers_circular_buffer_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_statistics_multiple_writers_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/multiple_writers_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_statistics_performance_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/performance_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_statistics_quick_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/quick_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_statistics_small_log_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/small_log_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_stats_store_test",
"build": "executable",
"language": "c",
"src": [
"test/core/statistics/rpc_stats_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_stub_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/census_stub_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_trace_store_test",
"build": "executable",
"language": "c",
"src": [
"test/core/statistics/trace_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "census_window_stats_test",
"build": "test",
"language": "c",
"src": [
"test/core/statistics/window_stats_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "chttp2_status_conversion_test",
"build": "test",

@ -1,13 +1,13 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
s.version = '0.0.1'
s.summary = 'Generic gRPC client library for iOS/OSX'
s.homepage = 'https://www.grpc.io'
s.version = '0.5.1'
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'http://www.grpc.io'
s.license = 'New BSD'
s.authors = { 'Jorge Canizales' => 'jcanizales@google.com',
'Michael Lumish' => 'mlumish@google.com' }
s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' }
# s.source = { :git => 'https://github.com/grpc/grpc.git', :tag => 'release-0_5_0' }
# s.source = { :git => 'https://github.com/grpc/grpc.git',
# :tag => 'release-0_9_1-objectivec-0.5.1' }
s.ios.deployment_target = '6.0'
s.osx.deployment_target = '10.8'
@ -15,7 +15,6 @@ Pod::Spec.new do |s|
s.subspec 'RxLibrary' do |rs|
rs.summary = 'Reactive Extensions library for iOS.'
rs.authors = { 'Jorge Canizales' => 'jcanizales@google.com' }
rs.source_files = 'src/objective-c/RxLibrary/*.{h,m}',
'src/objective-c/RxLibrary/transformations/*.{h,m}',
@ -25,16 +24,13 @@ Pod::Spec.new do |s|
s.subspec 'C-Core' do |cs|
cs.summary = 'Core cross-platform gRPC library, written in C.'
cs.authors = { 'Craig Tiller' => 'ctiller@google.com',
'David Klempner' => 'klempner@google.com',
'Nicolas Noble' => 'nnoble@google.com',
'Vijay Pai' => 'vpai@google.com',
'Yang Gao' => 'yangg@google.com' }
cs.source_files = 'src/core/**/*.{h,c}', 'include/grpc/*.h', 'include/grpc/**/*.h'
cs.private_header_files = 'src/core/**/*.h'
cs.header_mappings_dir = '.'
cs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Build/gRPC" "$(PODS_ROOT)/Headers/Build/gRPC/include"' }
cs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Build/gRPC" '
'"$(PODS_ROOT)/Headers/Build/gRPC/include"' }
cs.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
cs.requires_arc = false
cs.libraries = 'z'
@ -67,8 +63,6 @@ Pod::Spec.new do |s|
s.subspec 'GRPCClient' do |gs|
gs.summary = 'Objective-C wrapper around the core gRPC library.'
gs.authors = { 'Jorge Canizales' => 'jcanizales@google.com',
'Michael Lumish' => 'mlumish@google.com' }
gs.source_files = 'src/objective-c/GRPCClient/*.{h,m}',
'src/objective-c/GRPCClient/private/*.{h,m}'
@ -85,7 +79,6 @@ Pod::Spec.new do |s|
s.subspec 'ProtoRPC' do |ps|
ps.summary = 'RPC library for ProtocolBuffers, based on gRPC'
ps.authors = { 'Jorge Canizales' => 'jcanizales@google.com' }
ps.source_files = 'src/objective-c/ProtoRPC/*.{h,m}'

@ -76,9 +76,9 @@ class lock_guard {
template <class mutex>
class unique_lock : public lock_guard<mutex> {
public:
unique_lock(mutex &mu) : lock_guard(mu) { }
void lock() { lock_internal(); }
void unlock() { unlock_internal(); }
unique_lock(mutex &mu) : lock_guard<mutex>(mu) { }
void lock() { this->lock_internal(); }
void unlock() { this->unlock_internal(); }
};
class condition_variable {

@ -82,6 +82,10 @@ class thread {
thread_function_base *func_;
gpr_thd_id thd_;
bool joined_;
// Disallow copy and assign.
thread(const thread&);
void operator=(const thread&);
};
} // namespace grpc

@ -106,6 +106,10 @@ class ServerContext {
template <class R, class W>
friend class ::grpc::ServerReaderWriter;
// Prevent copying.
ServerContext(const ServerContext&);
ServerContext& operator=(const ServerContext&);
class CompletionOp;
void BeginCompletionOp(Call* call);

@ -0,0 +1,95 @@
/*
*
* 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.
*
*/
/* RPC-internal Census API's. These are designed to be generic enough that
* they can (ultimately) be used in many different RPC systems (with differing
* implementations). */
#ifndef CENSUS_CENSUS_H
#define CENSUS_CENSUS_H
#include <grpc/grpc.h>
/* Identify census functionality that can be enabled via census_initialize(). */
enum census_functions {
CENSUS_NONE = 0, /* Do not enable census. */
CENSUS_TRACING = 1, /* Enable census tracing. */
CENSUS_STATS = 2, /* Enable Census stats collection. */
CENSUS_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_ALL = CENSUS_TRACING | CENSUS_STATS | CENSUS_CPU
};
/* Shutdown and startup census subsystem. The 'functions' argument should be
* the OR (|) of census_functions values. If census fails to initialize, then
* census_initialize() will return a non-zero value. It is an error to call
* census_initialize() more than once (without an intervening
* census_shutdown()). */
int census_initialize(int functions);
void census_shutdown();
/* Internally, Census relies on a context, which should be propagated across
* RPC's. From the RPC subsystems viewpoint, this is an opaque data structure.
* A context must be used as the first argument to all other census
* functions. Conceptually, contexts should be thought of as specific to
* single RPC/thread. The context can be serialized for passing across the
* wire. */
typedef struct census_context census_context;
/* This function is called by the RPC subsystem whenever it needs to get a
* serialized form of the current census context (presumably to pass across
* the wire). Arguments:
* 'buffer': pointer to memory into which serialized context will be placed
* 'buf_size': size of 'buffer'
*
* Returns: the number of bytes used in buffer if successful, or 0 if the
* buffer is of insufficient size.
*
* TODO(aveitch): determine how best to communicate required/max buffer size
* so caller doesn't have to guess. */
size_t census_context_serialize(const census_context *context, char *buffer,
size_t buf_size);
/* Create a new census context, possibly from a serialized buffer. If 'buffer'
* is non-NULL, it is assumed that it is a buffer encoded by
* census_context_serialize(). If `buffer` is NULL, a new, empty context is
* created. The decoded/new contest is returned in 'context'.
*
* Returns 0 if no errors, non-zero if buffer is incorrectly formatted, in
* which case a new empty context will be returned. */
int census_context_deserialize(const char *buffer, census_context **context);
/* The given context is destroyed. Once destroyed, using the context in
* future census calls will result in undefined behavior. */
void census_context_destroy(census_context *context);
#endif /* CENSUS_CENSUS_H */

@ -93,7 +93,7 @@ typedef struct {
} grpc_arg;
/** An array of arguments that can be passed around.
Used to set optional channel-level configuration.
These configuration options are modelled as key-value pairs as defined
by grpc_arg; keys are strings to allow easy backwards-compatible extension
@ -170,14 +170,18 @@ void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
struct grpc_byte_buffer_reader;
typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
grpc_byte_buffer_reader *grpc_byte_buffer_reader_create(
grpc_byte_buffer *buffer);
/** Initialize \a reader to read over \a buffer */
void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer);
/** Cleanup and destroy \a reader */
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
/* At the end of the stream, returns 0. Otherwise, returns 1 and sets slice to
be the returned slice. Caller is responsible for calling gpr_slice_unref on
the result. */
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
gpr_slice *slice);
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
/* A single metadata element */
typedef struct grpc_metadata {

@ -1,5 +1,4 @@
/*
*
<!---
* Copyright 2015, Google Inc.
* All rights reserved.
*
@ -28,50 +27,50 @@
* 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.
*
*/
-->
# Census - a resource measurement and tracing system
#ifndef _ADAPTER__CALL_H_
#define _ADAPTER__CALL_H_
This directory contains code for Census, which will ultimately provide the
following features for any gRPC-using system:
* A [dapper](http://research.google.com/pubs/pub36356.html)-like tracing
system, enabling tracing across a distributed infrastructure.
* RPC statistics and measurements for key metrics, such as latency, bytes
transferred, number of errors etc.
* Resource measurement framework which can be used for measuring custom
metrics. Through the use of [tags](#Tags), these can be broken down across
the entire distributed stack.
* Easy integration of the above with
[Google Cloud Trace](https://cloud.google.com/tools/cloud-trace) and
[Google Cloud Monitoring](https://cloud.google.com/monitoring/).
#include <Python.h>
#include <grpc/grpc.h>
## Concepts
#include "grpc/_adapter/_completion_queue.h"
#include "grpc/_adapter/_channel.h"
#include "grpc/_adapter/_server.h"
### Context
typedef struct {
PyObject_HEAD
### Operations
CompletionQueue *completion_queue;
Channel *channel;
Server *server;
### Tags
/* Legacy state. */
grpc_call_details call_details;
grpc_metadata_array recv_metadata;
grpc_metadata_array recv_trailing_metadata;
grpc_metadata *send_metadata;
size_t send_metadata_count;
grpc_metadata *send_trailing_metadata;
size_t send_trailing_metadata_count;
int adding_to_trailing;
### Metrics
grpc_byte_buffer *send_message;
grpc_byte_buffer *recv_message;
## API
grpc_status_code status;
char *status_details;
size_t status_details_capacity;
### Internal/RPC API
int cancelled;
### External/Client API
grpc_call *c_call;
} Call;
### RPC API
extern PyTypeObject pygrpc_CallType;
## Files in this directory
int pygrpc_add_call(PyObject *module);
Note that files and functions in this directory can be split into two
categories:
* Files that define core census library functions. Functions etc. in these
files are named census\_\*, and constitute the core census library
functionality. At some time in the future, these will become a standalone
library.
* Files that define functions etc. that provide a convenient interface between
grpc and the core census functionality. These files are all named
grpc\_\*.{c,h}, and define function names beginning with grpc\_census\_\*.
#endif /* _ADAPTER__CALL_H_ */

@ -31,19 +31,29 @@
*
*/
#ifndef _ADAPTER__CLIENT_CREDENTIALS_H_
#define _ADAPTER__CLIENT_CREDENTIALS_H_
#include "context.h"
#include <Python.h>
#include <grpc/grpc_security.h>
#include <string.h>
#include <grpc/census.h>
#include <grpc/support/alloc.h>
typedef struct {
PyObject_HEAD
grpc_credentials *c_client_credentials;
} ClientCredentials;
/* Placeholder implementation only. */
extern PyTypeObject pygrpc_ClientCredentialsType;
size_t census_context_serialize(const census_context *context, char *buffer,
size_t buf_size) {
/* TODO(aveitch): implement serialization */
return 0;
}
int pygrpc_add_client_credentials(PyObject *module);
int census_context_deserialize(const char *buffer, census_context **context) {
int ret = 0;
if (buffer != NULL) {
/* TODO(aveitch): implement deserialization. */
ret = 1;
}
*context = gpr_malloc(sizeof(census_context));
memset(*context, 0, sizeof(census_context));
return ret;
}
#endif /* _ADAPTER__CLIENT_CREDENTIALS_H_ */
void census_context_destroy(census_context *context) { gpr_free(context); }

@ -31,19 +31,19 @@
*
*/
#ifndef _ADAPTER__COMPLETION_QUEUE_H_
#define _ADAPTER__COMPLETION_QUEUE_H_
#ifndef GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H
#define GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/census.h>
typedef struct {
PyObject_HEAD
grpc_completion_queue *c_completion_queue;
} CompletionQueue;
/* census_context is the in-memory representation of information needed to
* maintain tracing, RPC statistics and resource usage information. */
struct census_context {
gpr_uint64 op_id; /* Operation identifier - unique per-context */
gpr_uint64 trace_id; /* Globally unique trace identifier */
/* TODO(aveitch) Add census tags:
const census_tag_set *tags;
*/
};
extern PyTypeObject pygrpc_CompletionQueueType;
int pygrpc_add_completion_queue(PyObject *module);
#endif /* _ADAPTER__COMPLETION_QUEUE_H_ */
#endif /* GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H */

@ -31,19 +31,15 @@
*
*/
#ifndef _ADAPTER__CHANNEL_H_
#define _ADAPTER__CHANNEL_H_
#include <grpc/census.h>
#include "src/core/census/grpc_context.h"
#include <Python.h>
#include <grpc/grpc.h>
void *grpc_census_context_create() {
census_context *context;
census_context_deserialize(NULL, &context);
return (void *)context;
}
typedef struct {
PyObject_HEAD
grpc_channel *c_channel;
} Channel;
extern PyTypeObject pygrpc_ChannelType;
int pygrpc_add_channel(PyObject *module);
#endif /* _ADAPTER__CHANNEL_H_ */
void grpc_census_context_destroy(void *context) {
census_context_destroy((census_context *)context);
}

@ -31,12 +31,12 @@
*
*/
#ifndef _ADAPTER__ERROR_H_
#define _ADAPTER__ERROR_H_
/* GRPC <--> CENSUS context interface */
#include <Python.h>
#include <grpc/grpc.h>
#ifndef CENSUS_GRPC_CONTEXT_H
#define CENSUS_GRPC_CONTEXT_H
const PyObject *pygrpc_translate_call_error(grpc_call_error call_error);
void *grpc_census_context_create();
void grpc_census_context_destroy(void *context);
#endif /* _ADAPTER__ERROR_H_ */
#endif /* CENSUS_GRPC_CONTEXT_H */

@ -31,21 +31,20 @@
*
*/
#ifndef _ADAPTER__SERVER_H_
#define _ADAPTER__SERVER_H_
#include <grpc/census.h>
#include <Python.h>
#include <grpc/grpc.h>
static int census_fns_enabled = CENSUS_NONE;
#include "grpc/_adapter/_completion_queue.h"
int census_initialize(int functions) {
if (census_fns_enabled != CENSUS_NONE) {
return 1;
}
if (functions != CENSUS_NONE) {
return 1;
} else {
census_fns_enabled = functions;
return 0;
}
}
typedef struct {
PyObject_HEAD
CompletionQueue *completion_queue;
grpc_server *c_server;
} Server;
int pygrpc_add_server(PyObject *module);
#endif /* _ADAPTER__SERVER_H_ */
void census_shutdown() { census_fns_enabled = CENSUS_NONE; }

@ -58,6 +58,9 @@ typedef struct {
gpr_uint8 sending_farewell;
/* have we sent farewell (goaway + disconnect) */
gpr_uint8 sent_farewell;
grpc_iomgr_closure finally_destroy_channel_closure;
grpc_iomgr_closure send_farewells_closure;
} lb_channel_data;
typedef struct { grpc_child_channel *channel; } lb_call_data;
@ -213,12 +216,16 @@ static void maybe_destroy_channel(grpc_child_channel *channel) {
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
if (chand->destroyed && chand->disconnected && chand->active_calls == 0 &&
!chand->sending_farewell && !chand->calling_back) {
grpc_iomgr_add_callback(finally_destroy_channel, channel);
chand->finally_destroy_channel_closure.cb = finally_destroy_channel;
chand->finally_destroy_channel_closure.cb_arg = channel;
grpc_iomgr_add_callback(&chand->finally_destroy_channel_closure);
} else if (chand->destroyed && !chand->disconnected &&
chand->active_calls == 0 && !chand->sending_farewell &&
!chand->sent_farewell) {
chand->sending_farewell = 1;
grpc_iomgr_add_callback(send_farewells, channel);
chand->send_farewells_closure.cb = send_farewells;
chand->send_farewells_closure.cb_arg = channel;
grpc_iomgr_add_callback(&chand->send_farewells_closure);
}
}

@ -41,6 +41,7 @@ typedef struct {
grpc_endpoint *server;
} grpc_endpoint_pair;
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size);
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
size_t read_slice_size);
#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */

@ -44,6 +44,8 @@
#include <sys/socket.h>
#include "src/core/iomgr/tcp_posix.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
static void create_sockets(int sv[2]) {
@ -55,12 +57,21 @@ static void create_sockets(int sv[2]) {
GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size) {
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
size_t read_slice_size) {
int sv[2];
grpc_endpoint_pair p;
char *final_name;
create_sockets(sv);
p.client = grpc_tcp_create(grpc_fd_create(sv[1]), read_slice_size);
p.server = grpc_tcp_create(grpc_fd_create(sv[0]), read_slice_size);
gpr_asprintf(&final_name, "%s:client", name);
p.client =
grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size);
gpr_free(final_name);
gpr_asprintf(&final_name, "%s:server", name);
p.server =
grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size);
gpr_free(final_name);
return p;
}

@ -77,12 +77,12 @@ static void create_sockets(SOCKET sv[2]) {
sv[0] = svr_sock;
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size) {
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size) {
SOCKET sv[2];
grpc_endpoint_pair p;
create_sockets(sv);
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1]));
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0]));
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"));
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"));
return p;
}

@ -41,7 +41,6 @@
#include <sys/socket.h>
#include <unistd.h>
#include "src/core/iomgr/iomgr_internal.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
@ -91,6 +90,7 @@ static grpc_fd *alloc_fd(int fd) {
gpr_mu_init(&r->set_state_mu);
gpr_mu_init(&r->watcher_mu);
}
gpr_atm_rel_store(&r->refst, 1);
gpr_atm_rel_store(&r->readst, NOT_READY);
gpr_atm_rel_store(&r->writest, NOT_READY);
@ -116,10 +116,9 @@ static void ref_by(grpc_fd *fd, int n) {
static void unref_by(grpc_fd *fd, int n) {
gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
if (old == n) {
close(fd->fd);
grpc_iomgr_add_callback(fd->on_done, fd->on_done_user_data);
grpc_iomgr_add_callback(&fd->on_done_closure);
freelist_fd(fd);
grpc_iomgr_unref();
grpc_iomgr_unregister_object(&fd->iomgr_object);
} else {
GPR_ASSERT(old > n);
}
@ -138,9 +137,9 @@ void grpc_fd_global_shutdown(void) {
static void do_nothing(void *ignored, int success) {}
grpc_fd *grpc_fd_create(int fd) {
grpc_fd *grpc_fd_create(int fd, const char *name) {
grpc_fd *r = alloc_fd(fd);
grpc_iomgr_ref();
grpc_iomgr_register_object(&r->iomgr_object, name);
grpc_pollset_add_fd(grpc_backup_pollset(), r);
return r;
}
@ -180,8 +179,8 @@ static void wake_all_watchers_locked(grpc_fd *fd) {
}
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) {
fd->on_done = on_done ? on_done : do_nothing;
fd->on_done_user_data = user_data;
grpc_iomgr_closure_init(&fd->on_done_closure, on_done ? on_done : do_nothing,
user_data);
shutdown(fd->fd, SHUT_RDWR);
ref_by(fd, 1); /* remove active status, but keep referenced */
gpr_mu_lock(&fd->watcher_mu);
@ -195,21 +194,20 @@ void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
static void make_callback(grpc_iomgr_cb_func cb, void *arg, int success,
static void process_callback(grpc_iomgr_closure *closure, int success,
int allow_synchronous_callback) {
if (allow_synchronous_callback) {
cb(arg, success);
closure->cb(closure->cb_arg, success);
} else {
grpc_iomgr_add_delayed_callback(cb, arg, success);
grpc_iomgr_add_delayed_callback(closure, success);
}
}
static void make_callbacks(grpc_iomgr_closure *callbacks, size_t n, int success,
int allow_synchronous_callback) {
static void process_callbacks(grpc_iomgr_closure *callbacks, size_t n,
int success, int allow_synchronous_callback) {
size_t i;
for (i = 0; i < n; i++) {
make_callback(callbacks[i].cb, callbacks[i].cb_arg, success,
allow_synchronous_callback);
process_callback(callbacks + i, success, allow_synchronous_callback);
}
}
@ -234,10 +232,9 @@ static void notify_on(grpc_fd *fd, gpr_atm *st, grpc_iomgr_closure *closure,
/* swap was unsuccessful due to an intervening set_ready call.
Fall through to the READY code below */
case READY:
assert(gpr_atm_no_barrier_load(st) == READY);
GPR_ASSERT(gpr_atm_no_barrier_load(st) == READY);
gpr_atm_rel_store(st, NOT_READY);
make_callback(closure->cb, closure->cb_arg,
!gpr_atm_acq_load(&fd->shutdown),
process_callback(closure, !gpr_atm_acq_load(&fd->shutdown),
allow_synchronous_callback);
return;
default: /* WAITING */
@ -251,7 +248,7 @@ static void notify_on(grpc_fd *fd, gpr_atm *st, grpc_iomgr_closure *closure,
abort();
}
static void set_ready_locked(gpr_atm *st, grpc_iomgr_closure *callbacks,
static void set_ready_locked(gpr_atm *st, grpc_iomgr_closure **callbacks,
size_t *ncallbacks) {
gpr_intptr state = gpr_atm_acq_load(st);
@ -269,9 +266,9 @@ static void set_ready_locked(gpr_atm *st, grpc_iomgr_closure *callbacks,
Fall through to the WAITING code below */
state = gpr_atm_acq_load(st);
default: /* waiting */
assert(gpr_atm_no_barrier_load(st) != READY &&
gpr_atm_no_barrier_load(st) != NOT_READY);
callbacks[(*ncallbacks)++] = *(grpc_iomgr_closure *)state;
GPR_ASSERT(gpr_atm_no_barrier_load(st) != READY &&
gpr_atm_no_barrier_load(st) != NOT_READY);
callbacks[(*ncallbacks)++] = (grpc_iomgr_closure *)state;
gpr_atm_rel_store(st, NOT_READY);
return;
}
@ -282,25 +279,30 @@ static void set_ready(grpc_fd *fd, gpr_atm *st,
/* only one set_ready can be active at once (but there may be a racing
notify_on) */
int success;
grpc_iomgr_closure cb;
grpc_iomgr_closure* closure;
size_t ncb = 0;
gpr_mu_lock(&fd->set_state_mu);
set_ready_locked(st, &cb, &ncb);
set_ready_locked(st, &closure, &ncb);
gpr_mu_unlock(&fd->set_state_mu);
success = !gpr_atm_acq_load(&fd->shutdown);
make_callbacks(&cb, ncb, success, allow_synchronous_callback);
GPR_ASSERT(ncb <= 1);
if (ncb > 0) {
process_callbacks(closure, ncb, success, allow_synchronous_callback);
}
}
void grpc_fd_shutdown(grpc_fd *fd) {
grpc_iomgr_closure cb[2];
size_t ncb = 0;
gpr_mu_lock(&fd->set_state_mu);
GPR_ASSERT(!gpr_atm_no_barrier_load(&fd->shutdown));
gpr_atm_rel_store(&fd->shutdown, 1);
set_ready_locked(&fd->readst, cb, &ncb);
set_ready_locked(&fd->writest, cb, &ncb);
set_ready_locked(&fd->readst, &fd->shutdown_closures[0], &ncb);
set_ready_locked(&fd->writest, &fd->shutdown_closures[0], &ncb);
gpr_mu_unlock(&fd->set_state_mu);
make_callbacks(cb, ncb, 0, 0);
GPR_ASSERT(ncb <= 2);
process_callbacks(fd->shutdown_closures[0], ncb, 0 /* GPR_FALSE */,
0 /* GPR_FALSE */);
}
void grpc_fd_notify_on_read(grpc_fd *fd, grpc_iomgr_closure *closure) {

@ -34,17 +34,12 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H
#define GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H
#include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/pollset.h"
#include <grpc/support/atm.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
typedef struct {
grpc_iomgr_cb_func cb;
void *cb_arg;
} grpc_iomgr_closure;
typedef struct grpc_fd grpc_fd;
typedef struct grpc_fd_watcher {
@ -96,15 +91,18 @@ struct grpc_fd {
gpr_atm readst;
gpr_atm writest;
grpc_iomgr_cb_func on_done;
void *on_done_user_data;
struct grpc_fd *freelist_next;
grpc_iomgr_closure on_done_closure;
grpc_iomgr_closure *shutdown_closures[2];
grpc_iomgr_object iomgr_object;
};
/* Create a wrapped file descriptor.
Requires fd is a non-blocking file descriptor.
This takes ownership of closing fd. */
grpc_fd *grpc_fd_create(int fd);
grpc_fd *grpc_fd_create(int fd, const char *name);
/* Releases fd to be asynchronously destroyed.
on_done is called when the underlying file descriptor is definitely close()d.

@ -37,25 +37,19 @@
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/alarm_internal.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/thd.h>
#include <grpc/support/sync.h>
typedef struct delayed_callback {
grpc_iomgr_cb_func cb;
void *cb_arg;
int success;
struct delayed_callback *next;
} delayed_callback;
static gpr_mu g_mu;
static gpr_cv g_rcv;
static delayed_callback *g_cbs_head = NULL;
static delayed_callback *g_cbs_tail = NULL;
static grpc_iomgr_closure *g_cbs_head = NULL;
static grpc_iomgr_closure *g_cbs_tail = NULL;
static int g_shutdown;
static int g_refs;
static gpr_event g_background_callback_executor_done;
static grpc_iomgr_object g_root_object;
/* Execute followup callbacks continuously.
Other threads may check in and help during pollset_work() */
@ -66,12 +60,11 @@ static void background_callback_executor(void *ignored) {
gpr_timespec short_deadline =
gpr_time_add(gpr_now(), gpr_time_from_millis(100));
if (g_cbs_head) {
delayed_callback *cb = g_cbs_head;
g_cbs_head = cb->next;
grpc_iomgr_closure *closure = g_cbs_head;
g_cbs_head = closure->next;
if (!g_cbs_head) g_cbs_tail = NULL;
gpr_mu_unlock(&g_mu);
cb->cb(cb->cb_arg, cb->success);
gpr_free(cb);
closure->cb(closure->cb_arg, closure->success);
gpr_mu_lock(&g_mu);
} else if (grpc_alarm_check(&g_mu, gpr_now(), &deadline)) {
} else {
@ -96,34 +89,48 @@ void grpc_iomgr_init(void) {
gpr_mu_init(&g_mu);
gpr_cv_init(&g_rcv);
grpc_alarm_list_init(gpr_now());
g_refs = 0;
g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = "root";
grpc_iomgr_platform_init();
gpr_event_init(&g_background_callback_executor_done);
gpr_thd_new(&id, background_callback_executor, NULL, NULL);
}
static size_t count_objects(void) {
grpc_iomgr_object *obj;
size_t n = 0;
for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
n++;
}
return n;
}
void grpc_iomgr_shutdown(void) {
delayed_callback *cb;
grpc_iomgr_object *obj;
grpc_iomgr_closure *closure;
gpr_timespec shutdown_deadline =
gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
gpr_mu_lock(&g_mu);
g_shutdown = 1;
while (g_cbs_head || g_refs) {
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", g_refs,
while (g_cbs_head || g_root_object.next != &g_root_object) {
size_t nobjs = count_objects();
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", nobjs,
g_cbs_head ? " and executing final callbacks" : "");
while (g_cbs_head) {
cb = g_cbs_head;
g_cbs_head = cb->next;
if (!g_cbs_head) g_cbs_tail = NULL;
gpr_mu_unlock(&g_mu);
cb->cb(cb->cb_arg, 0);
gpr_free(cb);
gpr_mu_lock(&g_mu);
if (g_cbs_head) {
do {
closure = g_cbs_head;
g_cbs_head = closure->next;
if (!g_cbs_head) g_cbs_tail = NULL;
gpr_mu_unlock(&g_mu);
closure->cb(closure->cb_arg, 0);
gpr_mu_lock(&g_mu);
} while (g_cbs_head);
continue;
}
if (g_refs) {
if (nobjs > 0) {
int timeout = 0;
gpr_timespec short_deadline = gpr_time_add(gpr_now(),
gpr_time_from_millis(100));
@ -137,7 +144,10 @@ void grpc_iomgr_shutdown(void) {
gpr_log(GPR_DEBUG,
"Failed to free %d iomgr objects before shutdown deadline: "
"memory leaks are likely",
g_refs);
count_objects());
for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s", obj->name);
}
break;
}
}
@ -153,56 +163,66 @@ void grpc_iomgr_shutdown(void) {
gpr_cv_destroy(&g_rcv);
}
void grpc_iomgr_ref(void) {
void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
obj->name = gpr_strdup(name);
gpr_mu_lock(&g_mu);
++g_refs;
obj->next = &g_root_object;
obj->prev = obj->next->prev;
obj->next->prev = obj->prev->next = obj;
gpr_mu_unlock(&g_mu);
}
void grpc_iomgr_unref(void) {
void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
gpr_free(obj->name);
gpr_mu_lock(&g_mu);
if (0 == --g_refs) {
gpr_cv_signal(&g_rcv);
}
obj->next->prev = obj->prev;
obj->prev->next = obj->next;
gpr_cv_signal(&g_rcv);
gpr_mu_unlock(&g_mu);
}
void grpc_iomgr_add_delayed_callback(grpc_iomgr_cb_func cb, void *cb_arg,
int success) {
delayed_callback *dcb = gpr_malloc(sizeof(delayed_callback));
dcb->cb = cb;
dcb->cb_arg = cb_arg;
dcb->success = success;
void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
void *cb_arg) {
closure->cb = cb;
closure->cb_arg = cb_arg;
closure->next = NULL;
}
void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *closure, int success) {
closure->success = success;
gpr_mu_lock(&g_mu);
dcb->next = NULL;
closure->next = NULL;
if (!g_cbs_tail) {
g_cbs_head = g_cbs_tail = dcb;
g_cbs_head = g_cbs_tail = closure;
} else {
g_cbs_tail->next = dcb;
g_cbs_tail = dcb;
g_cbs_tail->next = closure;
g_cbs_tail = closure;
}
gpr_mu_unlock(&g_mu);
}
void grpc_iomgr_add_callback(grpc_iomgr_cb_func cb, void *cb_arg) {
grpc_iomgr_add_delayed_callback(cb, cb_arg, 1);
void grpc_iomgr_add_callback(grpc_iomgr_closure *closure) {
grpc_iomgr_add_delayed_callback(closure, 1 /* GPR_TRUE */);
}
int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) {
int n = 0;
gpr_mu *retake_mu = NULL;
delayed_callback *cb;
grpc_iomgr_closure *closure;
for (;;) {
/* check for new work */
if (!gpr_mu_trylock(&g_mu)) {
break;
}
cb = g_cbs_head;
if (!cb) {
closure = g_cbs_head;
if (!closure) {
gpr_mu_unlock(&g_mu);
break;
}
g_cbs_head = cb->next;
g_cbs_head = closure->next;
if (!g_cbs_head) g_cbs_tail = NULL;
gpr_mu_unlock(&g_mu);
/* if we have a mutex to drop, do so before executing work */
@ -211,8 +231,7 @@ int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) {
retake_mu = drop_mu;
drop_mu = NULL;
}
cb->cb(cb->cb_arg, success && cb->success);
gpr_free(cb);
closure->cb(closure->cb_arg, success && closure->success);
n++;
}
if (retake_mu) {

@ -34,14 +34,43 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_H
#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_H
/* gRPC Callback definition */
/** gRPC Callback definition.
*
* \param arg Arbitrary input.
* \param success An indication on the state of the iomgr. On false, cleanup
* actions should be taken (eg, shutdown). */
typedef void (*grpc_iomgr_cb_func)(void *arg, int success);
/** A closure over a grpc_iomgr_cb_func. */
typedef struct grpc_iomgr_closure {
/** Bound callback. */
grpc_iomgr_cb_func cb;
/** Arguments to be passed to "cb". */
void *cb_arg;
/** Internal. A boolean indication to "cb" on the state of the iomgr.
* For instance, closures created during a shutdown would have this field set
* to false. */
int success;
/**< Internal. Do not touch */
struct grpc_iomgr_closure *next;
} grpc_iomgr_closure;
/** Initializes \a closure with \a cb and \a cb_arg. */
void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
void *cb_arg);
/** Initializes the iomgr. */
void grpc_iomgr_init(void);
/** Signals the intention to shutdown the iomgr. */
void grpc_iomgr_shutdown(void);
/* This function is called from within a callback or from anywhere else
and causes the invocation of a callback at some point in the future */
void grpc_iomgr_add_callback(grpc_iomgr_cb_func cb, void *cb_arg);
/** Registers a closure to be invoked at some point in the future.
*
* Can be called from within a callback or from anywhere else */
void grpc_iomgr_add_callback(grpc_iomgr_closure *closure);
#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */

@ -35,15 +35,19 @@
#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
#include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/iomgr_internal.h"
#include <grpc/support/sync.h>
typedef struct grpc_iomgr_object {
char *name;
struct grpc_iomgr_object *next;
struct grpc_iomgr_object *prev;
} grpc_iomgr_object;
int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success);
void grpc_iomgr_add_delayed_callback(grpc_iomgr_cb_func cb, void *cb_arg,
int success);
void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *iocb, int success);
void grpc_iomgr_ref(void);
void grpc_iomgr_unref(void);
void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name);
void grpc_iomgr_unregister_object(grpc_iomgr_object *obj);
void grpc_iomgr_platform_init(void);
void grpc_iomgr_platform_shutdown(void);

@ -257,6 +257,7 @@ typedef struct grpc_unary_promote_args {
const grpc_pollset_vtable *original_vtable;
grpc_pollset *pollset;
grpc_fd *fd;
grpc_iomgr_closure promotion_closure;
} grpc_unary_promote_args;
static void unary_poll_do_promote(void *args, int success) {
@ -279,7 +280,7 @@ static void unary_poll_do_promote(void *args, int success) {
/* First we need to ensure that nobody is polling concurrently */
while (pollset->counter != 0) {
grpc_pollset_kick(pollset);
grpc_iomgr_add_callback(unary_poll_do_promote, up_args);
grpc_iomgr_add_callback(&up_args->promotion_closure);
gpr_mu_unlock(&pollset->mu);
return;
}
@ -363,7 +364,9 @@ static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
up_args->pollset = pollset;
up_args->fd = fd;
up_args->original_vtable = pollset->vtable;
grpc_iomgr_add_callback(unary_poll_do_promote, up_args);
up_args->promotion_closure.cb = unary_poll_do_promote;
up_args->promotion_closure.cb_arg = up_args;
grpc_iomgr_add_callback(&up_args->promotion_closure);
grpc_pollset_kick(pollset);
}

@ -66,15 +66,15 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
gpr_timespec now;
now = gpr_now();
if (gpr_time_cmp(now, deadline) > 0) {
return 0;
return 0 /* GPR_FALSE */;
}
if (grpc_maybe_call_delayed_callbacks(NULL, 1)) {
return 1;
if (grpc_maybe_call_delayed_callbacks(NULL, 1 /* GPR_TRUE */)) {
return 1 /* GPR_TRUE */;
}
if (grpc_alarm_check(NULL, now, &deadline)) {
return 1;
return 1 /* GPR_TRUE */;
}
return 0;
return 0 /* GPR_FALSE */;
}
void grpc_pollset_kick(grpc_pollset *p) { }

@ -55,6 +55,7 @@ typedef struct {
char *default_port;
grpc_resolve_cb cb;
void *arg;
grpc_iomgr_object iomgr_object;
} request;
grpc_resolved_addresses *grpc_blocking_resolve_address(
@ -153,9 +154,9 @@ static void do_request(void *rp) {
grpc_resolve_cb cb = r->cb;
gpr_free(r->name);
gpr_free(r->default_port);
grpc_iomgr_unregister_object(&r->iomgr_object);
gpr_free(r);
cb(arg, resolved);
grpc_iomgr_unref();
}
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
@ -167,7 +168,11 @@ void grpc_resolve_address(const char *name, const char *default_port,
grpc_resolve_cb cb, void *arg) {
request *r = gpr_malloc(sizeof(request));
gpr_thd_id id;
grpc_iomgr_ref();
char *tmp;
gpr_asprintf(&tmp, "resolve_address:name='%s':default_port='%s'", name,
default_port);
grpc_iomgr_register_object(&r->iomgr_object, tmp);
gpr_free(tmp);
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
r->cb = cb;

@ -54,6 +54,7 @@ typedef struct {
char *default_port;
grpc_resolve_cb cb;
void *arg;
grpc_iomgr_object iomgr_object;
} request;
grpc_resolved_addresses *grpc_blocking_resolve_address(
@ -135,7 +136,7 @@ static void do_request(void *rp) {
gpr_free(r->default_port);
gpr_free(r);
cb(arg, resolved);
grpc_iomgr_unref();
grpc_iomgr_unregister_object(&r->iomgr_object);
}
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
@ -147,7 +148,10 @@ void grpc_resolve_address(const char *name, const char *default_port,
grpc_resolve_cb cb, void *arg) {
request *r = gpr_malloc(sizeof(request));
gpr_thd_id id;
grpc_iomgr_ref();
const char *label;
gpr_asprintf(&label, "resolve:%s", name);
grpc_iomgr_register_object(&r->iomgr_object, label);
gpr_free(label);
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
r->cb = cb;

@ -39,18 +39,17 @@
#include <grpc/support/log.h>
#include "src/core/iomgr/iocp_windows.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/pollset.h"
#include "src/core/iomgr/pollset_windows.h"
#include "src/core/iomgr/socket_windows.h"
grpc_winsocket *grpc_winsocket_create(SOCKET socket) {
grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *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_ref();
grpc_iomgr_register_object(&r->iomgr_object, name);
grpc_iocp_add_socket(r);
return r;
}
@ -64,13 +63,15 @@ int grpc_winsocket_shutdown(grpc_winsocket *socket) {
gpr_mu_lock(&socket->state_mu);
if (socket->read_info.cb) {
callbacks_set++;
grpc_iomgr_add_delayed_callback(socket->read_info.cb,
socket->read_info.opaque, 0);
grpc_iomgr_closure_init(&socket->shutdown_closure, socket->read_info.cb,
socket->read_info.opaque);
grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
}
if (socket->write_info.cb) {
callbacks_set++;
grpc_iomgr_add_delayed_callback(socket->write_info.cb,
socket->write_info.opaque, 0);
grpc_iomgr_closure_init(&socket->shutdown_closure, socket->write_info.cb,
socket->write_info.opaque);
grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
}
gpr_mu_unlock(&socket->state_mu);
return callbacks_set;
@ -90,7 +91,7 @@ void grpc_winsocket_orphan(grpc_winsocket *winsocket) {
grpc_winsocket_destroy(winsocket);
}
closesocket(socket);
grpc_iomgr_unref();
grpc_iomgr_unregister_object(&winsocket->iomgr_object);
}
void grpc_winsocket_destroy(grpc_winsocket *winsocket) {

@ -39,6 +39,8 @@
#include <grpc/support/sync.h>
#include <grpc/support/atm.h>
#include "src/core/iomgr/iomgr_internal.h"
/* This holds the data for an outstanding read or write on a socket.
The mutex to protect the concurrent access to that data is the one
inside the winsocket wrapper. */
@ -93,11 +95,16 @@ typedef struct grpc_winsocket {
there is a pending operation that the IO Completion Port will have to
wait for. The socket will be collected at that time. */
int orphan;
grpc_iomgr_closure shutdown_closure;
/* A label for iomgr to track outstanding objects */
grpc_iomgr_object iomgr_object;
} grpc_winsocket;
/* Create a wrapped windows handle. This takes ownership of it, meaning that
it will be responsible for closing it. */
grpc_winsocket *grpc_winsocket_create(SOCKET socket);
grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name);
/* Initiate an asynchronous shutdown of the socket. Will call off any pending
operation to cancel them. Returns the number of callbacks that got setup. */

@ -48,6 +48,7 @@
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/iomgr/tcp_posix.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
@ -185,6 +186,8 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
async_connect *ac;
struct sockaddr_in6 addr6_v4mapped;
struct sockaddr_in addr4_copy;
char *name;
char *addr_str;
/* Use dualstack sockets where available. */
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
@ -211,24 +214,27 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
err = connect(fd, addr, addr_len);
} while (err < 0 && errno == EINTR);
grpc_sockaddr_to_string(&addr_str, addr, 1);
gpr_asprintf(&name, "tcp-client:%s", addr_str);
if (err >= 0) {
gpr_log(GPR_DEBUG, "instant connect");
cb(arg,
grpc_tcp_create(grpc_fd_create(fd), GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
return;
cb(arg, grpc_tcp_create(grpc_fd_create(fd, name),
GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
goto done;
}
if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
gpr_log(GPR_ERROR, "connect error: %s", strerror(errno));
gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
close(fd);
cb(arg, NULL);
return;
goto done;
}
ac = gpr_malloc(sizeof(async_connect));
ac->cb = cb;
ac->cb_arg = arg;
ac->fd = grpc_fd_create(fd);
ac->fd = grpc_fd_create(fd, name);
gpr_mu_init(&ac->mu);
ac->refs = 2;
ac->write_closure.cb = on_writable;
@ -236,6 +242,10 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
done:
gpr_free(name);
gpr_free(addr_str);
}
#endif

@ -193,7 +193,7 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
goto failure;
}
socket = grpc_winsocket_create(sock);
socket = grpc_winsocket_create(sock, "client");
info = &socket->write_info;
info->outstanding = 1;
success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped);

@ -280,6 +280,8 @@ typedef struct {
grpc_iomgr_closure read_closure;
grpc_iomgr_closure write_closure;
grpc_iomgr_closure handle_read_closure;
} grpc_tcp;
static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success);
@ -443,7 +445,8 @@ static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
tcp->finished_edge = 0;
grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure);
} else {
grpc_iomgr_add_callback(grpc_tcp_handle_read, tcp);
tcp->handle_read_closure.cb_arg = tcp;
grpc_iomgr_add_callback(&tcp->handle_read_closure);
}
}
@ -592,6 +595,8 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size) {
tcp->read_closure.cb_arg = tcp;
tcp->write_closure.cb = grpc_tcp_handle_write;
tcp->write_closure.cb_arg = tcp;
tcp->handle_read_closure.cb = grpc_tcp_handle_read;
return &tcp->base;
}

@ -60,6 +60,7 @@
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/iomgr/tcp_posix.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
@ -281,6 +282,8 @@ static void on_read(void *arg, int success) {
for (;;) {
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
char *addr_str;
char *name;
/* Note: If we ever decide to return this address to the user, remember to
strip off the ::ffff:0.0.0.0/96 prefix first. */
int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1);
@ -299,9 +302,15 @@ static void on_read(void *arg, int success) {
grpc_set_socket_no_sigpipe_if_possible(fd);
sp->server->cb(
sp->server->cb_arg,
grpc_tcp_create(grpc_fd_create(fd), GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
sp->server->cb(sp->server->cb_arg,
grpc_tcp_create(grpc_fd_create(fd, name),
GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
gpr_free(addr_str);
gpr_free(name);
}
abort();
@ -318,9 +327,13 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
const struct sockaddr *addr, int addr_len) {
server_port *sp;
int port;
char *addr_str;
char *name;
port = prepare_socket(fd, addr, addr_len);
if (port >= 0) {
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb && "must add ports before starting server");
/* append it to the list under a lock */
@ -331,11 +344,13 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
sp = &s->ports[s->nports++];
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd);
sp->emfd = grpc_fd_create(fd, name);
memcpy(sp->addr.untyped, addr, addr_len);
sp->addr_len = addr_len;
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
gpr_free(addr_str);
gpr_free(name);
}
return port;

@ -270,7 +270,8 @@ static void on_accept(void *arg, int from_iocp) {
gpr_free(utf8_message);
closesocket(sock);
} else {
ep = grpc_tcp_create(grpc_winsocket_create(sock));
/* 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.
@ -336,7 +337,7 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
}
sp = &s->ports[s->nports++];
sp->server = s;
sp->socket = grpc_winsocket_create(sock);
sp->socket = grpc_winsocket_create(sock, "listener");
sp->shutting_down = 0;
sp->AcceptEx = AcceptEx;
sp->new_socket = INVALID_SOCKET;

@ -54,6 +54,7 @@
typedef struct {
grpc_credentials *creds;
grpc_credentials_metadata_cb cb;
grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
void *user_data;
} grpc_credentials_metadata_request;
@ -65,6 +66,8 @@ grpc_credentials_metadata_request_create(grpc_credentials *creds,
gpr_malloc(sizeof(grpc_credentials_metadata_request));
r->creds = grpc_credentials_ref(creds);
r->cb = cb;
r->on_simulated_token_fetch_done_closure =
gpr_malloc(sizeof(grpc_iomgr_closure));
r->user_data = user_data;
return r;
}
@ -72,6 +75,7 @@ grpc_credentials_metadata_request_create(grpc_credentials *creds,
static void grpc_credentials_metadata_request_destroy(
grpc_credentials_metadata_request *r) {
grpc_credentials_unref(r->creds);
gpr_free(r->on_simulated_token_fetch_done_closure);
gpr_free(r);
}
@ -831,9 +835,11 @@ static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
if (c->is_async) {
grpc_iomgr_add_callback(
on_simulated_token_fetch_done,
grpc_credentials_metadata_request_create(creds, cb, user_data));
grpc_credentials_metadata_request *cb_arg =
grpc_credentials_metadata_request_create(creds, cb, user_data);
grpc_iomgr_closure_init(cb_arg->on_simulated_token_fetch_done_closure,
on_simulated_token_fetch_done, cb_arg);
grpc_iomgr_add_callback(cb_arg->on_simulated_token_fetch_done_closure);
} else {
cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
}

@ -39,15 +39,18 @@
#include <grpc/support/slice_buffer.h>
#include <grpc/byte_buffer.h>
grpc_byte_buffer_reader *grpc_byte_buffer_reader_create(
grpc_byte_buffer *buffer) {
grpc_byte_buffer_reader *reader = malloc(sizeof(grpc_byte_buffer_reader));
void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer) {
reader->buffer = buffer;
switch (buffer->type) {
case GRPC_BB_SLICE_BUFFER:
reader->current.index = 0;
}
return reader;
}
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
/* no-op: the user is responsible for memory deallocation.
* Other cleanup operations would go here if needed. */
}
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
@ -68,7 +71,3 @@ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
}
return 0;
}
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
free(reader);
}

@ -31,6 +31,7 @@
*
*/
#include "src/core/census/grpc_context.h"
#include "src/core/surface/call.h"
#include "src/core/channel/channel_stack.h"
#include "src/core/iomgr/alarm.h"
@ -226,6 +227,7 @@ struct grpc_call {
gpr_slice_buffer incoming_message;
gpr_uint32 incoming_message_length;
grpc_iomgr_closure destroy_closure;
};
#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
@ -242,9 +244,9 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op);
static void execute_op(grpc_call *call, grpc_transport_op *op);
static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata);
static void finish_read_ops(grpc_call *call);
static grpc_call_error cancel_with_status(
grpc_call *c, grpc_status_code status, const char *description,
gpr_uint8 locked);
static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
const char *description,
gpr_uint8 locked);
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
const void *server_transport_data,
@ -268,6 +270,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
if (call->is_client) {
call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE;
call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE;
call->context[GRPC_CONTEXT_TRACING].value = grpc_census_context_create();
call->context[GRPC_CONTEXT_TRACING].destroy = grpc_census_context_destroy;
}
GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT);
for (i = 0; i < add_initial_metadata_count; i++) {
@ -367,7 +371,9 @@ void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) {
if (allow_immediate_deletion) {
destroy_call(c, 1);
} else {
grpc_iomgr_add_callback(destroy_call, c);
c->destroy_closure.cb = destroy_call;
c->destroy_closure.cb_arg = c;
grpc_iomgr_add_callback(&c->destroy_closure);
}
}
}
@ -403,7 +409,8 @@ static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); }
static int need_more_data(grpc_call *call) {
if (call->read_state == READ_STATE_STREAM_CLOSED) return 0;
return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) ||
(is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) && grpc_bbq_empty(&call->incoming_queue)) ||
(is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) &&
grpc_bbq_empty(&call->incoming_queue)) ||
is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) ||
is_op_live(call, GRPC_IOREQ_RECV_STATUS) ||
is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) ||
@ -556,13 +563,13 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
break;
case GRPC_IOREQ_RECV_INITIAL_METADATA:
GPR_SWAP(grpc_metadata_array, call->buffered_metadata[0],
*call->request_data[GRPC_IOREQ_RECV_INITIAL_METADATA]
.recv_metadata);
*call->request_data[GRPC_IOREQ_RECV_INITIAL_METADATA]
.recv_metadata);
break;
case GRPC_IOREQ_RECV_TRAILING_METADATA:
GPR_SWAP(grpc_metadata_array, call->buffered_metadata[1],
*call->request_data[GRPC_IOREQ_RECV_TRAILING_METADATA]
.recv_metadata);
*call->request_data[GRPC_IOREQ_RECV_TRAILING_METADATA]
.recv_metadata);
break;
case GRPC_IOREQ_OP_COUNT:
abort();
@ -676,9 +683,8 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
}
/* we have to be reading a message to know what to do here */
if (!call->reading_message) {
cancel_with_status(
call, GRPC_STATUS_INVALID_ARGUMENT,
"Received payload data while not reading a message", 1);
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT,
"Received payload data while not reading a message", 1);
return 0;
}
/* append the slice to the incoming buffer */
@ -1025,9 +1031,9 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
return cancel_with_status(c, status, description, 0);
}
static grpc_call_error cancel_with_status(
grpc_call *c, grpc_status_code status, const char *description,
gpr_uint8 locked) {
static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
const char *description,
gpr_uint8 locked) {
grpc_transport_op op;
grpc_mdstr *details =
description ? grpc_mdstr_from_string(c->metadata_context, description)
@ -1294,12 +1300,11 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
grpc_cq_begin_op(call->cq, call);
return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func,
tag);
return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func, tag);
}
void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value,
void (*destroy)(void *value)) {
void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
void *value, void (*destroy)(void *value)) {
if (call->context[elem].destroy) {
call->context[elem].destroy(call->context[elem].value);
}

@ -61,6 +61,7 @@ struct grpc_channel {
gpr_mu registered_call_mu;
registered_call *registered_calls;
grpc_iomgr_closure destroy_closure;
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
@ -193,7 +194,9 @@ static void destroy_channel(void *p, int ok) {
void grpc_channel_internal_unref(grpc_channel *channel) {
if (gpr_unref(&channel->refs)) {
grpc_iomgr_add_callback(destroy_channel, channel);
channel->destroy_closure.cb = destroy_channel;
channel->destroy_closure.cb_arg = channel;
grpc_iomgr_add_callback(&channel->destroy_closure);
}
}

@ -195,9 +195,10 @@ grpc_channel *grpc_channel_create(const char *target,
const grpc_channel_filter *filters[MAX_FILTERS];
int n = 0;
filters[n++] = &grpc_client_surface_filter;
/* TODO(census)
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
}
} */
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(filters, n, args, mdctx, 1);

@ -31,11 +31,11 @@
*
*/
#include <grpc/census.h>
#include <grpc/grpc.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/debug/trace.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/statistics/census_interface.h"
#include "src/core/profiling/timers.h"
#include "src/core/surface/call.h"
#include "src/core/surface/init.h"
@ -64,7 +64,9 @@ void grpc_init(void) {
grpc_security_pre_init();
grpc_iomgr_init();
grpc_tracer_init("GRPC_TRACE");
census_init();
if (census_initialize(CENSUS_NONE)) {
gpr_log(GPR_ERROR, "Could not initialize census.");
}
grpc_timers_global_init();
}
gpr_mu_unlock(&g_init_mu);

@ -234,9 +234,10 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
new_args_from_connector != NULL ? new_args_from_connector : args,
&connector_arg);
filters[n++] = &grpc_client_surface_filter;
/* TODO(census)
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
}
} */
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);

@ -122,6 +122,8 @@ struct channel_data {
channel_registered_method *registered_methods;
gpr_uint32 registered_method_slots;
gpr_uint32 registered_method_max_probes;
grpc_iomgr_closure finish_shutdown_channel_closure;
grpc_iomgr_closure finish_destroy_channel_closure;
};
struct grpc_server {
@ -178,6 +180,8 @@ struct call_data {
void (*on_done_recv)(void *user_data, int success);
void *recv_user_data;
grpc_iomgr_closure kill_zombie_closure;
call_data **root[CALL_LIST_COUNT];
call_link links[CALL_LIST_COUNT];
};
@ -304,7 +308,9 @@ static void destroy_channel(channel_data *chand) {
GPR_ASSERT(chand->server != NULL);
orphan_channel(chand);
server_ref(chand->server);
grpc_iomgr_add_callback(finish_destroy_channel, chand);
chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
chand->finish_destroy_channel_closure.cb_arg = chand;
grpc_iomgr_add_callback(&chand->finish_destroy_channel_closure);
}
static void finish_start_new_rpc_and_unlock(grpc_server *server,
@ -416,7 +422,8 @@ static void server_on_recv(void *ptr, int success) {
gpr_mu_lock(&chand->server->mu);
if (calld->state == NOT_STARTED) {
calld->state = ZOMBIED;
grpc_iomgr_add_callback(kill_zombie, elem);
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
}
gpr_mu_unlock(&chand->server->mu);
break;
@ -424,11 +431,14 @@ static void server_on_recv(void *ptr, int success) {
gpr_mu_lock(&chand->server->mu);
if (calld->state == NOT_STARTED) {
calld->state = ZOMBIED;
grpc_iomgr_add_callback(kill_zombie, elem);
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
} else if (calld->state == PENDING) {
call_list_remove(calld, PENDING_START);
calld->state = ZOMBIED;
grpc_iomgr_add_callback(kill_zombie, elem);
grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
}
gpr_mu_unlock(&chand->server->mu);
break;
@ -502,7 +512,9 @@ static void finish_shutdown_channel(void *cd, int success) {
static void shutdown_channel(channel_data *chand) {
grpc_channel_internal_ref(chand->channel);
grpc_iomgr_add_callback(finish_shutdown_channel, chand);
chand->finish_shutdown_channel_closure.cb = finish_shutdown_channel;
chand->finish_shutdown_channel_closure.cb_arg = chand;
grpc_iomgr_add_callback(&chand->finish_shutdown_channel_closure);
}
static void init_call_elem(grpc_call_element *elem,
@ -594,9 +606,15 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
static const grpc_channel_filter server_surface_filter = {
server_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data), init_channel_elem,
destroy_channel_elem, "server",
server_start_transport_op,
channel_op,
sizeof(call_data),
init_call_elem,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
"server",
};
void grpc_server_register_completion_queue(grpc_server *server,
@ -616,7 +634,9 @@ grpc_server *grpc_server_create_from_filters(grpc_channel_filter **filters,
size_t filter_count,
const grpc_channel_args *args) {
size_t i;
int census_enabled = grpc_channel_args_is_census_enabled(args);
/* TODO(census): restore this once we finalize census filter etc.
int census_enabled = grpc_channel_args_is_census_enabled(args); */
int census_enabled = 0;
grpc_server *server = gpr_malloc(sizeof(grpc_server));
@ -642,9 +662,10 @@ grpc_server *grpc_server_create_from_filters(grpc_channel_filter **filters,
server->channel_filters =
gpr_malloc(server->channel_filter_count * sizeof(grpc_channel_filter *));
server->channel_filters[0] = &server_surface_filter;
/* TODO(census): restore this once we rework census filter
if (census_enabled) {
server->channel_filters[1] = &grpc_server_census_filter;
}
} */
for (i = 0; i < filter_count; i++) {
server->channel_filters[i + 1 + census_enabled] = filters[i];
}
@ -940,11 +961,15 @@ void grpc_server_destroy(grpc_server *server) {
while ((calld = call_list_remove_head(&server->lists[PENDING_START],
PENDING_START)) != NULL) {
/* TODO(dgq): If we knew the size of the call list (or an upper bound), we
* could allocate all the memory for the closures in advance in a single
* chunk */
gpr_log(GPR_DEBUG, "server destroys call %p", calld->call);
calld->state = ZOMBIED;
grpc_iomgr_add_callback(
kill_zombie,
grpc_iomgr_closure_init(
&calld->kill_zombie_closure, kill_zombie,
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
grpc_iomgr_add_callback(&calld->kill_zombie_closure);
}
for (c = server->root_channel_data.next; c != &server->root_channel_data;

@ -219,10 +219,10 @@ static int state_index(int bitofs, symset syms, int *isnew) {
emit - the symbol to emit on this nibble (or -1 if no symbol has been
found)
syms - the set of symbols that could be matched */
static void build_dec_tbl(int state, int nibble, int nibbits, int bitofs,
static void build_dec_tbl(int state, int nibble, int nibbits, unsigned bitofs,
int emit, symset syms) {
int i;
int bit;
unsigned bit;
/* If we have four bits in the nibble we're looking at, then we can fill in
a slot in the lookup tables. */
@ -338,7 +338,7 @@ static void generate_base64_inverse_table(void) {
static const char alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
unsigned char inverse[256];
int i;
unsigned i;
memset(inverse, 255, sizeof(inverse));
for (i = 0; i < strlen(alphabet); i++) {

@ -36,6 +36,7 @@
#include <grpc/grpc.h>
#include <grpc/byte_buffer.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/slice.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/port_platform.h>
@ -100,11 +101,9 @@ class GrpcBufferReader GRPC_FINAL
public:
explicit GrpcBufferReader(grpc_byte_buffer* buffer)
: byte_count_(0), backup_count_(0) {
reader_ = grpc_byte_buffer_reader_create(buffer);
}
~GrpcBufferReader() GRPC_OVERRIDE {
grpc_byte_buffer_reader_destroy(reader_);
grpc_byte_buffer_reader_init(&reader_, buffer);
}
~GrpcBufferReader() GRPC_OVERRIDE {}
bool Next(const void** data, int* size) GRPC_OVERRIDE {
if (backup_count_ > 0) {
@ -114,7 +113,7 @@ class GrpcBufferReader GRPC_FINAL
backup_count_ = 0;
return true;
}
if (!grpc_byte_buffer_reader_next(reader_, &slice_)) {
if (!grpc_byte_buffer_reader_next(&reader_, &slice_)) {
return false;
}
gpr_slice_unref(slice_);
@ -147,7 +146,7 @@ class GrpcBufferReader GRPC_FINAL
private:
gpr_int64 byte_count_;
gpr_int64 backup_count_;
grpc_byte_buffer_reader* reader_;
grpc_byte_buffer_reader reader_;
gpr_slice slice_;
};

@ -60,7 +60,7 @@ void ThreadPool::ThreadFunc() {
ThreadPool::ThreadPool(int num_threads) : shutdown_(false) {
for (int i = 0; i < num_threads; i++) {
threads_.push_back(grpc::thread(&ThreadPool::ThreadFunc, this));
threads_.push_back(new grpc::thread(&ThreadPool::ThreadFunc, this));
}
}
@ -71,7 +71,8 @@ ThreadPool::~ThreadPool() {
cv_.notify_all();
}
for (auto t = threads_.begin(); t != threads_.end(); t++) {
t->join();
(*t)->join();
delete *t;
}
}

@ -57,7 +57,7 @@ class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
grpc::condition_variable cv_;
bool shutdown_;
std::queue<std::function<void()>> callbacks_;
std::vector<grpc::thread> threads_;
std::vector<grpc::thread*> threads_;
void ThreadFunc();
};

@ -31,6 +31,7 @@
*
*/
#include <grpc/byte_buffer_reader.h>
#include <grpc++/byte_buffer.h>
namespace grpc {
@ -56,12 +57,12 @@ void ByteBuffer::Dump(std::vector<Slice>* slices) {
if (!buffer_) {
return;
}
grpc_byte_buffer_reader* reader = grpc_byte_buffer_reader_create(buffer_);
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader,buffer_);
gpr_slice s;
while (grpc_byte_buffer_reader_next(reader, &s)) {
while (grpc_byte_buffer_reader_next(&reader, &s)) {
slices->push_back(Slice(s, Slice::STEAL_REF));
}
grpc_byte_buffer_reader_destroy(reader);
}
size_t ByteBuffer::Length() {

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit.Runners" version="2.6.4" />
</packages>

@ -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.0</version>
<version>0.5.1</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.0 of gRPC C#</releaseNotes>
<releaseNotes>Release 0.5.1 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.0" />
<dependency id="Grpc.Core" version="0.5.1" />
</dependencies>
</metadata>
<files>

@ -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.0</version>
<version>0.5.1</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.0 of gRPC C#</releaseNotes>
<releaseNotes>Release 0.5.1 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="Ix-Async" version="1.2.3" />
<dependency id="grpc.native.csharp_ext" version="0.9.0.0" />
<dependency id="grpc.native.csharp_ext" version="0.9.1" />
</dependencies>
</metadata>
<files>

@ -5,13 +5,13 @@
<title>gRPC C# Tools</title>
<summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
<description>Precompiled Windows binaries for generating protocol buffer messages and gRPC client/server code</description>
<version>0.5.0</version>
<version>0.5.1</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>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version 0.5.0</releaseNotes>
<releaseNotes>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version 0.5.1</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
</metadata>

@ -5,17 +5,17 @@
<title>gRPC C#</title>
<summary>C# implementation of gRPC - an RPC library and framework</summary>
<description>C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
<version>0.5.0.1</version>
<version>0.5.1</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.0 of gRPC C#</releaseNotes>
<releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="Grpc.Core" version="0.5.0" />
<dependency id="Grpc.Core" version="0.5.1" />
</dependencies>
</metadata>
<files/>

@ -1,6 +1,8 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core", "Grpc.Core\Grpc.Core.csproj", "{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}"
@ -21,52 +23,60 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.csproj", "{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{B5B87121-35FE-49D1-8CB1-8A91AAA398A9}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Grpc.Examples\Grpc.Examples.csproj

@ -1,11 +1,15 @@
@rem Convenience script to build gRPC C# from command line
setlocal
@rem enter this directory
cd /d %~dp0
@rem Set VS variables (uses Visual Studio 2013)
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
@rem Build the C# native extension
msbuild ..\..\vsprojects\grpc.sln /t:grpc_csharp_ext || goto :error
msbuild ..\..\vsprojects\grpc.sln /t:grpc_csharp_ext /p:PlatformToolset=v120 || goto :error
msbuild Grpc.sln /p:Configuration=Debug || goto :error
msbuild Grpc.sln /p:Configuration=Release || goto :error

@ -33,6 +33,7 @@
#include "src/core/support/string.h"
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@ -236,13 +237,13 @@ GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
*/
GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer(
const grpcsharp_batch_context *ctx, char *buffer, size_t buffer_len) {
grpc_byte_buffer_reader *reader;
grpc_byte_buffer_reader reader;
gpr_slice slice;
size_t offset = 0;
reader = grpc_byte_buffer_reader_create(ctx->recv_message);
grpc_byte_buffer_reader_init(&reader, ctx->recv_message);
while (grpc_byte_buffer_reader_next(reader, &slice)) {
while (grpc_byte_buffer_reader_next(&reader, &slice)) {
size_t len = GPR_SLICE_LENGTH(slice);
GPR_ASSERT(offset + len <= buffer_len);
memcpy(buffer + offset, GPR_SLICE_START_PTR(slice),
@ -250,7 +251,6 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer(
offset += len;
gpr_slice_unref(slice);
}
grpc_byte_buffer_reader_destroy(reader);
}
GPR_EXPORT grpc_status_code GPR_CALLTYPE

@ -36,6 +36,7 @@
#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"
#include "byte_buffer.h"
@ -69,9 +70,10 @@ Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
size_t length = grpc_byte_buffer_length(buffer);
char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
size_t offset = 0;
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader, buffer);
gpr_slice next;
while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}

@ -34,23 +34,26 @@
#import "NSData+GRPC.h"
#include <grpc/byte_buffer.h>
#include <grpc/byte_buffer_reader.h>
#include <string.h>
// TODO(jcanizales): Move these two incantations to the C library.
static void CopyByteBufferToCharArray(grpc_byte_buffer *buffer, char *array) {
size_t offset = 0;
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader, buffer);
gpr_slice next;
while (grpc_byte_buffer_reader_next(reader, &next) != 0){
memcpy(array + offset, GPR_SLICE_START_PTR(next), (size_t) GPR_SLICE_LENGTH(next));
while (grpc_byte_buffer_reader_next(&reader, &next) != 0){
memcpy(array + offset, GPR_SLICE_START_PTR(next),
(size_t)GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
gpr_slice_unref(next);
}
grpc_byte_buffer_reader_destroy(reader);
}
static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, size_t length) {
static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array,
size_t length) {
gpr_slice slice = gpr_slice_from_copied_buffer(array, length);
grpc_byte_buffer *buffer = grpc_byte_buffer_create(&slice, 1);
gpr_slice_unref(slice);

@ -35,21 +35,90 @@
#include <grpc/support/alloc.h>
#pragma mark Category for binary metadata elements
@interface NSData (GRPCMetadata)
+ (instancetype)grpc_dataFromMetadataValue:(grpc_metadata *)metadata;
// Fill a metadata object with the binary value in this NSData and the given key.
- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key;
@end
@implementation NSData (GRPCMetadata)
+ (instancetype)grpc_dataFromMetadataValue:(grpc_metadata *)metadata {
// TODO(jcanizales): Should we use a non-copy constructor?
return [self dataWithBytes:metadata->value length:metadata->value_length];
}
- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key {
// TODO(jcanizales): Encode Unicode chars as ASCII.
metadata->key = [key stringByAppendingString:@"-bin"].UTF8String;
metadata->value = self.bytes;
metadata->value_length = self.length;
}
@end
#pragma mark Category for textual metadata elements
@interface NSString (GRPCMetadata)
+ (instancetype)grpc_stringFromMetadataValue:(grpc_metadata *)metadata;
// Fill a metadata object with the textual value in this NSString and the given key.
- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key;
@end
@implementation NSString (GRPCMetadata)
+ (instancetype)grpc_stringFromMetadataValue:(grpc_metadata *)metadata {
return [[self alloc] initWithBytes:metadata->value
length:metadata->value_length
encoding:NSASCIIStringEncoding];
}
- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key {
if ([key hasSuffix:@"-bin"]) {
// Disallow this, as at best it will confuse the server. If the app really needs to send a
// textual header with a name ending in "-bin", it can be done by removing the suffix and
// encoding the NSString as a NSData object.
//
// Why raise an exception: In the most common case, the developer knows this won't happen in
// their code, so the exception isn't triggered. In the rare cases when the developer can't
// tell, it's easy enough to add a sanitizing filter before the header is set. There, the
// developer can choose whether to drop such a header, or trim its name. Doing either ourselves,
// silently, would be very unintuitive for the user.
[NSException raise:NSInvalidArgumentException
format:@"Metadata keys ending in '-bin' are reserved for NSData values."];
}
// TODO(jcanizales): Encode Unicode chars as ASCII.
metadata->key = key.UTF8String;
metadata->value = self.UTF8String;
metadata->value_length = self.length;
}
@end
#pragma mark Category for metadata arrays
@implementation NSDictionary (GRPC)
+ (instancetype)grpc_dictionaryFromMetadata:(grpc_metadata *)entries count:(size_t)count {
NSMutableDictionary *metadata = [NSMutableDictionary dictionaryWithCapacity:count];
for (grpc_metadata *entry = entries; entry < entries + count; entry++) {
// TODO(jcanizales): Verify in a C library test that it's converting header names to lower case automatically.
NSString *name = [NSString stringWithUTF8String:entry->key];
// TODO(jcanizales): Verify in a C library test that it's converting header names to lower case
// automatically.
NSString *name = [NSString stringWithCString:entry->key encoding:NSASCIIStringEncoding];
if (!name) {
// log?
continue;
}
id value;
if ([name hasSuffix:@"-bin"]) {
name = [name substringToIndex:name.length - 4];
value = [NSData grpc_dataFromMetadataValue:entry];
} else {
value = [NSString grpc_stringFromMetadataValue:entry];
}
if (!metadata[name]) {
metadata[name] = [NSMutableArray array];
}
// TODO(jcanizales): Should we use a non-copy constructor?
[metadata[name] addObject:[NSData dataWithBytes:entry->value
length:entry->value_length]];
[metadata[name] addObject:value];
}
return metadata;
}
@ -60,11 +129,8 @@
for (id key in self) {
id value = self[key];
grpc_metadata *current = &metadata[i];
current->key = [key UTF8String];
if ([value isKindOfClass:[NSData class]]) {
current->value = [value bytes];
} else if ([value isKindOfClass:[NSString class]]) {
current->value = [value UTF8String];
if ([value respondsToSelector:@selector(grpc_initMetadata:withKey:)]) {
[value grpc_initMetadata:current withKey:key];
} else {
[NSException raise:NSInvalidArgumentException
format:@"Metadata values must be NSString or NSData."];

@ -46,6 +46,7 @@
#include "byte_buffer.h"
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/slice.h>
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
@ -65,9 +66,10 @@ void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t length = grpc_byte_buffer_length(buffer);
char *string = ecalloc(length + 1, sizeof(char));
size_t offset = 0;
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader, buffer);
gpr_slice next;
while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}

@ -1,86 +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 <Python.h>
#include <grpc/grpc.h>
#include "grpc/_adapter/_completion_queue.h"
#include "grpc/_adapter/_channel.h"
#include "grpc/_adapter/_call.h"
#include "grpc/_adapter/_server.h"
#include "grpc/_adapter/_client_credentials.h"
#include "grpc/_adapter/_server_credentials.h"
static PyObject *init(PyObject *self) {
grpc_init();
Py_RETURN_NONE;
}
static PyObject *shutdown(PyObject *self) {
grpc_shutdown();
Py_RETURN_NONE;
}
static PyMethodDef _c_methods[] = {
{"init", (PyCFunction)init, METH_NOARGS,
"Initialize the module's static state."},
{"shut_down", (PyCFunction)shutdown, METH_NOARGS,
"Shut down the module's static state."},
{NULL},
};
PyMODINIT_FUNC init_c(void) {
PyObject *module;
module = Py_InitModule3("_c", _c_methods,
"Wrappings of C structures and functions.");
if (pygrpc_add_completion_queue(module) == -1) {
return;
}
if (pygrpc_add_channel(module) == -1) {
return;
}
if (pygrpc_add_call(module) == -1) {
return;
}
if (pygrpc_add_server(module) == -1) {
return;
}
if (pygrpc_add_client_credentials(module) == -1) {
return;
}
if (pygrpc_add_server_credentials(module) == -1) {
return;
}
}

@ -0,0 +1,61 @@
/*
*
* 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 <stdlib.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include "grpc/_adapter/_c/types.h"
static PyMethodDef c_methods[] = {
{NULL}
};
PyMODINIT_FUNC init_c(void) {
PyObject *module;
module = Py_InitModule3("_c", c_methods,
"Wrappings of C structures and functions.");
if (pygrpc_module_add_types(module) < 0) {
return;
}
/* GRPC maintains an internal counter of how many times it has been
initialized and handles multiple pairs of grpc_init()/grpc_shutdown()
invocations accordingly. */
grpc_init();
atexit(&grpc_shutdown);
}

@ -0,0 +1,60 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
int pygrpc_module_add_types(PyObject *module) {
int i;
PyTypeObject *types[] = {
&pygrpc_ClientCredentials_type,
&pygrpc_ServerCredentials_type,
&pygrpc_CompletionQueue_type,
&pygrpc_Call_type,
&pygrpc_Channel_type,
&pygrpc_Server_type
};
for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
if (PyType_Ready(types[i]) < 0) {
return -1;
}
}
for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
Py_INCREF(types[i]);
PyModule_AddObject(module, types[i]->tp_name, (PyObject *)types[i]);
}
return 0;
}

@ -0,0 +1,271 @@
/*
*
* 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__ADAPTER__C_TYPES_H_
#define GRPC__ADAPTER__C_TYPES_H_
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
/*=========================*/
/* Client-side credentials */
/*=========================*/
typedef struct ClientCredentials {
PyObject_HEAD
grpc_credentials *c_creds;
} ClientCredentials;
void pygrpc_ClientCredentials_dealloc(ClientCredentials *self);
ClientCredentials *pygrpc_ClientCredentials_google_default(
PyTypeObject *type, PyObject *ignored);
ClientCredentials *pygrpc_ClientCredentials_ssl(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_compute_engine(
PyTypeObject *type, PyObject *ignored);
ClientCredentials *pygrpc_ClientCredentials_service_account(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_jwt(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_refresh_token(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_fake_transport_security(
PyTypeObject *type, PyObject *ignored);
ClientCredentials *pygrpc_ClientCredentials_iam(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
extern PyTypeObject pygrpc_ClientCredentials_type;
/*=========================*/
/* Server-side credentials */
/*=========================*/
typedef struct ServerCredentials {
PyObject_HEAD
grpc_server_credentials *c_creds;
} ServerCredentials;
void pygrpc_ServerCredentials_dealloc(ServerCredentials *self);
ServerCredentials *pygrpc_ServerCredentials_ssl(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ServerCredentials *pygrpc_ServerCredentials_fake_transport_security(
PyTypeObject *type, PyObject *ignored);
extern PyTypeObject pygrpc_ServerCredentials_type;
/*==================*/
/* Completion queue */
/*==================*/
typedef struct CompletionQueue {
PyObject_HEAD
grpc_completion_queue *c_cq;
} CompletionQueue;
CompletionQueue *pygrpc_CompletionQueue_new(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
void pygrpc_CompletionQueue_dealloc(CompletionQueue *self);
PyObject *pygrpc_CompletionQueue_next(
CompletionQueue *self, PyObject *args, PyObject *kwargs);
PyObject *pygrpc_CompletionQueue_shutdown(
CompletionQueue *self, PyObject *ignored);
extern PyTypeObject pygrpc_CompletionQueue_type;
/*======*/
/* Call */
/*======*/
typedef struct Call {
PyObject_HEAD
grpc_call *c_call;
CompletionQueue *cq;
} Call;
Call *pygrpc_Call_new_empty(CompletionQueue *cq);
void pygrpc_Call_dealloc(Call *self);
PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs);
PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs);
extern PyTypeObject pygrpc_Call_type;
/*=========*/
/* Channel */
/*=========*/
typedef struct Channel {
PyObject_HEAD
grpc_channel *c_chan;
} Channel;
Channel *pygrpc_Channel_new(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
void pygrpc_Channel_dealloc(Channel *self);
Call *pygrpc_Channel_create_call(
Channel *self, PyObject *args, PyObject *kwargs);
extern PyTypeObject pygrpc_Channel_type;
/*========*/
/* Server */
/*========*/
typedef struct Server {
PyObject_HEAD
grpc_server *c_serv;
CompletionQueue *cq;
} Server;
Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
void pygrpc_Server_dealloc(Server *self);
PyObject *pygrpc_Server_request_call(
Server *self, PyObject *args, PyObject *kwargs);
PyObject *pygrpc_Server_add_http2_port(
Server *self, PyObject *args, PyObject *kwargs);
PyObject *pygrpc_Server_start(Server *self, PyObject *ignored);
PyObject *pygrpc_Server_shutdown(
Server *self, PyObject *args, PyObject *kwargs);
extern PyTypeObject pygrpc_Server_type;
/*=========*/
/* Utility */
/*=========*/
/* Every tag that passes from Python GRPC to GRPC core is of this type. */
typedef struct pygrpc_tag {
PyObject *user_tag;
Call *call;
grpc_call_details request_call_details;
grpc_metadata_array request_metadata;
grpc_op *ops;
size_t nops;
int is_new_call;
} pygrpc_tag;
/* Construct a tag associated with a batch call. Does not take ownership of the
resources in the elements of ops. */
pygrpc_tag *pygrpc_produce_batch_tag(PyObject *user_tag, Call *call,
grpc_op *ops, size_t nops);
/* Construct a tag associated with a server request. The calling code should
use the appropriate fields of the produced tag in the invocation of
grpc_server_request_call. */
pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call);
/* Construct a tag associated with a server shutdown. */
pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag);
/* Frees all resources owned by the tag and the tag itself. */
void pygrpc_discard_tag(pygrpc_tag *tag);
/* Consumes an event and its associated tag, providing a Python tuple of the
form `(type, tag, call, call_details, results)` (where type is an integer
corresponding to a grpc_completion_type, tag is an arbitrary PyObject, call
is the call object associated with the event [if any], call_details is a
tuple of form `(method, host, deadline)` [if such details are available],
and resultd is a list of tuples of form `(type, metadata, message, status,
cancelled)` [where type corresponds to a grpc_op_type, metadata is a
sequence of 2-sequences of strings, message is a byte string, and status is
a 2-tuple of an integer corresponding to grpc_status_code and a string of
status details]).
Frees all resources associated with the event tag. */
PyObject *pygrpc_consume_event(grpc_event event);
/* Transliterate the Python tuple of form `(type, metadata, message,
status)` (where type is an integer corresponding to a grpc_op_type, metadata
is a sequence of 2-sequences of strings, message is a byte string, and
status is 2-tuple of an integer corresponding to grpc_status_code and a
string of status details) to a grpc_op suitable for use in a
grpc_call_start_batch invocation. The grpc_op is a 'directory' of resources
that must be freed after GRPC core is done with them.
Calls gpr_malloc (or the appropriate type-specific grpc_*_create function)
to populate the appropriate union-discriminated members of the op.
Returns true on success, false on failure. */
int pygrpc_produce_op(PyObject *op, grpc_op *result);
/* Discards all resources associated with the passed in op that was produced by
pygrpc_produce_op. */
void pygrpc_discard_op(grpc_op op);
/* Transliterate the grpc_ops (which have been sent through a
grpc_call_start_batch invocation and whose corresponding event has appeared
on a completion queue) to a Python tuple of form `(type, metadata, message,
status, cancelled)` (where type is an integer corresponding to a
grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a
byte string, and status is 2-tuple of an integer corresponding to
grpc_status_code and a string of status details).
Calls gpr_free (or the appropriate type-specific grpc_*_destroy function) on
the appropriate union-discriminated populated members of the ops. */
PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops);
/* Transliterate from a gpr_timespec to a double (in units of seconds, either
from the epoch if interpreted absolutely or as a delta otherwise). */
double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec);
/* Transliterate from a double (in units of seconds from the epoch if
interpreted absolutely or as a delta otherwise) to a gpr_timespec. */
gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds);
/* Returns true on success, false on failure. */
int pygrpc_cast_pylist_to_send_metadata(
PyObject *pylist, grpc_metadata **metadata, size_t *count);
/* Returns a metadata array as a Python object on success, else NULL. */
PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata);
/* Transliterate from a list of python channel arguments (2-tuples of string
and string|integer|None) to a grpc_channel_args object. The strings placed
in the grpc_channel_args object's grpc_arg elements are views of the Python
object. The Python object must live long enough for the grpc_channel_args
to be used. Arguments set to None are silently ignored. Returns true on
success, false on failure. */
int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args);
void pygrpc_discard_channel_args(grpc_channel_args args);
/* Read the bytes from grpc_byte_buffer to a gpr_malloc'd array of bytes;
output to result and result_size. */
void pygrpc_byte_buffer_to_bytes(
grpc_byte_buffer *buffer, char **result, size_t *result_size);
/*========*/
/* Module */
/*========*/
/* Returns 0 on success, -1 on failure. */
int pygrpc_module_add_types(PyObject *module);
#endif /* GRPC__ADAPTER__C_TYPES_H_ */

@ -0,0 +1,163 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
PyMethodDef pygrpc_Call_methods[] = {
{"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""},
{"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""},
{NULL}
};
const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call.";
PyTypeObject pygrpc_Call_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"Call", /* tp_name */
sizeof(Call), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_Call_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
pygrpc_Call_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_Call_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0 /* tp_new */
};
Call *pygrpc_Call_new_empty(CompletionQueue *cq) {
Call *call = (Call *)pygrpc_Call_type.tp_alloc(&pygrpc_Call_type, 0);
call->c_call = NULL;
call->cq = cq;
Py_XINCREF(call->cq);
return call;
}
void pygrpc_Call_dealloc(Call *self) {
if (self->c_call) {
grpc_call_destroy(self->c_call);
}
Py_XDECREF(self->cq);
self->ob_type->tp_free((PyObject *)self);
}
PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs) {
PyObject *op_list;
PyObject *user_tag;
grpc_op *ops;
size_t nops;
size_t i;
size_t j;
pygrpc_tag *tag;
grpc_call_error errcode;
static char *keywords[] = {"ops", "tag", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:start_batch", keywords,
&op_list, &user_tag)) {
return NULL;
}
if (!PyList_Check(op_list)) {
PyErr_SetString(PyExc_TypeError, "expected a list of OpArgs");
return NULL;
}
nops = PyList_Size(op_list);
ops = gpr_malloc(sizeof(grpc_op) * nops);
for (i = 0; i < nops; ++i) {
PyObject *item = PyList_GET_ITEM(op_list, i);
if (!pygrpc_produce_op(item, &ops[i])) {
for (j = 0; j < i; ++j) {
pygrpc_discard_op(ops[j]);
}
return NULL;
}
}
tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops);
errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag);
gpr_free(ops);
return PyInt_FromLong(errcode);
}
PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) {
PyObject *py_code = NULL;
grpc_call_error errcode;
int code;
char *details = NULL;
static char *keywords[] = {"code", "details", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:start_batch", keywords,
&py_code, &details)) {
return NULL;
}
if (py_code != NULL && details != NULL) {
if (!PyInt_Check(py_code)) {
PyErr_SetString(PyExc_TypeError, "expected integer code");
return NULL;
}
code = PyInt_AsLong(py_code);
errcode = grpc_call_cancel_with_status(self->c_call, code, details);
} else if (py_code != NULL || details != NULL) {
PyErr_SetString(PyExc_ValueError,
"if `code` is specified, so must `details`");
return NULL;
} else {
errcode = grpc_call_cancel(self->c_call);
}
return PyInt_FromLong(errcode);
}

@ -0,0 +1,134 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
PyMethodDef pygrpc_Channel_methods[] = {
{"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""},
{NULL}
};
const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel.";
PyTypeObject pygrpc_Channel_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"Channel", /* tp_name */
sizeof(Channel), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_Channel_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
pygrpc_Channel_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_Channel_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
(newfunc)pygrpc_Channel_new /* tp_new */
};
Channel *pygrpc_Channel_new(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
Channel *self;
const char *target;
PyObject *py_args;
ClientCredentials *creds = NULL;
grpc_channel_args c_args;
char *keywords[] = {"target", "args", "creds", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords,
&target, &py_args, &pygrpc_ClientCredentials_type, &creds)) {
return NULL;
}
if (!pygrpc_produce_channel_args(py_args, &c_args)) {
return NULL;
}
self = (Channel *)type->tp_alloc(type, 0);
if (creds) {
self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args);
} else {
self->c_chan = grpc_channel_create(target, &c_args);
}
pygrpc_discard_channel_args(c_args);
return self;
}
void pygrpc_Channel_dealloc(Channel *self) {
grpc_channel_destroy(self->c_chan);
self->ob_type->tp_free((PyObject *)self);
}
Call *pygrpc_Channel_create_call(
Channel *self, PyObject *args, PyObject *kwargs) {
Call *call;
CompletionQueue *cq;
const char *method;
const char *host;
double deadline;
char *keywords[] = {"cq", "method", "host", "deadline", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!ssd:create_call", keywords,
&pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) {
return NULL;
}
call = pygrpc_Call_new_empty(cq);
call->c_call = grpc_channel_create_call(
self->c_chan, cq->c_cq, method, host,
pygrpc_cast_double_to_gpr_timespec(deadline));
return call;
}

@ -0,0 +1,286 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
PyMethodDef pygrpc_ClientCredentials_methods[] = {
{"google_default", (PyCFunction)pygrpc_ClientCredentials_google_default,
METH_CLASS|METH_NOARGS, ""},
{"ssl", (PyCFunction)pygrpc_ClientCredentials_ssl,
METH_CLASS|METH_KEYWORDS, ""},
{"composite", (PyCFunction)pygrpc_ClientCredentials_composite,
METH_CLASS|METH_KEYWORDS, ""},
{"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine,
METH_CLASS|METH_NOARGS, ""},
{"service_account", (PyCFunction)pygrpc_ClientCredentials_service_account,
METH_CLASS|METH_KEYWORDS, ""},
{"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt,
METH_CLASS|METH_KEYWORDS, ""},
{"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token,
METH_CLASS|METH_KEYWORDS, ""},
{"fake_transport_security",
(PyCFunction)pygrpc_ClientCredentials_fake_transport_security,
METH_CLASS|METH_NOARGS, ""},
{"iam", (PyCFunction)pygrpc_ClientCredentials_iam,
METH_CLASS|METH_KEYWORDS, ""},
{NULL}
};
const char pygrpc_ClientCredentials_doc[] = "";
PyTypeObject pygrpc_ClientCredentials_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"ClientCredentials", /* tp_name */
sizeof(ClientCredentials), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_ClientCredentials_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
pygrpc_ClientCredentials_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_ClientCredentials_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0 /* tp_new */
};
void pygrpc_ClientCredentials_dealloc(ClientCredentials *self) {
grpc_credentials_release(self->c_creds);
self->ob_type->tp_free((PyObject *)self);
}
ClientCredentials *pygrpc_ClientCredentials_google_default(
PyTypeObject *type, PyObject *ignored) {
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_google_default_credentials_create();
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create Google default credentials");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_ssl(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ClientCredentials *self;
const char *root_certs;
const char *private_key = NULL;
const char *cert_chain = NULL;
grpc_ssl_pem_key_cert_pair key_cert_pair;
static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords,
&root_certs, &private_key, &cert_chain)) {
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
if (private_key && cert_chain) {
key_cert_pair.private_key = private_key;
key_cert_pair.cert_chain = cert_chain;
self->c_creds = grpc_ssl_credentials_create(root_certs, &key_cert_pair);
} else {
self->c_creds = grpc_ssl_credentials_create(root_certs, NULL);
}
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ClientCredentials *self;
ClientCredentials *creds1;
ClientCredentials *creds2;
static char *keywords[] = {"creds1", "creds2", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
&pygrpc_ClientCredentials_type, &creds1,
&pygrpc_ClientCredentials_type, &creds2)) {
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_composite_credentials_create(
creds1->c_creds, creds2->c_creds);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_compute_engine(
PyTypeObject *type, PyObject *ignored) {
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_compute_engine_credentials_create();
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create compute engine credentials");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_service_account(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ClientCredentials *self;
const char *json_key;
const char *scope;
double lifetime;
static char *keywords[] = {"json_key", "scope", "token_lifetime", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssd:service_account", keywords,
&json_key, &scope, &lifetime)) {
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_service_account_credentials_create(
json_key, scope, pygrpc_cast_double_to_gpr_timespec(lifetime));
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create service account credentials");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_jwt(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ClientCredentials *self;
const char *json_key;
double lifetime;
static char *keywords[] = {"json_key", "token_lifetime", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd:jwt", keywords,
&json_key, &lifetime)) {
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_jwt_credentials_create(
json_key, pygrpc_cast_double_to_gpr_timespec(lifetime));
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_refresh_token(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ClientCredentials *self;
const char *json_refresh_token;
static char *keywords[] = {"json_refresh_token", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords,
&json_refresh_token)) {
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_refresh_token_credentials_create(json_refresh_token);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create credentials from refresh token");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_fake_transport_security(
PyTypeObject *type, PyObject *ignored) {
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_fake_transport_security_credentials_create();
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
"couldn't create fake credentials; "
"something is horribly wrong with the universe");
return NULL;
}
return self;
}
ClientCredentials *pygrpc_ClientCredentials_iam(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ClientCredentials *self;
const char *authorization_token;
const char *authority_selector;
static char *keywords[] = {"authorization_token", "authority_selector", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:iam", keywords,
&authorization_token, &authority_selector)) {
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_iam_credentials_create(authorization_token,
authority_selector);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials");
return NULL;
}
return self;
}

@ -0,0 +1,124 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
PyMethodDef pygrpc_CompletionQueue_methods[] = {
{"next", (PyCFunction)pygrpc_CompletionQueue_next, METH_KEYWORDS, ""},
{"shutdown", (PyCFunction)pygrpc_CompletionQueue_shutdown, METH_NOARGS, ""},
{NULL}
};
const char pygrpc_CompletionQueue_doc[] =
"See grpc._adapter._types.CompletionQueue.";
PyTypeObject pygrpc_CompletionQueue_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"CompletionQueue", /* tp_name */
sizeof(CompletionQueue), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_CompletionQueue_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
pygrpc_CompletionQueue_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_CompletionQueue_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
(newfunc)pygrpc_CompletionQueue_new /* tp_new */
};
CompletionQueue *pygrpc_CompletionQueue_new(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0);
self->c_cq = grpc_completion_queue_create();
return self;
}
void pygrpc_CompletionQueue_dealloc(CompletionQueue *self) {
grpc_completion_queue_destroy(self->c_cq);
self->ob_type->tp_free((PyObject *)self);
}
PyObject *pygrpc_CompletionQueue_next(
CompletionQueue *self, PyObject *args, PyObject *kwargs) {
double deadline;
grpc_event event;
PyObject *transliterated_event;
static char *keywords[] = {"deadline", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:next", keywords,
&deadline)) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS;
event = grpc_completion_queue_next(
self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline));
Py_END_ALLOW_THREADS;
transliterated_event = pygrpc_consume_event(event);
return transliterated_event;
}
PyObject *pygrpc_CompletionQueue_shutdown(
CompletionQueue *self, PyObject *ignored) {
grpc_completion_queue_shutdown(self->c_cq);
Py_RETURN_NONE;
}

@ -0,0 +1,183 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
PyMethodDef pygrpc_Server_methods[] = {
{"request_call", (PyCFunction)pygrpc_Server_request_call,
METH_KEYWORDS, ""},
{"add_http2_port", (PyCFunction)pygrpc_Server_add_http2_port,
METH_KEYWORDS, ""},
{"start", (PyCFunction)pygrpc_Server_start, METH_NOARGS, ""},
{"shutdown", (PyCFunction)pygrpc_Server_shutdown, METH_KEYWORDS, ""},
{NULL}
};
const char pygrpc_Server_doc[] = "See grpc._adapter._types.Server.";
PyTypeObject pygrpc_Server_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"Server", /* tp_name */
sizeof(Server), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_Server_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
pygrpc_Server_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_Server_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
(newfunc)pygrpc_Server_new /* tp_new */
};
Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
Server *self;
CompletionQueue *cq;
PyObject *py_args;
grpc_channel_args c_args;
char *keywords[] = {"cq", "args", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Channel", keywords,
&pygrpc_CompletionQueue_type, &cq, &py_args)) {
return NULL;
}
if (!pygrpc_produce_channel_args(py_args, &c_args)) {
return NULL;
}
self = (Server *)type->tp_alloc(type, 0);
self->c_serv = grpc_server_create(&c_args);
pygrpc_discard_channel_args(c_args);
self->cq = cq;
Py_INCREF(self->cq);
return self;
}
void pygrpc_Server_dealloc(Server *self) {
grpc_server_destroy(self->c_serv);
Py_XDECREF(self->cq);
self->ob_type->tp_free((PyObject *)self);
}
PyObject *pygrpc_Server_request_call(
Server *self, PyObject *args, PyObject *kwargs) {
CompletionQueue *cq;
PyObject *user_tag;
pygrpc_tag *tag;
Call *empty_call;
grpc_call_error errcode;
static char *keywords[] = {"cq", "tag", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "O!O", keywords,
&pygrpc_CompletionQueue_type, &cq, &user_tag)) {
return NULL;
}
empty_call = pygrpc_Call_new_empty(cq);
tag = pygrpc_produce_request_tag(user_tag, empty_call);
errcode = grpc_server_request_call(
self->c_serv, &tag->call->c_call, &tag->request_call_details,
&tag->request_metadata, tag->call->cq->c_cq, self->cq->c_cq, tag);
Py_DECREF(empty_call);
return PyInt_FromLong(errcode);
}
PyObject *pygrpc_Server_add_http2_port(
Server *self, PyObject *args, PyObject *kwargs) {
const char *addr;
ServerCredentials *creds = NULL;
int port;
static char *keywords[] = {"addr", "creds", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "s|O!:add_http2_port", keywords,
&addr, &pygrpc_ServerCredentials_type, &creds)) {
return NULL;
}
if (creds) {
port = grpc_server_add_secure_http2_port(
self->c_serv, addr, creds->c_creds);
} else {
port = grpc_server_add_http2_port(self->c_serv, addr);
}
return PyInt_FromLong(port);
}
PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) {
grpc_server_start(self->c_serv);
Py_RETURN_NONE;
}
PyObject *pygrpc_Server_shutdown(
Server *self, PyObject *args, PyObject *kwargs) {
PyObject *user_tag = NULL;
pygrpc_tag *tag;
static char *keywords[] = {"tag", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", keywords, &user_tag)) {
return NULL;
}
if (user_tag) {
tag = pygrpc_produce_server_shutdown_tag(user_tag);
grpc_server_shutdown_and_notify(self->c_serv, tag);
} else {
grpc_server_shutdown(self->c_serv);
}
Py_RETURN_NONE;
}

@ -0,0 +1,146 @@
/*
*
* 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/_adapter/_c/types.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
PyMethodDef pygrpc_ServerCredentials_methods[] = {
{"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl,
METH_CLASS|METH_KEYWORDS, ""},
{"fake_transport_security",
(PyCFunction)pygrpc_ServerCredentials_fake_transport_security,
METH_CLASS|METH_NOARGS, ""},
{NULL}
};
const char pygrpc_ServerCredentials_doc[] = "";
PyTypeObject pygrpc_ServerCredentials_type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"ServerCredentials", /* tp_name */
sizeof(ServerCredentials), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pygrpc_ServerCredentials_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
pygrpc_ServerCredentials_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pygrpc_ServerCredentials_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0 /* tp_new */
};
void pygrpc_ServerCredentials_dealloc(ServerCredentials *self) {
grpc_server_credentials_release(self->c_creds);
self->ob_type->tp_free((PyObject *)self);
}
ServerCredentials *pygrpc_ServerCredentials_ssl(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
ServerCredentials *self;
const char *root_certs;
PyObject *py_key_cert_pairs;
grpc_ssl_pem_key_cert_pair *key_cert_pairs;
size_t num_key_cert_pairs;
size_t i;
static char *keywords[] = {"root_certs", "key_cert_pairs", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zO:ssl", keywords,
&root_certs, &py_key_cert_pairs)) {
return NULL;
}
if (!PyList_Check(py_key_cert_pairs)) {
PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings");
return NULL;
}
num_key_cert_pairs = PyList_Size(py_key_cert_pairs);
key_cert_pairs =
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
for (i = 0; i < num_key_cert_pairs; ++i) {
PyObject *item = PyList_GET_ITEM(py_key_cert_pairs, i);
const char *key;
const char *cert;
if (!PyArg_ParseTuple(item, "zz", &key, &cert)) {
gpr_free(key_cert_pairs);
PyErr_SetString(PyExc_TypeError,
"expected a list of 2-tuples of strings");
return NULL;
}
key_cert_pairs[i].private_key = key;
key_cert_pairs[i].cert_chain = cert;
}
self = (ServerCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_ssl_server_credentials_create(
root_certs, key_cert_pairs, num_key_cert_pairs);
gpr_free(key_cert_pairs);
return self;
}
ServerCredentials *pygrpc_ServerCredentials_fake_transport_security(
PyTypeObject *type, PyObject *ignored) {
ServerCredentials *self = (ServerCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_fake_transport_security_server_credentials_create();
return self;
}

@ -0,0 +1,461 @@
/*
*
* 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 <math.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/alloc.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#include "grpc/_adapter/_c/types.h"
pygrpc_tag *pygrpc_produce_batch_tag(
PyObject *user_tag, Call *call, grpc_op *ops, size_t nops) {
pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
tag->user_tag = user_tag;
Py_XINCREF(tag->user_tag);
tag->call = call;
Py_XINCREF(tag->call);
tag->ops = gpr_malloc(sizeof(grpc_op)*nops);
memcpy(tag->ops, ops, sizeof(grpc_op)*nops);
tag->nops = nops;
grpc_call_details_init(&tag->request_call_details);
grpc_metadata_array_init(&tag->request_metadata);
tag->is_new_call = 0;
return tag;
}
pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call) {
pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
tag->user_tag = user_tag;
Py_XINCREF(tag->user_tag);
tag->call = empty_call;
Py_XINCREF(tag->call);
tag->ops = NULL;
tag->nops = 0;
grpc_call_details_init(&tag->request_call_details);
grpc_metadata_array_init(&tag->request_metadata);
tag->is_new_call = 1;
return tag;
}
pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag) {
pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
tag->user_tag = user_tag;
Py_XINCREF(tag->user_tag);
tag->call = NULL;
tag->ops = NULL;
tag->nops = 0;
grpc_call_details_init(&tag->request_call_details);
grpc_metadata_array_init(&tag->request_metadata);
tag->is_new_call = 0;
return tag;
}
void pygrpc_discard_tag(pygrpc_tag *tag) {
if (!tag) {
return;
}
Py_XDECREF(tag->user_tag);
Py_XDECREF(tag->call);
gpr_free(tag->ops);
grpc_call_details_destroy(&tag->request_call_details);
grpc_metadata_array_destroy(&tag->request_metadata);
gpr_free(tag);
}
PyObject *pygrpc_consume_event(grpc_event event) {
pygrpc_tag *tag;
PyObject *result;
if (event.type == GRPC_QUEUE_TIMEOUT) {
Py_RETURN_NONE;
}
tag = event.tag;
switch (event.type) {
case GRPC_QUEUE_SHUTDOWN:
result = Py_BuildValue("iOOOOO", GRPC_QUEUE_SHUTDOWN,
Py_None, Py_None, Py_None, Py_None, Py_True);
break;
case GRPC_OP_COMPLETE:
if (tag->is_new_call) {
result = Py_BuildValue(
"iOO(ssd)[(iNOOOO)]O", GRPC_OP_COMPLETE, tag->user_tag, tag->call,
tag->request_call_details.method, tag->request_call_details.host,
pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline),
GRPC_OP_RECV_INITIAL_METADATA,
pygrpc_cast_metadata_array_to_pylist(tag->request_metadata), Py_None,
Py_None, Py_None, Py_None,
event.success ? Py_True : Py_False);
} else {
result = Py_BuildValue("iOOONO", GRPC_OP_COMPLETE, tag->user_tag,
tag->call, Py_None, pygrpc_consume_ops(tag->ops, tag->nops),
event.success ? Py_True : Py_False);
}
break;
default:
PyErr_SetString(PyExc_ValueError,
"unknown completion type; could not translate event");
return NULL;
}
pygrpc_discard_tag(tag);
return result;
}
int pygrpc_produce_op(PyObject *op, grpc_op *result) {
static const int OP_TUPLE_SIZE = 5;
static const int STATUS_TUPLE_SIZE = 2;
static const int TYPE_INDEX = 0;
static const int INITIAL_METADATA_INDEX = 1;
static const int TRAILING_METADATA_INDEX = 2;
static const int MESSAGE_INDEX = 3;
static const int STATUS_INDEX = 4;
static const int STATUS_CODE_INDEX = 0;
static const int STATUS_DETAILS_INDEX = 1;
grpc_op c_op;
if (!PyTuple_Check(op)) {
PyErr_SetString(PyExc_TypeError, "expected tuple op");
return 0;
}
if (PyTuple_Size(op) != OP_TUPLE_SIZE) {
char buf[64];
snprintf(buf, sizeof(buf), "expected tuple op of length %d", OP_TUPLE_SIZE);
PyErr_SetString(PyExc_ValueError, buf);
return 0;
}
int type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX));
if (PyErr_Occurred()) {
return 0;
}
Py_ssize_t message_size;
char *message;
char *status_details;
gpr_slice message_slice;
c_op.op = type;
switch (type) {
case GRPC_OP_SEND_INITIAL_METADATA:
if (!pygrpc_cast_pylist_to_send_metadata(
PyTuple_GetItem(op, INITIAL_METADATA_INDEX),
&c_op.data.send_initial_metadata.metadata,
&c_op.data.send_initial_metadata.count)) {
return 0;
}
break;
case GRPC_OP_SEND_MESSAGE:
PyString_AsStringAndSize(
PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size);
message_slice = gpr_slice_from_copied_buffer(message, message_size);
c_op.data.send_message = grpc_byte_buffer_create(&message_slice, 1);
gpr_slice_unref(message_slice);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
/* Don't need to fill in any other fields. */
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
if (!pygrpc_cast_pylist_to_send_metadata(
PyTuple_GetItem(op, TRAILING_METADATA_INDEX),
&c_op.data.send_status_from_server.trailing_metadata,
&c_op.data.send_status_from_server.trailing_metadata_count)) {
return 0;
}
if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) {
char buf[64];
snprintf(buf, sizeof(buf), "expected tuple status in op of length %d",
STATUS_TUPLE_SIZE);
PyErr_SetString(PyExc_TypeError, buf);
return 0;
}
c_op.data.send_status_from_server.status = PyInt_AsLong(
PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX));
status_details = PyString_AsString(
PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX));
if (PyErr_Occurred()) {
return 0;
}
c_op.data.send_status_from_server.status_details =
gpr_malloc(strlen(status_details) + 1);
strcpy((char *)c_op.data.send_status_from_server.status_details,
status_details);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array));
grpc_metadata_array_init(c_op.data.recv_initial_metadata);
break;
case GRPC_OP_RECV_MESSAGE:
c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *));
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
c_op.data.recv_status_on_client.trailing_metadata =
gpr_malloc(sizeof(grpc_metadata_array));
grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata);
c_op.data.recv_status_on_client.status =
gpr_malloc(sizeof(grpc_status_code *));
c_op.data.recv_status_on_client.status_details =
gpr_malloc(sizeof(char *));
*c_op.data.recv_status_on_client.status_details = NULL;
c_op.data.recv_status_on_client.status_details_capacity =
gpr_malloc(sizeof(size_t));
*c_op.data.recv_status_on_client.status_details_capacity = 0;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int));
break;
default:
return 0;
}
*result = c_op;
return 1;
}
void pygrpc_discard_op(grpc_op op) {
switch(op.op) {
case GRPC_OP_SEND_INITIAL_METADATA:
gpr_free(op.data.send_initial_metadata.metadata);
break;
case GRPC_OP_SEND_MESSAGE:
grpc_byte_buffer_destroy(op.data.send_message);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
/* Don't need to free any fields. */
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
gpr_free(op.data.send_status_from_server.trailing_metadata);
gpr_free((char *)op.data.send_status_from_server.status_details);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
grpc_metadata_array_destroy(op.data.recv_initial_metadata);
gpr_free(op.data.recv_initial_metadata);
break;
case GRPC_OP_RECV_MESSAGE:
grpc_byte_buffer_destroy(*op.data.recv_message);
gpr_free(op.data.recv_message);
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
grpc_metadata_array_destroy(op.data.recv_status_on_client.trailing_metadata);
gpr_free(op.data.recv_status_on_client.trailing_metadata);
gpr_free(op.data.recv_status_on_client.status);
gpr_free(*op.data.recv_status_on_client.status_details);
gpr_free(op.data.recv_status_on_client.status_details);
gpr_free(op.data.recv_status_on_client.status_details_capacity);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
gpr_free(op.data.recv_close_on_server.cancelled);
break;
}
}
PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) {
static const int TYPE_INDEX = 0;
static const int INITIAL_METADATA_INDEX = 1;
static const int TRAILING_METADATA_INDEX = 2;
static const int MESSAGE_INDEX = 3;
static const int STATUS_INDEX = 4;
static const int CANCELLED_INDEX = 5;
static const int OPRESULT_LENGTH = 6;
PyObject *list;
size_t i;
size_t j;
char *bytes;
size_t bytes_size;
PyObject *results = PyList_New(nops);
if (!results) {
return NULL;
}
for (i = 0; i < nops; ++i) {
PyObject *result = PyTuple_Pack(OPRESULT_LENGTH, Py_None, Py_None, Py_None,
Py_None, Py_None, Py_None);
PyTuple_SetItem(result, TYPE_INDEX, PyInt_FromLong(op[i].op));
switch(op[i].op) {
case GRPC_OP_RECV_INITIAL_METADATA:
PyTuple_SetItem(result, INITIAL_METADATA_INDEX,
list=PyList_New(op[i].data.recv_initial_metadata->count));
for (j = 0; j < op[i].data.recv_initial_metadata->count; ++j) {
grpc_metadata md = op[i].data.recv_initial_metadata->metadata[j];
PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value,
(Py_ssize_t)md.value_length));
}
break;
case GRPC_OP_RECV_MESSAGE:
if (*op[i].data.recv_message) {
pygrpc_byte_buffer_to_bytes(
*op[i].data.recv_message, &bytes, &bytes_size);
PyTuple_SetItem(result, MESSAGE_INDEX,
PyString_FromStringAndSize(bytes, bytes_size));
gpr_free(bytes);
} else {
PyTuple_SetItem(result, MESSAGE_INDEX, Py_BuildValue(""));
}
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
PyTuple_SetItem(
result, TRAILING_METADATA_INDEX,
list = PyList_New(op[i].data.recv_status_on_client.trailing_metadata->count));
for (j = 0; j < op[i].data.recv_status_on_client.trailing_metadata->count; ++j) {
grpc_metadata md =
op[i].data.recv_status_on_client.trailing_metadata->metadata[j];
PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value,
(Py_ssize_t)md.value_length));
}
PyTuple_SetItem(
result, STATUS_INDEX, Py_BuildValue(
"is", *op[i].data.recv_status_on_client.status,
*op[i].data.recv_status_on_client.status_details));
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
PyTuple_SetItem(
result, CANCELLED_INDEX,
PyBool_FromLong(*op[i].data.recv_close_on_server.cancelled));
break;
default:
break;
}
pygrpc_discard_op(op[i]);
PyList_SetItem(results, i, result);
}
return results;
}
double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) {
return timespec.tv_sec + 1e-9*timespec.tv_nsec;
}
gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) {
gpr_timespec result;
if isinf(seconds) {
result = seconds > 0.0 ? gpr_inf_future : gpr_inf_past;
} else {
result.tv_sec = (time_t)seconds;
result.tv_nsec = ((seconds - result.tv_sec) * 1e9);
}
return result;
}
int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args) {
size_t num_args = PyList_Size(py_args);
size_t i;
grpc_channel_args args = {num_args, gpr_malloc(sizeof(grpc_arg) * num_args)};
for (i = 0; i < args.num_args; ++i) {
char *key;
PyObject *value;
if (!PyArg_ParseTuple(PyList_GetItem(py_args, i), "zO", &key, &value)) {
gpr_free(args.args);
args.num_args = 0;
args.args = NULL;
PyErr_SetString(PyExc_TypeError,
"expected a list of 2-tuple of str and str|int|None");
return 0;
}
args.args[i].key = key;
if (PyInt_Check(value)) {
args.args[i].type = GRPC_ARG_INTEGER;
args.args[i].value.integer = PyInt_AsLong(value);
} else if (PyString_Check(value)) {
args.args[i].type = GRPC_ARG_STRING;
args.args[i].value.string = PyString_AsString(value);
} else if (value == Py_None) {
--args.num_args;
--i;
continue;
} else {
gpr_free(args.args);
args.num_args = 0;
args.args = NULL;
PyErr_SetString(PyExc_TypeError,
"expected a list of 2-tuple of str and str|int|None");
return 0;
}
}
*c_args = args;
return 1;
}
void pygrpc_discard_channel_args(grpc_channel_args args) {
gpr_free(args.args);
}
int pygrpc_cast_pylist_to_send_metadata(
PyObject *pylist, grpc_metadata **metadata, size_t *count) {
size_t i;
Py_ssize_t value_length;
*count = PyList_Size(pylist);
*metadata = gpr_malloc(sizeof(grpc_metadata) * *count);
for (i = 0; i < *count; ++i) {
if (!PyArg_ParseTuple(
PyList_GetItem(pylist, i), "ss#",
&(*metadata)[i].key, &(*metadata)[i].value, &value_length)) {
gpr_free(*metadata);
*count = 0;
*metadata = NULL;
return 0;
}
(*metadata)[i].value_length = value_length;
}
return 1;
}
PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata) {
PyObject *result = PyList_New(metadata.count);
size_t i;
for (i = 0; i < metadata.count; ++i) {
PyList_SetItem(
result, i, Py_BuildValue(
"ss#", metadata.metadata[i].key, metadata.metadata[i].value,
(Py_ssize_t)metadata.metadata[i].value_length));
if (PyErr_Occurred()) {
Py_DECREF(result);
return NULL;
}
}
return result;
}
void pygrpc_byte_buffer_to_bytes(
grpc_byte_buffer *buffer, char **result, size_t *result_size) {
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader, buffer);
gpr_slice slice;
char *read_result = NULL;
size_t size = 0;
while (grpc_byte_buffer_reader_next(&reader, &slice)) {
read_result = gpr_realloc(read_result, size + GPR_SLICE_LENGTH(slice));
memcpy(read_result + size, GPR_SLICE_START_PTR(slice),
GPR_SLICE_LENGTH(slice));
size = size + GPR_SLICE_LENGTH(slice);
gpr_slice_unref(slice);
}
*result_size = size;
*result = read_result;
}

@ -27,192 +27,40 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Tests for _adapter._c."""
import threading
import time
import unittest
from grpc._adapter import _c
from grpc._adapter import _datatypes
_TIMEOUT = 3
_FUTURE = time.time() + 60 * 60 * 24
_IDEMPOTENCE_DEMONSTRATION = 7
class _CTest(unittest.TestCase):
def testUpAndDown(self):
_c.init()
_c.shut_down()
def testCompletionQueue(self):
_c.init()
completion_queue = _c.CompletionQueue()
event = completion_queue.get(0)
self.assertIsNone(event)
event = completion_queue.get(time.time())
self.assertIsNone(event)
event = completion_queue.get(time.time() + _TIMEOUT)
self.assertIsNone(event)
completion_queue.stop()
for _ in range(_IDEMPOTENCE_DEMONSTRATION):
event = completion_queue.get(time.time() + _TIMEOUT)
self.assertIs(event.kind, _datatypes.Event.Kind.STOP)
del completion_queue
del event
from grpc._adapter import _types
_c.shut_down()
def testChannel(self):
_c.init()
channel = _c.Channel(
'test host:12345', None, server_host_override='ignored')
del channel
_c.shut_down()
def testCall(self):
method = 'test method'
host = 'test host'
_c.init()
channel = _c.Channel('%s:%d' % (host, 12345), None)
completion_queue = _c.CompletionQueue()
call = _c.Call(channel, completion_queue, method, host,
time.time() + _TIMEOUT)
del call
del completion_queue
del channel
class CTypeSmokeTest(unittest.TestCase):
_c.shut_down()
def testClientCredentialsUpDown(self):
credentials = _c.ClientCredentials.fake_transport_security()
del credentials
def testServer(self):
_c.init()
def testServerCredentialsUpDown(self):
credentials = _c.ServerCredentials.fake_transport_security()
del credentials
def testCompletionQueueUpDown(self):
completion_queue = _c.CompletionQueue()
server = _c.Server(completion_queue)
server.add_http2_addr('[::]:0')
server.start()
server.stop()
completion_queue.stop()
del server
del completion_queue
service_tag = object()
def testServerUpDown(self):
completion_queue = _c.CompletionQueue()
server = _c.Server(completion_queue)
server.add_http2_addr('[::]:0')
server.start()
server.service(service_tag)
server.stop()
completion_queue.stop()
event = completion_queue.get(time.time() + _TIMEOUT)
self.assertIs(event.kind, _datatypes.Event.Kind.SERVICE_ACCEPTED)
self.assertIs(event.tag, service_tag)
self.assertIsNone(event.service_acceptance)
for _ in range(_IDEMPOTENCE_DEMONSTRATION):
event = completion_queue.get(time.time() + _TIMEOUT)
self.assertIs(event.kind, _datatypes.Event.Kind.STOP)
del server
serv = _c.Server(completion_queue, [])
del serv
del completion_queue
completion_queue = _c.CompletionQueue()
server = _c.Server(completion_queue)
server.add_http2_addr('[::]:0')
server.start()
thread = threading.Thread(target=completion_queue.get, args=(_FUTURE,))
thread.start()
time.sleep(1)
server.stop()
completion_queue.stop()
for _ in range(_IDEMPOTENCE_DEMONSTRATION):
event = completion_queue.get(time.time() + _TIMEOUT)
self.assertIs(event.kind, _datatypes.Event.Kind.STOP)
thread.join()
del server
del completion_queue
_c.shut_down()
def test_client_credentials(self):
root_certificates = b'Trust starts here. Really.'
private_key = b'This is a really bad private key, yo.'
certificate_chain = b'Trust me! Do I not look trustworty?'
_c.init()
client_credentials = _c.ClientCredentials(
None, None, None)
self.assertIsNotNone(client_credentials)
client_credentials = _c.ClientCredentials(
root_certificates, None, None)
self.assertIsNotNone(client_credentials)
client_credentials = _c.ClientCredentials(
None, private_key, certificate_chain)
self.assertIsNotNone(client_credentials)
client_credentials = _c.ClientCredentials(
root_certificates, private_key, certificate_chain)
self.assertIsNotNone(client_credentials)
del client_credentials
_c.shut_down()
def test_server_credentials(self):
root_certificates = b'Trust starts here. Really.'
first_private_key = b'This is a really bad private key, yo.'
first_certificate_chain = b'Trust me! Do I not look trustworty?'
second_private_key = b'This is another bad private key, yo.'
second_certificate_chain = b'Look into my eyes; you can totes trust me.'
_c.init()
server_credentials = _c.ServerCredentials(
None, ((first_private_key, first_certificate_chain),))
del server_credentials
server_credentials = _c.ServerCredentials(
root_certificates, ((first_private_key, first_certificate_chain),))
del server_credentials
server_credentials = _c.ServerCredentials(
root_certificates,
((first_private_key, first_certificate_chain),
(second_private_key, second_certificate_chain),))
del server_credentials
with self.assertRaises(TypeError):
_c.ServerCredentials(
root_certificates, first_private_key, second_certificate_chain)
_c.shut_down()
@unittest.skip('TODO(nathaniel): find and use real-enough test credentials')
def test_secure_server(self):
_c.init()
server_credentials = _c.ServerCredentials(
'root certificate', (('private key', 'certificate chain'),))
completion_queue = _c.CompletionQueue()
server = _c.Server(completion_queue, server_credentials)
server.add_http2_addr('[::]:0')
server.start()
thread = threading.Thread(target=completion_queue.get, args=(_FUTURE,))
thread.start()
time.sleep(1)
server.stop()
completion_queue.stop()
for _ in range(_IDEMPOTENCE_DEMONSTRATION):
event = completion_queue.get(time.time() + _TIMEOUT)
self.assertIs(event.kind, _datatypes.Event.Kind.STOP)
thread.join()
del server
del completion_queue
def testChannelUpDown(self):
channel = _c.Channel('[::]:0', [])
del channel
_c.shut_down()
def testSecureChannelUpDown(self):
channel = _c.Channel('[::]:0', [], _c.ClientCredentials.fake_transport_security())
del channel
if __name__ == '__main__':

@ -1,438 +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/_adapter/_call.h"
#include <math.h>
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include "grpc/_adapter/_channel.h"
#include "grpc/_adapter/_completion_queue.h"
#include "grpc/_adapter/_error.h"
#include "grpc/_adapter/_tag.h"
static PyObject *pygrpc_call_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
Call *self = (Call *)type->tp_alloc(type, 0);
Channel *channel;
CompletionQueue *completion_queue;
const char *method;
const char *host;
double deadline;
static char *kwlist[] = {"channel", "completion_queue",
"method", "host", "deadline", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwds, "O!O!ssd:Call", kwlist,
&pygrpc_ChannelType, &channel,
&pygrpc_CompletionQueueType, &completion_queue,
&method, &host, &deadline)) {
return NULL;
}
/* TODO(nathaniel): Hoist the gpr_timespec <-> PyFloat arithmetic into its own
* function with its own test coverage.
*/
self->c_call = grpc_channel_create_call(
channel->c_channel, completion_queue->c_completion_queue, method, host,
gpr_time_from_nanos(deadline * GPR_NS_PER_SEC));
self->completion_queue = completion_queue;
Py_INCREF(self->completion_queue);
self->channel = channel;
Py_INCREF(self->channel);
grpc_call_details_init(&self->call_details);
grpc_metadata_array_init(&self->recv_metadata);
grpc_metadata_array_init(&self->recv_trailing_metadata);
self->send_metadata = NULL;
self->send_metadata_count = 0;
self->send_trailing_metadata = NULL;
self->send_trailing_metadata_count = 0;
self->send_message = NULL;
self->recv_message = NULL;
self->adding_to_trailing = 0;
return (PyObject *)self;
}
static void pygrpc_call_dealloc(Call *self) {
if (self->c_call != NULL) {
grpc_call_destroy(self->c_call);
}
Py_XDECREF(self->completion_queue);
Py_XDECREF(self->channel);
Py_XDECREF(self->server);
grpc_call_details_destroy(&self->call_details);
grpc_metadata_array_destroy(&self->recv_metadata);
grpc_metadata_array_destroy(&self->recv_trailing_metadata);
if (self->send_message) {
grpc_byte_buffer_destroy(self->send_message);
}
if (self->recv_message) {
grpc_byte_buffer_destroy(self->recv_message);
}
gpr_free(self->status_details);
gpr_free(self->send_metadata);
gpr_free(self->send_trailing_metadata);
self->ob_type->tp_free((PyObject *)self);
}
static const PyObject *pygrpc_call_invoke(Call *self, PyObject *args) {
PyObject *completion_queue;
PyObject *metadata_tag;
PyObject *finish_tag;
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_init_metadata_tag;
pygrpc_tag *c_metadata_tag;
pygrpc_tag *c_finish_tag;
grpc_op send_initial_metadata;
grpc_op recv_initial_metadata;
grpc_op recv_status_on_client;
if (!(PyArg_ParseTuple(args, "O!OO:invoke", &pygrpc_CompletionQueueType,
&completion_queue, &metadata_tag, &finish_tag))) {
return NULL;
}
send_initial_metadata.op = GRPC_OP_SEND_INITIAL_METADATA;
send_initial_metadata.data.send_initial_metadata.metadata = self->send_metadata;
send_initial_metadata.data.send_initial_metadata.count = self->send_metadata_count;
recv_initial_metadata.op = GRPC_OP_RECV_INITIAL_METADATA;
recv_initial_metadata.data.recv_initial_metadata = &self->recv_metadata;
recv_status_on_client.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
recv_status_on_client.data.recv_status_on_client.trailing_metadata = &self->recv_trailing_metadata;
recv_status_on_client.data.recv_status_on_client.status = &self->status;
recv_status_on_client.data.recv_status_on_client.status_details = &self->status_details;
recv_status_on_client.data.recv_status_on_client.status_details_capacity = &self->status_details_capacity;
c_init_metadata_tag = pygrpc_tag_new(PYGRPC_INITIAL_METADATA, NULL, self);
c_metadata_tag = pygrpc_tag_new(PYGRPC_CLIENT_METADATA_READ, metadata_tag, self);
c_finish_tag = pygrpc_tag_new(PYGRPC_FINISHED_CLIENT, finish_tag, self);
call_error = grpc_call_start_batch(self->c_call, &send_initial_metadata, 1, c_init_metadata_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_init_metadata_tag);
pygrpc_tag_destroy(c_metadata_tag);
pygrpc_tag_destroy(c_finish_tag);
return result;
}
call_error = grpc_call_start_batch(self->c_call, &recv_initial_metadata, 1, c_metadata_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_metadata_tag);
pygrpc_tag_destroy(c_finish_tag);
return result;
}
call_error = grpc_call_start_batch(self->c_call, &recv_status_on_client, 1, c_finish_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_finish_tag);
return result;
}
return result;
}
static const PyObject *pygrpc_call_write(Call *self, PyObject *args) {
const char *bytes;
int length;
PyObject *tag;
gpr_slice slice;
grpc_byte_buffer *byte_buffer;
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag;
grpc_op op;
if (!(PyArg_ParseTuple(args, "s#O:write", &bytes, &length, &tag))) {
return NULL;
}
c_tag = pygrpc_tag_new(PYGRPC_WRITE_ACCEPTED, tag, self);
slice = gpr_slice_from_copied_buffer(bytes, length);
byte_buffer = grpc_byte_buffer_create(&slice, 1);
gpr_slice_unref(slice);
if (self->send_message) {
grpc_byte_buffer_destroy(self->send_message);
}
self->send_message = byte_buffer;
op.op = GRPC_OP_SEND_MESSAGE;
op.data.send_message = self->send_message;
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_complete(Call *self, PyObject *tag) {
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_FINISH_ACCEPTED, tag, self);
grpc_op op;
op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_accept(Call *self, PyObject *args) {
PyObject *completion_queue;
PyObject *tag;
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag;
grpc_op op;
if (!(PyArg_ParseTuple(args, "O!O:accept", &pygrpc_CompletionQueueType,
&completion_queue, &tag))) {
return NULL;
}
op.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op.data.recv_close_on_server.cancelled = &self->cancelled;
c_tag = pygrpc_tag_new(PYGRPC_FINISHED_SERVER, tag, self);
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_add_metadata(Call *self, PyObject *args) {
const char* key = NULL;
const char* value = NULL;
int value_length = 0;
grpc_metadata metadata;
if (!PyArg_ParseTuple(args, "ss#", &key, &value, &value_length)) {
return NULL;
}
metadata.key = key;
metadata.value = value;
metadata.value_length = value_length;
if (self->adding_to_trailing) {
self->send_trailing_metadata = gpr_realloc(self->send_trailing_metadata, (self->send_trailing_metadata_count + 1) * sizeof(grpc_metadata));
self->send_trailing_metadata[self->send_trailing_metadata_count] = metadata;
self->send_trailing_metadata_count = self->send_trailing_metadata_count + 1;
} else {
self->send_metadata = gpr_realloc(self->send_metadata, (self->send_metadata_count + 1) * sizeof(grpc_metadata));
self->send_metadata[self->send_metadata_count] = metadata;
self->send_metadata_count = self->send_metadata_count + 1;
}
return pygrpc_translate_call_error(GRPC_CALL_OK);
}
static const PyObject *pygrpc_call_premetadata(Call *self) {
grpc_op op;
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_INITIAL_METADATA, NULL, self);
op.op = GRPC_OP_SEND_INITIAL_METADATA;
op.data.send_initial_metadata.metadata = self->send_metadata;
op.data.send_initial_metadata.count = self->send_metadata_count;
self->adding_to_trailing = 1;
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_read(Call *self, PyObject *tag) {
grpc_op op;
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_READ, tag, self);
op.op = GRPC_OP_RECV_MESSAGE;
if (self->recv_message) {
grpc_byte_buffer_destroy(self->recv_message);
self->recv_message = NULL;
}
op.data.recv_message = &self->recv_message;
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_status(Call *self, PyObject *args) {
PyObject *status;
PyObject *code;
PyObject *details;
PyObject *tag;
grpc_status_code c_code;
char *c_message;
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag;
grpc_op op;
if (!(PyArg_ParseTuple(args, "OO:status", &status, &tag))) {
return NULL;
}
c_tag = pygrpc_tag_new(PYGRPC_FINISH_ACCEPTED, tag, self);
code = PyObject_GetAttrString(status, "code");
if (code == NULL) {
return NULL;
}
details = PyObject_GetAttrString(status, "details");
if (details == NULL) {
Py_DECREF(code);
return NULL;
}
c_code = PyInt_AsLong(code);
Py_DECREF(code);
if (c_code == -1 && PyErr_Occurred()) {
Py_DECREF(details);
return NULL;
}
c_message = PyBytes_AsString(details);
Py_DECREF(details);
if (c_message == NULL) {
return NULL;
}
if (self->status_details) {
gpr_free(self->status_details);
}
self->status_details = gpr_malloc(strlen(c_message)+1);
strcpy(self->status_details, c_message);
op.op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op.data.send_status_from_server.trailing_metadata_count = self->send_trailing_metadata_count;
op.data.send_status_from_server.trailing_metadata = self->send_trailing_metadata;
op.data.send_status_from_server.status = c_code;
op.data.send_status_from_server.status_details = self->status_details;
call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result == NULL) {
pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_cancel(Call *self) {
return pygrpc_translate_call_error(grpc_call_cancel(self->c_call));
}
static PyMethodDef methods[] = {
{"invoke", (PyCFunction)pygrpc_call_invoke, METH_VARARGS,
"Invoke this call."},
{"write", (PyCFunction)pygrpc_call_write, METH_VARARGS,
"Write bytes to this call."},
{"complete", (PyCFunction)pygrpc_call_complete, METH_O,
"Complete writes to this call."},
{"accept", (PyCFunction)pygrpc_call_accept, METH_VARARGS, "Accept an RPC."},
{"add_metadata", (PyCFunction)pygrpc_call_add_metadata, METH_VARARGS,
"Add metadata to the call. May not be called after invoke on the client "
"side. On the server side: when called before premetadata it provides "
"'leading' metadata, when called after premetadata but before status it "
"provides 'trailing metadata'; may not be called after status."},
{"premetadata", (PyCFunction)pygrpc_call_premetadata, METH_VARARGS,
"Indicate the end of leading metadata in the response."},
{"read", (PyCFunction)pygrpc_call_read, METH_O,
"Read bytes from this call."},
{"status", (PyCFunction)pygrpc_call_status, METH_VARARGS,
"Report this call's status."},
{"cancel", (PyCFunction)pygrpc_call_cancel, METH_NOARGS,
"Cancel this call."},
{NULL}};
PyTypeObject pygrpc_CallType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_grpc.Call", /*tp_name*/
sizeof(Call), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)pygrpc_call_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Wrapping of grpc_call.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
pygrpc_call_new, /* tp_new */
};
int pygrpc_add_call(PyObject *module) {
if (PyType_Ready(&pygrpc_CallType) < 0) {
return -1;
}
if (PyModule_AddObject(module, "Call", (PyObject *)&pygrpc_CallType) == -1) {
return -1;
}
return 0;
}

@ -1,135 +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/_adapter/_channel.h"
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include "grpc/_adapter/_client_credentials.h"
static int pygrpc_channel_init(Channel *self, PyObject *args, PyObject *kwds) {
const char *hostport;
PyObject *client_credentials;
char *server_host_override = NULL;
static char *kwlist[] = {"hostport", "client_credentials",
"server_host_override", NULL};
grpc_arg server_host_override_arg;
grpc_channel_args channel_args;
if (!(PyArg_ParseTupleAndKeywords(args, kwds, "sO|z:Channel", kwlist,
&hostport, &client_credentials,
&server_host_override))) {
return -1;
}
if (client_credentials == Py_None) {
self->c_channel = grpc_channel_create(hostport, NULL);
return 0;
} else {
if (server_host_override == NULL) {
self->c_channel = grpc_secure_channel_create(
((ClientCredentials *)client_credentials)->c_client_credentials,
hostport, NULL);
} else {
server_host_override_arg.type = GRPC_ARG_STRING;
server_host_override_arg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
server_host_override_arg.value.string = server_host_override;
channel_args.num_args = 1;
channel_args.args = &server_host_override_arg;
self->c_channel = grpc_secure_channel_create(
((ClientCredentials *)client_credentials)->c_client_credentials,
hostport, &channel_args);
}
return 0;
}
}
static void pygrpc_channel_dealloc(Channel *self) {
if (self->c_channel != NULL) {
grpc_channel_destroy(self->c_channel);
}
self->ob_type->tp_free((PyObject *)self);
}
PyTypeObject pygrpc_ChannelType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_grpc.Channel", /*tp_name*/
sizeof(Channel), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)pygrpc_channel_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Wrapping of grpc_channel.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pygrpc_channel_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
int pygrpc_add_channel(PyObject *module) {
if (PyType_Ready(&pygrpc_ChannelType) < 0) {
return -1;
}
if (PyModule_AddObject(module, "Channel", (PyObject *)&pygrpc_ChannelType) ==
-1) {
return -1;
}
return 0;
}

@ -1,121 +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/_adapter/_client_credentials.h"
#include <Python.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
static int pygrpc_client_credentials_init(ClientCredentials *self,
PyObject *args, PyObject *kwds) {
char *root_certificates;
grpc_ssl_pem_key_cert_pair key_certificate_pair;
static char *kwlist[] = {"root_certificates", "private_key",
"certificate_chain", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "zzz:ClientCredentials", kwlist,
&root_certificates,
&key_certificate_pair.private_key,
&key_certificate_pair.cert_chain)) {
return -1;
}
if (key_certificate_pair.private_key != NULL && key_certificate_pair.cert_chain != NULL) {
self->c_client_credentials =
grpc_ssl_credentials_create(root_certificates, &key_certificate_pair);
} else {
self->c_client_credentials =
grpc_ssl_credentials_create(root_certificates, NULL);
}
return 0;
}
static void pygrpc_client_credentials_dealloc(ClientCredentials *self) {
if (self->c_client_credentials != NULL) {
grpc_credentials_release(self->c_client_credentials);
}
self->ob_type->tp_free((PyObject *)self);
}
PyTypeObject pygrpc_ClientCredentialsType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_grpc.ClientCredencials", /*tp_name*/
sizeof(ClientCredentials), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)pygrpc_client_credentials_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Wrapping of grpc_credentials.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pygrpc_client_credentials_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
int pygrpc_add_client_credentials(PyObject *module) {
if (PyType_Ready(&pygrpc_ClientCredentialsType) < 0) {
return -1;
}
if (PyModule_AddObject(module, "ClientCredentials",
(PyObject *)&pygrpc_ClientCredentialsType) == -1) {
return -1;
}
return 0;
}

@ -1,653 +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/_adapter/_completion_queue.h"
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include "grpc/_adapter/_call.h"
#include "grpc/_adapter/_tag.h"
static PyObject *status_class;
static PyObject *service_acceptance_class;
static PyObject *event_class;
static PyObject *ok_status_code;
static PyObject *cancelled_status_code;
static PyObject *unknown_status_code;
static PyObject *invalid_argument_status_code;
static PyObject *expired_status_code;
static PyObject *not_found_status_code;
static PyObject *already_exists_status_code;
static PyObject *permission_denied_status_code;
static PyObject *unauthenticated_status_code;
static PyObject *resource_exhausted_status_code;
static PyObject *failed_precondition_status_code;
static PyObject *aborted_status_code;
static PyObject *out_of_range_status_code;
static PyObject *unimplemented_status_code;
static PyObject *internal_error_status_code;
static PyObject *unavailable_status_code;
static PyObject *data_loss_status_code;
static PyObject *stop_event_kind;
static PyObject *write_event_kind;
static PyObject *complete_event_kind;
static PyObject *service_event_kind;
static PyObject *read_event_kind;
static PyObject *metadata_event_kind;
static PyObject *finish_event_kind;
static PyObject *pygrpc_as_py_time(gpr_timespec *timespec) {
return PyFloat_FromDouble(
timespec->tv_sec + ((double)timespec->tv_nsec) / 1.0E9);
}
static PyObject *pygrpc_status_code(grpc_status_code c_status_code) {
switch (c_status_code) {
case GRPC_STATUS_OK:
return ok_status_code;
case GRPC_STATUS_CANCELLED:
return cancelled_status_code;
case GRPC_STATUS_UNKNOWN:
return unknown_status_code;
case GRPC_STATUS_INVALID_ARGUMENT:
return invalid_argument_status_code;
case GRPC_STATUS_DEADLINE_EXCEEDED:
return expired_status_code;
case GRPC_STATUS_NOT_FOUND:
return not_found_status_code;
case GRPC_STATUS_ALREADY_EXISTS:
return already_exists_status_code;
case GRPC_STATUS_PERMISSION_DENIED:
return permission_denied_status_code;
case GRPC_STATUS_UNAUTHENTICATED:
return unauthenticated_status_code;
case GRPC_STATUS_RESOURCE_EXHAUSTED:
return resource_exhausted_status_code;
case GRPC_STATUS_FAILED_PRECONDITION:
return failed_precondition_status_code;
case GRPC_STATUS_ABORTED:
return aborted_status_code;
case GRPC_STATUS_OUT_OF_RANGE:
return out_of_range_status_code;
case GRPC_STATUS_UNIMPLEMENTED:
return unimplemented_status_code;
case GRPC_STATUS_INTERNAL:
return internal_error_status_code;
case GRPC_STATUS_UNAVAILABLE:
return unavailable_status_code;
case GRPC_STATUS_DATA_LOSS:
return data_loss_status_code;
default:
return NULL;
}
}
static PyObject *pygrpc_metadata_collection_get(
grpc_metadata *metadata_elements, size_t count) {
PyObject *metadata = PyList_New(count);
size_t i;
for (i = 0; i < count; ++i) {
grpc_metadata elem = metadata_elements[i];
PyObject *key = PyString_FromString(elem.key);
PyObject *value = PyString_FromStringAndSize(elem.value, elem.value_length);
PyObject* kvp = PyTuple_Pack(2, key, value);
/* n.b. PyList_SetItem *steals* a reference to the set element. */
PyList_SetItem(metadata, i, kvp);
Py_DECREF(key);
Py_DECREF(value);
}
return metadata;
}
static PyObject *pygrpc_stop_event_args(grpc_event *c_event) {
return PyTuple_Pack(8, stop_event_kind, Py_None, Py_None, Py_None,
Py_None, Py_None, Py_None, Py_None);
}
static PyObject *pygrpc_write_event_args(grpc_event *c_event) {
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
PyObject *write_accepted = Py_True;
return PyTuple_Pack(8, write_event_kind, user_tag,
write_accepted, Py_None, Py_None, Py_None, Py_None,
Py_None);
}
static PyObject *pygrpc_complete_event_args(grpc_event *c_event) {
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
PyObject *complete_accepted = Py_True;
return PyTuple_Pack(8, complete_event_kind, user_tag,
Py_None, complete_accepted, Py_None, Py_None, Py_None,
Py_None);
}
static PyObject *pygrpc_service_event_args(grpc_event *c_event) {
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
if (tag->call->call_details.method == NULL) {
return PyTuple_Pack(
8, service_event_kind, user_tag, Py_None, Py_None, Py_None, Py_None,
Py_None, Py_None);
} else {
PyObject *method = NULL;
PyObject *host = NULL;
PyObject *service_deadline = NULL;
PyObject *service_acceptance = NULL;
PyObject *metadata = NULL;
PyObject *event_args = NULL;
method = PyBytes_FromString(tag->call->call_details.method);
if (method == NULL) {
goto error;
}
host = PyBytes_FromString(tag->call->call_details.host);
if (host == NULL) {
goto error;
}
service_deadline =
pygrpc_as_py_time(&tag->call->call_details.deadline);
if (service_deadline == NULL) {
goto error;
}
service_acceptance =
PyObject_CallFunctionObjArgs(service_acceptance_class, tag->call,
method, host, service_deadline, NULL);
if (service_acceptance == NULL) {
goto error;
}
metadata = pygrpc_metadata_collection_get(
tag->call->recv_metadata.metadata,
tag->call->recv_metadata.count);
event_args = PyTuple_Pack(8, service_event_kind,
user_tag, Py_None, Py_None,
service_acceptance, Py_None, Py_None,
metadata);
Py_DECREF(service_acceptance);
Py_DECREF(metadata);
error:
Py_XDECREF(method);
Py_XDECREF(host);
Py_XDECREF(service_deadline);
return event_args;
}
}
static PyObject *pygrpc_read_event_args(grpc_event *c_event) {
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
if (tag->call->recv_message == NULL) {
return PyTuple_Pack(8, read_event_kind, user_tag,
Py_None, Py_None, Py_None, Py_None, Py_None, Py_None);
} else {
size_t length;
size_t offset;
grpc_byte_buffer_reader *reader;
gpr_slice slice;
char *c_bytes;
PyObject *bytes;
PyObject *event_args;
length = grpc_byte_buffer_length(tag->call->recv_message);
reader = grpc_byte_buffer_reader_create(tag->call->recv_message);
c_bytes = gpr_malloc(length);
offset = 0;
while (grpc_byte_buffer_reader_next(reader, &slice)) {
memcpy(c_bytes + offset, GPR_SLICE_START_PTR(slice),
GPR_SLICE_LENGTH(slice));
offset += GPR_SLICE_LENGTH(slice);
}
grpc_byte_buffer_reader_destroy(reader);
bytes = PyBytes_FromStringAndSize(c_bytes, length);
gpr_free(c_bytes);
if (bytes == NULL) {
return NULL;
}
event_args = PyTuple_Pack(8, read_event_kind, user_tag,
Py_None, Py_None, Py_None, bytes, Py_None,
Py_None);
Py_DECREF(bytes);
return event_args;
}
}
static PyObject *pygrpc_metadata_event_args(grpc_event *c_event) {
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
PyObject *metadata = pygrpc_metadata_collection_get(
tag->call->recv_metadata.metadata,
tag->call->recv_metadata.count);
PyObject* result = PyTuple_Pack(
8, metadata_event_kind, user_tag, Py_None, Py_None,
Py_None, Py_None, Py_None, metadata);
Py_DECREF(metadata);
return result;
}
static PyObject *pygrpc_finished_server_event_args(grpc_event *c_event) {
PyObject *code;
PyObject *details;
PyObject *status;
PyObject *event_args;
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
code = pygrpc_status_code(tag->call->cancelled ? GRPC_STATUS_CANCELLED : GRPC_STATUS_OK);
if (code == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Unrecognized status code!");
return NULL;
}
details = PyBytes_FromString("");
if (details == NULL) {
return NULL;
}
status = PyObject_CallFunctionObjArgs(status_class, code, details, NULL);
Py_DECREF(details);
if (status == NULL) {
return NULL;
}
event_args = PyTuple_Pack(8, finish_event_kind, user_tag,
Py_None, Py_None, Py_None, Py_None, status,
Py_None);
Py_DECREF(status);
return event_args;
}
static PyObject *pygrpc_finished_client_event_args(grpc_event *c_event) {
PyObject *code;
PyObject *details;
PyObject *status;
PyObject *event_args;
PyObject *metadata;
pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
PyObject *user_tag = tag->user_tag;
code = pygrpc_status_code(tag->call->status);
if (code == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Unrecognized status code!");
return NULL;
}
if (tag->call->status_details == NULL) {
details = PyBytes_FromString("");
} else {
details = PyBytes_FromString(tag->call->status_details);
}
if (details == NULL) {
return NULL;
}
status = PyObject_CallFunctionObjArgs(status_class, code, details, NULL);
Py_DECREF(details);
if (status == NULL) {
return NULL;
}
metadata = pygrpc_metadata_collection_get(
tag->call->recv_trailing_metadata.metadata,
tag->call->recv_trailing_metadata.count);
event_args = PyTuple_Pack(8, finish_event_kind, user_tag,
Py_None, Py_None, Py_None, Py_None, status,
metadata);
Py_DECREF(status);
Py_DECREF(metadata);
return event_args;
}
static int pygrpc_completion_queue_init(CompletionQueue *self, PyObject *args,
PyObject *kwds) {
static char *kwlist[] = {NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, ":CompletionQueue", kwlist)) {
return -1;
}
self->c_completion_queue = grpc_completion_queue_create();
return 0;
}
static void pygrpc_completion_queue_dealloc(CompletionQueue *self) {
grpc_completion_queue_destroy(self->c_completion_queue);
self->ob_type->tp_free((PyObject *)self);
}
static PyObject *pygrpc_completion_queue_get(CompletionQueue *self,
PyObject *args) {
PyObject *deadline;
double double_deadline;
gpr_timespec deadline_timespec;
grpc_event c_event;
PyObject *event_args;
PyObject *event;
pygrpc_tag *tag;
if (!(PyArg_ParseTuple(args, "O:get", &deadline))) {
return NULL;
}
if (deadline == Py_None) {
deadline_timespec = gpr_inf_future;
} else {
double_deadline = PyFloat_AsDouble(deadline);
if (PyErr_Occurred()) {
return NULL;
}
deadline_timespec = gpr_time_from_nanos((long)(double_deadline * 1.0E9));
}
/* TODO(nathaniel): Suppress clang-format in this block and remove the
unnecessary and unPythonic semicolons trailing the _ALLOW_THREADS macros.
(Right now clang-format only understands //-demarcated suppressions.) */
Py_BEGIN_ALLOW_THREADS;
c_event =
grpc_completion_queue_next(self->c_completion_queue, deadline_timespec);
Py_END_ALLOW_THREADS;
tag = (pygrpc_tag *)c_event.tag;
switch (c_event.type) {
case GRPC_QUEUE_TIMEOUT:
Py_RETURN_NONE;
break;
case GRPC_QUEUE_SHUTDOWN:
event_args = pygrpc_stop_event_args(&c_event);
break;
case GRPC_OP_COMPLETE: {
if (!tag) {
PyErr_SetString(PyExc_Exception, "Unrecognized event type!");
return NULL;
}
switch (tag->type) {
case PYGRPC_INITIAL_METADATA:
if (tag) {
pygrpc_tag_destroy(tag);
}
return pygrpc_completion_queue_get(self, args);
case PYGRPC_WRITE_ACCEPTED:
event_args = pygrpc_write_event_args(&c_event);
break;
case PYGRPC_FINISH_ACCEPTED:
event_args = pygrpc_complete_event_args(&c_event);
break;
case PYGRPC_SERVER_RPC_NEW:
event_args = pygrpc_service_event_args(&c_event);
break;
case PYGRPC_READ:
event_args = pygrpc_read_event_args(&c_event);
break;
case PYGRPC_CLIENT_METADATA_READ:
event_args = pygrpc_metadata_event_args(&c_event);
break;
case PYGRPC_FINISHED_CLIENT:
event_args = pygrpc_finished_client_event_args(&c_event);
break;
case PYGRPC_FINISHED_SERVER:
event_args = pygrpc_finished_server_event_args(&c_event);
break;
default:
PyErr_SetString(PyExc_Exception, "Unrecognized op event type!");
return NULL;
}
break;
}
default:
PyErr_SetString(PyExc_Exception, "Unrecognized event type!");
return NULL;
}
if (event_args == NULL) {
return NULL;
}
event = PyObject_CallObject(event_class, event_args);
Py_DECREF(event_args);
if (tag) {
pygrpc_tag_destroy(tag);
}
return event;
}
static PyObject *pygrpc_completion_queue_stop(CompletionQueue *self) {
grpc_completion_queue_shutdown(self->c_completion_queue);
Py_RETURN_NONE;
}
static PyMethodDef methods[] = {
{"get", (PyCFunction)pygrpc_completion_queue_get, METH_VARARGS,
"Get the next event."},
{"stop", (PyCFunction)pygrpc_completion_queue_stop, METH_NOARGS,
"Stop this completion queue."},
{NULL}};
PyTypeObject pygrpc_CompletionQueueType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_gprc.CompletionQueue", /*tp_name*/
sizeof(CompletionQueue), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)pygrpc_completion_queue_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Wrapping of grpc_completion_queue.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pygrpc_completion_queue_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
static int pygrpc_get_status_codes(PyObject *datatypes_module) {
PyObject *code_class = PyObject_GetAttrString(datatypes_module, "Code");
if (code_class == NULL) {
return -1;
}
ok_status_code = PyObject_GetAttrString(code_class, "OK");
if (ok_status_code == NULL) {
return -1;
}
cancelled_status_code = PyObject_GetAttrString(code_class, "CANCELLED");
if (cancelled_status_code == NULL) {
return -1;
}
unknown_status_code = PyObject_GetAttrString(code_class, "UNKNOWN");
if (unknown_status_code == NULL) {
return -1;
}
invalid_argument_status_code =
PyObject_GetAttrString(code_class, "INVALID_ARGUMENT");
if (invalid_argument_status_code == NULL) {
return -1;
}
expired_status_code = PyObject_GetAttrString(code_class, "EXPIRED");
if (expired_status_code == NULL) {
return -1;
}
not_found_status_code = PyObject_GetAttrString(code_class, "NOT_FOUND");
if (not_found_status_code == NULL) {
return -1;
}
already_exists_status_code =
PyObject_GetAttrString(code_class, "ALREADY_EXISTS");
if (already_exists_status_code == NULL) {
return -1;
}
permission_denied_status_code =
PyObject_GetAttrString(code_class, "PERMISSION_DENIED");
if (permission_denied_status_code == NULL) {
return -1;
}
unauthenticated_status_code =
PyObject_GetAttrString(code_class, "UNAUTHENTICATED");
if (unauthenticated_status_code == NULL) {
return -1;
}
resource_exhausted_status_code =
PyObject_GetAttrString(code_class, "RESOURCE_EXHAUSTED");
if (resource_exhausted_status_code == NULL) {
return -1;
}
failed_precondition_status_code =
PyObject_GetAttrString(code_class, "FAILED_PRECONDITION");
if (failed_precondition_status_code == NULL) {
return -1;
}
aborted_status_code = PyObject_GetAttrString(code_class, "ABORTED");
if (aborted_status_code == NULL) {
return -1;
}
out_of_range_status_code = PyObject_GetAttrString(code_class, "OUT_OF_RANGE");
if (out_of_range_status_code == NULL) {
return -1;
}
unimplemented_status_code =
PyObject_GetAttrString(code_class, "UNIMPLEMENTED");
if (unimplemented_status_code == NULL) {
return -1;
}
internal_error_status_code =
PyObject_GetAttrString(code_class, "INTERNAL_ERROR");
if (internal_error_status_code == NULL) {
return -1;
}
unavailable_status_code = PyObject_GetAttrString(code_class, "UNAVAILABLE");
if (unavailable_status_code == NULL) {
return -1;
}
data_loss_status_code = PyObject_GetAttrString(code_class, "DATA_LOSS");
if (data_loss_status_code == NULL) {
return -1;
}
Py_DECREF(code_class);
return 0;
}
static int pygrpc_get_event_kinds(PyObject *event_class) {
PyObject *kind_class = PyObject_GetAttrString(event_class, "Kind");
if (kind_class == NULL) {
return -1;
}
stop_event_kind = PyObject_GetAttrString(kind_class, "STOP");
if (stop_event_kind == NULL) {
return -1;
}
write_event_kind = PyObject_GetAttrString(kind_class, "WRITE_ACCEPTED");
if (write_event_kind == NULL) {
return -1;
}
complete_event_kind = PyObject_GetAttrString(kind_class, "COMPLETE_ACCEPTED");
if (complete_event_kind == NULL) {
return -1;
}
service_event_kind = PyObject_GetAttrString(kind_class, "SERVICE_ACCEPTED");
if (service_event_kind == NULL) {
return -1;
}
read_event_kind = PyObject_GetAttrString(kind_class, "READ_ACCEPTED");
if (read_event_kind == NULL) {
return -1;
}
metadata_event_kind = PyObject_GetAttrString(kind_class, "METADATA_ACCEPTED");
if (metadata_event_kind == NULL) {
return -1;
}
finish_event_kind = PyObject_GetAttrString(kind_class, "FINISH");
if (finish_event_kind == NULL) {
return -1;
}
Py_DECREF(kind_class);
return 0;
}
int pygrpc_add_completion_queue(PyObject *module) {
char *datatypes_module_path = "grpc._adapter._datatypes";
PyObject *datatypes_module = PyImport_ImportModule(datatypes_module_path);
if (datatypes_module == NULL) {
return -1;
}
status_class = PyObject_GetAttrString(datatypes_module, "Status");
service_acceptance_class =
PyObject_GetAttrString(datatypes_module, "ServiceAcceptance");
event_class = PyObject_GetAttrString(datatypes_module, "Event");
if (status_class == NULL || service_acceptance_class == NULL ||
event_class == NULL) {
return -1;
}
if (pygrpc_get_status_codes(datatypes_module) == -1) {
return -1;
}
if (pygrpc_get_event_kinds(event_class) == -1) {
return -1;
}
Py_DECREF(datatypes_module);
if (PyType_Ready(&pygrpc_CompletionQueueType) < 0) {
return -1;
}
if (PyModule_AddObject(module, "CompletionQueue",
(PyObject *)&pygrpc_CompletionQueueType) == -1) {
return -1;
}
return 0;
}

@ -1,86 +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.
"""Datatypes passed between Python and C code."""
import collections
import enum
@enum.unique
class Code(enum.IntEnum):
"""One Platform error codes (see status.h and codes.proto)."""
OK = 0
CANCELLED = 1
UNKNOWN = 2
INVALID_ARGUMENT = 3
EXPIRED = 4
NOT_FOUND = 5
ALREADY_EXISTS = 6
PERMISSION_DENIED = 7
UNAUTHENTICATED = 16
RESOURCE_EXHAUSTED = 8
FAILED_PRECONDITION = 9
ABORTED = 10
OUT_OF_RANGE = 11
UNIMPLEMENTED = 12
INTERNAL_ERROR = 13
UNAVAILABLE = 14
DATA_LOSS = 15
class Status(collections.namedtuple('Status', ['code', 'details'])):
"""Describes an RPC's overall status."""
class ServiceAcceptance(
collections.namedtuple(
'ServiceAcceptance', ['call', 'method', 'host', 'deadline'])):
"""Describes an RPC on the service side at the start of service."""
class Event(
collections.namedtuple(
'Event',
['kind', 'tag', 'write_accepted', 'complete_accepted',
'service_acceptance', 'bytes', 'status', 'metadata'])):
"""Describes an event emitted from a completion queue."""
@enum.unique
class Kind(enum.Enum):
"""Describes the kind of an event."""
STOP = object()
WRITE_ACCEPTED = object()
COMPLETE_ACCEPTED = object()
SERVICE_ACCEPTED = object()
READ_ACCEPTED = object()
METADATA_ACCEPTED = object()
FINISH = object()

@ -1,79 +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/_adapter/_error.h"
#include <Python.h>
#include <grpc/grpc.h>
const PyObject *pygrpc_translate_call_error(grpc_call_error call_error) {
switch (call_error) {
case GRPC_CALL_OK:
Py_RETURN_NONE;
case GRPC_CALL_ERROR:
PyErr_SetString(PyExc_Exception, "Defect: unknown defect!");
return NULL;
case GRPC_CALL_ERROR_NOT_ON_SERVER:
PyErr_SetString(PyExc_Exception,
"Defect: client-only method called on server!");
return NULL;
case GRPC_CALL_ERROR_NOT_ON_CLIENT:
PyErr_SetString(PyExc_Exception,
"Defect: server-only method called on client!");
return NULL;
case GRPC_CALL_ERROR_ALREADY_ACCEPTED:
PyErr_SetString(PyExc_Exception,
"Defect: attempted to accept already-accepted call!");
return NULL;
case GRPC_CALL_ERROR_ALREADY_INVOKED:
PyErr_SetString(PyExc_Exception,
"Defect: attempted to invoke already-invoked call!");
return NULL;
case GRPC_CALL_ERROR_NOT_INVOKED:
PyErr_SetString(PyExc_Exception, "Defect: Call not yet invoked!");
return NULL;
case GRPC_CALL_ERROR_ALREADY_FINISHED:
PyErr_SetString(PyExc_Exception, "Defect: Call already finished!");
return NULL;
case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS:
PyErr_SetString(PyExc_Exception,
"Defect: Attempted extra read or extra write on call!");
return NULL;
case GRPC_CALL_ERROR_INVALID_FLAGS:
PyErr_SetString(PyExc_Exception, "Defect: invalid flags!");
return NULL;
default:
PyErr_SetString(PyExc_Exception, "Defect: Unknown call error!");
return NULL;
}
}

@ -0,0 +1,258 @@
# 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.
"""Temporary old _low-like layer.
Eases refactoring burden while we overhaul the Python framework.
Plan:
The layers used to look like:
... # outside _adapter
fore.py + rear.py # visible outside _adapter
_low
_c
The layers currently look like:
... # outside _adapter
fore.py + rear.py # visible outside _adapter
_low_intermediary # adapter for new '_low' to old '_low'
_low # new '_low'
_c # new '_c'
We will later remove _low_intermediary after refactoring of fore.py and
rear.py according to the ticket system refactoring and get:
... # outside _adapter, refactored
fore.py + rear.py # visible outside _adapter, refactored
_low # new '_low'
_c # new '_c'
"""
import collections
import enum
from grpc._adapter import _low
from grpc._adapter import _types
_IGNORE_ME_TAG = object()
Code = _types.StatusCode
class Status(collections.namedtuple('Status', ['code', 'details'])):
"""Describes an RPC's overall status."""
class ServiceAcceptance(
collections.namedtuple(
'ServiceAcceptance', ['call', 'method', 'host', 'deadline'])):
"""Describes an RPC on the service side at the start of service."""
class Event(
collections.namedtuple(
'Event',
['kind', 'tag', 'write_accepted', 'complete_accepted',
'service_acceptance', 'bytes', 'status', 'metadata'])):
"""Describes an event emitted from a completion queue."""
@enum.unique
class Kind(enum.Enum):
"""Describes the kind of an event."""
STOP = object()
WRITE_ACCEPTED = object()
COMPLETE_ACCEPTED = object()
SERVICE_ACCEPTED = object()
READ_ACCEPTED = object()
METADATA_ACCEPTED = object()
FINISH = object()
class _TagAdapter(collections.namedtuple('_TagAdapter', [
'user_tag',
'kind'
])):
pass
class Call(object):
"""Adapter from old _low.Call interface to new _low.Call."""
def __init__(self, channel, completion_queue, method, host, deadline):
self._internal = channel._internal.create_call(
completion_queue._internal, method, host, deadline)
self._metadata = []
@staticmethod
def _from_internal(internal):
call = Call.__new__(Call)
call._internal = internal
call._metadata = []
return call
def invoke(self, completion_queue, metadata_tag, finish_tag):
err0 = self._internal.start_batch([
_types.OpArgs.send_initial_metadata(self._metadata)
], _IGNORE_ME_TAG)
err1 = self._internal.start_batch([
_types.OpArgs.recv_initial_metadata()
], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED))
err2 = self._internal.start_batch([
_types.OpArgs.recv_status_on_client()
], _TagAdapter(finish_tag, Event.Kind.FINISH))
return err0 if err0 != _types.CallError.OK else err1 if err1 != _types.CallError.OK else err2 if err2 != _types.CallError.OK else _types.CallError.OK
def write(self, message, tag):
return self._internal.start_batch([
_types.OpArgs.send_message(message)
], _TagAdapter(tag, Event.Kind.WRITE_ACCEPTED))
def complete(self, tag):
return self._internal.start_batch([
_types.OpArgs.send_close_from_client()
], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED))
def accept(self, completion_queue, tag):
return self._internal.start_batch([
_types.OpArgs.recv_close_on_server()
], _TagAdapter(tag, Event.Kind.FINISH))
def add_metadata(self, key, value):
self._metadata.append((key, value))
def premetadata(self):
return self._internal.start_batch([
_types.OpArgs.send_initial_metadata(self._metadata)
], _IGNORE_ME_TAG)
self._metadata = []
def read(self, tag):
return self._internal.start_batch([
_types.OpArgs.recv_message()
], _TagAdapter(tag, Event.Kind.READ_ACCEPTED))
def status(self, status, tag):
return self._internal.start_batch([
_types.OpArgs.send_status_from_server(self._metadata, status.code, status.details)
], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED))
def cancel(self):
return self._internal.cancel()
class Channel(object):
"""Adapter from old _low.Channel interface to new _low.Channel."""
def __init__(self, hostport, client_credentials, server_host_override=None):
args = []
if server_host_override:
args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override))
creds = None
if client_credentials:
creds = client_credentials._internal
self._internal = _low.Channel(hostport, args, creds)
class CompletionQueue(object):
"""Adapter from old _low.CompletionQueue interface to new _low.CompletionQueue."""
def __init__(self):
self._internal = _low.CompletionQueue()
def get(self, deadline=None):
if deadline is None:
ev = self._internal.next()
else:
ev = self._internal.next(deadline)
if ev is None:
return None
elif ev.tag is _IGNORE_ME_TAG:
return self.get(deadline)
elif ev.type == _types.EventType.QUEUE_SHUTDOWN:
kind = Event.Kind.STOP
tag = None
write_accepted = None
complete_accepted = None
service_acceptance = None
message_bytes = None
status = None
metadata = None
elif ev.type == _types.EventType.OP_COMPLETE:
kind = ev.tag.kind
tag = ev.tag.user_tag
write_accepted = ev.success if kind == Event.Kind.WRITE_ACCEPTED else None
complete_accepted = ev.success if kind == Event.Kind.COMPLETE_ACCEPTED else None
service_acceptance = ServiceAcceptance(Call._from_internal(ev.call), ev.call_details.method, ev.call_details.host, ev.call_details.deadline) if kind == Event.Kind.SERVICE_ACCEPTED else None
message_bytes = ev.results[0].message if kind == Event.Kind.READ_ACCEPTED else None
status = Status(ev.results[0].status.code, ev.results[0].status.details) if (kind == Event.Kind.FINISH and ev.results[0].status) else Status(_types.StatusCode.CANCELLED if ev.results[0].cancelled else _types.StatusCode.OK, '') if ev.results[0].cancelled is not None else None
metadata = ev.results[0].initial_metadata if (kind in [Event.Kind.SERVICE_ACCEPTED, Event.Kind.METADATA_ACCEPTED]) else (ev.results[0].trailing_metadata if kind == Event.Kind.FINISH else None)
else:
raise RuntimeError('unknown event')
result_ev = Event(kind=kind, tag=tag, write_accepted=write_accepted, complete_accepted=complete_accepted, service_acceptance=service_acceptance, bytes=message_bytes, status=status, metadata=metadata)
return result_ev
def stop(self):
self._internal.shutdown()
class Server(object):
"""Adapter from old _low.Server interface to new _low.Server."""
def __init__(self, completion_queue):
self._internal = _low.Server(completion_queue._internal, [])
self._internal_cq = completion_queue._internal
def add_http2_addr(self, addr):
return self._internal.add_http2_port(addr)
def add_secure_http2_addr(self, addr, server_credentials):
if server_credentials is None:
return self._internal.add_http2_port(addr, None)
else:
return self._internal.add_http2_port(addr, server_credentials._internal)
def start(self):
return self._internal.start()
def service(self, tag):
return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED))
def stop(self):
return self._internal.shutdown()
class ClientCredentials(object):
"""Adapter from old _low.ClientCredentials interface to new _low.ClientCredentials."""
def __init__(self, root_certificates, private_key, certificate_chain):
self._internal = _low.ClientCredentials.ssl(root_certificates, private_key, certificate_chain)
class ServerCredentials(object):
"""Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials."""
def __init__(self, root_credentials, pair_sequence):
self._internal = _low.ServerCredentials.ssl(root_credentials, list(pair_sequence))

@ -0,0 +1,421 @@
# 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.
"""Tests for the old '_low'."""
import time
import unittest
from grpc._adapter import _intermediary_low as _low
_STREAM_LENGTH = 300
_TIMEOUT = 5
_AFTER_DELAY = 2
_FUTURE = time.time() + 60 * 60 * 24
_BYTE_SEQUENCE = b'\abcdefghijklmnopqrstuvwxyz0123456789' * 200
_BYTE_SEQUENCE_SEQUENCE = tuple(
bytes(bytearray((row + column) % 256 for column in range(row)))
for row in range(_STREAM_LENGTH))
class LonelyClientTest(unittest.TestCase):
def testLonelyClient(self):
host = 'nosuchhostexists'
port = 54321
method = 'test method'
deadline = time.time() + _TIMEOUT
after_deadline = deadline + _AFTER_DELAY
metadata_tag = object()
finish_tag = object()
completion_queue = _low.CompletionQueue()
channel = _low.Channel('%s:%d' % (host, port), None)
client_call = _low.Call(channel, completion_queue, method, host, deadline)
client_call.invoke(completion_queue, metadata_tag, finish_tag)
first_event = completion_queue.get(after_deadline)
self.assertIsNotNone(first_event)
second_event = completion_queue.get(after_deadline)
self.assertIsNotNone(second_event)
kinds = [event.kind for event in (first_event, second_event)]
self.assertItemsEqual(
(_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH),
kinds)
self.assertIsNone(completion_queue.get(after_deadline))
completion_queue.stop()
stop_event = completion_queue.get(_FUTURE)
self.assertEqual(_low.Event.Kind.STOP, stop_event.kind)
del client_call
del channel
del completion_queue
class EchoTest(unittest.TestCase):
def setUp(self):
self.host = 'localhost'
self.server_completion_queue = _low.CompletionQueue()
self.server = _low.Server(self.server_completion_queue)
port = self.server.add_http2_addr('[::]:0')
self.server.start()
self.client_completion_queue = _low.CompletionQueue()
self.channel = _low.Channel('%s:%d' % (self.host, port), None)
def tearDown(self):
self.server.stop()
# NOTE(nathaniel): Yep, this is weird; it's a consequence of
# grpc_server_destroy's being what has the effect of telling the server's
# completion queue to pump out all pending events/tags immediately rather
# than gracefully completing all outstanding RPCs while accepting no new
# ones.
# TODO(nathaniel): Deallocation of a Python object shouldn't have this kind
# of observable side effect let alone such an important one.
del self.server
self.server_completion_queue.stop()
self.client_completion_queue.stop()
while True:
event = self.server_completion_queue.get(_FUTURE)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
while True:
event = self.client_completion_queue.get(_FUTURE)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
self.server_completion_queue = None
self.client_completion_queue = None
def _perform_echo_test(self, test_data):
method = 'test method'
details = 'test details'
server_leading_metadata_key = 'my_server_leading_key'
server_leading_metadata_value = 'my_server_leading_value'
server_trailing_metadata_key = 'my_server_trailing_key'
server_trailing_metadata_value = 'my_server_trailing_value'
client_metadata_key = 'my_client_key'
client_metadata_value = 'my_client_value'
server_leading_binary_metadata_key = 'my_server_leading_key-bin'
server_leading_binary_metadata_value = b'\0'*2047
server_trailing_binary_metadata_key = 'my_server_trailing_key-bin'
server_trailing_binary_metadata_value = b'\0'*2047
client_binary_metadata_key = 'my_client_key-bin'
client_binary_metadata_value = b'\0'*2047
deadline = _FUTURE
metadata_tag = object()
finish_tag = object()
write_tag = object()
complete_tag = object()
service_tag = object()
read_tag = object()
status_tag = object()
server_data = []
client_data = []
client_call = _low.Call(self.channel, self.client_completion_queue,
method, self.host, deadline)
client_call.add_metadata(client_metadata_key, client_metadata_value)
client_call.add_metadata(client_binary_metadata_key,
client_binary_metadata_value)
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
self.server.service(service_tag)
service_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(service_accepted)
self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED)
self.assertIs(service_accepted.tag, service_tag)
self.assertEqual(method, service_accepted.service_acceptance.method)
self.assertEqual(self.host, service_accepted.service_acceptance.host)
self.assertIsNotNone(service_accepted.service_acceptance.call)
metadata = dict(service_accepted.metadata)
self.assertIn(client_metadata_key, metadata)
self.assertEqual(client_metadata_value, metadata[client_metadata_key])
self.assertIn(client_binary_metadata_key, metadata)
self.assertEqual(client_binary_metadata_value,
metadata[client_binary_metadata_key])
server_call = service_accepted.service_acceptance.call
server_call.accept(self.server_completion_queue, finish_tag)
server_call.add_metadata(server_leading_metadata_key,
server_leading_metadata_value)
server_call.add_metadata(server_leading_binary_metadata_key,
server_leading_binary_metadata_value)
server_call.premetadata()
metadata_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(metadata_accepted)
self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
self.assertEqual(metadata_tag, metadata_accepted.tag)
metadata = dict(metadata_accepted.metadata)
self.assertIn(server_leading_metadata_key, metadata)
self.assertEqual(server_leading_metadata_value,
metadata[server_leading_metadata_key])
self.assertIn(server_leading_binary_metadata_key, metadata)
self.assertEqual(server_leading_binary_metadata_value,
metadata[server_leading_binary_metadata_key])
for datum in test_data:
client_call.write(datum, write_tag)
write_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(write_accepted)
self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED)
self.assertIs(write_accepted.tag, write_tag)
self.assertIs(write_accepted.write_accepted, True)
server_call.read(read_tag)
read_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(read_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNotNone(read_accepted.bytes)
server_data.append(read_accepted.bytes)
server_call.write(read_accepted.bytes, write_tag)
write_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(write_accepted)
self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind)
self.assertEqual(write_tag, write_accepted.tag)
self.assertTrue(write_accepted.write_accepted)
client_call.read(read_tag)
read_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(read_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNotNone(read_accepted.bytes)
client_data.append(read_accepted.bytes)
client_call.complete(complete_tag)
complete_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(complete_accepted)
self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED)
self.assertIs(complete_accepted.tag, complete_tag)
self.assertIs(complete_accepted.complete_accepted, True)
server_call.read(read_tag)
read_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(read_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNone(read_accepted.bytes)
server_call.add_metadata(server_trailing_metadata_key,
server_trailing_metadata_value)
server_call.add_metadata(server_trailing_binary_metadata_key,
server_trailing_binary_metadata_value)
server_call.status(_low.Status(_low.Code.OK, details), status_tag)
server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED:
status_accepted = server_terminal_event_one
rpc_accepted = server_terminal_event_two
else:
status_accepted = server_terminal_event_two
rpc_accepted = server_terminal_event_one
self.assertIsNotNone(status_accepted)
self.assertIsNotNone(rpc_accepted)
self.assertEqual(_low.Event.Kind.COMPLETE_ACCEPTED, status_accepted.kind)
self.assertEqual(status_tag, status_accepted.tag)
self.assertTrue(status_accepted.complete_accepted)
self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
self.assertEqual(finish_tag, rpc_accepted.tag)
self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status)
client_call.read(read_tag)
client_terminal_event_one = self.client_completion_queue.get(_FUTURE)
client_terminal_event_two = self.client_completion_queue.get(_FUTURE)
if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
read_accepted = client_terminal_event_one
finish_accepted = client_terminal_event_two
else:
read_accepted = client_terminal_event_two
finish_accepted = client_terminal_event_one
self.assertIsNotNone(read_accepted)
self.assertIsNotNone(finish_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNone(read_accepted.bytes)
self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind)
self.assertEqual(finish_tag, finish_accepted.tag)
self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status)
metadata = dict(finish_accepted.metadata)
self.assertIn(server_trailing_metadata_key, metadata)
self.assertEqual(server_trailing_metadata_value,
metadata[server_trailing_metadata_key])
self.assertIn(server_trailing_binary_metadata_key, metadata)
self.assertEqual(server_trailing_binary_metadata_value,
metadata[server_trailing_binary_metadata_key])
server_timeout_none_event = self.server_completion_queue.get(0)
self.assertIsNone(server_timeout_none_event)
client_timeout_none_event = self.client_completion_queue.get(0)
self.assertIsNone(client_timeout_none_event)
self.assertSequenceEqual(test_data, server_data)
self.assertSequenceEqual(test_data, client_data)
def testNoEcho(self):
self._perform_echo_test(())
def testOneByteEcho(self):
self._perform_echo_test([b'\x07'])
def testOneManyByteEcho(self):
self._perform_echo_test([_BYTE_SEQUENCE])
def testManyOneByteEchoes(self):
self._perform_echo_test(_BYTE_SEQUENCE)
def testManyManyByteEchoes(self):
self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE)
class CancellationTest(unittest.TestCase):
def setUp(self):
self.host = 'localhost'
self.server_completion_queue = _low.CompletionQueue()
self.server = _low.Server(self.server_completion_queue)
port = self.server.add_http2_addr('[::]:0')
self.server.start()
self.client_completion_queue = _low.CompletionQueue()
self.channel = _low.Channel('%s:%d' % (self.host, port), None)
def tearDown(self):
self.server.stop()
del self.server
self.server_completion_queue.stop()
self.client_completion_queue.stop()
while True:
event = self.server_completion_queue.get(0)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
while True:
event = self.client_completion_queue.get(0)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
def testCancellation(self):
method = 'test method'
deadline = _FUTURE
metadata_tag = object()
finish_tag = object()
write_tag = object()
service_tag = object()
read_tag = object()
test_data = _BYTE_SEQUENCE_SEQUENCE
server_data = []
client_data = []
client_call = _low.Call(self.channel, self.client_completion_queue,
method, self.host, deadline)
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
self.server.service(service_tag)
service_accepted = self.server_completion_queue.get(_FUTURE)
server_call = service_accepted.service_acceptance.call
server_call.accept(self.server_completion_queue, finish_tag)
server_call.premetadata()
metadata_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(metadata_accepted)
for datum in test_data:
client_call.write(datum, write_tag)
write_accepted = self.client_completion_queue.get(_FUTURE)
server_call.read(read_tag)
read_accepted = self.server_completion_queue.get(_FUTURE)
server_data.append(read_accepted.bytes)
server_call.write(read_accepted.bytes, write_tag)
write_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(write_accepted)
client_call.read(read_tag)
read_accepted = self.client_completion_queue.get(_FUTURE)
client_data.append(read_accepted.bytes)
client_call.cancel()
# cancel() is idempotent.
client_call.cancel()
client_call.cancel()
client_call.cancel()
server_call.read(read_tag)
server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
read_accepted = server_terminal_event_one
rpc_accepted = server_terminal_event_two
else:
read_accepted = server_terminal_event_two
rpc_accepted = server_terminal_event_one
self.assertIsNotNone(read_accepted)
self.assertIsNotNone(rpc_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertIsNone(read_accepted.bytes)
self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status)
finish_event = self.client_completion_queue.get(_FUTURE)
self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
finish_event.status)
server_timeout_none_event = self.server_completion_queue.get(0)
self.assertIsNone(server_timeout_none_event)
client_timeout_none_event = self.client_completion_queue.get(0)
self.assertIsNone(client_timeout_none_event)
self.assertSequenceEqual(test_data, server_data)
self.assertSequenceEqual(test_data, client_data)
class ExpirationTest(unittest.TestCase):
@unittest.skip('TODO(nathaniel): Expiration test!')
def testExpiration(self):
pass
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -27,31 +27,85 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A Python interface for GRPC C core structures and behaviors."""
import atexit
import gc
from grpc._adapter import _c
from grpc._adapter import _datatypes
def _shut_down():
# force garbage collection before shutting down grpc, to ensure all grpc
# objects are cleaned up
gc.collect()
_c.shut_down()
_c.init()
atexit.register(_shut_down)
# pylint: disable=invalid-name
Code = _datatypes.Code
Status = _datatypes.Status
Event = _datatypes.Event
Call = _c.Call
Channel = _c.Channel
CompletionQueue = _c.CompletionQueue
Server = _c.Server
from grpc._adapter import _types
ClientCredentials = _c.ClientCredentials
ServerCredentials = _c.ServerCredentials
# pylint: enable=invalid-name
class CompletionQueue(_types.CompletionQueue):
def __init__(self):
self.completion_queue = _c.CompletionQueue()
def next(self, deadline=float('+inf')):
raw_event = self.completion_queue.next(deadline)
if raw_event is None:
return None
event = _types.Event(*raw_event)
if event.call is not None:
event = event._replace(call=Call(event.call))
if event.call_details is not None:
event = event._replace(call_details=_types.CallDetails(*event.call_details))
if event.results is not None:
new_results = [_types.OpResult(*r) for r in event.results]
new_results = [r if r.status is None else r._replace(status=_types.Status(_types.StatusCode(r.status[0]), r.status[1])) for r in new_results]
event = event._replace(results=new_results)
return event
def shutdown(self):
self.completion_queue.shutdown()
class Call(_types.Call):
def __init__(self, call):
self.call = call
def start_batch(self, ops, tag):
return self.call.start_batch(ops, tag)
def cancel(self, code=None, details=None):
if code is None and details is None:
return self.call.cancel()
else:
return self.call.cancel(code, details)
class Channel(_types.Channel):
def __init__(self, target, args, creds=None):
if creds is None:
self.channel = _c.Channel(target, args)
else:
self.channel = _c.Channel(target, args, creds)
def create_call(self, completion_queue, method, host, deadline=None):
return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline))
_NO_TAG = object()
class Server(_types.Server):
def __init__(self, completion_queue, args):
self.server = _c.Server(completion_queue.completion_queue, args)
def add_http2_port(self, addr, creds=None):
if creds is None:
return self.server.add_http2_port(addr)
else:
return self.server.add_http2_port(addr, creds)
def start(self):
return self.server.start()
def shutdown(self, tag=_NO_TAG):
if tag is _NO_TAG:
return self.server.shutdown()
else:
return self.server.shutdown(tag)
def request_call(self, completion_queue, tag):
return self.server.request_call(completion_queue.completion_queue, tag)

@ -27,388 +27,141 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Tests for _adapter._low."""
import time
import unittest
from grpc._adapter import _types
from grpc._adapter import _low
_STREAM_LENGTH = 300
_TIMEOUT = 5
_AFTER_DELAY = 2
_FUTURE = time.time() + 60 * 60 * 24
_BYTE_SEQUENCE = b'\abcdefghijklmnopqrstuvwxyz0123456789' * 200
_BYTE_SEQUENCE_SEQUENCE = tuple(
bytes(bytearray((row + column) % 256 for column in range(row)))
for row in range(_STREAM_LENGTH))
class LonelyClientTest(unittest.TestCase):
def testLonelyClient(self):
host = 'nosuchhostexists'
port = 54321
method = 'test method'
deadline = time.time() + _TIMEOUT
after_deadline = deadline + _AFTER_DELAY
metadata_tag = object()
finish_tag = object()
completion_queue = _low.CompletionQueue()
channel = _low.Channel('%s:%d' % (host, port), None)
client_call = _low.Call(channel, completion_queue, method, host, deadline)
client_call.invoke(completion_queue, metadata_tag, finish_tag)
first_event = completion_queue.get(after_deadline)
self.assertIsNotNone(first_event)
second_event = completion_queue.get(after_deadline)
self.assertIsNotNone(second_event)
kinds = [event.kind for event in (first_event, second_event)]
self.assertItemsEqual(
(_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH),
kinds)
self.assertIsNone(completion_queue.get(after_deadline))
completion_queue.stop()
stop_event = completion_queue.get(_FUTURE)
self.assertEqual(_low.Event.Kind.STOP, stop_event.kind)
class EchoTest(unittest.TestCase):
class InsecureServerInsecureClient(unittest.TestCase):
def setUp(self):
self.host = 'localhost'
self.server_completion_queue = _low.CompletionQueue()
self.server = _low.Server(self.server_completion_queue)
port = self.server.add_http2_addr('[::]:0')
self.server.start()
self.server = _low.Server(self.server_completion_queue, [])
self.port = self.server.add_http2_port('[::]:0')
self.client_completion_queue = _low.CompletionQueue()
self.channel = _low.Channel('%s:%d' % (self.host, port), None)
def tearDown(self):
self.server.stop()
# NOTE(nathaniel): Yep, this is weird; it's a consequence of
# grpc_server_destroy's being what has the effect of telling the server's
# completion queue to pump out all pending events/tags immediately rather
# than gracefully completing all outstanding RPCs while accepting no new
# ones.
# TODO(nathaniel): Deallocation of a Python object shouldn't have this kind
# of observable side effect let alone such an important one.
del self.server
self.server_completion_queue.stop()
self.client_completion_queue.stop()
while True:
event = self.server_completion_queue.get(_FUTURE)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
while True:
event = self.client_completion_queue.get(_FUTURE)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
self.server_completion_queue = None
self.client_completion_queue = None
def _perform_echo_test(self, test_data):
method = 'test method'
details = 'test details'
server_leading_metadata_key = 'my_server_leading_key'
server_leading_metadata_value = 'my_server_leading_value'
server_trailing_metadata_key = 'my_server_trailing_key'
server_trailing_metadata_value = 'my_server_trailing_value'
client_metadata_key = 'my_client_key'
client_metadata_value = 'my_client_value'
server_leading_binary_metadata_key = 'my_server_leading_key-bin'
server_leading_binary_metadata_value = b'\0'*2047
server_trailing_binary_metadata_key = 'my_server_trailing_key-bin'
server_trailing_binary_metadata_value = b'\0'*2047
client_binary_metadata_key = 'my_client_key-bin'
client_binary_metadata_value = b'\0'*2047
deadline = _FUTURE
metadata_tag = object()
finish_tag = object()
write_tag = object()
complete_tag = object()
service_tag = object()
read_tag = object()
status_tag = object()
server_data = []
client_data = []
client_call = _low.Call(self.channel, self.client_completion_queue,
method, self.host, deadline)
client_call.add_metadata(client_metadata_key, client_metadata_value)
client_call.add_metadata(client_binary_metadata_key,
client_binary_metadata_value)
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
self.server.service(service_tag)
service_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(service_accepted)
self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED)
self.assertIs(service_accepted.tag, service_tag)
self.assertEqual(method, service_accepted.service_acceptance.method)
self.assertEqual(self.host, service_accepted.service_acceptance.host)
self.assertIsNotNone(service_accepted.service_acceptance.call)
metadata = dict(service_accepted.metadata)
self.assertIn(client_metadata_key, metadata)
self.assertEqual(client_metadata_value, metadata[client_metadata_key])
self.assertIn(client_binary_metadata_key, metadata)
self.assertEqual(client_binary_metadata_value,
metadata[client_binary_metadata_key])
server_call = service_accepted.service_acceptance.call
server_call.accept(self.server_completion_queue, finish_tag)
server_call.add_metadata(server_leading_metadata_key,
server_leading_metadata_value)
server_call.add_metadata(server_leading_binary_metadata_key,
server_leading_binary_metadata_value)
server_call.premetadata()
metadata_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(metadata_accepted)
self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
self.assertEqual(metadata_tag, metadata_accepted.tag)
metadata = dict(metadata_accepted.metadata)
self.assertIn(server_leading_metadata_key, metadata)
self.assertEqual(server_leading_metadata_value,
metadata[server_leading_metadata_key])
self.assertIn(server_leading_binary_metadata_key, metadata)
self.assertEqual(server_leading_binary_metadata_value,
metadata[server_leading_binary_metadata_key])
for datum in test_data:
client_call.write(datum, write_tag)
write_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(write_accepted)
self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED)
self.assertIs(write_accepted.tag, write_tag)
self.assertIs(write_accepted.write_accepted, True)
server_call.read(read_tag)
read_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(read_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNotNone(read_accepted.bytes)
server_data.append(read_accepted.bytes)
server_call.write(read_accepted.bytes, write_tag)
write_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(write_accepted)
self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind)
self.assertEqual(write_tag, write_accepted.tag)
self.assertTrue(write_accepted.write_accepted)
client_call.read(read_tag)
read_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(read_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNotNone(read_accepted.bytes)
client_data.append(read_accepted.bytes)
client_call.complete(complete_tag)
complete_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(complete_accepted)
self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED)
self.assertIs(complete_accepted.tag, complete_tag)
self.assertIs(complete_accepted.complete_accepted, True)
server_call.read(read_tag)
read_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(read_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNone(read_accepted.bytes)
server_call.add_metadata(server_trailing_metadata_key,
server_trailing_metadata_value)
server_call.add_metadata(server_trailing_binary_metadata_key,
server_trailing_binary_metadata_value)
server_call.status(_low.Status(_low.Code.OK, details), status_tag)
server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED:
status_accepted = server_terminal_event_one
rpc_accepted = server_terminal_event_two
else:
status_accepted = server_terminal_event_two
rpc_accepted = server_terminal_event_one
self.assertIsNotNone(status_accepted)
self.assertIsNotNone(rpc_accepted)
self.assertEqual(_low.Event.Kind.COMPLETE_ACCEPTED, status_accepted.kind)
self.assertEqual(status_tag, status_accepted.tag)
self.assertTrue(status_accepted.complete_accepted)
self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
self.assertEqual(finish_tag, rpc_accepted.tag)
self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status)
client_call.read(read_tag)
client_terminal_event_one = self.client_completion_queue.get(_FUTURE)
client_terminal_event_two = self.client_completion_queue.get(_FUTURE)
if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
read_accepted = client_terminal_event_one
finish_accepted = client_terminal_event_two
else:
read_accepted = client_terminal_event_two
finish_accepted = client_terminal_event_one
self.assertIsNotNone(read_accepted)
self.assertIsNotNone(finish_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNone(read_accepted.bytes)
self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind)
self.assertEqual(finish_tag, finish_accepted.tag)
self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status)
metadata = dict(finish_accepted.metadata)
self.assertIn(server_trailing_metadata_key, metadata)
self.assertEqual(server_trailing_metadata_value,
metadata[server_trailing_metadata_key])
self.assertIn(server_trailing_binary_metadata_key, metadata)
self.assertEqual(server_trailing_binary_metadata_value,
metadata[server_trailing_binary_metadata_key])
server_timeout_none_event = self.server_completion_queue.get(0)
self.assertIsNone(server_timeout_none_event)
client_timeout_none_event = self.client_completion_queue.get(0)
self.assertIsNone(client_timeout_none_event)
self.assertSequenceEqual(test_data, server_data)
self.assertSequenceEqual(test_data, client_data)
self.client_channel = _low.Channel('localhost:%d'%self.port, [])
def testNoEcho(self):
self._perform_echo_test(())
def testOneByteEcho(self):
self._perform_echo_test([b'\x07'])
def testOneManyByteEcho(self):
self._perform_echo_test([_BYTE_SEQUENCE])
def testManyOneByteEchoes(self):
self._perform_echo_test(_BYTE_SEQUENCE)
def testManyManyByteEchoes(self):
self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE)
class CancellationTest(unittest.TestCase):
def setUp(self):
self.host = 'localhost'
self.server_completion_queue = _low.CompletionQueue()
self.server = _low.Server(self.server_completion_queue)
port = self.server.add_http2_addr('[::]:0')
self.server.start()
self.client_completion_queue = _low.CompletionQueue()
self.channel = _low.Channel('%s:%d' % (self.host, port), None)
def tearDown(self):
self.server.stop()
self.server.shutdown()
del self.client_channel
del self.server
self.server_completion_queue.stop()
self.client_completion_queue.stop()
while True:
event = self.server_completion_queue.get(0)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
while True:
event = self.client_completion_queue.get(0)
if event is not None and event.kind is _low.Event.Kind.STOP:
break
def testCancellation(self):
method = 'test method'
deadline = _FUTURE
metadata_tag = object()
finish_tag = object()
write_tag = object()
service_tag = object()
read_tag = object()
test_data = _BYTE_SEQUENCE_SEQUENCE
server_data = []
client_data = []
client_call = _low.Call(self.channel, self.client_completion_queue,
method, self.host, deadline)
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
self.server.service(service_tag)
service_accepted = self.server_completion_queue.get(_FUTURE)
server_call = service_accepted.service_acceptance.call
server_call.accept(self.server_completion_queue, finish_tag)
server_call.premetadata()
metadata_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(metadata_accepted)
for datum in test_data:
client_call.write(datum, write_tag)
write_accepted = self.client_completion_queue.get(_FUTURE)
server_call.read(read_tag)
read_accepted = self.server_completion_queue.get(_FUTURE)
server_data.append(read_accepted.bytes)
server_call.write(read_accepted.bytes, write_tag)
write_accepted = self.server_completion_queue.get(_FUTURE)
self.assertIsNotNone(write_accepted)
client_call.read(read_tag)
read_accepted = self.client_completion_queue.get(_FUTURE)
client_data.append(read_accepted.bytes)
client_call.cancel()
# cancel() is idempotent.
client_call.cancel()
client_call.cancel()
client_call.cancel()
server_call.read(read_tag)
server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
read_accepted = server_terminal_event_one
rpc_accepted = server_terminal_event_two
else:
read_accepted = server_terminal_event_two
rpc_accepted = server_terminal_event_one
self.assertIsNotNone(read_accepted)
self.assertIsNotNone(rpc_accepted)
self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
self.assertIsNone(read_accepted.bytes)
self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status)
finish_event = self.client_completion_queue.get(_FUTURE)
self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
finish_event.status)
server_timeout_none_event = self.server_completion_queue.get(0)
self.assertIsNone(server_timeout_none_event)
client_timeout_none_event = self.client_completion_queue.get(0)
self.assertIsNone(client_timeout_none_event)
self.assertSequenceEqual(test_data, server_data)
self.assertSequenceEqual(test_data, client_data)
class ExpirationTest(unittest.TestCase):
@unittest.skip('TODO(nathaniel): Expiration test!')
def testExpiration(self):
pass
self.client_completion_queue.shutdown()
while self.client_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN:
pass
self.server_completion_queue.shutdown()
while self.server_completion_queue.next().type != _types.EventType.QUEUE_SHUTDOWN:
pass
del self.client_completion_queue
del self.server_completion_queue
def testEcho(self):
DEADLINE = time.time()+5
DEADLINE_TOLERANCE = 0.25
CLIENT_METADATA_ASCII_KEY = 'key'
CLIENT_METADATA_ASCII_VALUE = 'val'
CLIENT_METADATA_BIN_KEY = 'key-bin'
CLIENT_METADATA_BIN_VALUE = b'\0'*1000
SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
SERVER_TRAILING_METADATA_KEY = 'California_is_in_a_drought'
SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
SERVER_STATUS_CODE = _types.StatusCode.OK
SERVER_STATUS_DETAILS = 'our work is never over'
REQUEST = 'in death a member of project mayhem has a name'
RESPONSE = 'his name is robert paulson'
METHOD = 'twinkies'
HOST = 'hostess'
server_request_tag = object()
request_call_result = self.server.request_call(self.server_completion_queue, server_request_tag)
self.assertEquals(_types.CallError.OK, request_call_result)
client_call_tag = object()
client_call = self.client_channel.create_call(self.client_completion_queue, METHOD, HOST, DEADLINE)
client_initial_metadata = [(CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE), (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]
client_start_batch_result = client_call.start_batch([
_types.OpArgs.send_initial_metadata(client_initial_metadata),
_types.OpArgs.send_message(REQUEST),
_types.OpArgs.send_close_from_client(),
_types.OpArgs.recv_initial_metadata(),
_types.OpArgs.recv_message(),
_types.OpArgs.recv_status_on_client()
], client_call_tag)
self.assertEquals(_types.CallError.OK, client_start_batch_result)
request_event = self.server_completion_queue.next(DEADLINE)
self.assertEquals(_types.EventType.OP_COMPLETE, request_event.type)
self.assertIsInstance(request_event.call, _low.Call)
self.assertIs(server_request_tag, request_event.tag)
self.assertEquals(1, len(request_event.results))
self.assertEquals(dict(client_initial_metadata), dict(request_event.results[0].initial_metadata))
self.assertEquals(METHOD, request_event.call_details.method)
self.assertEquals(HOST, request_event.call_details.host)
self.assertLess(abs(DEADLINE - request_event.call_details.deadline), DEADLINE_TOLERANCE)
server_call_tag = object()
server_call = request_event.call
server_initial_metadata = [(SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]
server_trailing_metadata = [(SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)]
server_start_batch_result = server_call.start_batch([
_types.OpArgs.send_initial_metadata(server_initial_metadata),
_types.OpArgs.recv_message(),
_types.OpArgs.send_message(RESPONSE),
_types.OpArgs.recv_close_on_server(),
_types.OpArgs.send_status_from_server(server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
], server_call_tag)
self.assertEquals(_types.CallError.OK, server_start_batch_result)
client_event = self.client_completion_queue.next(DEADLINE)
server_event = self.server_completion_queue.next(DEADLINE)
self.assertEquals(6, len(client_event.results))
found_client_op_types = set()
for client_result in client_event.results:
self.assertNotIn(client_result.type, found_client_op_types) # we expect each op type to be unique
found_client_op_types.add(client_result.type)
if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
self.assertEquals(dict(server_initial_metadata), dict(client_result.initial_metadata))
elif client_result.type == _types.OpType.RECV_MESSAGE:
self.assertEquals(RESPONSE, client_result.message)
elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
self.assertEquals(dict(server_trailing_metadata), dict(client_result.trailing_metadata))
self.assertEquals(SERVER_STATUS_DETAILS, client_result.status.details)
self.assertEquals(SERVER_STATUS_CODE, client_result.status.code)
self.assertEquals(set([
_types.OpType.SEND_INITIAL_METADATA,
_types.OpType.SEND_MESSAGE,
_types.OpType.SEND_CLOSE_FROM_CLIENT,
_types.OpType.RECV_INITIAL_METADATA,
_types.OpType.RECV_MESSAGE,
_types.OpType.RECV_STATUS_ON_CLIENT
]), found_client_op_types)
self.assertEquals(5, len(server_event.results))
found_server_op_types = set()
for server_result in server_event.results:
self.assertNotIn(client_result.type, found_server_op_types)
found_server_op_types.add(server_result.type)
if server_result.type == _types.OpType.RECV_MESSAGE:
self.assertEquals(REQUEST, server_result.message)
elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
self.assertFalse(server_result.cancelled)
self.assertEquals(set([
_types.OpType.SEND_INITIAL_METADATA,
_types.OpType.RECV_MESSAGE,
_types.OpType.SEND_MESSAGE,
_types.OpType.RECV_CLOSE_ON_SERVER,
_types.OpType.SEND_STATUS_FROM_SERVER
]), found_server_op_types)
del client_call
del server_call
if __name__ == '__main__':

@ -1,202 +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/_adapter/_server.h"
#include <Python.h>
#include <grpc/grpc.h>
#include "grpc/_adapter/_call.h"
#include "grpc/_adapter/_completion_queue.h"
#include "grpc/_adapter/_error.h"
#include "grpc/_adapter/_server_credentials.h"
#include "grpc/_adapter/_tag.h"
static int pygrpc_server_init(Server *self, PyObject *args, PyObject *kwds) {
CompletionQueue *completion_queue;
static char *kwlist[] = {"completion_queue", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!:Server", kwlist,
&pygrpc_CompletionQueueType,
&completion_queue)) {
return -1;
}
self->c_server = grpc_server_create(NULL);
grpc_server_register_completion_queue(self->c_server,
completion_queue->c_completion_queue);
self->completion_queue = completion_queue;
Py_INCREF(completion_queue);
return 0;
}
static void pygrpc_server_dealloc(Server *self) {
if (self->c_server != NULL) {
grpc_server_destroy(self->c_server);
}
Py_XDECREF(self->completion_queue);
self->ob_type->tp_free((PyObject *)self);
}
static PyObject *pygrpc_server_add_http2_addr(Server *self, PyObject *args) {
const char *addr;
int port;
if (!PyArg_ParseTuple(args, "s:add_http2_addr", &addr)) {
return NULL;
}
port = grpc_server_add_http2_port(self->c_server, addr);
if (port == 0) {
PyErr_SetString(PyExc_RuntimeError, "Couldn't add port to server!");
return NULL;
}
return PyInt_FromLong(port);
}
static PyObject *pygrpc_server_add_secure_http2_addr(Server *self,
PyObject *args,
PyObject *kwargs) {
const char *addr;
PyObject *server_credentials;
static char *kwlist[] = {"addr", "server_credentials", NULL};
int port;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!:add_secure_http2_addr",
kwlist, &addr, &pygrpc_ServerCredentialsType,
&server_credentials)) {
return NULL;
}
port = grpc_server_add_secure_http2_port(
self->c_server, addr,
((ServerCredentials *)server_credentials)->c_server_credentials);
if (port == 0) {
PyErr_SetString(PyExc_RuntimeError, "Couldn't add port to server!");
return NULL;
}
return PyInt_FromLong(port);
}
static PyObject *pygrpc_server_start(Server *self) {
grpc_server_start(self->c_server);
Py_RETURN_NONE;
}
static const PyObject *pygrpc_server_service(Server *self, PyObject *tag) {
grpc_call_error call_error;
const PyObject *result;
pygrpc_tag *c_tag = pygrpc_tag_new_server_rpc_call(tag);
c_tag->call->completion_queue = self->completion_queue;
c_tag->call->server = self;
Py_INCREF(c_tag->call->completion_queue);
Py_INCREF(c_tag->call->server);
call_error = grpc_server_request_call(
self->c_server, &c_tag->call->c_call, &c_tag->call->call_details,
&c_tag->call->recv_metadata, self->completion_queue->c_completion_queue,
self->completion_queue->c_completion_queue, c_tag);
result = pygrpc_translate_call_error(call_error);
if (result != NULL) {
Py_INCREF(tag);
}
return result;
}
static PyObject *pygrpc_server_stop(Server *self) {
grpc_server_shutdown(self->c_server);
Py_RETURN_NONE;
}
static PyMethodDef methods[] = {
{"add_http2_addr", (PyCFunction)pygrpc_server_add_http2_addr, METH_VARARGS,
"Add an HTTP2 address."},
{"add_secure_http2_addr", (PyCFunction)pygrpc_server_add_secure_http2_addr,
METH_VARARGS, "Add a secure HTTP2 address."},
{"start", (PyCFunction)pygrpc_server_start, METH_NOARGS,
"Starts the server."},
{"service", (PyCFunction)pygrpc_server_service, METH_O, "Services a call."},
{"stop", (PyCFunction)pygrpc_server_stop, METH_NOARGS, "Stops the server."},
{NULL}};
static PyTypeObject pygrpc_ServerType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_gprc.Server", /*tp_name*/
sizeof(Server), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)pygrpc_server_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Wrapping of grpc_server.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pygrpc_server_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
int pygrpc_add_server(PyObject *module) {
if (PyType_Ready(&pygrpc_ServerType) < 0) {
return -1;
}
if (PyModule_AddObject(module, "Server", (PyObject *)&pygrpc_ServerType) ==
-1) {
return -1;
}
return 0;
}

@ -1,152 +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/_adapter/_server_credentials.h"
#include <Python.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
static int pygrpc_server_credentials_init(ServerCredentials *self,
PyObject *args, PyObject *kwds) {
char *root_certificates;
PyObject *pair_sequence;
Py_ssize_t pair_count;
grpc_ssl_pem_key_cert_pair *pairs;
int error;
PyObject *iterator;
int i;
PyObject *pair;
static char *kwlist[] = {"root_credentials", "pair_sequence", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "zO:ServerCredentials", kwlist,
&root_certificates, &pair_sequence)) {
return -1;
}
pair_count = PySequence_Length(pair_sequence);
if (pair_count == -1) {
return -1;
}
iterator = PyObject_GetIter(pair_sequence);
if (iterator == NULL) {
return -1;
}
pairs = gpr_malloc(pair_count * sizeof(grpc_ssl_pem_key_cert_pair));
error = 0;
for (i = 0; i < pair_count; i++) {
pair = PyIter_Next(iterator);
if (pair == NULL) {
error = 1;
break;
}
if (!PyArg_ParseTuple(pair, "ss", &pairs[i].private_key,
&pairs[i].cert_chain)) {
error = 1;
Py_DECREF(pair);
break;
}
Py_DECREF(pair);
}
Py_DECREF(iterator);
if (error) {
gpr_free(pairs);
return -1;
} else {
self->c_server_credentials = grpc_ssl_server_credentials_create(
root_certificates, pairs, pair_count);
gpr_free(pairs);
return 0;
}
}
static void pygrpc_server_credentials_dealloc(ServerCredentials *self) {
if (self->c_server_credentials != NULL) {
grpc_server_credentials_release(self->c_server_credentials);
}
self->ob_type->tp_free((PyObject *)self);
}
PyTypeObject pygrpc_ServerCredentialsType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_grpc.ServerCredencials", /*tp_name*/
sizeof(ServerCredentials), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)pygrpc_server_credentials_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Wrapping of grpc_server_credentials.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pygrpc_server_credentials_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
int pygrpc_add_server_credentials(PyObject *module) {
if (PyType_Ready(&pygrpc_ServerCredentialsType) < 0) {
return -1;
}
if (PyModule_AddObject(module, "ServerCredentials",
(PyObject *)&pygrpc_ServerCredentialsType) == -1) {
return -1;
}
return 0;
}

@ -1,49 +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.
*
*/
#ifndef _ADAPTER__SERVER_CREDENTIALS_H_
#define _ADAPTER__SERVER_CREDENTIALS_H_
#include <Python.h>
#include <grpc/grpc_security.h>
typedef struct {
PyObject_HEAD
grpc_server_credentials *c_server_credentials;
} ServerCredentials;
extern PyTypeObject pygrpc_ServerCredentialsType;
int pygrpc_add_server_credentials(PyObject *module);
#endif /* _ADAPTER__SERVER_CREDENTIALS_H_ */

@ -1,65 +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/_adapter/_tag.h"
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
pygrpc_tag *pygrpc_tag_new(pygrpc_tag_type type, PyObject *user_tag,
Call *call) {
pygrpc_tag *self = (pygrpc_tag *)gpr_malloc(sizeof(pygrpc_tag));
memset(self, 0, sizeof(pygrpc_tag));
if (user_tag == NULL) {
self->user_tag = Py_None;
} else {
self->user_tag = user_tag;
}
Py_INCREF(self->user_tag);
self->type = type;
self->call = call;
Py_INCREF(call);
return self;
}
pygrpc_tag *pygrpc_tag_new_server_rpc_call(PyObject *user_tag) {
return pygrpc_tag_new(PYGRPC_SERVER_RPC_NEW, user_tag,
(Call *)pygrpc_CallType.tp_alloc(&pygrpc_CallType, 0));
}
void pygrpc_tag_destroy(pygrpc_tag *self) {
Py_XDECREF(self->user_tag);
Py_XDECREF(self->call);
gpr_free(self);
}

@ -1,70 +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.
*
*/
#ifndef _ADAPTER__TAG_H_
#define _ADAPTER__TAG_H_
#include <Python.h>
#include <grpc/grpc.h>
#include "grpc/_adapter/_call.h"
#include "grpc/_adapter/_completion_queue.h"
/* grpc_completion_type is becoming meaningless in grpc_event; this is a partial
replacement for its descriptive functionality until Python can move its whole
C and C adapter stack to more closely resemble the core batching API. */
typedef enum {
PYGRPC_SERVER_RPC_NEW = 0,
PYGRPC_INITIAL_METADATA = 1,
PYGRPC_READ = 2,
PYGRPC_WRITE_ACCEPTED = 3,
PYGRPC_FINISH_ACCEPTED = 4,
PYGRPC_CLIENT_METADATA_READ = 5,
PYGRPC_FINISHED_CLIENT = 6,
PYGRPC_FINISHED_SERVER = 7
} pygrpc_tag_type;
typedef struct {
pygrpc_tag_type type;
PyObject *user_tag;
Call *call;
} pygrpc_tag;
pygrpc_tag *pygrpc_tag_new(pygrpc_tag_type type, PyObject *user_tag,
Call *call);
pygrpc_tag *pygrpc_tag_new_server_rpc_call(PyObject *user_tag);
void pygrpc_tag_destroy(pygrpc_tag *self);
#endif /* _ADAPTER__TAG_H_ */

@ -0,0 +1,368 @@
# 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.
import abc
import collections
import enum
# TODO(atash): decide whether or not to move these enums to the _c module to
# force build errors with upstream changes.
class GrpcChannelArgumentKeys(enum.Enum):
"""Mirrors keys used in grpc_channel_args for GRPC-specific arguments."""
SSL_TARGET_NAME_OVERRIDE = 'grpc.ssl_target_name_override'
@enum.unique
class CallError(enum.IntEnum):
"""Mirrors grpc_call_error in the C core."""
OK = 0
ERROR = 1
ERROR_NOT_ON_SERVER = 2
ERROR_NOT_ON_CLIENT = 3
ERROR_ALREADY_ACCEPTED = 4
ERROR_ALREADY_INVOKED = 5
ERROR_NOT_INVOKED = 6
ERROR_ALREADY_FINISHED = 7
ERROR_TOO_MANY_OPERATIONS = 8
ERROR_INVALID_FLAGS = 9
ERROR_INVALID_METADATA = 10
@enum.unique
class StatusCode(enum.IntEnum):
"""Mirrors grpc_status_code in the C core."""
OK = 0
CANCELLED = 1
UNKNOWN = 2
INVALID_ARGUMENT = 3
DEADLINE_EXCEEDED = 4
NOT_FOUND = 5
ALREADY_EXISTS = 6
PERMISSION_DENIED = 7
RESOURCE_EXHAUSTED = 8
FAILED_PRECONDITION = 9
ABORTED = 10
OUT_OF_RANGE = 11
UNIMPLEMENTED = 12
INTERNAL = 13
UNAVAILABLE = 14
DATA_LOSS = 15
UNAUTHENTICATED = 16
@enum.unique
class OpType(enum.IntEnum):
"""Mirrors grpc_op_type in the C core."""
SEND_INITIAL_METADATA = 0
SEND_MESSAGE = 1
SEND_CLOSE_FROM_CLIENT = 2
SEND_STATUS_FROM_SERVER = 3
RECV_INITIAL_METADATA = 4
RECV_MESSAGE = 5
RECV_STATUS_ON_CLIENT = 6
RECV_CLOSE_ON_SERVER = 7
@enum.unique
class EventType(enum.IntEnum):
"""Mirrors grpc_completion_type in the C core."""
QUEUE_SHUTDOWN = 0
QUEUE_TIMEOUT = 1 # if seen on the Python side, something went horridly wrong
OP_COMPLETE = 2
class Status(collections.namedtuple(
'Status', [
'code',
'details',
])):
"""The end status of a GRPC call.
Attributes:
code (StatusCode): ...
details (str): ...
"""
class CallDetails(collections.namedtuple(
'CallDetails', [
'method',
'host',
'deadline',
])):
"""Provides information to the server about the client's call.
Attributes:
method (str): ...
host (str): ...
deadline (float): ...
"""
class OpArgs(collections.namedtuple(
'OpArgs', [
'type',
'initial_metadata',
'trailing_metadata',
'message',
'status',
])):
"""Arguments passed into a GRPC operation.
Attributes:
type (OpType): ...
initial_metadata (sequence of 2-sequence of str): Only valid if type ==
OpType.SEND_INITIAL_METADATA, else is None.
trailing_metadata (sequence of 2-sequence of str): Only valid if type ==
OpType.SEND_STATUS_FROM_SERVER, else is None.
message (bytes): Only valid if type == OpType.SEND_MESSAGE, else is None.
status (Status): Only valid if type == OpType.SEND_STATUS_FROM_SERVER, else
is None.
"""
@staticmethod
def send_initial_metadata(initial_metadata):
return OpArgs(OpType.SEND_INITIAL_METADATA, initial_metadata, None, None, None)
@staticmethod
def send_message(message):
return OpArgs(OpType.SEND_MESSAGE, None, None, message, None)
@staticmethod
def send_close_from_client():
return OpArgs(OpType.SEND_CLOSE_FROM_CLIENT, None, None, None, None)
@staticmethod
def send_status_from_server(trailing_metadata, status_code, status_details):
return OpArgs(OpType.SEND_STATUS_FROM_SERVER, None, trailing_metadata, None, Status(status_code, status_details))
@staticmethod
def recv_initial_metadata():
return OpArgs(OpType.RECV_INITIAL_METADATA, None, None, None, None);
@staticmethod
def recv_message():
return OpArgs(OpType.RECV_MESSAGE, None, None, None, None)
@staticmethod
def recv_status_on_client():
return OpArgs(OpType.RECV_STATUS_ON_CLIENT, None, None, None, None)
@staticmethod
def recv_close_on_server():
return OpArgs(OpType.RECV_CLOSE_ON_SERVER, None, None, None, None)
class OpResult(collections.namedtuple(
'OpResult', [
'type',
'initial_metadata',
'trailing_metadata',
'message',
'status',
'cancelled',
])):
"""Results received from a GRPC operation.
Attributes:
type (OpType): ...
initial_metadata (sequence of 2-sequence of str): Only valid if type ==
OpType.RECV_INITIAL_METADATA, else is None.
trailing_metadata (sequence of 2-sequence of str): Only valid if type ==
OpType.RECV_STATUS_ON_CLIENT, else is None.
message (bytes): Only valid if type == OpType.RECV_MESSAGE, else is None.
status (Status): Only valid if type == OpType.RECV_STATUS_ON_CLIENT, else
is None.
cancelled (bool): Only valid if type == OpType.RECV_CLOSE_ON_SERVER, else
is None.
"""
class Event(collections.namedtuple(
'Event', [
'type',
'tag',
'call',
'call_details',
'results',
'success',
])):
"""An event received from a GRPC completion queue.
Attributes:
type (EventType): ...
tag (object): ...
call (Call): The Call object associated with this event (if there is one,
else None).
call_details (CallDetails): The call details associated with the
server-side call (if there is such information, else None).
results (list of OpResult): ...
success (bool): ...
"""
class CompletionQueue:
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def __init__(self):
pass
def __iter__(self):
"""This class may be iterated over.
This is the equivalent of calling next() repeatedly with an absolute
deadline of None (i.e. no deadline).
"""
return self
@abc.abstractmethod
def next(self, deadline=float('+inf')):
"""Get the next event on this completion queue.
Args:
deadline (float): absolute deadline in seconds from the Python epoch, or
None for no deadline.
Returns:
Event: ...
"""
pass
@abc.abstractmethod
def shutdown(self):
"""Begin the shutdown process of this completion queue.
Note that this does not immediately destroy the completion queue.
Nevertheless, user code should not pass it around after invoking this.
"""
return None
class Call:
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def start_batch(self, ops, tag):
"""Start a batch of operations.
Args:
ops (sequence of OpArgs): ...
tag (object): ...
Returns:
CallError: ...
"""
return CallError.ERROR
@abc.abstractmethod
def cancel(self, code=None, details=None):
"""Cancel the call.
Args:
code (int): Status code to cancel with (on the server side). If
specified, so must `details`.
details (str): Status details to cancel with (on the server side). If
specified, so must `code`.
Returns:
CallError: ...
"""
return CallError.ERROR
class Channel:
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def __init__(self, target, args, credentials=None):
"""Initialize a Channel.
Args:
target (str): ...
args (sequence of 2-sequence of str, (str|integer)): ...
credentials (ClientCredentials): If None, create an insecure channel,
else create a secure channel using the client credentials.
"""
@abc.abstractmethod
def create_call(self, completion_queue, method, host, deadline=float('+inf')):
"""Create a call from this channel.
Args:
completion_queue (CompletionQueue): ...
method (str): ...
host (str): ...
deadline (float): absolute deadline in seconds from the Python epoch, or
None for no deadline.
Returns:
Call: call object associated with this Channel and passed parameters.
"""
return None
class Server:
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def __init__(self, completion_queue, args):
"""Initialize a server.
Args:
completion_queue (CompletionQueue): ...
args (sequence of 2-sequence of str, (str|integer)): ...
"""
@abc.abstractmethod
def add_http2_port(self, address, credentials=None):
"""Adds an HTTP/2 address+port to the server.
Args:
address (str): ...
credentials (ServerCredentials): If None, create an insecure port, else
create a secure port using the server credentials.
"""
@abc.abstractmethod
def start(self):
"""Starts the server."""
@abc.abstractmethod
def shutdown(self, tag=None):
"""Shuts down the server. Does not immediately destroy the server.
Args:
tag (object): if not None, have the server place an event on its
completion queue notifying it when this server has completely shut down.
"""
@abc.abstractmethod
def request_call(self, completion_queue, tag):
"""Requests a call from the server on the server's completion queue.
Args:
completion_queue (CompletionQueue): Completion queue for the call. May be
the same as the server's completion queue.
tag (object) ...
"""

@ -35,7 +35,7 @@ import threading
import time
from grpc._adapter import _common
from grpc._adapter import _low
from grpc._adapter import _intermediary_low as _low
from grpc.framework.base import interfaces as base_interfaces
from grpc.framework.base import null
from grpc.framework.foundation import activated
@ -204,7 +204,7 @@ class ForeLink(base_interfaces.ForeLink, activated.Activated):
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.CANCELLATION, None, None,
None, None, None)
elif code is _low.Code.EXPIRED:
elif code is _low.Code.DEADLINE_EXCEEDED:
ticket = base_interfaces.FrontToBackTicket(
call, sequence_number,
base_interfaces.FrontToBackTicket.Kind.EXPIRATION, None, None, None,

@ -35,7 +35,7 @@ import threading
import time
from grpc._adapter import _common
from grpc._adapter import _low
from grpc._adapter import _intermediary_low as _low
from grpc.framework.base import interfaces as base_interfaces
from grpc.framework.base import null
from grpc.framework.foundation import activated
@ -195,7 +195,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
kind = base_interfaces.BackToFrontTicket.Kind.COMPLETION
elif event.status.code is _low.Code.CANCELLED:
kind = base_interfaces.BackToFrontTicket.Kind.CANCELLATION
elif event.status.code is _low.Code.EXPIRED:
elif event.status.code is _low.Code.DEADLINE_EXCEEDED:
kind = base_interfaces.BackToFrontTicket.Kind.EXPIRATION
else:
kind = base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE

@ -34,15 +34,15 @@ import setuptools
import sys
_EXTENSION_SOURCES = (
'grpc/_adapter/_c.c',
'grpc/_adapter/_call.c',
'grpc/_adapter/_channel.c',
'grpc/_adapter/_completion_queue.c',
'grpc/_adapter/_error.c',
'grpc/_adapter/_server.c',
'grpc/_adapter/_client_credentials.c',
'grpc/_adapter/_server_credentials.c',
'grpc/_adapter/_tag.c'
'grpc/_adapter/_c/module.c',
'grpc/_adapter/_c/types.c',
'grpc/_adapter/_c/utility.c',
'grpc/_adapter/_c/types/client_credentials.c',
'grpc/_adapter/_c/types/server_credentials.c',
'grpc/_adapter/_c/types/completion_queue.c',
'grpc/_adapter/_c/types/call.c',
'grpc/_adapter/_c/types/channel.c',
'grpc/_adapter/_c/types/server.c',
)
_EXTENSION_INCLUDE_DIRECTORIES = (

@ -274,6 +274,7 @@ class NamedTests
op = @stub.streaming_input_call(reqs, return_op: true)
op.cancel
assert_raises(GRPC::Cancelled) { op.execute }
assert(op.cancelled, 'call operation should be CANCELLED')
p 'OK: cancel_after_begin'
end
@ -282,7 +283,8 @@ class NamedTests
ppp = PingPongPlayer.new(msg_sizes)
op = @stub.full_duplex_call(ppp.each_item, return_op: true)
ppp.canceller_op = op # causes ppp to cancel after the 1st message
assert_raises(GRPC::Cancelled) { op.execute.each { |r| ppp.queue.push(r) } }
op.execute.each { |r| ppp.queue.push(r) }
assert(op.cancelled, 'call operation should be CANCELLED')
p 'OK: cancel_after_first_response'
end

@ -36,6 +36,7 @@
#include <ruby/ruby.h>
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/slice.h>
#include "rb_grpc.h"
@ -50,7 +51,7 @@ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
size_t length = 0;
char *string = NULL;
size_t offset = 0;
grpc_byte_buffer_reader *reader = NULL;
grpc_byte_buffer_reader reader;
gpr_slice next;
if (buffer == NULL) {
return Qnil;
@ -58,8 +59,8 @@ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
}
length = grpc_byte_buffer_length(buffer);
string = xmalloc(length + 1);
reader = grpc_byte_buffer_reader_create(buffer);
while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
grpc_byte_buffer_reader_init(&reader, buffer);
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}

@ -55,7 +55,6 @@ module GRPC
# The ActiveCall class provides simple methods for sending marshallable
# data to a call
class ActiveCall
include Core::StatusCodes
include Core::TimeConsts
include Core::CallOps
extend Forwardable
@ -129,6 +128,11 @@ module GRPC
@output_metadata ||= {}
end
# cancelled indicates if the call was cancelled
def cancelled
!@call.status.nil? && @call.status.code == Core::StatusCodes::CANCELLED
end
# multi_req_view provides a restricted view of this ActiveCall for use
# in a server client-streaming handler.
def multi_req_view
@ -162,6 +166,7 @@ module GRPC
ops[RECV_STATUS_ON_CLIENT] = nil if assert_finished
batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
return unless assert_finished
@call.status = batch_result.status
batch_result.check_status
end
@ -178,6 +183,7 @@ module GRPC
@call.metadata.merge!(batch_result.status.metadata)
end
end
@call.status = batch_result.status
batch_result.check_status
end
@ -410,9 +416,6 @@ module GRPC
start_call(**kw) unless @started
bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
bd.run_on_client(requests, &blk)
rescue GRPC::Core::CallError => e
finished # checks for Cancelled
raise e
end
# run_server_bidi orchestrates a BiDi stream processing on a server.

@ -78,11 +78,9 @@ module GRPC
# @param requests the Enumerable of requests to send
# @return an Enumerator of requests to yield
def run_on_client(requests, &blk)
@enq_th = start_write_loop(requests)
@enq_th = Thread.new { write_loop(requests) }
@loop_th = start_read_loop
replies = each_queued_msg
return replies if blk.nil?
replies.each { |r| blk.call(r) }
each_queued_msg(&blk)
end
# Begins orchestration of the Bidi stream for a server generating replies.
@ -98,9 +96,8 @@ module GRPC
# @param gen_each_reply [Proc] generates the BiDi stream replies.
def run_on_server(gen_each_reply)
replys = gen_each_reply.call(each_queued_msg)
@enq_th = start_write_loop(replys, is_client: false)
@loop_th = start_read_loop
@enq_th.join if @enq_th.alive?
write_loop(replys, is_client: false)
end
private
@ -126,37 +123,32 @@ module GRPC
end
end
# during bidi-streaming, read the requests to send from a separate thread
# read so that read_loop does not block waiting for requests to read.
def start_write_loop(requests, is_client: true)
Thread.new do # TODO: run on a thread pool
GRPC.logger.debug('bidi-write-loop: starting')
begin
write_tag = Object.new
count = 0
requests.each do |req|
GRPC.logger.debug("bidi-write-loop: #{count}")
count += 1
payload = @marshal.call(req)
@call.run_batch(@cq, write_tag, INFINITE_FUTURE,
SEND_MESSAGE => payload)
end
GRPC.logger.debug("bidi-write-loop: #{count} writes done")
if is_client
GRPC.logger.debug("bidi-write-loop: client sent #{count}, waiting")
@call.run_batch(@cq, write_tag, INFINITE_FUTURE,
SEND_CLOSE_FROM_CLIENT => nil)
batch_result = @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
RECV_STATUS_ON_CLIENT => nil)
batch_result.check_status
end
rescue StandardError => e
GRPC.logger.warn('bidi-write-loop: failed')
GRPC.logger.warn(e)
raise e
end
GRPC.logger.debug('bidi-write-loop: finished')
def write_loop(requests, is_client: true)
GRPC.logger.debug('bidi-write-loop: starting')
write_tag = Object.new
count = 0
requests.each do |req|
GRPC.logger.debug("bidi-write-loop: #{count}")
count += 1
payload = @marshal.call(req)
@call.run_batch(@cq, write_tag, INFINITE_FUTURE,
SEND_MESSAGE => payload)
end
GRPC.logger.debug("bidi-write-loop: #{count} writes done")
if is_client
GRPC.logger.debug("bidi-write-loop: client sent #{count}, waiting")
batch_result = @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
SEND_CLOSE_FROM_CLIENT => nil,
RECV_STATUS_ON_CLIENT => nil)
@call.status = batch_result.status
batch_result.check_status
GRPC.logger.debug("bidi-write-loop: done status #{@call.status}")
end
GRPC.logger.debug('bidi-write-loop: finished')
rescue StandardError => e
GRPC.logger.warn('bidi-write-loop: failed')
GRPC.logger.warn(e)
raise e
end
# starts the read loop

@ -276,6 +276,8 @@ LDFLAGS += -fPIC
endif
INCLUDES = . include $(GENDIR)
LDFLAGS += -Llibs/$(CONFIG)
ifeq ($(SYSTEM),Darwin)
ifneq ($(wildcard /usr/local/ssl/include),)
INCLUDES += /usr/local/ssl/include
@ -1220,7 +1222,7 @@ endif
mingw_lib_deps = mingw_lib_deps + ' $(LIBDIR)/$(CONFIG)/' + dep + '.$(SHARED_EXT)'
if lib.get('secure', 'check') == 'yes':
common = common + ' $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS)'
common = common + ' $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE)'
for src in lib.src:
sources_that_need_openssl.add(src)
else:

@ -88,7 +88,7 @@ void grpc_run_bad_client_test(const char *name, const char *client_payload,
grpc_init();
/* Create endpoints */
sfd = grpc_iomgr_create_endpoint_pair(65536);
sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
/* Create server, completion events */
a.server = grpc_server_create_from_filters(NULL, 0, NULL);

@ -98,7 +98,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.client_cq = grpc_completion_queue_create();
f.server_cq = grpc_completion_queue_create();
*sfd = grpc_iomgr_create_endpoint_pair(65536);
*sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
return f;
}

@ -98,7 +98,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.client_cq = grpc_completion_queue_create();
f.server_cq = grpc_completion_queue_create();
*sfd = grpc_iomgr_create_endpoint_pair(1);
*sfd = grpc_iomgr_create_endpoint_pair("fixture", 1);
return f;
}

@ -99,7 +99,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.client_cq = grpc_completion_queue_create();
f.server_cq = grpc_completion_queue_create();
*sfd = grpc_iomgr_create_endpoint_pair(65536);
*sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
return f;
}

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

Loading…
Cancel
Save