Merge branch 'master' into fix-time

pull/14894/head
Sree Kuchibhotla 7 years ago
commit 94d9034673
  1. 5
      .clang-format
  2. 1
      BUILD
  3. 2
      build.yaml
  4. 7
      grpc.def
  5. 70
      include/grpc/grpc_security.h
  6. 11
      include/grpc/impl/codegen/port_platform.h
  7. 4
      include/grpc/support/log.h
  8. 4
      include/grpcpp/impl/codegen/byte_buffer.h
  9. 6
      include/grpcpp/impl/codegen/proto_buffer_reader.h
  10. 13
      include/grpcpp/impl/codegen/proto_buffer_writer.h
  11. 7
      include/grpcpp/impl/codegen/proto_utils.h
  12. 16
      include/grpcpp/security/credentials.h
  13. 12
      include/grpcpp/security/server_credentials.h
  14. 3
      setup.py
  15. 9
      src/android/test/interop/.gitignore
  16. 37
      src/android/test/interop/README.md
  17. 1
      src/android/test/interop/app/.gitignore
  18. 119
      src/android/test/interop/app/CMakeLists.txt
  19. 56
      src/android/test/interop/app/build.gradle
  20. 21
      src/android/test/interop/app/proguard-rules.pro
  21. 93
      src/android/test/interop/app/src/androidTest/java/io/grpc/interop/cpp/InteropTest.java
  22. 22
      src/android/test/interop/app/src/main/AndroidManifest.xml
  23. 4475
      src/android/test/interop/app/src/main/assets/roots.pem
  24. 124
      src/android/test/interop/app/src/main/cpp/grpc-interop.cc
  25. 122
      src/android/test/interop/app/src/main/java/io/grpc/interop/cpp/InteropActivity.java
  26. 48
      src/android/test/interop/app/src/main/res/layout/activity_interop.xml
  27. BIN
      src/android/test/interop/app/src/main/res/mipmap-hdpi/ic_launcher.png
  28. BIN
      src/android/test/interop/app/src/main/res/mipmap-mdpi/ic_launcher.png
  29. BIN
      src/android/test/interop/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  30. BIN
      src/android/test/interop/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  31. 3
      src/android/test/interop/app/src/main/res/values/strings.xml
  32. 24
      src/android/test/interop/build.gradle
  33. 17
      src/android/test/interop/gradle.properties
  34. BIN
      src/android/test/interop/gradle/wrapper/gradle-wrapper.jar
  35. 6
      src/android/test/interop/gradle/wrapper/gradle-wrapper.properties
  36. 160
      src/android/test/interop/gradlew
  37. 90
      src/android/test/interop/gradlew.bat
  38. 1
      src/android/test/interop/settings.gradle
  39. 1
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  40. 30
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  41. 10
      src/core/lib/gpr/log.cc
  42. 4
      src/core/lib/gpr/log_android.cc
  43. 4
      src/core/lib/gpr/log_linux.cc
  44. 4
      src/core/lib/gpr/log_posix.cc
  45. 5
      src/core/lib/gpr/log_windows.cc
  46. 24
      src/core/lib/iomgr/socket_utils_common_posix.cc
  47. 3
      src/core/lib/iomgr/socket_utils_posix.h
  48. 27
      src/core/lib/iomgr/tcp_server_posix.cc
  49. 153
      src/core/lib/iomgr/udp_server.cc
  50. 12
      src/core/lib/iomgr/udp_server.h
  51. 20
      src/core/lib/security/credentials/alts/alts_credentials.h
  52. 14
      src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
  53. 39
      src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
  54. 21
      src/cpp/client/secure_credentials.cc
  55. 14
      src/cpp/server/secure_server_credentials.cc
  56. 10
      src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
  57. 3
      src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
  58. 4
      src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
  59. 17
      src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m
  60. 6
      src/objective-c/GRPCClient/GRPCCall+Cronet.h
  61. 4
      src/objective-c/GRPCClient/GRPCCall+GID.h
  62. 6
      src/objective-c/GRPCClient/GRPCCall+OAuth2.m
  63. 7
      src/objective-c/GRPCClient/GRPCCall+Tests.m
  64. 9
      src/objective-c/GRPCClient/GRPCCall.h
  65. 140
      src/objective-c/GRPCClient/GRPCCall.m
  66. 6
      src/objective-c/GRPCClient/private/GRPCChannel.h
  67. 50
      src/objective-c/GRPCClient/private/GRPCChannel.m
  68. 2
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
  69. 5
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  70. 5
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
  71. 11
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
  72. 1
      src/objective-c/GRPCClient/private/GRPCHost.h
  73. 56
      src/objective-c/GRPCClient/private/GRPCHost.m
  74. 1
      src/objective-c/GRPCClient/private/GRPCOpBatchLog.h
  75. 6
      src/objective-c/GRPCClient/private/GRPCOpBatchLog.m
  76. 6
      src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
  77. 20
      src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
  78. 17
      src/objective-c/GRPCClient/private/GRPCWrappedCall.h
  79. 77
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  80. 10
      src/objective-c/GRPCClient/private/NSData+GRPC.m
  81. 5
      src/objective-c/GRPCClient/private/NSDictionary+GRPC.m
  82. 4
      src/objective-c/GRPCClient/private/NSError+GRPC.m
  83. 1
      src/objective-c/GRPCClient/private/version.h
  84. 9
      src/objective-c/ProtoRPC/ProtoMethod.h
  85. 26
      src/objective-c/ProtoRPC/ProtoRPC.h
  86. 32
      src/objective-c/ProtoRPC/ProtoRPC.m
  87. 21
      src/objective-c/ProtoRPC/ProtoService.h
  88. 5
      src/objective-c/ProtoRPC/ProtoService.m
  89. 5
      src/objective-c/RxLibrary/GRXBufferedPipe.m
  90. 2
      src/objective-c/RxLibrary/GRXConcurrentWriteable.h
  91. 9
      src/objective-c/RxLibrary/GRXConcurrentWriteable.m
  92. 2
      src/objective-c/RxLibrary/GRXForwardingWriter.m
  93. 7
      src/objective-c/RxLibrary/GRXImmediateWriter.m
  94. 2
      src/objective-c/RxLibrary/GRXWriteable.h
  95. 18
      src/objective-c/RxLibrary/GRXWriteable.m
  96. 2
      src/objective-c/RxLibrary/GRXWriter+Immediate.m
  97. 7
      src/objective-c/RxLibrary/transformations/GRXMappingWriter.h
  98. 2
      src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
  99. 4
      src/objective-c/examples/Sample/Sample/AppDelegate.h
  100. 42
      src/objective-c/examples/Sample/Sample/ViewController.m
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,5 +3,10 @@ Language: Cpp
BasedOnStyle: Google BasedOnStyle: Google
DerivePointerAlignment: false DerivePointerAlignment: false
PointerAlignment: Left PointerAlignment: Left
---
Language: ObjC
BasedOnStyle: Google
ColumnLimit: 100
ObjCBlockIndentWidth: 2
... ...

@ -1708,6 +1708,7 @@ grpc_cc_library(
"src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h", "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h",
"src/core/tsi/alts/handshaker/transport_security_common_api.h", "src/core/tsi/alts/handshaker/transport_security_common_api.h",
], ],
public_hdrs = GRPC_SECURE_PUBLIC_HDRS,
external_deps = [ external_deps = [
"nanopb", "nanopb",
], ],

@ -70,6 +70,8 @@ filegroups:
- tsi_interface - tsi_interface
- tsi - tsi
- name: alts_util - name: alts_util
public_headers:
- include/grpc/grpc_security.h
headers: headers:
- src/core/lib/security/credentials/alts/check_gcp_environment.h - src/core/lib/security/credentials/alts/check_gcp_environment.h
- src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h - src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h

@ -115,6 +115,12 @@ EXPORTS
grpc_server_add_secure_http2_port grpc_server_add_secure_http2_port
grpc_call_set_credentials grpc_call_set_credentials
grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor
grpc_alts_credentials_client_options_create
grpc_alts_credentials_server_options_create
grpc_alts_credentials_client_options_add_target_service_account
grpc_alts_credentials_options_destroy
grpc_alts_credentials_create
grpc_alts_server_credentials_create
grpc_raw_byte_buffer_create grpc_raw_byte_buffer_create
grpc_raw_compressed_byte_buffer_create grpc_raw_compressed_byte_buffer_create
grpc_byte_buffer_copy grpc_byte_buffer_copy
@ -185,6 +191,7 @@ EXPORTS
gpr_cpu_current_cpu gpr_cpu_current_cpu
gpr_log_severity_string gpr_log_severity_string
gpr_log gpr_log
gpr_should_log
gpr_log_message gpr_log_message
gpr_set_log_verbosity gpr_set_log_verbosity
gpr_log_verbosity_init gpr_log_verbosity_init

@ -488,6 +488,76 @@ typedef struct {
GRPCAPI void grpc_server_credentials_set_auth_metadata_processor( GRPCAPI void grpc_server_credentials_set_auth_metadata_processor(
grpc_server_credentials* creds, grpc_auth_metadata_processor processor); grpc_server_credentials* creds, grpc_auth_metadata_processor processor);
/** --- ALTS channel/server credentials --- **/
/**
* Main interface for ALTS credentials options. The options will contain
* information that will be passed from grpc to TSI layer such as RPC protocol
* versions. ALTS client (channel) and server credentials will have their own
* implementation of this interface. The APIs listed in this header are
* thread-compatible. It is used for experimental purpose for now and subject
* to change.
*/
typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
/**
* This method creates a grpc ALTS credentials client options instance.
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
grpc_alts_credentials_client_options_create();
/**
* This method creates a grpc ALTS credentials server options instance.
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
grpc_alts_credentials_server_options_create();
/**
* This method adds a target service account to grpc client's ALTS credentials
* options instance. It is used for experimental purpose for now and subject
* to change.
*
* - options: grpc ALTS credentials options instance.
* - service_account: service account of target endpoint.
*/
GRPCAPI void grpc_alts_credentials_client_options_add_target_service_account(
grpc_alts_credentials_options* options, const char* service_account);
/**
* This method destroys a grpc_alts_credentials_options instance by
* de-allocating all of its occupied memory. It is used for experimental purpose
* for now and subject to change.
*
* - options: a grpc_alts_credentials_options instance that needs to be
* destroyed.
*/
GRPCAPI void grpc_alts_credentials_options_destroy(
grpc_alts_credentials_options* options);
/**
* This method creates an ALTS channel credential object. It is used for
* experimental purpose for now and subject to change.
*
* - options: grpc ALTS credentials options instance for client.
*
* It returns the created ALTS channel credential object.
*/
GRPCAPI grpc_channel_credentials* grpc_alts_credentials_create(
const grpc_alts_credentials_options* options);
/**
* This method creates an ALTS server credential object. It is used for
* experimental purpose for now and subject to change.
*
* - options: grpc ALTS credentials options instance for server.
*
* It returns the created ALTS server credential object.
*/
GRPCAPI grpc_server_credentials* grpc_alts_server_credentials_create(
const grpc_alts_credentials_options* options);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -500,6 +500,17 @@ typedef unsigned __int64 uint64_t;
#endif /* __GPR_WINDOWS */ #endif /* __GPR_WINDOWS */
#endif /* GRPC_ALLOW_EXCEPTIONS */ #endif /* GRPC_ALLOW_EXCEPTIONS */
/* Use GPR_LIKELY only in cases where you are sure that a certain outcome is the
* most likely. Ideally, also collect performance numbers to justify the claim.
*/
#ifdef __GNUC__
#define GPR_LIKELY(x) __builtin_expect((x), 1)
#define GPR_UNLIKELY(x) __builtin_expect((x), 0)
#else /* __GNUC__ */
#define GPR_LIKELY(x) (x)
#define GPR_UNLIKELY(x) (x)
#endif /* __GNUC__ */
#ifndef __STDC_FORMAT_MACROS #ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS
#endif #endif

@ -61,6 +61,8 @@ GPRAPI const char* gpr_log_severity_string(gpr_log_severity severity);
GPRAPI void gpr_log(const char* file, int line, gpr_log_severity severity, GPRAPI void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) GPR_PRINT_FORMAT_CHECK(4, 5); const char* format, ...) GPR_PRINT_FORMAT_CHECK(4, 5);
GPRAPI int gpr_should_log(gpr_log_severity severity);
GPRAPI void gpr_log_message(const char* file, int line, GPRAPI void gpr_log_message(const char* file, int line,
gpr_log_severity severity, const char* message); gpr_log_severity severity, const char* message);
@ -91,7 +93,7 @@ GPRAPI void gpr_set_log_function(gpr_log_func func);
an exception in a higher-level language, consider returning error code. */ an exception in a higher-level language, consider returning error code. */
#define GPR_ASSERT(x) \ #define GPR_ASSERT(x) \
do { \ do { \
if (!(x)) { \ if (GPR_UNLIKELY(!(x))) { \
gpr_log(GPR_ERROR, "assertion failed: %s", #x); \ gpr_log(GPR_ERROR, "assertion failed: %s", #x); \
abort(); \ abort(); \
} \ } \

@ -146,8 +146,8 @@ class ByteBuffer final {
friend class internal::ServerStreamingHandler; friend class internal::ServerStreamingHandler;
template <class R> template <class R>
friend class internal::DeserializeFuncType; friend class internal::DeserializeFuncType;
friend class GrpcProtoBufferReader; friend class ProtoBufferReader;
friend class GrpcProtoBufferWriter; friend class ProtoBufferWriter;
friend class internal::GrpcByteBufferPeer; friend class internal::GrpcByteBufferPeer;
grpc_byte_buffer* buffer_; grpc_byte_buffer* buffer_;

@ -43,11 +43,11 @@ extern CoreCodegenInterface* g_core_codegen_interface;
/// ///
/// Read more about ZeroCopyInputStream interface here: /// Read more about ZeroCopyInputStream interface here:
/// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream /// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream
class GrpcProtoBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream { class ProtoBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream {
public: public:
/// Constructs buffer reader from \a buffer. Will set \a status() to non ok /// Constructs buffer reader from \a buffer. Will set \a status() to non ok
/// if \a buffer is invalid (the internal buffer has not been initialized). /// if \a buffer is invalid (the internal buffer has not been initialized).
explicit GrpcProtoBufferReader(ByteBuffer* buffer) explicit ProtoBufferReader(ByteBuffer* buffer)
: byte_count_(0), backup_count_(0), status_() { : byte_count_(0), backup_count_(0), status_() {
/// Implemented through a grpc_byte_buffer_reader which iterates /// Implemented through a grpc_byte_buffer_reader which iterates
/// over the slices that make up a byte buffer /// over the slices that make up a byte buffer
@ -59,7 +59,7 @@ class GrpcProtoBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream {
} }
} }
~GrpcProtoBufferReader() { ~ProtoBufferReader() {
if (status_.ok()) { if (status_.ok()) {
g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_); g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_);
} }

@ -38,10 +38,10 @@ extern CoreCodegenInterface* g_core_codegen_interface;
// Forward declaration for testing use only // Forward declaration for testing use only
namespace internal { namespace internal {
class GrpcProtoBufferWriterPeer; class ProtoBufferWriterPeer;
} // namespace internal } // namespace internal
const int kGrpcProtoBufferWriterMaxBufferLength = 1024 * 1024; const int kProtoBufferWriterMaxBufferLength = 1024 * 1024;
/// This is a specialization of the protobuf class ZeroCopyOutputStream. /// This is a specialization of the protobuf class ZeroCopyOutputStream.
/// The principle is to give the proto layer one buffer of bytes at a time /// The principle is to give the proto layer one buffer of bytes at a time
@ -50,15 +50,14 @@ const int kGrpcProtoBufferWriterMaxBufferLength = 1024 * 1024;
/// ///
/// Read more about ZeroCopyOutputStream interface here: /// Read more about ZeroCopyOutputStream interface here:
/// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyOutputStream /// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyOutputStream
class GrpcProtoBufferWriter class ProtoBufferWriter : public ::grpc::protobuf::io::ZeroCopyOutputStream {
: public ::grpc::protobuf::io::ZeroCopyOutputStream {
public: public:
/// Constructor for this derived class /// Constructor for this derived class
/// ///
/// \param[out] byte_buffer A pointer to the grpc::ByteBuffer created /// \param[out] byte_buffer A pointer to the grpc::ByteBuffer created
/// \param block_size How big are the chunks to allocate at a time /// \param block_size How big are the chunks to allocate at a time
/// \param total_size How many total bytes are required for this proto /// \param total_size How many total bytes are required for this proto
GrpcProtoBufferWriter(ByteBuffer* byte_buffer, int block_size, int total_size) ProtoBufferWriter(ByteBuffer* byte_buffer, int block_size, int total_size)
: block_size_(block_size), : block_size_(block_size),
total_size_(total_size), total_size_(total_size),
byte_count_(0), byte_count_(0),
@ -71,7 +70,7 @@ class GrpcProtoBufferWriter
slice_buffer_ = &bp->data.raw.slice_buffer; slice_buffer_ = &bp->data.raw.slice_buffer;
} }
~GrpcProtoBufferWriter() { ~ProtoBufferWriter() {
if (have_backup_) { if (have_backup_) {
g_core_codegen_interface->grpc_slice_unref(backup_slice_); g_core_codegen_interface->grpc_slice_unref(backup_slice_);
} }
@ -151,7 +150,7 @@ class GrpcProtoBufferWriter
private: private:
// friend for testing purposes only // friend for testing purposes only
friend class internal::GrpcProtoBufferWriterPeer; friend class internal::ProtoBufferWriterPeer;
const int block_size_; ///< size to alloc for each new \a grpc_slice needed const int block_size_; ///< size to alloc for each new \a grpc_slice needed
const int total_size_; ///< byte size of proto being serialized const int total_size_; ///< byte size of proto being serialized
int64_t byte_count_; ///< bytes written since this object was created int64_t byte_count_; ///< bytes written since this object was created

@ -60,8 +60,7 @@ Status GenericSerialize(const grpc::protobuf::Message& msg, ByteBuffer* bb,
return g_core_codegen_interface->ok(); return g_core_codegen_interface->ok();
} }
ProtoBufferWriter writer(bb, kGrpcProtoBufferWriterMaxBufferLength, ProtoBufferWriter writer(bb, kProtoBufferWriterMaxBufferLength, byte_size);
byte_size);
return msg.SerializeToZeroCopyStream(&writer) return msg.SerializeToZeroCopyStream(&writer)
? g_core_codegen_interface->ok() ? g_core_codegen_interface->ok()
: Status(StatusCode::INTERNAL, "Failed to serialize message"); : Status(StatusCode::INTERNAL, "Failed to serialize message");
@ -108,11 +107,11 @@ class SerializationTraits<T, typename std::enable_if<std::is_base_of<
public: public:
static Status Serialize(const grpc::protobuf::Message& msg, ByteBuffer* bb, static Status Serialize(const grpc::protobuf::Message& msg, ByteBuffer* bb,
bool* own_buffer) { bool* own_buffer) {
return GenericSerialize<GrpcProtoBufferWriter, T>(msg, bb, own_buffer); return GenericSerialize<ProtoBufferWriter, T>(msg, bb, own_buffer);
} }
static Status Deserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) { static Status Deserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) {
return GenericDeserialize<GrpcProtoBufferReader, T>(buffer, msg); return GenericDeserialize<ProtoBufferReader, T>(buffer, msg);
} }
}; };
#endif #endif

@ -21,6 +21,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <vector>
#include <grpcpp/impl/codegen/grpc_library.h> #include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h> #include <grpcpp/security/auth_context.h>
@ -219,6 +220,21 @@ class MetadataCredentialsPlugin {
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin( std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin); std::unique_ptr<MetadataCredentialsPlugin> plugin);
namespace experimental {
/// Options used to build AltsCredentials.
struct AltsCredentialsOptions {
/// service accounts of target endpoint that will be acceptable
/// by the client. If service accounts are provided and none of them matches
/// that of the server, authentication will fail.
std::vector<grpc::string> target_service_accounts;
};
/// Builds ALTS Credentials given ALTS specific options
std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options);
} // namespace experimental
} // namespace grpc } // namespace grpc
#endif // GRPCPP_SECURITY_CREDENTIALS_H #endif // GRPCPP_SECURITY_CREDENTIALS_H

@ -86,6 +86,18 @@ std::shared_ptr<ServerCredentials> SslServerCredentials(
/// Builds insecure server credentials. /// Builds insecure server credentials.
std::shared_ptr<ServerCredentials> InsecureServerCredentials(); std::shared_ptr<ServerCredentials> InsecureServerCredentials();
namespace experimental {
/// Options to create ServerCredentials with ALTS
struct AltsServerCredentialsOptions {
/// Add fields if needed.
};
/// Builds ALTS ServerCredentials given ALTS specific options
std::shared_ptr<ServerCredentials> AltsServerCredentials(
const AltsServerCredentialsOptions& options);
} // namespace experimental
} // namespace grpc } // namespace grpc
#endif // GRPCPP_SECURITY_SERVER_CREDENTIALS_H #endif // GRPCPP_SECURITY_SERVER_CREDENTIALS_H

@ -239,9 +239,6 @@ PACKAGE_DIRECTORIES = {
INSTALL_REQUIRES = ( INSTALL_REQUIRES = (
'six>=1.5.2', 'six>=1.5.2',
# TODO(atash): eventually split the grpcio package into a metapackage
# depending on protobuf and the runtime component (independent of protobuf)
'protobuf>=3.5.0.post1',
) )
if not PY3: if not PY3:

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild

@ -0,0 +1,37 @@
gRPC on Android
==============
Note: Building the protobuf dependency for Android requires
https://github.com/google/protobuf/pull/3878. This fix will be in the next
protobuf release, but until then must be manually patched in to
`third_party/protobuf` to build gRPC for Android.
PREREQUISITES
-------------
- Android SDK
- Android NDK
- `protoc` and `grpc_cpp_plugin` binaries on the host system
INSTALL
-------
The example application can be built via Android Studio or on the command line
using `gradle`:
```sh
$ ./gradlew installDebug
```
INSTRUMENTATION TESTS
---------------------
The instrumentation tests can be run via the following `gradle` command. This
requires an emulator already running on your computer.
```
$ ./gradlew connectedAndroidTest \
-Pandroid.testInstrumentationRunnerArguments.server_host=grpc-test.sandbox.googleapis.com \
-Pandroid.testInstrumentationRunnerArguments.server_port=443 \
-Pandroid.testInstrumentationRunnerArguments.use_tls=true
```

@ -0,0 +1,119 @@
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PROTOBUF_PROTOC_EXECUTABLE "/usr/local/bin/protoc" CACHE STRING "Protoc binary on host")
set(gRPC_CPP_PLUGIN_EXECUTABLE "/usr/local/bin/grpc_cpp_plugin" CACHE STRING "gRPC CPP plugin binary on host")
set(GRPC_SRC_DIR ../../../../../)
set(GRPC_BUILD_DIR ../grpc/outputs/${ANDROID_ABI})
file(MAKE_DIRECTORY ${GRPC_BUILD_DIR})
add_subdirectory(${GRPC_SRC_DIR} ${GRPC_BUILD_DIR})
#include_directories(${GRPC_SRC_DIR}/include)
include_directories(${GRPC_SRC_DIR})
set(GRPC_PROTO_GENS_DIR ${CMAKE_BINARY_DIR}/gens)
file(MAKE_DIRECTORY ${GRPC_PROTO_GENS_DIR})
include_directories(${GRPC_PROTO_GENS_DIR})
function(android_protobuf_grpc_generate_cpp SRC_FILES HDR_FILES INCLUDE_ROOT)
if(NOT ARGN)
message(SEND_ERROR "Error: android_protobuf_grpc_generate_cpp() called without any proto files")
return()
endif()
set(${SRC_FILES})
set(${HDR_FILES})
set(PROTOBUF_INCLUDE_PATH -I ${INCLUDE_ROOT})
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_ROOT} ${ABS_FIL})
get_filename_component(REL_DIR ${REL_FIL} DIRECTORY)
set(RELFIL_WE "${REL_DIR}/${FIL_WE}")
list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc")
list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h")
list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc")
list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h")
add_custom_command(
OUTPUT "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc"
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h"
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc"
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --grpc_out=${GRPC_PROTO_GENS_DIR}
--cpp_out=${GRPC_PROTO_GENS_DIR}
--plugin=protoc-gen-grpc=${gRPC_CPP_PLUGIN_EXECUTABLE}
${PROTOBUF_INCLUDE_PATH}
${REL_FIL}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${PROTOBUF_PROTOC_EXECUTABLE} ${gRPC_CPP_PLUGIN_EXECUTABLE} ${ABS_FIL} )
endforeach()
set_source_files_properties(${${SRC_FILES}} ${${HDR_FILES}} PROPERTIES GENERATED TRUE)
set(${SRC_FILES} ${${SRC_FILES}} PARENT_SCOPE)
set(${HDR_FILES} ${${HDR_FILES}} PARENT_SCOPE)
endfunction()
set(PROTO_BASE_DIR ${GRPC_SRC_DIR}/examples/protos)
android_protobuf_grpc_generate_cpp(
MESSAGES_PROTO_SRCS MESSAGES_PROTO_HDRS
${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/messages.proto)
add_library(messages_proto_lib
SHARED ${MESSAGES_PROTO_SRCS} ${MESSAGES_PROTO_HDRS})
target_link_libraries(messages_proto_lib
libprotobuf
grpc++
android
log)
android_protobuf_grpc_generate_cpp(
EMPTY_PROTO_SRCS EMPTY_PROTO_HDRS
${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/empty.proto)
add_library(empty_proto_lib
SHARED ${EMPTY_PROTO_SRCS} ${EMPTY_PROTO_HDRS})
target_link_libraries(empty_proto_lib
libprotobuf
grpc++
android
log)
android_protobuf_grpc_generate_cpp(
TEST_PROTO_SRCS TEST_PROTO_HDRS ${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/test.proto)
add_library(test_proto_lib
SHARED ${TEST_PROTO_SRCS} ${TEST_PROTO_HDRS})
target_link_libraries(test_proto_lib
libprotobuf
grpc++
empty_proto_lib
messages_proto_lib
android
log)
find_library(log-lib
log)
add_library(grpc-interop
SHARED
src/main/cpp/grpc-interop.cc
${GRPC_SRC_DIR}/test/cpp/interop/interop_client.h
${GRPC_SRC_DIR}/test/cpp/interop/interop_client.cc)
target_link_libraries(grpc-interop
messages_proto_lib
empty_proto_lib
test_proto_lib
android
${log-lib})

@ -0,0 +1,56 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "io.grpc.android.interop.cpp"
minSdkVersion 14
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
// The paths to the protoc and grpc_cpp_plugin binaries on the host system (codegen
// is not cross-compiled to Android)
def protoc = project.hasProperty('protoc') ?
project.property('protoc') : '/usr/local/bin/protoc'
def grpc_cpp_plugin = project.hasProperty('grpc_cpp_plugin') ?
project.property('grpc_cpp_plugin') : '/usr/local/bin/grpc_cpp_plugin'
cppFlags "-std=c++14 -frtti -fexceptions"
arguments '-DANDROID_STL=c++_shared'
arguments '-DRUN_HAVE_POSIX_REGEX=0'
arguments '-DRUN_HAVE_STD_REGEX=0'
arguments '-DRUN_HAVE_STEADY_CLOCK=0'
arguments '-Dprotobuf_BUILD_PROTOC_BINARIES=off'
arguments '-DgRPC_BUILD_CODEGEN=off'
arguments '-DPROTOBUF_PROTOC_EXECUTABLE=' + protoc
arguments '-DgRPC_CPP_PLUGIN_EXECUTABLE=' + grpc_cpp_plugin
}
}
ndk.abiFilters 'x86'
}
buildTypes {
debug {
minifyEnabled false
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,93 @@
/*
* Copyright 2018, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.interop.cpp;
import static junit.framework.Assert.assertTrue;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class InteropTest {
private String host;
private int port;
private boolean useTls;
@Before
public void setUp() throws Exception {
host =
InstrumentationRegistry.getArguments()
.getString("server_host", "grpc-test.sandbox.googleapis.com");
port = Integer.parseInt(InstrumentationRegistry.getArguments().getString("server_port", "443"));
useTls =
Boolean.parseBoolean(InstrumentationRegistry.getArguments().getString("use_tls", "true"));
if (useTls) {
Context ctx = InstrumentationRegistry.getTargetContext();
String sslRootsFile = "roots.pem";
InputStream in = ctx.getAssets().open(sslRootsFile);
File outFile = new File(ctx.getExternalFilesDir(null), sslRootsFile);
OutputStream out = new FileOutputStream(outFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
in.close();
out.close();
InteropActivity.configureSslRoots(outFile.getCanonicalPath());
}
}
@Test
public void emptyUnary() {
assertTrue(InteropActivity.doEmpty(host, port, useTls));
}
@Test
public void largeUnary() {
assertTrue(InteropActivity.doLargeUnary(host, port, useTls));
}
@Test
public void emptyStream() {
assertTrue(InteropActivity.doEmptyStream(host, port, useTls));
}
@Test
public void requestStreaming() {
assertTrue(InteropActivity.doRequestStreaming(host, port, useTls));
}
@Test
public void responseStreaming() {
assertTrue(InteropActivity.doResponseStreaming(host, port, useTls));
}
@Test
public void pingPong() {
assertTrue(InteropActivity.doPingPong(host, port, useTls));
}
}

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.grpc.interop.cpp" >
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Base.V7.Theme.AppCompat.Light" >
<activity
android:name=".InteropActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,124 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpcpp/grpcpp.h>
#include <jni.h>
#include <src/core/lib/gpr/env.h>
#include "test/cpp/interop/interop_client.h"
extern "C" JNIEXPORT void JNICALL
Java_io_grpc_interop_cpp_InteropActivity_configureSslRoots(JNIEnv* env,
jobject obj_this,
jstring path_raw) {
const char* path = env->GetStringUTFChars(path_raw, (jboolean*)0);
gpr_setenv("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH", path);
}
std::shared_ptr<grpc::testing::InteropClient> GetClient(const char* host,
int port,
bool use_tls) {
const int host_port_buf_size = 1024;
char host_port[host_port_buf_size];
snprintf(host_port, host_port_buf_size, "%s:%d", host, port);
std::shared_ptr<grpc::ChannelCredentials> credentials;
if (use_tls) {
credentials = grpc::SslCredentials(grpc::SslCredentialsOptions());
} else {
credentials = grpc::InsecureChannelCredentials();
}
return std::shared_ptr<grpc::testing::InteropClient>(
new grpc::testing::InteropClient(
grpc::CreateChannel(host_port, credentials), true, false));
}
extern "C" JNIEXPORT jboolean JNICALL
Java_io_grpc_interop_cpp_InteropActivity_doEmpty(JNIEnv* env, jobject obj_this,
jstring host_raw,
jint port_raw,
jboolean use_tls_raw) {
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0);
int port = static_cast<int>(port_raw);
bool use_tls = static_cast<bool>(use_tls_raw);
return GetClient(host, port, use_tls)->DoEmpty();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_io_grpc_interop_cpp_InteropActivity_doLargeUnary(JNIEnv* env,
jobject obj_this,
jstring host_raw,
jint port_raw,
jboolean use_tls_raw) {
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0);
int port = static_cast<int>(port_raw);
bool use_tls = static_cast<bool>(use_tls_raw);
return GetClient(host, port, use_tls)->DoLargeUnary();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_io_grpc_interop_cpp_InteropActivity_doEmptyStream(JNIEnv* env,
jobject obj_this,
jstring host_raw,
jint port_raw,
jboolean use_tls_raw) {
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0);
int port = static_cast<int>(port_raw);
bool use_tls = static_cast<bool>(use_tls_raw);
return GetClient(host, port, use_tls)->DoEmptyStream();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_io_grpc_interop_cpp_InteropActivity_doRequestStreaming(
JNIEnv* env, jobject obj_this, jstring host_raw, jint port_raw,
jboolean use_tls_raw) {
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0);
int port = static_cast<int>(port_raw);
bool use_tls = static_cast<bool>(use_tls_raw);
return GetClient(host, port, use_tls)->DoRequestStreaming();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_io_grpc_interop_cpp_InteropActivity_doResponseStreaming(
JNIEnv* env, jobject obj_this, jstring host_raw, jint port_raw,
jboolean use_tls_raw) {
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0);
int port = static_cast<int>(port_raw);
bool use_tls = static_cast<bool>(use_tls_raw);
return GetClient(host, port, use_tls)->DoResponseStreaming();
}
extern "C" JNIEXPORT jboolean JNICALL
Java_io_grpc_interop_cpp_InteropActivity_doPingPong(JNIEnv* env,
jobject obj_this,
jstring host_raw,
jint port_raw,
jboolean use_tls_raw) {
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0);
int port = static_cast<int>(port_raw);
bool use_tls = static_cast<bool>(use_tls_raw);
return GetClient(host, port, use_tls)->DoPingPong();
}

@ -0,0 +1,122 @@
/*
* Copyright 2018, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.interop.cpp;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.lang.ref.WeakReference;
public class InteropActivity extends AppCompatActivity {
static {
System.loadLibrary("grpc-interop");
}
private Button sendButton;
private EditText hostEdit;
private EditText portEdit;
private TextView resultText;
private GrpcTask grpcTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_interop);
sendButton = (Button) findViewById(R.id.ping_pong_button);
hostEdit = (EditText) findViewById(R.id.host_edit_text);
portEdit = (EditText) findViewById(R.id.port_edit_text);
resultText = (TextView) findViewById(R.id.grpc_result_text);
resultText.setMovementMethod(new ScrollingMovementMethod());
}
@Override
protected void onPause() {
super.onPause();
if (grpcTask != null) {
grpcTask.cancel(true);
grpcTask = null;
}
}
public void doPingPong(View view) {
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(hostEdit.getWindowToken(), 0);
sendButton.setEnabled(false);
resultText.setText("");
grpcTask = new GrpcTask(this);
grpcTask.executeOnExecutor(
AsyncTask.THREAD_POOL_EXECUTOR,
hostEdit.getText().toString(),
portEdit.getText().toString());
}
private static class GrpcTask extends AsyncTask<String, Void, String> {
private final WeakReference<InteropActivity> activityReference;
private GrpcTask(InteropActivity activity) {
this.activityReference = new WeakReference<InteropActivity>(activity);
}
@Override
protected String doInBackground(String... params) {
String host = params[0];
String portStr = params[1];
int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr);
// TODO(ericgribkoff) Support other test cases in the app UI
if (doPingPong(host, port, false)) {
return "Success";
} else {
return "Failure";
}
}
@Override
protected void onPostExecute(String result) {
InteropActivity activity = activityReference.get();
if (activity == null || isCancelled()) {
return;
}
TextView resultText = (TextView) activity.findViewById(R.id.grpc_result_text);
Button sendButton = (Button) activity.findViewById(R.id.ping_pong_button);
resultText.setText(result);
sendButton.setEnabled(true);
}
}
public static native void configureSslRoots(String path);
public static native boolean doEmpty(String host, int port, boolean useTls);
public static native boolean doLargeUnary(String host, int port, boolean useTls);
public static native boolean doEmptyStream(String host, int port, boolean useTls);
public static native boolean doRequestStreaming(String host, int port, boolean useTls);
public static native boolean doResponseStreaming(String host, int port, boolean useTls);
public static native boolean doPingPong(String host, int port, boolean useTls);
}

@ -0,0 +1,48 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".InteropActivity"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/host_edit_text"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Enter Host" />
<EditText
android:id="@+id/port_edit_text"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:hint="Enter Port" />
</LinearLayout>
<Button
android:id="@+id/ping_pong_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doPingPong"
android:text="Ping Pong" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:textSize="16sp"
android:text="Result:" />
<TextView
android:id="@+id/grpc_result_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars = "vertical"
android:textSize="16sp" />
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

@ -0,0 +1,3 @@
<resources>
<string name="app_name">gRPC C++ Interop App</string>
</resources>

@ -0,0 +1,24 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

@ -0,0 +1,17 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

@ -0,0 +1,6 @@
#Thu Jan 25 11:45:30 PST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

@ -135,6 +135,7 @@ AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
if (path[0] == '/') ++path; if (path[0] == '/') ++path;
name_to_resolve_ = gpr_strdup(path); name_to_resolve_ = gpr_strdup(path);
// Get DNS server from URI authority. // Get DNS server from URI authority.
dns_server_ = nullptr;
if (0 != strcmp(args.uri->authority, "")) { if (0 != strcmp(args.uri->authority, "")) {
dns_server_ = gpr_strdup(args.uri->authority); dns_server_ = gpr_strdup(args.uri->authority);
} }

@ -1676,6 +1676,33 @@ static void send_ping_locked(grpc_chttp2_transport* t,
GRPC_ERROR_NONE); GRPC_ERROR_NONE);
} }
/*
* Specialized form of send_ping_locked for keepalive ping. If there is already
* a ping in progress, the keepalive ping would piggyback onto that ping,
* instead of waiting for that ping to complete and then starting a new ping.
*/
static void send_keepalive_ping_locked(grpc_chttp2_transport* t) {
if (t->closed_with_error != GRPC_ERROR_NONE) {
GRPC_CLOSURE_SCHED(&t->start_keepalive_ping_locked,
GRPC_ERROR_REF(t->closed_with_error));
GRPC_CLOSURE_SCHED(&t->finish_keepalive_ping_locked,
GRPC_ERROR_REF(t->closed_with_error));
return;
}
grpc_chttp2_ping_queue* pq = &t->ping_queue;
if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) {
/* There is a ping in flight. Add yourself to the inflight closure list. */
GRPC_CLOSURE_SCHED(&t->start_keepalive_ping_locked, GRPC_ERROR_NONE);
grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INFLIGHT],
&t->finish_keepalive_ping_locked, GRPC_ERROR_NONE);
return;
}
grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE],
&t->start_keepalive_ping_locked, GRPC_ERROR_NONE);
grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT],
&t->finish_keepalive_ping_locked, GRPC_ERROR_NONE);
}
static void retry_initiate_ping_locked(void* tp, grpc_error* error) { static void retry_initiate_ping_locked(void* tp, grpc_error* error) {
grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp); grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
t->ping_state.is_delayed_ping_timer_set = false; t->ping_state.is_delayed_ping_timer_set = false;
@ -2619,8 +2646,7 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
grpc_chttp2_stream_map_size(&t->stream_map) > 0) { grpc_chttp2_stream_map_size(&t->stream_map) > 0) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING; t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING;
GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end"); GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end");
send_ping_locked(t, &t->start_keepalive_ping_locked, send_keepalive_ping_locked(t);
&t->finish_keepalive_ping_locked);
grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING); grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING);
} else { } else {
GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");

@ -44,10 +44,16 @@ const char* gpr_log_severity_string(gpr_log_severity severity) {
GPR_UNREACHABLE_CODE(return "UNKNOWN"); GPR_UNREACHABLE_CODE(return "UNKNOWN");
} }
int gpr_should_log(gpr_log_severity severity) {
return static_cast<gpr_atm>(severity) >=
gpr_atm_no_barrier_load(&g_min_severity_to_print)
? 1
: 0;
}
void gpr_log_message(const char* file, int line, gpr_log_severity severity, void gpr_log_message(const char* file, int line, gpr_log_severity severity,
const char* message) { const char* message) {
if (static_cast<gpr_atm>(severity) < if (gpr_should_log(severity) == 0) {
gpr_atm_no_barrier_load(&g_min_severity_to_print)) {
return; return;
} }

@ -41,6 +41,10 @@ static android_LogPriority severity_to_log_priority(gpr_log_severity severity) {
void gpr_log(const char* file, int line, gpr_log_severity severity, void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) { const char* format, ...) {
/* Avoid message construction if gpr_log_message won't log */
if (gpr_should_log(severity) == 0) {
return;
}
char* message = NULL; char* message = NULL;
va_list args; va_list args;
va_start(args, format); va_start(args, format);

@ -44,6 +44,10 @@ static long gettid(void) { return syscall(__NR_gettid); }
void gpr_log(const char* file, int line, gpr_log_severity severity, void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) { const char* format, ...) {
/* Avoid message construction if gpr_log_message won't log */
if (gpr_should_log(severity) == 0) {
return;
}
char* message = nullptr; char* message = nullptr;
va_list args; va_list args;
va_start(args, format); va_start(args, format);

@ -34,6 +34,10 @@ static intptr_t gettid(void) { return (intptr_t)pthread_self(); }
void gpr_log(const char* file, int line, gpr_log_severity severity, void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) { const char* format, ...) {
/* Avoid message construction if gpr_log_message won't log */
if (gpr_should_log(severity) == 0) {
return;
}
char buf[64]; char buf[64];
char* allocated = nullptr; char* allocated = nullptr;
char* message = nullptr; char* message = nullptr;

@ -34,6 +34,11 @@
void gpr_log(const char* file, int line, gpr_log_severity severity, void gpr_log(const char* file, int line, gpr_log_severity severity,
const char* format, ...) { const char* format, ...) {
/* Avoid message construction if gpr_log_message won't log */
if (gpr_should_log(severity) == 0) {
return;
}
char* message = NULL; char* message = NULL;
va_list args; va_list args;
int ret; int ret;

@ -181,6 +181,30 @@ grpc_error* grpc_set_socket_reuse_port(int fd, int reuse) {
#endif #endif
} }
static gpr_once g_probe_so_reuesport_once = GPR_ONCE_INIT;
static int g_support_so_reuseport = false;
void probe_so_reuseport_once(void) {
#ifndef GPR_MANYLINUX1
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
/* This might be an ipv6-only environment in which case 'socket(AF_INET,..)'
call would fail. Try creating IPv6 socket in that case */
s = socket(AF_INET6, SOCK_STREAM, 0);
}
if (s >= 0) {
g_support_so_reuseport = GRPC_LOG_IF_ERROR(
"check for SO_REUSEPORT", grpc_set_socket_reuse_port(s, 1));
close(s);
}
#endif
}
bool grpc_is_socket_reuse_port_supported() {
gpr_once_init(&g_probe_so_reuesport_once, probe_so_reuseport_once);
return g_support_so_reuseport;
}
/* disable nagle */ /* disable nagle */
grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) { grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
int val = (low_latency != 0); int val = (low_latency != 0);

@ -44,6 +44,9 @@ grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec);
/* set a socket to reuse old addresses */ /* set a socket to reuse old addresses */
grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse); grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse);
/* return true if SO_REUSEPORT is supported */
bool grpc_is_socket_reuse_port_supported();
/* disable nagle */ /* disable nagle */
grpc_error* grpc_set_socket_low_latency(int fd, int low_latency); grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);

@ -55,39 +55,18 @@
#include "src/core/lib/iomgr/tcp_server_utils_posix.h" #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h" #include "src/core/lib/iomgr/unix_sockets_posix.h"
static gpr_once check_init = GPR_ONCE_INIT;
static bool has_so_reuseport = false;
static void init(void) {
#ifndef GPR_MANYLINUX1
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
/* This might be an ipv6-only environment in which case 'socket(AF_INET,..)'
call would fail. Try creating IPv6 socket in that case */
s = socket(AF_INET6, SOCK_STREAM, 0);
}
if (s >= 0) {
has_so_reuseport = GRPC_LOG_IF_ERROR("check for SO_REUSEPORT",
grpc_set_socket_reuse_port(s, 1));
close(s);
}
#endif
}
static grpc_error* tcp_server_create(grpc_closure* shutdown_complete, static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
const grpc_channel_args* args, const grpc_channel_args* args,
grpc_tcp_server** server) { grpc_tcp_server** server) {
gpr_once_init(&check_init, init);
grpc_tcp_server* s = grpc_tcp_server* s =
static_cast<grpc_tcp_server*>(gpr_zalloc(sizeof(grpc_tcp_server))); static_cast<grpc_tcp_server*>(gpr_zalloc(sizeof(grpc_tcp_server)));
s->so_reuseport = has_so_reuseport; s->so_reuseport = grpc_is_socket_reuse_port_supported();
s->expand_wildcard_addrs = false; s->expand_wildcard_addrs = false;
for (size_t i = 0; i < (args == nullptr ? 0 : args->num_args); i++) { for (size_t i = 0; i < (args == nullptr ? 0 : args->num_args); i++) {
if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) { if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_INTEGER) { if (args->args[i].type == GRPC_ARG_INTEGER) {
s->so_reuseport = s->so_reuseport = grpc_is_socket_reuse_port_supported() &&
has_so_reuseport && (args->args[i].value.integer != 0); (args->args[i].value.integer != 0);
} else { } else {
gpr_free(s); gpr_free(s);
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT

@ -191,6 +191,9 @@ struct grpc_udp_server {
size_t pollset_count; size_t pollset_count;
/* opaque object to pass to callbacks */ /* opaque object to pass to callbacks */
void* user_data; void* user_data;
/* latch has_so_reuseport during server creation */
bool so_reuseport;
}; };
static grpc_socket_factory* get_socket_factory(const grpc_channel_args* args) { static grpc_socket_factory* get_socket_factory(const grpc_channel_args* args) {
@ -214,6 +217,7 @@ grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args) {
s->active_ports = 0; s->active_ports = 0;
s->destroyed_ports = 0; s->destroyed_ports = 0;
s->shutdown = 0; s->shutdown = 0;
s->so_reuseport = grpc_is_socket_reuse_port_supported();
return s; return s;
} }
@ -353,7 +357,7 @@ static int bind_socket(grpc_socket_factory* socket_factory, int sockfd,
/* Prepare a recently-created socket for listening. */ /* Prepare a recently-created socket for listening. */
static int prepare_socket(grpc_socket_factory* socket_factory, int fd, static int prepare_socket(grpc_socket_factory* socket_factory, int fd,
const grpc_resolved_address* addr, int rcv_buf_size, const grpc_resolved_address* addr, int rcv_buf_size,
int snd_buf_size) { int snd_buf_size, bool so_reuseport) {
grpc_resolved_address sockname_temp; grpc_resolved_address sockname_temp;
grpc_sockaddr* addr_ptr = grpc_sockaddr* addr_ptr =
reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr)); reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr));
@ -381,21 +385,6 @@ static int prepare_socket(grpc_socket_factory* socket_factory, int fd,
} }
} }
if (bind_socket(socket_factory, fd, addr) < 0) {
char* addr_str;
grpc_sockaddr_to_string(&addr_str, addr, 0);
gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
gpr_free(addr_str);
goto error;
}
sockname_temp.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
&sockname_temp.len) < 0) {
goto error;
}
if (grpc_set_socket_sndbuf(fd, snd_buf_size) != GRPC_ERROR_NONE) { if (grpc_set_socket_sndbuf(fd, snd_buf_size) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes", gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes",
snd_buf_size); snd_buf_size);
@ -415,6 +404,30 @@ static int prepare_socket(grpc_socket_factory* socket_factory, int fd,
gpr_log(GPR_INFO, "Failed to set socket overflow support"); gpr_log(GPR_INFO, "Failed to set socket overflow support");
} }
} }
if (so_reuseport && !grpc_is_unix_socket(addr) &&
grpc_set_socket_reuse_port(fd, 1) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Failed to set SO_REUSEPORT for fd %d", fd);
goto error;
}
if (bind_socket(socket_factory, fd, addr) < 0) {
char* addr_str;
grpc_sockaddr_to_string(&addr_str, addr, 0);
gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
gpr_free(addr_str);
goto error;
}
sockname_temp.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
&sockname_temp.len) < 0) {
gpr_log(GPR_ERROR, "Unable to get the address socket %d is bound to: %s",
fd, strerror(errno));
goto error;
}
return grpc_sockaddr_get_port(&sockname_temp); return grpc_sockaddr_get_port(&sockname_temp);
error: error:
@ -541,8 +554,8 @@ static int add_socket_to_server(grpc_udp_server* s, int fd,
int rcv_buf_size, int snd_buf_size) { int rcv_buf_size, int snd_buf_size) {
gpr_log(GPR_DEBUG, "add socket %d to server", fd); gpr_log(GPR_DEBUG, "add socket %d to server", fd);
int port = int port = prepare_socket(s->socket_factory, fd, addr, rcv_buf_size,
prepare_socket(s->socket_factory, fd, addr, rcv_buf_size, snd_buf_size); snd_buf_size, s->so_reuseport);
if (port >= 0) { if (port >= 0) {
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
s->listeners.emplace_back(s, fd, addr); s->listeners.emplace_back(s, fd, addr);
@ -557,7 +570,18 @@ static int add_socket_to_server(grpc_udp_server* s, int fd,
int grpc_udp_server_add_port(grpc_udp_server* s, int grpc_udp_server_add_port(grpc_udp_server* s,
const grpc_resolved_address* addr, const grpc_resolved_address* addr,
int rcv_buf_size, int snd_buf_size, int rcv_buf_size, int snd_buf_size,
GrpcUdpHandlerFactory* handler_factory) { GrpcUdpHandlerFactory* handler_factory,
size_t num_listeners) {
if (num_listeners > 1 && !s->so_reuseport) {
gpr_log(GPR_ERROR,
"Try to have multiple listeners on same port, but SO_REUSEPORT is "
"not supported. Only create 1 listener.");
}
char* addr_str;
grpc_sockaddr_to_string(&addr_str, addr, 1);
gpr_log(GPR_DEBUG, "add address: %s to server", addr_str);
gpr_free(addr_str);
int allocated_port1 = -1; int allocated_port1 = -1;
int allocated_port2 = -1; int allocated_port2 = -1;
int fd; int fd;
@ -568,11 +592,12 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
grpc_resolved_address addr4_copy; grpc_resolved_address addr4_copy;
grpc_resolved_address* allocated_addr = nullptr; grpc_resolved_address* allocated_addr = nullptr;
grpc_resolved_address sockname_temp; grpc_resolved_address sockname_temp;
int port; int port = 0;
/* Check if this is a wildcard port, and if so, try to keep the port the same /* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */ as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) { if (grpc_sockaddr_get_port(addr) == 0) {
/* Loop through existing listeners to find the port in use. */
for (size_t i = 0; i < s->listeners.size(); ++i) { for (size_t i = 0; i < s->listeners.size(); ++i) {
sockname_temp.len = sockname_temp.len =
static_cast<socklen_t>(sizeof(struct sockaddr_storage)); static_cast<socklen_t>(sizeof(struct sockaddr_storage));
@ -581,6 +606,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
&sockname_temp.len)) { &sockname_temp.len)) {
port = grpc_sockaddr_get_port(&sockname_temp); port = grpc_sockaddr_get_port(&sockname_temp);
if (port > 0) { if (port > 0) {
/* Found such a port, update |addr| to reflects this port. */
allocated_addr = static_cast<grpc_resolved_address*>( allocated_addr = static_cast<grpc_resolved_address*>(
gpr_malloc(sizeof(grpc_resolved_address))); gpr_malloc(sizeof(grpc_resolved_address)));
memcpy(allocated_addr, addr, sizeof(grpc_resolved_address)); memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
@ -597,44 +623,73 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
} }
s->handler_factory = handler_factory; s->handler_factory = handler_factory;
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ for (size_t i = 0; i < num_listeners; ++i) {
if (grpc_sockaddr_is_wildcard(addr, &port)) { /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
grpc_sockaddr_make_wildcards(port, &wild4, &wild6); if (grpc_sockaddr_is_wildcard(addr, &port)) {
grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
/* Try listening on IPv6 first. */
addr = &wild6;
// TODO(rjshade): Test and propagate the returned grpc_error*:
GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
allocated_port1 =
add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
if (port == 0) {
/* This is the first time to bind to |addr|. If its port is still
* wildcard port, update |addr| with the ephermeral port returned by
* kernel. Thus |addr| can have a specific port in following
* iterations. */
grpc_sockaddr_set_port(addr, allocated_port1);
port = allocated_port1;
} else if (allocated_port1 >= 0) {
/* The following sucessfully created socket should have same port as
* the first one. */
GPR_ASSERT(port == allocated_port1);
}
/* A dualstack socket is created, no need to create corresponding IPV4
* socket. */
continue;
}
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
if (port == 0 && allocated_port1 > 0) {
/* |port| hasn't been assigned to an emphemeral port yet, |wild4| must
* have a wildcard port. Update it with the emphemeral port created
* during binding.*/
grpc_sockaddr_set_port(&wild4, allocated_port1);
port = allocated_port1;
}
/* |wild4| should have been updated with an emphemeral port by now. Use
* this IPV4 address to create a IPV4 socket. */
addr = &wild4;
}
/* Try listening on IPv6 first. */
addr = &wild6;
// TODO(rjshade): Test and propagate the returned grpc_error*: // TODO(rjshade): Test and propagate the returned grpc_error*:
GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory( GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd)); s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
allocated_port1 = if (fd < 0) {
add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size); gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
} }
if (dsmode == GRPC_DSMODE_IPV4 &&
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
if (port == 0 && allocated_port1 > 0) { addr = &addr4_copy;
grpc_sockaddr_set_port(&wild4, allocated_port1); }
allocated_port2 =
add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
if (port == 0) {
/* Update |addr| with the ephermeral port returned by kernel. So |addr|
* can have a specific port in following iterations. */
grpc_sockaddr_set_port(addr, allocated_port2);
port = allocated_port2;
} else if (allocated_port2 >= 0) {
GPR_ASSERT(port == allocated_port2);
} }
addr = &wild4;
}
// TODO(rjshade): Test and propagate the returned grpc_error*:
GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
}
if (dsmode == GRPC_DSMODE_IPV4 &&
grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
addr = &addr4_copy;
} }
allocated_port2 =
add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
done:
gpr_free(allocated_addr); gpr_free(allocated_addr);
return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; return port;
} }
int grpc_udp_server_get_fd(grpc_udp_server* s, unsigned port_index) { int grpc_udp_server_get_fd(grpc_udp_server* s, unsigned port_index) {

@ -86,17 +86,21 @@ int grpc_udp_server_get_fd(grpc_udp_server* s, unsigned port_index);
/* Add a port to the server, returning port number on success, or negative /* Add a port to the server, returning port number on success, or negative
on failure. on failure.
Create |num_listeners| sockets for given address to listen on using
SO_REUSEPORT if supported.
The :: and 0.0.0.0 wildcard addresses are treated identically, accepting The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
both IPv4 and IPv6 connections, but :: is the preferred style. This usually both IPv4 and IPv6 connections, but :: is the preferred style. This usually
creates one socket, but possibly two on systems which support IPv6, creates |num_listeners| sockets, but possibly 2 * |num_listeners| on systems
but not dualstack sockets. */ which support IPv6, but not dualstack sockets. */
/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle /* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle
all of the multiple socket port matching logic in one place */ all of the multiple socket port matching logic in one place */
int grpc_udp_server_add_port(grpc_udp_server* s, int grpc_udp_server_add_port(grpc_udp_server* s,
const grpc_resolved_address* addr, const grpc_resolved_address* addr,
int rcv_buf_size, int snd_buf_size, int rcv_buf_size, int snd_buf_size,
GrpcUdpHandlerFactory* handler_factory); GrpcUdpHandlerFactory* handler_factory,
size_t num_listeners);
void grpc_udp_server_destroy(grpc_udp_server* server, grpc_closure* on_done); void grpc_udp_server_destroy(grpc_udp_server* server, grpc_closure* on_done);

@ -40,26 +40,6 @@ typedef struct grpc_alts_server_credentials {
char* handshaker_service_url; char* handshaker_service_url;
} grpc_alts_server_credentials; } grpc_alts_server_credentials;
/**
* This method creates an ALTS channel credential object.
*
* - options: grpc ALTS credentials options instance for client.
*
* It returns the created ALTS channel credential object.
*/
grpc_channel_credentials* grpc_alts_credentials_create(
const grpc_alts_credentials_options* options);
/**
* This method creates an ALTS server credential object.
*
* - options: grpc ALTS credentials options instance for server.
*
* It returns the created ALTS server credential object.
*/
grpc_server_credentials* grpc_alts_server_credentials_create(
const grpc_alts_credentials_options* options);
/** /**
* This method creates an ALTS channel credential object with customized * This method creates an ALTS channel credential object with customized
* information provided by caller. * information provided by caller.

@ -44,20 +44,20 @@ static target_service_account* target_service_account_create(
return sa; return sa;
} }
bool grpc_alts_credentials_client_options_add_target_service_account( void grpc_alts_credentials_client_options_add_target_service_account(
grpc_alts_credentials_client_options* options, grpc_alts_credentials_options* options, const char* service_account) {
const char* service_account) {
if (options == nullptr || service_account == nullptr) { if (options == nullptr || service_account == nullptr) {
gpr_log( gpr_log(
GPR_ERROR, GPR_ERROR,
"Invalid nullptr arguments to " "Invalid nullptr arguments to "
"grpc_alts_credentials_client_options_add_target_service_account()"); "grpc_alts_credentials_client_options_add_target_service_account()");
return false; return;
} }
auto client_options =
reinterpret_cast<grpc_alts_credentials_client_options*>(options);
target_service_account* node = target_service_account_create(service_account); target_service_account* node = target_service_account_create(service_account);
node->next = options->target_account_list_head; node->next = client_options->target_account_list_head;
options->target_account_list_head = node; client_options->target_account_list_head = node;
return true;
} }
static void target_service_account_destroy( static void target_service_account_destroy(

@ -21,19 +21,10 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <stdbool.h> #include <grpc/grpc_security.h>
#include "src/core/tsi/alts/handshaker/transport_security_common_api.h" #include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
/**
* Main interface for ALTS credentials options. The options will contain
* information that will be passed from grpc to TSI layer such as RPC protocol
* versions. ALTS client (channel) and server credentials will have their own
* implementation of this interface. The APIs listed in this header are
* thread-compatible.
*/
typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
/* V-table for grpc_alts_credentials_options */ /* V-table for grpc_alts_credentials_options */
typedef struct grpc_alts_credentials_options_vtable { typedef struct grpc_alts_credentials_options_vtable {
grpc_alts_credentials_options* (*copy)( grpc_alts_credentials_options* (*copy)(
@ -80,33 +71,5 @@ typedef struct grpc_alts_credentials_server_options {
grpc_alts_credentials_options* grpc_alts_credentials_options_copy( grpc_alts_credentials_options* grpc_alts_credentials_options_copy(
const grpc_alts_credentials_options* options); const grpc_alts_credentials_options* options);
/**
* This method destroys a grpc_alts_credentials_options instance by
* de-allocating all of its occupied memory.
*
* - options: a grpc_alts_credentials_options instance that needs to be
* destroyed.
*/
void grpc_alts_credentials_options_destroy(
grpc_alts_credentials_options* options);
/* This method creates a grpc ALTS credentials client options instance. */
grpc_alts_credentials_options* grpc_alts_credentials_client_options_create();
/* This method creates a grpc ALTS credentials server options instance. */
grpc_alts_credentials_options* grpc_alts_credentials_server_options_create();
/**
* This method adds a target service account to grpc ALTS credentials client
* options instance.
*
* - options: grpc ALTS credentials client options instance.
* - service_account: service account of target endpoint.
*
* It returns true on success and false on failure.
*/
bool grpc_alts_credentials_client_options_add_target_service_account(
grpc_alts_credentials_client_options* options, const char* service_account);
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H \ #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H \
*/ */

@ -87,6 +87,27 @@ std::shared_ptr<ChannelCredentials> SslCredentials(
return WrapChannelCredentials(c_creds); return WrapChannelCredentials(c_creds);
} }
namespace experimental {
// Builds ALTS Credentials given ALTS specific options
std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options) {
GrpcLibraryCodegen init; // To call grpc_init().
grpc_alts_credentials_options* c_options =
grpc_alts_credentials_client_options_create();
for (auto service_account = options.target_service_accounts.begin();
service_account != options.target_service_accounts.end();
service_account++) {
grpc_alts_credentials_client_options_add_target_service_account(
c_options, service_account->c_str());
}
grpc_channel_credentials* c_creds = grpc_alts_credentials_create(c_options);
grpc_alts_credentials_options_destroy(c_options);
return WrapChannelCredentials(c_creds);
}
} // namespace experimental
// Builds credentials for use when running in GCE // Builds credentials for use when running in GCE
std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() { std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() {
GrpcLibraryCodegen init; // To call grpc_init(). GrpcLibraryCodegen init; // To call grpc_init().

@ -126,4 +126,18 @@ std::shared_ptr<ServerCredentials> SslServerCredentials(
new SecureServerCredentials(c_creds)); new SecureServerCredentials(c_creds));
} }
namespace experimental {
std::shared_ptr<ServerCredentials> AltsServerCredentials(
const AltsServerCredentialsOptions& options) {
grpc_alts_credentials_options* c_options =
grpc_alts_credentials_server_options_create();
grpc_server_credentials* c_creds =
grpc_alts_server_credentials_create(c_options);
grpc_alts_credentials_options_destroy(c_options);
return std::shared_ptr<ServerCredentials>(
new SecureServerCredentials(c_creds));
}
} // namespace experimental
} // namespace grpc } // namespace grpc

@ -39,12 +39,12 @@ typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) {
/** The default response size limit is 4MB. Set this to override that default. */ /** The default response size limit is 4MB. Set this to override that default. */
+ (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host; + (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host;
+ (void)closeOpenConnections DEPRECATED_MSG_ATTRIBUTE("The API for this feature is experimental, " + (void)closeOpenConnections DEPRECATED_MSG_ATTRIBUTE(
"and might be removed or modified at any " "The API for this feature is experimental, "
"time."); "and might be removed or modified at any "
"time.");
+ (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host;
forhost:(nonnull NSString *)host;
/** Enable keepalive and configure keepalive parameters. A user should call this function once to /** Enable keepalive and configure keepalive parameters. A user should call this function once to
* enable keepalive for a particular host. gRPC client sends a ping after every \a interval ms to * enable keepalive for a particular host. gRPC client sends a ping after every \a interval ms to

@ -38,8 +38,7 @@
[GRPCHost flushChannelCache]; [GRPCHost flushChannelCache];
} }
+ (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host {
forhost:(nonnull NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
switch (algorithm) { switch (algorithm) {
case GRPCCompressNone: case GRPCCompressNone:

@ -26,7 +26,7 @@
*/ */
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert + (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert
forHost:(nonnull NSString *)host forHost:(nonnull NSString *)host
error:(NSError * _Nullable * _Nullable)errorPtr; error:(NSError *_Nullable *_Nullable)errorPtr;
/** /**
* Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate * Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate
* Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be * Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be
@ -36,6 +36,6 @@
withPrivateKey:(nullable NSString *)pemPrivateKey withPrivateKey:(nullable NSString *)pemPrivateKey
withCertChain:(nullable NSString *)pemCertChain withCertChain:(nullable NSString *)pemCertChain
forHost:(nonnull NSString *)host forHost:(nonnull NSString *)host
error:(NSError * _Nullable * _Nullable)errorPtr; error:(NSError *_Nullable *_Nullable)errorPtr;
@end @end

@ -28,24 +28,23 @@
forHost:(nonnull NSString *)host forHost:(nonnull NSString *)host
error:(NSError **)errorPtr { error:(NSError **)errorPtr {
if (!host) { if (!host) {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException format:@"host must be provided."];
format:@"host must be provided."];
} }
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
return [hostConfig setTLSPEMRootCerts:pemRootCerts return [hostConfig setTLSPEMRootCerts:pemRootCerts
withPrivateKey:pemPrivateKey withPrivateKey:pemPrivateKey
withCertChain:pemCertChain withCertChain:pemCertChain
error:errorPtr]; error:errorPtr];
} }
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts + (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
forHost:(nonnull NSString *)host forHost:(nonnull NSString *)host
error:(NSError **)errorPtr { error:(NSError **)errorPtr {
return [GRPCCall setTLSPEMRootCerts:pemRootCerts return [GRPCCall setTLSPEMRootCerts:pemRootCerts
withPrivateKey:nil withPrivateKey:nil
withCertChain:nil withCertChain:nil
forHost:host forHost:host
error:errorPtr]; error:errorPtr];
} }
@end @end

@ -32,11 +32,11 @@
* all subsequent RPCs will use Cronet transport. The method is not thread * all subsequent RPCs will use Cronet transport. The method is not thread
* safe. * safe.
*/ */
+(void)useCronetWithEngine:(stream_engine *)engine; + (void)useCronetWithEngine:(stream_engine*)engine;
+(stream_engine *)cronetEngine; + (stream_engine*)cronetEngine;
+(BOOL)isUsingCronet; + (BOOL)isUsingCronet;
@end @end
#endif #endif

@ -16,14 +16,14 @@
* *
*/ */
#import "GRPCCall.h"
#import "GRPCCall+OAuth2.h" #import "GRPCCall+OAuth2.h"
#import "GRPCCall.h"
#import <Google/SignIn.h> #import <Google/SignIn.h>
/** /**
* Extend GIDSignIn class to comply GRPCAuthorizationProtocol * Extend GIDSignIn class to comply GRPCAuthorizationProtocol
*/ */
@interface GIDSignIn (GRPC) <GRPCAuthorizationProtocol> @interface GIDSignIn (GRPC)<GRPCAuthorizationProtocol>
- (void)getTokenWithHandler:(void (^)(NSString *token))hander; - (void)getTokenWithHandler:(void (^)(NSString *token))hander;
@end @end

@ -20,9 +20,9 @@
#import "GRPCCall+OAuth2.h" #import "GRPCCall+OAuth2.h"
static NSString * const kAuthorizationHeader = @"authorization"; static NSString *const kAuthorizationHeader = @"authorization";
static NSString * const kBearerPrefix = @"Bearer "; static NSString *const kBearerPrefix = @"Bearer ";
static NSString * const kChallengeHeader = @"www-authenticate"; static NSString *const kChallengeHeader = @"www-authenticate";
@implementation GRPCCall (OAuth2) @implementation GRPCCall (OAuth2)
@dynamic tokenProvider; @dynamic tokenProvider;

@ -29,11 +29,10 @@
[NSException raise:NSInvalidArgumentException format:@"host, path and name must be provided."]; [NSException raise:NSInvalidArgumentException format:@"host, path and name must be provided."];
} }
NSError *error = nil; NSError *error = nil;
NSString *certs = [NSString stringWithContentsOfFile:certsPath NSString *certs =
encoding:NSUTF8StringEncoding [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
error:&error];
if (error != nil) { if (error != nil) {
[NSException raise:[error localizedDescription] format:@"failed to load certs"]; [NSException raise:[error localizedDescription] format:@"failed to load certs"];
} }
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];

@ -147,7 +147,8 @@ typedef NS_ENUM(NSUInteger, GRPCCallSafety) {
GRPCCallSafetyDefault = 0, GRPCCallSafetyDefault = 0,
/** Signal that the call is idempotent. gRPC is free to use PUT verb. */ /** Signal that the call is idempotent. gRPC is free to use PUT verb. */
GRPCCallSafetyIdempotentRequest = 1, GRPCCallSafetyIdempotentRequest = 1,
/** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET verb. */ /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET
verb. */
GRPCCallSafetyCacheableRequest = 2, GRPCCallSafetyCacheableRequest = 2,
}; };
@ -167,7 +168,7 @@ extern id const kGRPCTrailersKey;
* The authority for the RPC. If nil, the default authority will be used. This property must be nil * The authority for the RPC. If nil, the default authority will be used. This property must be nil
* when Cronet transport is enabled. * when Cronet transport is enabled.
*/ */
@property (atomic, copy, readwrite) NSString *serverName; @property(atomic, copy, readwrite) NSString *serverName;
/** /**
* The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to
@ -265,7 +266,7 @@ extern id const kGRPCTrailersKey;
/** This protocol is kept for backwards compatibility with existing code. */ /** This protocol is kept for backwards compatibility with existing code. */
DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.")
@protocol GRPCRequestHeaders <NSObject> @protocol GRPCRequestHeaders<NSObject>
@property(nonatomic, readonly) NSUInteger count; @property(nonatomic, readonly) NSUInteger count;
- (id)objectForKeyedSubscript:(id)key; - (id)objectForKeyedSubscript:(id)key;
@ -278,6 +279,6 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.")
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated" #pragma clang diagnostic ignored "-Wdeprecated"
/** This is only needed for backwards-compatibility. */ /** This is only needed for backwards-compatibility. */
@interface NSMutableDictionary (GRPCRequestHeaders) <GRPCRequestHeaders> @interface NSMutableDictionary (GRPCRequestHeaders)<GRPCRequestHeaders>
@end @end
#pragma clang diagnostic pop #pragma clang diagnostic pop

@ -20,10 +20,10 @@
#import "GRPCCall+OAuth2.h" #import "GRPCCall+OAuth2.h"
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#import <RxLibrary/GRXConcurrentWriteable.h> #import <RxLibrary/GRXConcurrentWriteable.h>
#import <RxLibrary/GRXImmediateSingleWriter.h> #import <RxLibrary/GRXImmediateSingleWriter.h>
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#import "private/GRPCConnectivityMonitor.h" #import "private/GRPCConnectivityMonitor.h"
#import "private/GRPCHost.h" #import "private/GRPCHost.h"
@ -38,14 +38,14 @@
// and RECV_STATUS_ON_CLIENT. // and RECV_STATUS_ON_CLIENT.
NSInteger kMaxClientBatch = 6; NSInteger kMaxClientBatch = 6;
NSString * const kGRPCHeadersKey = @"io.grpc.HeadersKey"; NSString *const kGRPCHeadersKey = @"io.grpc.HeadersKey";
NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey"; NSString *const kGRPCTrailersKey = @"io.grpc.TrailersKey";
static NSMutableDictionary *callFlags; static NSMutableDictionary *callFlags;
static NSString * const kAuthorizationHeader = @"authorization"; static NSString *const kAuthorizationHeader = @"authorization";
static NSString * const kBearerPrefix = @"Bearer "; static NSString *const kBearerPrefix = @"Bearer ";
@interface GRPCCall () <GRXWriteable> @interface GRPCCall ()<GRXWriteable>
// Make them read-write. // Make them read-write.
@property(atomic, strong) NSDictionary *responseHeaders; @property(atomic, strong) NSDictionary *responseHeaders;
@property(atomic, strong) NSDictionary *responseTrailers; @property(atomic, strong) NSDictionary *responseTrailers;
@ -219,9 +219,11 @@ static NSString * const kBearerPrefix = @"Bearer ";
} }
- (void)cancel { - (void)cancel {
[self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain [self
code:GRPCErrorCodeCancelled maybeFinishWithError:[NSError
userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]]; errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]];
if (!self.isWaitingForToken) { if (!self.isWaitingForToken) {
[self cancelCall]; [self cancelCall];
@ -254,9 +256,9 @@ static NSString * const kBearerPrefix = @"Bearer ";
// Only called from the call queue. // Only called from the call queue.
// The handler will be called from the network queue. // The handler will be called from the network queue.
- (void)startReadWithHandler:(void(^)(grpc_byte_buffer *))handler { - (void)startReadWithHandler:(void (^)(grpc_byte_buffer *))handler {
// TODO(jcanizales): Add error handlers for async failures // TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvMessage alloc] initWithHandler:handler]]]; [_wrappedCall startBatchWithOperations:@[ [[GRPCOpRecvMessage alloc] initWithHandler:handler] ]];
} }
// Called initially from the network queue once response headers are received, // Called initially from the network queue once response headers are received,
@ -287,15 +289,21 @@ static NSString * const kBearerPrefix = @"Bearer ";
// don't want to throw, because the app shouldn't crash for a behavior // don't want to throw, because the app shouldn't crash for a behavior
// that's on the hands of any server to have. Instead we finish and ask // that's on the hands of any server to have. Instead we finish and ask
// the server to cancel. // the server to cancel.
[strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain [strongSelf
code:GRPCErrorCodeResourceExhausted maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
userInfo:@{NSLocalizedDescriptionKey: @"Client does not have enough memory to hold the server response."}]]; code:GRPCErrorCodeResourceExhausted
userInfo:@{
NSLocalizedDescriptionKey :
@"Client does not have enough memory to "
@"hold the server response."
}]];
[strongSelf cancelCall]; [strongSelf cancelCall];
return; return;
} }
[strongWriteable enqueueValue:data completionHandler:^{ [strongWriteable enqueueValue:data
[strongSelf startNextRead]; completionHandler:^{
}]; [strongSelf startNextRead];
}];
}]; }];
}); });
} }
@ -304,11 +312,12 @@ static NSString * const kBearerPrefix = @"Bearer ";
- (void)sendHeaders:(NSDictionary *)headers { - (void)sendHeaders:(NSDictionary *)headers {
// TODO(jcanizales): Add error handlers for async failures // TODO(jcanizales): Add error handlers for async failures
GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc] initWithMetadata:headers GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc]
flags:[GRPCCall callFlagsForHost:_host path:_path] initWithMetadata:headers
handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA flags:[GRPCCall callFlagsForHost:_host path:_path]
handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA
if (!_unaryCall) { if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[op]]; [_wrappedCall startBatchWithOperations:@[ op ]];
} else { } else {
[_unaryOpBatch addObject:op]; [_unaryOpBatch addObject:op];
} }
@ -321,9 +330,8 @@ static NSString * const kBearerPrefix = @"Bearer ";
// If the call is a unary call, parameter \a errorHandler will be ignored and // If the call is a unary call, parameter \a errorHandler will be ignored and
// the error handler of GRPCOpSendClose will be executed in case of error. // the error handler of GRPCOpSendClose will be executed in case of error.
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler { - (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler {
__weak GRPCCall *weakSelf = self; __weak GRPCCall *weakSelf = self;
void(^resumingHandler)(void) = ^{ void (^resumingHandler)(void) = ^{
// Resume the request writer. // Resume the request writer.
GRPCCall *strongSelf = weakSelf; GRPCCall *strongSelf = weakSelf;
if (strongSelf) { if (strongSelf) {
@ -333,11 +341,10 @@ static NSString * const kBearerPrefix = @"Bearer ";
} }
}; };
GRPCOpSendMessage *op = [[GRPCOpSendMessage alloc] initWithMessage:message GRPCOpSendMessage *op =
handler:resumingHandler]; [[GRPCOpSendMessage alloc] initWithMessage:message handler:resumingHandler];
if (!_unaryCall) { if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[op] [_wrappedCall startBatchWithOperations:@[ op ] errorHandler:errorHandler];
errorHandler:errorHandler];
} else { } else {
// Ignored errorHandler since it is the same as the one for GRPCOpSendClose. // Ignored errorHandler since it is the same as the one for GRPCOpSendClose.
// TODO (mxyan): unify the error handlers of all Ops into a single closure. // TODO (mxyan): unify the error handlers of all Ops into a single closure.
@ -364,12 +371,11 @@ static NSString * const kBearerPrefix = @"Bearer ";
// network queue if the requests stream couldn't be closed successfully. // network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler { - (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler {
if (!_unaryCall) { if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[[[GRPCOpSendClose alloc] init]] [_wrappedCall startBatchWithOperations:@[ [[GRPCOpSendClose alloc] init] ]
errorHandler:errorHandler]; errorHandler:errorHandler];
} else { } else {
[_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]]; [_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]];
[_wrappedCall startBatchWithOperations:_unaryOpBatch [_wrappedCall startBatchWithOperations:_unaryOpBatch errorHandler:errorHandler];
errorHandler:errorHandler];
} }
} }
@ -390,13 +396,13 @@ static NSString * const kBearerPrefix = @"Bearer ";
// after this. // after this.
// The first one (headersHandler), when the response headers are received. // The first one (headersHandler), when the response headers are received.
// The second one (completionHandler), whenever the RPC finishes for any reason. // The second one (completionHandler), whenever the RPC finishes for any reason.
- (void)invokeCallWithHeadersHandler:(void(^)(NSDictionary *))headersHandler - (void)invokeCallWithHeadersHandler:(void (^)(NSDictionary *))headersHandler
completionHandler:(void(^)(NSError *, NSDictionary *))completionHandler { completionHandler:(void (^)(NSError *, NSDictionary *))completionHandler {
// TODO(jcanizales): Add error handlers for async failures // TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvMetadata alloc] [_wrappedCall
initWithHandler:headersHandler]]]; startBatchWithOperations:@[ [[GRPCOpRecvMetadata alloc] initWithHandler:headersHandler] ]];
[_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvStatus alloc] [_wrappedCall
initWithHandler:completionHandler]]]; startBatchWithOperations:@[ [[GRPCOpRecvStatus alloc] initWithHandler:completionHandler] ]];
} }
- (void)invokeCall { - (void)invokeCall {
@ -408,30 +414,31 @@ static NSString * const kBearerPrefix = @"Bearer ";
strongSelf.responseHeaders = headers; strongSelf.responseHeaders = headers;
[strongSelf startNextRead]; [strongSelf startNextRead];
} }
} completionHandler:^(NSError *error, NSDictionary *trailers) { }
__strong GRPCCall *strongSelf = weakSelf; completionHandler:^(NSError *error, NSDictionary *trailers) {
if (strongSelf) { __strong GRPCCall *strongSelf = weakSelf;
strongSelf.responseTrailers = trailers; if (strongSelf) {
strongSelf.responseTrailers = trailers;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; if (error) {
if (error.userInfo) { NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo addEntriesFromDictionary:error.userInfo]; if (error.userInfo) {
} [userInfo addEntriesFromDictionary:error.userInfo];
userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers; }
// TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
// called before this one, so an error might end up with trailers but no headers. We // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
// shouldn't call finishWithError until ater both blocks are called. It is also when this is // called before this one, so an error might end up with trailers but no headers. We
// done that we can provide a merged view of response headers and trailers in a thread-safe // shouldn't call finishWithError until ater both blocks are called. It is also when
// way. // this is done that we can provide a merged view of response headers and trailers in a
if (strongSelf.responseHeaders) { // thread-safe way.
userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders; if (strongSelf.responseHeaders) {
userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
}
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
[strongSelf maybeFinishWithError:error];
} }
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; }];
}
[strongSelf maybeFinishWithError:error];
}
}];
// Now that the RPC has been initiated, request writes can start. // Now that the RPC has been initiated, request writes can start.
@synchronized(_requestWriter) { @synchronized(_requestWriter) {
[_requestWriter startWithWriteable:self]; [_requestWriter startWithWriteable:self];
@ -441,8 +448,8 @@ static NSString * const kBearerPrefix = @"Bearer ";
#pragma mark GRXWriter implementation #pragma mark GRXWriter implementation
- (void)startCallWithWriteable:(id<GRXWriteable>)writeable { - (void)startCallWithWriteable:(id<GRXWriteable>)writeable {
_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable _responseWriteable =
dispatchQueue:_responseQueue]; [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host
serverName:_serverName serverName:_serverName
@ -453,8 +460,7 @@ static NSString * const kBearerPrefix = @"Bearer ";
[self sendHeaders:_requestHeaders]; [self sendHeaders:_requestHeaders];
[self invokeCall]; [self invokeCall];
[GRPCConnectivityMonitor registerObserver:self [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
selector:@selector(connectivityChanged:)];
} }
- (void)startWithWriteable:(id<GRXWriteable>)writeable { - (void)startWithWriteable:(id<GRXWriteable>)writeable {
@ -472,7 +478,7 @@ static NSString * const kBearerPrefix = @"Bearer ";
if (self.tokenProvider != nil) { if (self.tokenProvider != nil) {
self.isWaitingForToken = YES; self.isWaitingForToken = YES;
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
[self.tokenProvider getTokenWithHandler:^(NSString *token){ [self.tokenProvider getTokenWithHandler:^(NSString *token) {
typeof(self) strongSelf = weakSelf; typeof(self) strongSelf = weakSelf;
if (strongSelf && strongSelf.isWaitingForToken) { if (strongSelf && strongSelf.isWaitingForToken) {
if (token) { if (token) {
@ -521,7 +527,9 @@ static NSString * const kBearerPrefix = @"Bearer ";
- (void)connectivityChanged:(NSNotification *)note { - (void)connectivityChanged:(NSNotification *)note {
[self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable code:GRPCErrorCodeUnavailable
userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]]; userInfo:@{
NSLocalizedDescriptionKey : @"Connectivity lost."
}]];
// Cancel underlying call upon this notification // Cancel underlying call upon this notification
[self cancelCall]; [self cancelCall];
} }

@ -23,7 +23,6 @@
@class GRPCCompletionQueue; @class GRPCCompletionQueue;
struct grpc_channel_credentials; struct grpc_channel_credentials;
/** /**
* Each separate instance of this class represents at least one TCP connection to the provided host. * Each separate instance of this class represents at least one TCP connection to the provided host.
*/ */
@ -52,8 +51,9 @@ struct grpc_channel_credentials;
* @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. * @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.
*/ */
+ (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host + (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
credentials:(nonnull struct grpc_channel_credentials *)credentials credentials:
channelArgs:(nullable NSDictionary *)channelArgs; (nonnull struct grpc_channel_credentials *)credentials
channelArgs:(nullable NSDictionary *)channelArgs;
/** /**
* Creates an insecure channel to the specified @c host using the specified @c channelArgs. * Creates an insecure channel to the specified @c host using the specified @c channelArgs.

@ -32,7 +32,7 @@
#endif #endif
#import "GRPCCompletionQueue.h" #import "GRPCCompletionQueue.h"
static void* copy_pointer_arg(void *p) { static void *copy_pointer_arg(void *p) {
// Add ref count to the object when making copy // Add ref count to the object when making copy
id obj = (__bridge id)p; id obj = (__bridge id)p;
return (__bridge_retained void *)obj; return (__bridge_retained void *)obj;
@ -43,12 +43,10 @@ static void destroy_pointer_arg(void *p) {
CFRelease((CFTreeRef)p); CFRelease((CFTreeRef)p);
} }
static int cmp_pointer_arg(void *p, void *q) { static int cmp_pointer_arg(void *p, void *q) { return p == q; }
return p == q;
}
static const grpc_arg_pointer_vtable objc_arg_vtable = { static const grpc_arg_pointer_vtable objc_arg_vtable = {copy_pointer_arg, destroy_pointer_arg,
copy_pointer_arg, destroy_pointer_arg, cmp_pointer_arg}; cmp_pointer_arg};
static void FreeChannelArgs(grpc_channel_args *channel_args) { static void FreeChannelArgs(grpc_channel_args *channel_args) {
for (size_t i = 0; i < channel_args->num_args; ++i) { for (size_t i = 0; i < channel_args->num_args; ++i) {
@ -124,10 +122,8 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
if (self = [super init]) { if (self = [super init]) {
_channelArgs = BuildChannelArgs(channelArgs); _channelArgs = BuildChannelArgs(channelArgs);
_host = [host copy]; _host = [host copy];
_unmanagedChannel = grpc_cronet_secure_channel_create(cronetEngine, _unmanagedChannel =
_host.UTF8String, grpc_cronet_secure_channel_create(cronetEngine, _host.UTF8String, _channelArgs, NULL);
_channelArgs,
NULL);
} }
return self; return self;
@ -150,8 +146,8 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
_channelArgs = BuildChannelArgs(channelArgs); _channelArgs = BuildChannelArgs(channelArgs);
_host = [host copy]; _host = [host copy];
if (secure) { if (secure) {
_unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs, _unmanagedChannel =
NULL); grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs, NULL);
} else { } else {
_unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channelArgs, NULL); _unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channelArgs, NULL);
} }
@ -172,8 +168,7 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
channelArgs:(NSDictionary *)channelArgs { channelArgs:(NSDictionary *)channelArgs {
stream_engine *engine = [GRPCCall cronetEngine]; stream_engine *engine = [GRPCCall cronetEngine];
if (!engine) { if (!engine) {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException format:@"cronet_engine is NULL. Set it first."];
format:@"cronet_engine is NULL. Set it first."];
return nil; return nil;
} }
return [[GRPCChannel alloc] initWithHost:host cronetEngine:engine channelArgs:channelArgs]; return [[GRPCChannel alloc] initWithHost:host cronetEngine:engine channelArgs:channelArgs];
@ -191,15 +186,10 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
secure:YES secure:YES
credentials:credentials credentials:credentials
channelArgs:channelArgs]; channelArgs:channelArgs];
} }
+ (GRPCChannel *)insecureChannelWithHost:(NSString *)host + (GRPCChannel *)insecureChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)channelArgs {
channelArgs:(NSDictionary *)channelArgs { return [[GRPCChannel alloc] initWithHost:host secure:NO credentials:NULL channelArgs:channelArgs];
return [[GRPCChannel alloc] initWithHost:host
secure:NO
credentials:NULL
channelArgs:channelArgs];
} }
- (grpc_call *)unmanagedCallWithPath:(NSString *)path - (grpc_call *)unmanagedCallWithPath:(NSString *)path
@ -215,17 +205,13 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
host_slice = grpc_slice_from_copied_string(serverName.UTF8String); host_slice = grpc_slice_from_copied_string(serverName.UTF8String);
} }
grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String);
gpr_timespec deadline_ms = timeout == 0 ? gpr_timespec deadline_ms =
gpr_inf_future(GPR_CLOCK_REALTIME) : timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME)
gpr_time_add( : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN));
gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); grpc_call *call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS,
grpc_call *call = grpc_channel_create_call(_unmanagedChannel, queue.unmanagedQueue, path_slice,
NULL, GRPC_PROPAGATE_DEFAULTS, serverName ? &host_slice : NULL, deadline_ms, NULL);
queue.unmanagedQueue,
path_slice,
serverName ? &host_slice : NULL,
deadline_ms, NULL);
if (serverName) { if (serverName) {
grpc_slice_unref(host_slice); grpc_slice_unref(host_slice);
} }

@ -19,7 +19,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <grpc/grpc.h> #include <grpc/grpc.h>
typedef void(^GRPCQueueCompletionHandler)(bool success); typedef void (^GRPCQueueCompletionHandler)(bool success);
/** /**
* This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the * This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the

@ -53,9 +53,8 @@
dispatch_async(gDefaultConcurrentQueue, ^{ dispatch_async(gDefaultConcurrentQueue, ^{
while (YES) { while (YES) {
// The following call blocks until an event is available. // The following call blocks until an event is available.
grpc_event event = grpc_completion_queue_next(unmanagedQueue, grpc_event event =
gpr_inf_future(GPR_CLOCK_REALTIME), grpc_completion_queue_next(unmanagedQueue, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
NULL);
GRPCQueueCompletionHandler handler; GRPCQueueCompletionHandler handler;
switch (event.type) { switch (event.type) {
case GRPC_OP_COMPLETE: case GRPC_OP_COMPLETE:

@ -26,7 +26,7 @@ typedef NS_ENUM(NSInteger, GRPCConnectivityStatus) {
GRPCConnectivityWiFi = 3, GRPCConnectivityWiFi = 3,
}; };
extern NSString * _Nonnull kGRPCConnectivityNotification; extern NSString* _Nonnull kGRPCConnectivityNotification;
// This interface monitors OS reachability interface for any network status // This interface monitors OS reachability interface for any network status
// change. Parties interested in these events should register themselves as // change. Parties interested in these events should register themselves as
@ -39,8 +39,7 @@ extern NSString * _Nonnull kGRPCConnectivityNotification;
// must have a notification method with one parameter of type // must have a notification method with one parameter of type
// (NSNotification *) and should pass it to parameter \a selector. The // (NSNotification *) and should pass it to parameter \a selector. The
// parameter of this notification method is not used for now. // parameter of this notification method is not used for now.
+ (void)registerObserver:(_Nonnull id)observer + (void)registerObserver:(_Nonnull id)observer selector:(_Nonnull SEL)selector;
selector:(_Nonnull SEL)selector;
// Ungegister an object from observers of network status change. // Ungegister an object from observers of network status change.
+ (void)unregisterObserver:(_Nonnull id)observer; + (void)unregisterObserver:(_Nonnull id)observer;

@ -41,8 +41,8 @@ GRPCConnectivityStatus CalculateConnectivityStatus(SCNetworkReachabilityFlags fl
return result; return result;
} }
static void ReachabilityCallback( static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags,
SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { void *info) {
GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags); GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags);
if (newStatus != currentStatus) { if (newStatus != currentStatus) {
@ -69,15 +69,14 @@ static void ReachabilityCallback(
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) || if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) ||
!SCNetworkReachabilityScheduleWithRunLoop( !SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(),
reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)) { kCFRunLoopCommonModes)) {
NSLog(@"gRPC connectivity monitor fail to set"); NSLog(@"gRPC connectivity monitor fail to set");
} }
} }
} }
+ (void)registerObserver:(_Nonnull id)observer + (void)registerObserver:(_Nonnull id)observer selector:(SEL)selector {
selector:(SEL)selector {
[[NSNotificationCenter defaultCenter] addObserver:observer [[NSNotificationCenter defaultCenter] addObserver:observer
selector:selector selector:selector
name:kGRPCConnectivityNotification name:kGRPCConnectivityNotification

@ -47,7 +47,6 @@ struct grpc_channel_credentials;
/** The default response size limit is 4MB. Set this to override that default. */ /** The default response size limit is 4MB. Set this to override that default. */
@property(nonatomic, strong, nullable) NSNumber *responseSizeLimitOverride; @property(nonatomic, strong, nullable) NSNumber *responseSizeLimitOverride;
- (nullable instancetype)init NS_UNAVAILABLE; - (nullable instancetype)init NS_UNAVAILABLE;
/** Host objects initialized with the same address are the same. */ /** Host objects initialized with the same address are the same. */
+ (nullable instancetype)hostWithAddress:(NSString *)address; + (nullable instancetype)hostWithAddress:(NSString *)address;

@ -18,10 +18,10 @@
#import "GRPCHost.h" #import "GRPCHost.h"
#import <GRPCClient/GRPCCall+MobileLog.h>
#import <GRPCClient/GRPCCall.h>
#include <grpc/grpc.h> #include <grpc/grpc.h>
#include <grpc/grpc_security.h> #include <grpc/grpc_security.h>
#import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCCall+MobileLog.h>
#ifdef GRPC_COMPILE_WITH_CRONET #ifdef GRPC_COMPILE_WITH_CRONET
#import <GRPCClient/GRPCCall+ChannelArg.h> #import <GRPCClient/GRPCCall+ChannelArg.h>
#import <GRPCClient/GRPCCall+Cronet.h> #import <GRPCClient/GRPCCall+Cronet.h>
@ -91,16 +91,15 @@ static NSMutableDictionary *kHostCache;
+ (void)flushChannelCache { + (void)flushChannelCache {
@synchronized(kHostCache) { @synchronized(kHostCache) {
[kHostCache enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, [kHostCache enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, GRPCHost *_Nonnull host,
GRPCHost * _Nonnull host, BOOL *_Nonnull stop) {
BOOL * _Nonnull stop) {
[host disconnect]; [host disconnect];
}]; }];
} }
} }
+ (void)resetAllHostSettings { + (void)resetAllHostSettings {
@synchronized (kHostCache) { @synchronized(kHostCache) {
kHostCache = [NSMutableDictionary dictionary]; kHostCache = [NSMutableDictionary dictionary];
} }
} }
@ -131,38 +130,38 @@ static NSMutableDictionary *kHostCache;
static NSError *kDefaultRootsError; static NSError *kDefaultRootsError;
static dispatch_once_t loading; static dispatch_once_t loading;
dispatch_once(&loading, ^{ dispatch_once(&loading, ^{
NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
// Do not use NSBundle.mainBundle, as it's nil for tests of library projects. // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
NSBundle *bundle = [NSBundle bundleForClass:self.class]; NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"]; NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
NSError *error; NSError *error;
// Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
// issuer). Load them as UTF8 and produce an ASCII equivalent. // issuer). Load them as UTF8 and produce an ASCII equivalent.
NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path NSString *contentInUTF8 =
encoding:NSUTF8StringEncoding [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
error:&error];
if (contentInUTF8 == nil) { if (contentInUTF8 == nil) {
kDefaultRootsError = error; kDefaultRootsError = error;
return; return;
} }
kDefaultRootsASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding kDefaultRootsASCII =
allowLossyConversion:YES]; [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
}); });
NSData *rootsASCII; NSData *rootsASCII;
if (pemRootCerts != nil) { if (pemRootCerts != nil) {
rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
allowLossyConversion:YES];
} else { } else {
if (kDefaultRootsASCII == nil) { if (kDefaultRootsASCII == nil) {
if (errorPtr) { if (errorPtr) {
*errorPtr = kDefaultRootsError; *errorPtr = kDefaultRootsError;
} }
NSAssert(kDefaultRootsASCII, @"Could not read gRPCCertificates.bundle/roots.pem. This file, " NSAssert(
"with the root certificates, is needed to establish secure (TLS) connections. " kDefaultRootsASCII,
"Because the file is distributed with the gRPC library, this error is usually a sign " @"Could not read gRPCCertificates.bundle/roots.pem. This file, "
"that the library wasn't configured correctly for your project. Error: %@", "with the root certificates, is needed to establish secure (TLS) connections. "
kDefaultRootsError); "Because the file is distributed with the gRPC library, this error is usually a sign "
"that the library wasn't configured correctly for your project. Error: %@",
kDefaultRootsError);
return NO; return NO;
} }
rootsASCII = kDefaultRootsASCII; rootsASCII = kDefaultRootsASCII;
@ -173,10 +172,10 @@ static NSMutableDictionary *kHostCache;
creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL); creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
} else { } else {
grpc_ssl_pem_key_cert_pair key_cert_pair; grpc_ssl_pem_key_cert_pair key_cert_pair;
NSData *privateKeyASCII = [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding NSData *privateKeyASCII =
allowLossyConversion:YES]; [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSData *certChainASCII = [pemCertChain dataUsingEncoding:NSASCIIStringEncoding NSData *certChainASCII =
allowLossyConversion:YES]; [pemCertChain dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
key_cert_pair.private_key = privateKeyASCII.bytes; key_cert_pair.private_key = privateKeyASCII.bytes;
key_cert_pair.cert_chain = certChainASCII.bytes; key_cert_pair.cert_chain = certChainASCII.bytes;
creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL); creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);
@ -212,8 +211,7 @@ static NSMutableDictionary *kHostCache;
} }
if (_compressAlgorithm != GRPC_COMPRESS_NONE) { if (_compressAlgorithm != GRPC_COMPRESS_NONE) {
args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = [NSNumber numberWithInt:_compressAlgorithm];
[NSNumber numberWithInt:_compressAlgorithm];
} }
if (_keepaliveInterval != 0) { if (_keepaliveInterval != 0) {
@ -247,14 +245,12 @@ static NSMutableDictionary *kHostCache;
} }
#ifdef GRPC_COMPILE_WITH_CRONET #ifdef GRPC_COMPILE_WITH_CRONET
if (useCronet) { if (useCronet) {
channel = [GRPCChannel secureCronetChannelWithHost:_address channel = [GRPCChannel secureCronetChannelWithHost:_address channelArgs:args];
channelArgs:args];
} else } else
#endif #endif
{ {
channel = [GRPCChannel secureChannelWithHost:_address channel =
credentials:_channelCreds [GRPCChannel secureChannelWithHost:_address credentials:_channelCreds channelArgs:args];
channelArgs:args];
} }
} }
return channel; return channel;

@ -16,7 +16,6 @@
* *
*/ */
#ifdef GRPC_TEST_OBJC #ifdef GRPC_TEST_OBJC
/** /**

@ -25,7 +25,7 @@ static NSMutableArray *opBatchLog = nil;
@implementation GRPCOpBatchLog @implementation GRPCOpBatchLog
+ (void)enableOpBatchLog:(BOOL)enabled { + (void)enableOpBatchLog:(BOOL)enabled {
@synchronized (opBatchLog) { @synchronized(opBatchLog) {
if (enabled) { if (enabled) {
if (!opBatchLog) { if (!opBatchLog) {
opBatchLog = [NSMutableArray array]; opBatchLog = [NSMutableArray array];
@ -39,13 +39,13 @@ static NSMutableArray *opBatchLog = nil;
} }
+ (void)addOpBatchToLog:(NSArray *)batch { + (void)addOpBatchToLog:(NSArray *)batch {
@synchronized (opBatchLog) { @synchronized(opBatchLog) {
[opBatchLog addObject:batch]; [opBatchLog addObject:batch];
} }
} }
+ (NSArray *)obtainAndCleanOpBatchLog { + (NSArray *)obtainAndCleanOpBatchLog {
@synchronized (opBatchLog) { @synchronized(opBatchLog) {
NSArray *out = opBatchLog; NSArray *out = opBatchLog;
opBatchLog = [NSMutableArray array]; opBatchLog = [NSMutableArray array];
return out; return out;

@ -17,7 +17,8 @@
*/ */
/** /**
* "X-macro" file that lists the flags names of Apple's Network Reachability API, along with a nice * "X-macro" file that lists the flags names of Apple's Network Reachability
API, along with a nice
* Objective-C method name used to query each of them. * Objective-C method name used to query each of them.
* *
* Example usage: To generate a dictionary from flag value to name, one can do: * Example usage: To generate a dictionary from flag value to name, one can do:
@ -29,7 +30,8 @@
#undef GRPC_XMACRO_ITEM #undef GRPC_XMACRO_ITEM
}; };
XCTAssertEqualObjects(flagNames[@(kSCNetworkReachabilityFlagsIsWWAN)], @"isCell"); XCTAssertEqualObjects(flagNames[@(kSCNetworkReachabilityFlagsIsWWAN)],
@"isCell");
*/ */

@ -23,7 +23,7 @@
#import "NSDictionary+GRPC.h" #import "NSDictionary+GRPC.h"
// Used by the setter. // Used by the setter.
static void CheckIsNonNilASCII(NSString *name, NSString* value) { static void CheckIsNonNilASCII(NSString *name, NSString *value) {
if (!value) { if (!value) {
[NSException raise:NSInvalidArgumentException format:@"%@ cannot be nil", name]; [NSException raise:NSInvalidArgumentException format:@"%@ cannot be nil", name];
} }
@ -38,14 +38,18 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
if ([key hasSuffix:@"-bin"]) { if ([key hasSuffix:@"-bin"]) {
if (![value isKindOfClass:NSData.class]) { if (![value isKindOfClass:NSData.class]) {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException
format:@"Expected NSData value for header %@ ending in \"-bin\", " format:
@"instead got %@", key, value]; @"Expected NSData value for header %@ ending in \"-bin\", "
@"instead got %@",
key, value];
} }
} else { } else {
if (![value isKindOfClass:NSString.class]) { if (![value isKindOfClass:NSString.class]) {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException
format:@"Expected NSString value for header %@ not ending in \"-bin\", " format:
@"instead got %@", key, value]; @"Expected NSString value for header %@ not ending in \"-bin\", "
@"instead got %@",
key, value];
} }
CheckIsNonNilASCII(@"Text header value", (NSString *)value); CheckIsNonNilASCII(@"Text header value", (NSString *)value);
} }
@ -85,8 +89,8 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
return self; return self;
} }
- (instancetype)initWithObjects:(const id _Nonnull __unsafe_unretained *)objects - (instancetype)initWithObjects:(const id _Nonnull __unsafe_unretained *)objects
forKeys:(const id<NSCopying> _Nonnull __unsafe_unretained *)keys forKeys:(const id<NSCopying> _Nonnull __unsafe_unretained *)keys
count:(NSUInteger)cnt { count:(NSUInteger)cnt {
return [self init]; return [self init];
} }
@ -118,7 +122,7 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
return _delegate.count; return _delegate.count;
} }
- (NSEnumerator * _Nonnull)keyEnumerator { - (NSEnumerator *_Nonnull)keyEnumerator {
return [_delegate keyEnumerator]; return [_delegate keyEnumerator];
} }

@ -29,43 +29,42 @@
@interface GRPCOpSendMetadata : GRPCOperation @interface GRPCOpSendMetadata : GRPCOperation
- (instancetype)initWithMetadata:(NSDictionary *)metadata - (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)(void))handler;
handler:(void(^)(void))handler;
- (instancetype)initWithMetadata:(NSDictionary *)metadata - (instancetype)initWithMetadata:(NSDictionary *)metadata
flags:(uint32_t)flags flags:(uint32_t)flags
handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER; handler:(void (^)(void))handler NS_DESIGNATED_INITIALIZER;
@end @end
@interface GRPCOpSendMessage : GRPCOperation @interface GRPCOpSendMessage : GRPCOperation
- (instancetype)initWithMessage:(NSData *)message - (instancetype)initWithMessage:(NSData *)message
handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER; handler:(void (^)(void))handler NS_DESIGNATED_INITIALIZER;
@end @end
@interface GRPCOpSendClose : GRPCOperation @interface GRPCOpSendClose : GRPCOperation
- (instancetype)initWithHandler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHandler:(void (^)(void))handler NS_DESIGNATED_INITIALIZER;
@end @end
@interface GRPCOpRecvMetadata : GRPCOperation @interface GRPCOpRecvMetadata : GRPCOperation
- (instancetype)initWithHandler:(void(^)(NSDictionary *))handler NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHandler:(void (^)(NSDictionary *))handler NS_DESIGNATED_INITIALIZER;
@end @end
@interface GRPCOpRecvMessage : GRPCOperation @interface GRPCOpRecvMessage : GRPCOperation
- (instancetype)initWithHandler:(void(^)(grpc_byte_buffer *))handler NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHandler:(void (^)(grpc_byte_buffer *))handler NS_DESIGNATED_INITIALIZER;
@end @end
@interface GRPCOpRecvStatus : GRPCOperation @interface GRPCOpRecvStatus : GRPCOperation
- (instancetype)initWithHandler:(void(^)(NSError *, NSDictionary *))handler - (instancetype)initWithHandler:(void (^)(NSError *, NSDictionary *))handler
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
@end @end
@ -79,7 +78,7 @@
path:(NSString *)path path:(NSString *)path
timeout:(NSTimeInterval)timeout NS_DESIGNATED_INITIALIZER; timeout:(NSTimeInterval)timeout NS_DESIGNATED_INITIALIZER;
- (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)(void))errorHandler; - (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void (^)(void))errorHandler;
- (void)startBatchWithOperations:(NSArray *)ops; - (void)startBatchWithOperations:(NSArray *)ops;

@ -19,29 +19,29 @@
#import "GRPCWrappedCall.h" #import "GRPCWrappedCall.h"
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <grpc/grpc.h>
#include <grpc/byte_buffer.h> #include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#import "GRPCCompletionQueue.h" #import "GRPCCompletionQueue.h"
#import "GRPCHost.h" #import "GRPCHost.h"
#import "NSDictionary+GRPC.h"
#import "NSData+GRPC.h" #import "NSData+GRPC.h"
#import "NSDictionary+GRPC.h"
#import "NSError+GRPC.h" #import "NSError+GRPC.h"
#import "GRPCOpBatchLog.h" #import "GRPCOpBatchLog.h"
@implementation GRPCOperation { @implementation GRPCOperation {
@protected @protected
// Most operation subclasses don't set any flags in the grpc_op, and rely on the flag member being // Most operation subclasses don't set any flags in the grpc_op, and rely on the flag member being
// initialized to zero. // initialized to zero.
grpc_op _op; grpc_op _op;
void(^_handler)(void); void (^_handler)(void);
} }
- (void)finish { - (void)finish {
if (_handler) { if (_handler) {
void(^handler)(void) = _handler; void (^handler)(void) = _handler;
_handler = nil; _handler = nil;
handler(); handler();
} }
@ -54,8 +54,7 @@
return [self initWithMetadata:nil flags:0 handler:nil]; return [self initWithMetadata:nil flags:0 handler:nil];
} }
- (instancetype)initWithMetadata:(NSDictionary *)metadata - (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)(void))handler {
handler:(void (^)(void))handler {
return [self initWithMetadata:metadata flags:0 handler:handler]; return [self initWithMetadata:metadata flags:0 handler:handler];
} }
@ -128,11 +127,11 @@
grpc_metadata_array _headers; grpc_metadata_array _headers;
} }
- (instancetype) init { - (instancetype)init {
return [self initWithHandler:nil]; return [self initWithHandler:nil];
} }
- (instancetype) initWithHandler:(void (^)(NSDictionary *))handler { - (instancetype)initWithHandler:(void (^)(NSDictionary *))handler {
if (self = [super init]) { if (self = [super init]) {
_op.op = GRPC_OP_RECV_INITIAL_METADATA; _op.op = GRPC_OP_RECV_INITIAL_METADATA;
grpc_metadata_array_init(&_headers); grpc_metadata_array_init(&_headers);
@ -142,8 +141,8 @@
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
_handler = ^{ _handler = ^{
__strong typeof(self) strongSelf = weakSelf; __strong typeof(self) strongSelf = weakSelf;
NSDictionary *metadata = [NSDictionary NSDictionary *metadata =
grpc_dictionaryFromMetadataArray:strongSelf->_headers]; [NSDictionary grpc_dictionaryFromMetadataArray:strongSelf->_headers];
handler(metadata); handler(metadata);
}; };
} }
@ -157,7 +156,7 @@
@end @end
@implementation GRPCOpRecvMessage{ @implementation GRPCOpRecvMessage {
grpc_byte_buffer *_receivedMessage; grpc_byte_buffer *_receivedMessage;
} }
@ -183,18 +182,18 @@
@end @end
@implementation GRPCOpRecvStatus{ @implementation GRPCOpRecvStatus {
grpc_status_code _statusCode; grpc_status_code _statusCode;
grpc_slice _details; grpc_slice _details;
size_t _detailsCapacity; size_t _detailsCapacity;
grpc_metadata_array _trailers; grpc_metadata_array _trailers;
} }
- (instancetype) init { - (instancetype)init {
return [self initWithHandler:nil]; return [self initWithHandler:nil];
} }
- (instancetype) initWithHandler:(void (^)(NSError *, NSDictionary *))handler { - (instancetype)initWithHandler:(void (^)(NSError *, NSDictionary *))handler {
if (self = [super init]) { if (self = [super init]) {
_op.op = GRPC_OP_RECV_STATUS_ON_CLIENT; _op.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
_op.data.recv_status_on_client.status = &_statusCode; _op.data.recv_status_on_client.status = &_statusCode;
@ -208,10 +207,10 @@
__strong typeof(self) strongSelf = weakSelf; __strong typeof(self) strongSelf = weakSelf;
if (strongSelf) { if (strongSelf) {
char *details = grpc_slice_to_c_string(strongSelf->_details); char *details = grpc_slice_to_c_string(strongSelf->_details);
NSError *error = [NSError grpc_errorFromStatusCode:strongSelf->_statusCode NSError *error =
details:details]; [NSError grpc_errorFromStatusCode:strongSelf->_statusCode details:details];
NSDictionary *trailers = [NSDictionary NSDictionary *trailers =
grpc_dictionaryFromMetadataArray:strongSelf->_trailers]; [NSDictionary grpc_dictionaryFromMetadataArray:strongSelf->_trailers];
handler(error, trailers); handler(error, trailers);
gpr_free(details); gpr_free(details);
} }
@ -244,8 +243,7 @@
path:(NSString *)path path:(NSString *)path
timeout:(NSTimeInterval)timeout { timeout:(NSTimeInterval)timeout {
if (!path || !host) { if (!path || !host) {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException format:@"path and host cannot be nil."];
format:@"path and host cannot be nil."];
} }
if (self = [super init]) { if (self = [super init]) {
@ -270,8 +268,8 @@
} }
- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)(void))errorHandler { - (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)(void))errorHandler {
// Keep logs of op batches when we are running tests. Disabled when in production for improved // Keep logs of op batches when we are running tests. Disabled when in production for improved
// performance. // performance.
#ifdef GRPC_TEST_OBJC #ifdef GRPC_TEST_OBJC
[GRPCOpBatchLog addOpBatchToLog:operations]; [GRPCOpBatchLog addOpBatchToLog:operations];
#endif #endif
@ -282,25 +280,26 @@
for (GRPCOperation *operation in operations) { for (GRPCOperation *operation in operations) {
ops_array[i++] = operation.op; ops_array[i++] = operation.op;
} }
grpc_call_error error = grpc_call_start_batch(_call, ops_array, nops, grpc_call_error error =
(__bridge_retained void *)(^(bool success){ grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) {
if (!success) { if (!success) {
if (errorHandler) { if (errorHandler) {
errorHandler(); errorHandler();
} else { } else {
return; return;
} }
} }
for (GRPCOperation *operation in operations) { for (GRPCOperation *operation in operations) {
[operation finish]; [operation finish];
} }
}), NULL); }),
NULL);
gpr_free(ops_array); gpr_free(ops_array);
if (error != GRPC_CALL_OK) { if (error != GRPC_CALL_OK) {
[NSException raise:NSInternalInconsistencyException [NSException
format:@"A precondition for calling grpc_call_start_batch wasn't met. Error %i", raise:NSInternalInconsistencyException
error]; format:@"A precondition for calling grpc_call_start_batch wasn't met. Error %i", error];
} }
} }

@ -24,8 +24,8 @@
// TODO(jcanizales): Move these two incantations to the C library. // TODO(jcanizales): Move these two incantations to the C library.
static void MallocAndCopyByteBufferToCharArray(grpc_byte_buffer *buffer, static void MallocAndCopyByteBufferToCharArray(grpc_byte_buffer *buffer, size_t *length,
size_t *length, char **array) { char **array) {
grpc_byte_buffer_reader reader; grpc_byte_buffer_reader reader;
if (!grpc_byte_buffer_reader_init(&reader, buffer)) { if (!grpc_byte_buffer_reader_init(&reader, buffer)) {
// grpc_byte_buffer_reader_init can fail if the data sent by the server // grpc_byte_buffer_reader_init can fail if the data sent by the server
@ -51,8 +51,7 @@ static void MallocAndCopyByteBufferToCharArray(grpc_byte_buffer *buffer,
grpc_byte_buffer_reader_destroy(&reader); grpc_byte_buffer_reader_destroy(&reader);
} }
static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, size_t length) {
size_t length) {
grpc_slice slice = grpc_slice_from_copied_buffer(array, length); grpc_slice slice = grpc_slice_from_copied_buffer(array, length);
grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1); grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1);
grpc_slice_unref(slice); grpc_slice_unref(slice);
@ -89,7 +88,6 @@ static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array,
// to create an array of grpc_slice objects to pass to // to create an array of grpc_slice objects to pass to
// grpc_raw_byte_buffer_create. // grpc_raw_byte_buffer_create.
// That would make it do exactly one copy, always. // That would make it do exactly one copy, always.
return CopyCharArrayToNewByteBuffer((const char *)self.bytes, return CopyCharArrayToNewByteBuffer((const char *)self.bytes, (size_t)self.length);
(size_t)self.length);
} }
@end @end

@ -74,8 +74,7 @@
NSMutableDictionary *metadata = [NSMutableDictionary dictionaryWithCapacity:count]; NSMutableDictionary *metadata = [NSMutableDictionary dictionaryWithCapacity:count];
for (grpc_metadata *entry = entries; entry < entries + count; entry++) { for (grpc_metadata *entry = entries; entry < entries + count; entry++) {
char *key = grpc_slice_to_c_string(entry->key); char *key = grpc_slice_to_c_string(entry->key);
NSString *name = [NSString stringWithCString:key NSString *name = [NSString stringWithCString:key encoding:NSASCIIStringEncoding];
encoding:NSASCIIStringEncoding];
gpr_free(key); gpr_free(key);
if (!name || metadata[name]) { if (!name || metadata[name]) {
// Log if name is nil? // Log if name is nil?
@ -97,7 +96,7 @@
- (grpc_metadata *)grpc_metadataArray { - (grpc_metadata *)grpc_metadataArray {
grpc_metadata *metadata = gpr_malloc([self count] * sizeof(grpc_metadata)); grpc_metadata *metadata = gpr_malloc([self count] * sizeof(grpc_metadata));
grpc_metadata *current = metadata; grpc_metadata *current = metadata;
for (NSString* key in self) { for (NSString *key in self) {
id value = self[key]; id value = self[key];
current->key = grpc_slice_from_copied_string(key.UTF8String); current->key = grpc_slice_from_copied_string(key.UTF8String);
if ([value respondsToSelector:@selector(grpc_initMetadata:)]) { if ([value respondsToSelector:@selector(grpc_initMetadata:)]) {

@ -20,7 +20,7 @@
#include <grpc/grpc.h> #include <grpc/grpc.h>
NSString * const kGRPCErrorDomain = @"io.grpc"; NSString *const kGRPCErrorDomain = @"io.grpc";
@implementation NSError (GRPC) @implementation NSError (GRPC)
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details { + (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details {
@ -30,6 +30,6 @@ NSString * const kGRPCErrorDomain = @"io.grpc";
NSString *message = [NSString stringWithCString:details encoding:NSASCIIStringEncoding]; NSString *message = [NSString stringWithCString:details encoding:NSASCIIStringEncoding];
return [NSError errorWithDomain:kGRPCErrorDomain return [NSError errorWithDomain:kGRPCErrorDomain
code:statusCode code:statusCode
userInfo:@{NSLocalizedDescriptionKey: message}]; userInfo:@{NSLocalizedDescriptionKey : message}];
} }
@end @end

@ -22,5 +22,4 @@
// instead. This file can be regenerated from the template by running // instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`. // `tools/buildgen/generate_projects.sh`.
#define GRPC_OBJC_VERSION_STRING @"1.12.0-dev" #define GRPC_OBJC_VERSION_STRING @"1.12.0-dev"

@ -22,9 +22,8 @@
* A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint * A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint
* can implement multiple services. * can implement multiple services.
*/ */
__attribute__((deprecated("Please use GRPCProtoMethod."))) __attribute__((deprecated("Please use GRPCProtoMethod."))) @interface ProtoMethod
@interface ProtoMethod : NSObject : NSObject @property(nonatomic, readonly) NSString *package;
@property(nonatomic, readonly) NSString *package;
@property(nonatomic, readonly) NSString *service; @property(nonatomic, readonly) NSString *service;
@property(nonatomic, readonly) NSString *method; @property(nonatomic, readonly) NSString *method;
@ -41,7 +40,7 @@ __attribute__((deprecated("Please use GRPCProtoMethod.")))
*/ */
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface GRPCProtoMethod : ProtoMethod @interface GRPCProtoMethod : ProtoMethod
#pragma clang diagnostic pop #pragma clang diagnostic pop
@end @end

@ -21,18 +21,18 @@
#import "ProtoMethod.h" #import "ProtoMethod.h"
__attribute__((deprecated("Please use GRPCProtoCall."))) __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC
@interface ProtoRPC : GRPCCall : GRPCCall
/** /**
* host parameter should not contain the scheme (http:// or https://), only the name or IP addr * host parameter should not contain the scheme (http:// or https://), only the name or IP
* and the port number, for example @"localhost:5050". * addr and the port number, for example @"localhost:5050".
*/ */
- (instancetype)initWithHost:(NSString *)host -
method:(GRPCProtoMethod *)method (instancetype)initWithHost : (NSString *)host method
requestsWriter:(GRXWriter *)requestsWriter : (GRPCProtoMethod *)method requestsWriter : (GRXWriter *)requestsWriter responseClass
responseClass:(Class)responseClass : (Class)responseClass responsesWriteable
responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER; : (id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
- (void)start; - (void)start;
@end @end
@ -43,7 +43,7 @@ __attribute__((deprecated("Please use GRPCProtoCall.")))
*/ */
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface GRPCProtoCall : ProtoRPC @interface GRPCProtoCall : ProtoRPC
#pragma clang diagnostic pop #pragma clang diagnostic pop
@end @end

@ -19,27 +19,26 @@
#import "ProtoRPC.h" #import "ProtoRPC.h"
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers.h> #import <Protobuf/GPBProtocolBuffers.h>
#else #else
#import <GPBProtocolBuffers.h> #import <GPBProtocolBuffers.h>
#endif #endif
#import <RxLibrary/GRXWriteable.h> #import <RxLibrary/GRXWriteable.h>
#import <RxLibrary/GRXWriter+Transformations.h> #import <RxLibrary/GRXWriter+Transformations.h>
static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) {
NSDictionary *info = @{ NSDictionary *info = @{
NSLocalizedDescriptionKey: @"Unable to parse response from the server", NSLocalizedDescriptionKey : @"Unable to parse response from the server",
NSLocalizedRecoverySuggestionErrorKey: @"If this RPC is idempotent, retry " NSLocalizedRecoverySuggestionErrorKey :
@"with exponential backoff. Otherwise, query the server status before " @"If this RPC is idempotent, retry "
@"retrying.", @"with exponential backoff. Otherwise, query the server status before "
NSUnderlyingErrorKey: parsingError, @"retrying.",
@"Expected class": expectedClass, NSUnderlyingErrorKey : parsingError,
@"Received value": proto, @"Expected class" : expectedClass,
}; @"Received value" : proto,
};
// TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public.
return [NSError errorWithDomain:@"io.grpc" return [NSError errorWithDomain:@"io.grpc" code:13 userInfo:info];
code:13
userInfo:info];
} }
#pragma clang diagnostic push #pragma clang diagnostic push
@ -92,9 +91,10 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
} else { } else {
[weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)]; [weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)];
} }
} completionHandler:^(NSError *errorOrNil) { }
[responsesWriteable writesFinishedWithError:errorOrNil]; completionHandler:^(NSError *errorOrNil) {
}]; [responsesWriteable writesFinishedWithError:errorOrNil];
}];
} }
return self; return self;
} }

@ -22,27 +22,24 @@
@protocol GRXWriteable; @protocol GRXWriteable;
@class GRXWriter; @class GRXWriter;
__attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoService
__attribute__((deprecated("Please use GRPCProtoService."))) : NSObject -
@interface ProtoService : NSObject (instancetype)initWithHost : (NSString *)host packageName
- (instancetype)initWithHost:(NSString *)host : (NSString *)packageName serviceName : (NSString *)serviceName NS_DESIGNATED_INITIALIZER;
packageName:(NSString *)packageName
serviceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER;
- (GRPCProtoCall *)RPCToMethod:(NSString *)method - (GRPCProtoCall *)RPCToMethod:(NSString *)method
requestsWriter:(GRXWriter *)requestsWriter requestsWriter:(GRXWriter *)requestsWriter
responseClass:(Class)responseClass responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable; responsesWriteable:(id<GRXWriteable>)responsesWriteable;
@end @end
/** /**
* This subclass is empty now. Eventually we'll remove ProtoService class * This subclass is empty now. Eventually we'll remove ProtoService class
* to avoid potential naming conflict * to avoid potential naming conflict
*/ */
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface GRPCProtoService : ProtoService @interface GRPCProtoService : ProtoService
#pragma clang diagnostic pop #pragma clang diagnostic pop
@end @end

@ -57,9 +57,8 @@
requestsWriter:(GRXWriter *)requestsWriter requestsWriter:(GRXWriter *)requestsWriter
responseClass:(Class)responseClass responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable { responsesWriteable:(id<GRXWriteable>)responsesWriteable {
GRPCProtoMethod *methodName = [[GRPCProtoMethod alloc] initWithPackage:_packageName GRPCProtoMethod *methodName =
service:_serviceName [[GRPCProtoMethod alloc] initWithPackage:_packageName service:_serviceName method:method];
method:method];
return [[GRPCProtoCall alloc] initWithHost:_host return [[GRPCProtoCall alloc] initWithHost:_host
method:methodName method:methodName
requestsWriter:requestsWriter requestsWriter:requestsWriter

@ -67,7 +67,7 @@
#pragma mark GRXWriter implementation #pragma mark GRXWriter implementation
- (void)setState:(GRXWriterState)newState { - (void)setState:(GRXWriterState)newState {
@synchronized (self) { @synchronized(self) {
// Manual transitions are only allowed from the started or paused states. // Manual transitions are only allowed from the started or paused states.
if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) { if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
return; return;
@ -112,8 +112,7 @@
- (void)dealloc { - (void)dealloc {
GRXWriterState state = self.state; GRXWriterState state = self.state;
if (state == GRXWriterStateNotStarted || if (state == GRXWriterStateNotStarted || state == GRXWriterStatePaused) {
state == GRXWriterStatePaused) {
dispatch_resume(_writeQueue); dispatch_resume(_writeQueue);
} }
} }

@ -18,8 +18,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "GRXWriter.h"
#import "GRXWriteable.h" #import "GRXWriteable.h"
#import "GRXWriter.h"
/** /**
* This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a * This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a

@ -46,8 +46,7 @@
} }
- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable { - (instancetype)initWithWriteable:(id<GRXWriteable>)writeable {
return [self initWithWriteable:writeable return [self initWithWriteable:writeable dispatchQueue:dispatch_get_main_queue()];
dispatchQueue:dispatch_get_main_queue()];
} }
- (void)enqueueValue:(id)value completionHandler:(void (^)(void))handler { - (void)enqueueValue:(id)value completionHandler:(void (^)(void))handler {
@ -69,7 +68,7 @@
typeof(self) strongSelf = weakSelf; typeof(self) strongSelf = weakSelf;
if (strongSelf) { if (strongSelf) {
BOOL finished = NO; BOOL finished = NO;
@synchronized (self) { @synchronized(self) {
if (!strongSelf->_alreadyFinished) { if (!strongSelf->_alreadyFinished) {
strongSelf->_alreadyFinished = YES; strongSelf->_alreadyFinished = YES;
} else { } else {
@ -90,7 +89,7 @@
- (void)cancelWithError:(NSError *)error { - (void)cancelWithError:(NSError *)error {
NSAssert(error, @"For a successful completion, use enqueueSuccessfulCompletion."); NSAssert(error, @"For a successful completion, use enqueueSuccessfulCompletion.");
BOOL finished = NO; BOOL finished = NO;
@synchronized (self) { @synchronized(self) {
if (!_alreadyFinished) { if (!_alreadyFinished) {
_alreadyFinished = YES; _alreadyFinished = YES;
} else { } else {
@ -112,7 +111,7 @@
- (void)cancelSilently { - (void)cancelSilently {
BOOL finished = NO; BOOL finished = NO;
@synchronized (self) { @synchronized(self) {
if (!_alreadyFinished) { if (!_alreadyFinished) {
_alreadyFinished = YES; _alreadyFinished = YES;
} else { } else {

@ -18,7 +18,7 @@
#import "GRXForwardingWriter.h" #import "GRXForwardingWriter.h"
@interface GRXForwardingWriter () <GRXWriteable> @interface GRXForwardingWriter ()<GRXWriteable>
@end @end
@implementation GRXForwardingWriter { @implementation GRXForwardingWriter {

@ -28,8 +28,8 @@
@synthesize state = _state; @synthesize state = _state;
- (instancetype) init { - (instancetype)init {
return [self initWithEnumerator:nil error:nil]; // results in an empty writer. return [self initWithEnumerator:nil error:nil]; // results in an empty writer.
} }
// Designated initializer // Designated initializer
@ -57,7 +57,8 @@
} }
+ (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container { + (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container {
return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithContainer:container]];; return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithContainer:container]];
;
} }
+ (GRXWriter *)writerWithValue:(id)value { + (GRXWriter *)writerWithValue:(id)value {

@ -22,7 +22,7 @@
* A GRXWriteable is an object to which a sequence of values can be sent. The * A GRXWriteable is an object to which a sequence of values can be sent. The
* sequence finishes with an optional error. * sequence finishes with an optional error.
*/ */
@protocol GRXWriteable <NSObject> @protocol GRXWriteable<NSObject>
/** Push the next value of the sequence to the receiving object. */ /** Push the next value of the sequence to the receiving object. */
- (void)writeValue:(id)value; - (void)writeValue:(id)value;

@ -42,9 +42,8 @@
} else if (error) { } else if (error) {
singleHandler(nil, error); singleHandler(nil, error);
} else { } else {
NSDictionary *userInfo = @{ NSDictionary *userInfo =
NSLocalizedDescriptionKey: @"The writer finished without producing any value." @{NSLocalizedDescriptionKey : @"The writer finished without producing any value."};
};
// Even though RxLibrary is independent of gRPC, the domain and code here are, for the moment, // Even though RxLibrary is independent of gRPC, the domain and code here are, for the moment,
// set to the values of kGRPCErrorDomain and GRPCErrorCodeInternal. This way, the error formed // set to the values of kGRPCErrorDomain and GRPCErrorCodeInternal. This way, the error formed
// is the one user of gRPC would expect if the server failed to produce a response. // is the one user of gRPC would expect if the server failed to produce a response.
@ -55,9 +54,9 @@
// the two domains. // the two domains.
static NSString *kGRPCErrorDomain = @"io.grpc"; static NSString *kGRPCErrorDomain = @"io.grpc";
static NSUInteger kGRPCErrorCodeInternal = 13; static NSUInteger kGRPCErrorCodeInternal = 13;
singleHandler(nil, [NSError errorWithDomain:kGRPCErrorDomain singleHandler(
code:kGRPCErrorCodeInternal nil,
userInfo:userInfo]); [NSError errorWithDomain:kGRPCErrorDomain code:kGRPCErrorCodeInternal userInfo:userInfo]);
} }
}; };
return [self writeableWithEventHandler:^(BOOL done, id value, NSError *error) { return [self writeableWithEventHandler:^(BOOL done, id value, NSError *error) {
@ -73,9 +72,10 @@
} }
return [[self alloc] initWithValueHandler:^(id value) { return [[self alloc] initWithValueHandler:^(id value) {
handler(NO, value, nil); handler(NO, value, nil);
} completionHandler:^(NSError *errorOrNil) { }
handler(YES, nil, errorOrNil); completionHandler:^(NSError *errorOrNil) {
}]; handler(YES, nil, errorOrNil);
}];
} }
- (instancetype)init { - (instancetype)init {

@ -18,8 +18,8 @@
#import "GRXWriter+Immediate.h" #import "GRXWriter+Immediate.h"
#import "GRXImmediateWriter.h"
#import "GRXImmediateSingleWriter.h" #import "GRXImmediateSingleWriter.h"
#import "GRXImmediateWriter.h"
@implementation GRXWriter (Immediate) @implementation GRXWriter (Immediate)

@ -18,8 +18,9 @@
#import "RxLibrary/GRXForwardingWriter.h" #import "RxLibrary/GRXForwardingWriter.h"
/** A "proxy" writer that transforms all the values of its input writer by using a mapping function. */ /** A "proxy" writer that transforms all the values of its input writer by using a mapping function.
*/
@interface GRXMappingWriter : GRXForwardingWriter @interface GRXMappingWriter : GRXForwardingWriter
- (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map - (instancetype)initWithWriter:(GRXWriter *)writer
NS_DESIGNATED_INITIALIZER; map:(id (^)(id value))map NS_DESIGNATED_INITIALIZER;
@end @end

@ -18,7 +18,7 @@
#import "GRXMappingWriter.h" #import "GRXMappingWriter.h"
@interface GRXForwardingWriter () <GRXWriteable> @interface GRXForwardingWriter ()<GRXWriteable>
@end @end
@implementation GRXMappingWriter { @implementation GRXMappingWriter {

@ -18,6 +18,6 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate> @interface AppDelegate : UIResponder<UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window; @property(strong, nonatomic) UIWindow* window;
@end @end

@ -22,15 +22,15 @@
#import <ProtoRPC/ProtoMethod.h> #import <ProtoRPC/ProtoMethod.h>
#import <RemoteTest/Messages.pbobjc.h> #import <RemoteTest/Messages.pbobjc.h>
#import <RemoteTest/Test.pbrpc.h> #import <RemoteTest/Test.pbrpc.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#import <RxLibrary/GRXWriteable.h> #import <RxLibrary/GRXWriteable.h>
#import <RxLibrary/GRXWriter+Immediate.h>
@implementation ViewController @implementation ViewController
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
NSString * const kRemoteHost = @"grpc-test.sandbox.googleapis.com"; NSString *const kRemoteHost = @"grpc-test.sandbox.googleapis.com";
RMTSimpleRequest *request = [[RMTSimpleRequest alloc] init]; RMTSimpleRequest *request = [[RMTSimpleRequest alloc] init];
request.responseSize = 10; request.responseSize = 10;
@ -40,14 +40,14 @@
// Example gRPC call using a generated proto client library: // Example gRPC call using a generated proto client library:
RMTTestService *service = [[RMTTestService alloc] initWithHost:kRemoteHost]; RMTTestService *service = [[RMTTestService alloc] initWithHost:kRemoteHost];
[service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { [service unaryCallWithRequest:request
if (response) { handler:^(RMTSimpleResponse *response, NSError *error) {
NSLog(@"Finished successfully with response:\n%@", response); if (response) {
} else if (error) { NSLog(@"Finished successfully with response:\n%@", response);
NSLog(@"Finished with error: %@", error); } else if (error) {
} NSLog(@"Finished with error: %@", error);
}]; }
}];
// Same example call using the generic gRPC client library: // Same example call using the generic gRPC client library:
@ -61,16 +61,18 @@
path:method.HTTPPath path:method.HTTPPath
requestsWriter:requestsWriter]; requestsWriter:requestsWriter];
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { id<GRXWriteable> responsesWriteable =
RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value error:NULL]; [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
NSLog(@"Received response:\n%@", response); RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value error:NULL];
} completionHandler:^(NSError *errorOrNil) { NSLog(@"Received response:\n%@", response);
if (errorOrNil) { }
NSLog(@"Finished with error: %@", errorOrNil); completionHandler:^(NSError *errorOrNil) {
} else { if (errorOrNil) {
NSLog(@"Finished successfully."); NSLog(@"Finished with error: %@", errorOrNil);
} } else {
}]; NSLog(@"Finished successfully.");
}
}];
[call startWithWriteable:responsesWriteable]; [call startWithWriteable:responsesWriteable];
} }

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

Loading…
Cancel
Save