mirror of https://github.com/grpc/grpc.git
commit
4fad281ce8
1398 changed files with 53935 additions and 26727 deletions
@ -0,0 +1,108 @@ |
||||
[VARIABLES] |
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/1345): How does the inspection |
||||
# not include "unused_" and "ignored_" by default? |
||||
dummy-variables-rgx=^ignored_|^unused_ |
||||
|
||||
[DESIGN] |
||||
|
||||
# NOTE(nathaniel): Not particularly attached to this value; it just seems to |
||||
# be what works for us at the moment (excepting the dead-code-walking Beta |
||||
# API). |
||||
max-args=6 |
||||
|
||||
[MISCELLANEOUS] |
||||
|
||||
# NOTE(nathaniel): We are big fans of "TODO(<issue link>): " and |
||||
# "NOTE(<username or issue link>): ". We do not allow "TODO:", |
||||
# "TODO(<username>):", "FIXME:", or anything else. |
||||
notes=FIXME,XXX |
||||
|
||||
[MESSAGES CONTROL] |
||||
|
||||
disable= |
||||
# These suppressions are specific to tests: |
||||
# |
||||
# TODO(https://github.com/grpc/grpc/issues/261): investigate |
||||
# each of the following one by one and consider eliminating |
||||
# the suppression category. |
||||
# Eventually, the hope is to eliminate the .pylintrc-tests |
||||
# altogether and rely on .pylintrc for everything. |
||||
pointless-statement, |
||||
no-member, |
||||
no-self-use, |
||||
attribute-defined-outside-init, |
||||
unused-argument, |
||||
unused-variable, |
||||
unused-import, |
||||
redefined-builtin, |
||||
too-many-public-methods, |
||||
too-many-locals, |
||||
redefined-variable-type, |
||||
redefined-outer-name, |
||||
ungrouped-imports, |
||||
too-many-branches, |
||||
too-many-arguments, |
||||
too-many-format-args, |
||||
too-many-return-statements, |
||||
too-many-statements, |
||||
line-too-long, |
||||
wrong-import-position, |
||||
wrong-import-order, |
||||
# -- END OF TEST-SPECIFIC SUPPRESSIONS -- |
||||
|
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/59#issuecomment-283774279): |
||||
# Enable cyclic-import after a 1.7-or-later pylint release that |
||||
# recognizes our disable=cyclic-import suppressions. |
||||
cyclic-import, |
||||
# TODO(https://github.com/grpc/grpc/issues/8622): Enable this after the |
||||
# Beta API is removed. |
||||
duplicate-code, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't seem to |
||||
# understand enum and concurrent.futures; look into this later with the |
||||
# latest pylint version. |
||||
import-error, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Enable this one. |
||||
# Should take a little configuration but not much. |
||||
invalid-name, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): This doesn't seem to |
||||
# work for now? Try with a later pylint? |
||||
locally-disabled, |
||||
# NOTE(nathaniel): What even is this? *Enabling* an inspection results |
||||
# in a warning? How does that encourage more analysis and coverage? |
||||
locally-enabled, |
||||
# NOTE(nathaniel): We don't write doc strings for most private code |
||||
# elements. |
||||
missing-docstring, |
||||
# NOTE(nathaniel): In numeric comparisons it is better to have the |
||||
# lesser (or lesser-or-equal-to) quantity on the left when the |
||||
# expression is true than it is to worry about which is an identifier |
||||
# and which a literal value. |
||||
misplaced-comparison-constant, |
||||
# NOTE(nathaniel): Our completely abstract interface classes don't have |
||||
# constructors. |
||||
no-init, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't yet play |
||||
# nicely with some of our code being implemented in Cython. Maybe in a |
||||
# later version? |
||||
no-name-in-module, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Suppress these where |
||||
# the odd shape of the authentication portion of the API forces them on |
||||
# us and enable everywhere else. |
||||
protected-access, |
||||
# NOTE(nathaniel): Pylint and I will probably never agree on this. |
||||
too-few-public-methods, |
||||
# NOTE(nathaniel): Pylint and I wil probably never agree on this for |
||||
# private classes. For public classes maybe? |
||||
too-many-instance-attributes, |
||||
# NOTE(nathaniel): Some of our modules have a lot of lines... of |
||||
# specification and documentation. Maybe if this were |
||||
# lines-of-code-based we would use it. |
||||
too-many-lines, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have |
||||
# this one if we extracted just a few more helper functions... |
||||
too-many-nested-blocks, |
||||
# NOTE(nathaniel): I have disputed the premise of this inspection from |
||||
# the beginning and will continue to do so until it goes away for good. |
||||
useless-else-on-loop, |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,16 @@ |
||||
# Copyright 2017 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. |
||||
|
||||
set(_gRPC_ADDRESS_SORTING_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/address_sorting/include") |
||||
set(_gRPC_ADDRESS_SORTING_LIBRARIES address_sorting) |
@ -0,0 +1,46 @@ |
||||
# Background # |
||||
|
||||
In Python, multithreading is ineffective at concurrency for CPU bound tasks |
||||
due to the GIL (global interpreter lock). Extension modules can release |
||||
the GIL in CPU bound tasks, but that isn't an option in pure Python. |
||||
Users use libraries such as multiprocessing, subprocess, concurrent.futures.ProcessPoolExecutor, |
||||
etc, to work around the GIL. These modules call ```fork()``` underneath the hood. Various issues have |
||||
been reported when using these modules with gRPC Python. gRPC Python wraps |
||||
gRPC core, which uses multithreading for performance, and hence doesn't support ```fork()```. |
||||
Historically, we didn't support forking in gRPC, but some users seemed |
||||
to be doing fine until their code started to break on version 1.6. This was |
||||
likely caused by the addition of background c-threads and a background |
||||
Python thread. |
||||
|
||||
# Current Status # |
||||
|
||||
## 1.11 ## |
||||
The background Python thread was removed entirely. This allows forking |
||||
after creating a channel. However, the channel must not have issued any |
||||
RPCs prior to the fork. Attempting to fork with an active channel that |
||||
has been used can result in deadlocks/corrupted wire data. |
||||
|
||||
## 1.9 ## |
||||
A regression was noted in cases where users are doing fork/exec. This |
||||
was due to ```pthread_atfork()``` handler that was added in 1.7 to partially |
||||
support forking in gRPC. A deadlock can happen when pthread_atfork |
||||
handler is running, and an application thread is calling into gRPC. |
||||
We have provided a workaround for this issue by allowing users to turn |
||||
off the handler using env flag ```GRPC_ENABLE_FORK_SUPPORT=False```. |
||||
This should be set whenever a user expects to always call exec |
||||
immediately following fork. It will disable the fork handlers. |
||||
|
||||
## 1.7 ## |
||||
A ```pthread_atfork()``` handler was added in 1.7 to automatically shut down |
||||
the background c-threads when fork was called. This does not shut down the |
||||
background Python thread, so users could not have any open channels when |
||||
forking. |
||||
|
||||
# Future Work # |
||||
|
||||
## 1.13 ## |
||||
The workaround when using fork/exec by setting |
||||
```GRPC_ENABLE_FORK_SUPPORT=False``` should no longer be needed. Following |
||||
[this PR](https://github.com/grpc/grpc/pull/14647), fork |
||||
handlers will not automatically run when multiple threads are calling |
||||
into gRPC. |
@ -1,17 +1,15 @@ |
||||
Each version of gRPC gets a new description of what the 'g' stands for, since |
||||
we've never really been able to figure it out. |
||||
'g' stands for something different every gRPC release: |
||||
|
||||
Below is a list of already-used definitions (that should not be repeated in the |
||||
future), and the corresponding version numbers that used them: |
||||
|
||||
- 1.0 'g' stands for 'gRPC' |
||||
- 1.1 'g' stands for 'good' |
||||
- 1.2 'g' stands for 'green' |
||||
- 1.3 'g' stands for 'gentle' |
||||
- 1.4 'g' stands for 'gregarious' |
||||
- 1.6 'g' stands for 'garcia' |
||||
- 1.7 'g' stands for 'gambit' |
||||
- 1.8 'g' stands for 'generous' |
||||
- 1.9 'g' stands for 'glossy' |
||||
- 1.10 'g' stands for 'glamorous' |
||||
- 1.11 'g' stands for 'gorgeous' |
||||
- 1.0 'g' stands for ['gRPC'](https://github.com/grpc/grpc/tree/v1.0.x) |
||||
- 1.1 'g' stands for ['good'](https://github.com/grpc/grpc/tree/v1.1.x) |
||||
- 1.2 'g' stands for ['green'](https://github.com/grpc/grpc/tree/v1.2.x) |
||||
- 1.3 'g' stands for ['gentle'](https://github.com/grpc/grpc/tree/v1.3.x) |
||||
- 1.4 'g' stands for ['gregarious'](https://github.com/grpc/grpc/tree/v1.4.x) |
||||
- 1.6 'g' stands for ['garcia'](https://github.com/grpc/grpc/tree/v1.6.x) |
||||
- 1.7 'g' stands for ['gambit'](https://github.com/grpc/grpc/tree/v1.7.x) |
||||
- 1.8 'g' stands for ['generous'](https://github.com/grpc/grpc/tree/v1.8.x) |
||||
- 1.9 'g' stands for ['glossy'](https://github.com/grpc/grpc/tree/v1.9.x) |
||||
- 1.10 'g' stands for ['glamorous'](https://github.com/grpc/grpc/tree/v1.10.x) |
||||
- 1.11 'g' stands for ['gorgeous'](https://github.com/grpc/grpc/tree/v1.11.x) |
||||
- 1.12 'g' stands for ['glorious'](https://github.com/grpc/grpc/tree/v1.12.x) |
||||
- 1.13 'g' stands for ['gloriosa'](https://github.com/grpc/grpc/tree/master) |
||||
|
@ -0,0 +1,116 @@ |
||||
# 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. |
||||
# |
||||
# cmake "superbuild" file for C++ helloworld example. |
||||
# This build file demonstrates how to build the helloworld project |
||||
# and all its dependencies in a single cmake build (hence "superbuild") |
||||
# that is easy to build and maintain. |
||||
# cmake's ExternalProject_Add() is used to import all the sub-projects, |
||||
# including the "helloworld" project itself. |
||||
# See https://blog.kitware.com/cmake-superbuilds-git-submodules/ |
||||
|
||||
cmake_minimum_required(VERSION 2.8) |
||||
|
||||
# Project |
||||
project(HelloWorld-SuperBuild C CXX) |
||||
|
||||
include(ExternalProject) |
||||
|
||||
# Builds c-ares project from the git submodule. |
||||
# Note: For all external projects, instead of using checked-out code, one could |
||||
# specify GIT_REPOSITORY and GIT_TAG to have cmake download the dependency directly, |
||||
# without needing to add a submodule to your project. |
||||
ExternalProject_Add(c-ares |
||||
PREFIX c-ares |
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../third_party/cares/cares" |
||||
CMAKE_CACHE_ARGS |
||||
-DCARES_SHARED:BOOL=OFF |
||||
-DCARES_STATIC:BOOL=ON |
||||
-DCARES_STATIC_PIC:BOOL=ON |
||||
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/c-ares |
||||
) |
||||
|
||||
# Builds protobuf project from the git submodule. |
||||
ExternalProject_Add(protobuf |
||||
PREFIX protobuf |
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../third_party/protobuf/cmake" |
||||
CMAKE_CACHE_ARGS |
||||
-Dprotobuf_BUILD_TESTS:BOOL=OFF |
||||
-Dprotobuf_WITH_ZLIB:BOOL=OFF |
||||
-Dprotobuf_MSVC_STATIC_RUNTIME:BOOL=OFF |
||||
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/protobuf |
||||
) |
||||
|
||||
# Builds zlib project from the git submodule. |
||||
ExternalProject_Add(zlib |
||||
PREFIX zlib |
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../third_party/zlib" |
||||
CMAKE_CACHE_ARGS |
||||
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/zlib |
||||
) |
||||
|
||||
# the location where protobuf-config.cmake will be installed varies by platform |
||||
if (WIN32) |
||||
set(_FINDPACKAGE_PROTOBUF_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf/cmake") |
||||
else() |
||||
set(_FINDPACKAGE_PROTOBUF_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf/lib/cmake/protobuf") |
||||
endif() |
||||
|
||||
# if OPENSSL_ROOT_DIR is set, propagate that hint path to the external projects with OpenSSL dependency. |
||||
set(_CMAKE_ARGS_OPENSSL_ROOT_DIR "") |
||||
if (OPENSSL_ROOT_DIR) |
||||
set(_CMAKE_ARGS_OPENSSL_ROOT_DIR "-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR}") |
||||
endif() |
||||
|
||||
# Builds gRPC based on locally checked-out sources and set arguments so that all the dependencies |
||||
# are correctly located. |
||||
ExternalProject_Add(grpc |
||||
PREFIX grpc |
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../.." |
||||
CMAKE_CACHE_ARGS |
||||
-DgRPC_INSTALL:BOOL=ON |
||||
-DgRPC_BUILD_TESTS:BOOL=OFF |
||||
-DgRPC_PROTOBUF_PROVIDER:STRING=package |
||||
-DgRPC_PROTOBUF_PACKAGE_TYPE:STRING=CONFIG |
||||
-DProtobuf_DIR:PATH=${_FINDPACKAGE_PROTOBUF_CONFIG_DIR} |
||||
-DgRPC_ZLIB_PROVIDER:STRING=package |
||||
-DZLIB_ROOT:STRING=${CMAKE_CURRENT_BINARY_DIR}/zlib |
||||
-DgRPC_CARES_PROVIDER:STRING=package |
||||
-Dc-ares_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/c-ares/lib/cmake/c-ares |
||||
-DgRPC_SSL_PROVIDER:STRING=package |
||||
${_CMAKE_ARGS_OPENSSL_ROOT_DIR} |
||||
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/grpc |
||||
DEPENDS c-ares protobuf zlib |
||||
) |
||||
|
||||
# Build the helloworld projects itself using a CMakeLists.txt that assumes all the dependencies |
||||
# have already been installed. |
||||
# Even though helloworld is not really an "external project" from perspective of this build, |
||||
# we are still importing it using ExternalProject_Add because that allows us to use find_package() |
||||
# to locate all the dependencies (if we were building helloworld directly in this build we, |
||||
# we would have needed to manually import the libraries as opposed to reusing targets exported by |
||||
# gRPC and protobuf). |
||||
ExternalProject_Add(helloworld |
||||
PREFIX helloworld |
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." |
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/helloworld" |
||||
INSTALL_COMMAND "" |
||||
CMAKE_CACHE_ARGS |
||||
-DProtobuf_DIR:PATH=${_FINDPACKAGE_PROTOBUF_CONFIG_DIR} |
||||
-Dc-ares_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/c-ares/lib/cmake/c-ares |
||||
-DZLIB_ROOT:STRING=${CMAKE_CURRENT_BINARY_DIR}/zlib |
||||
${_CMAKE_ARGS_OPENSSL_ROOT_DIR} |
||||
-DgRPC_DIR:PATH=${CMAKE_CURRENT_BINARY_DIR}/grpc/lib/cmake/grpc |
||||
DEPENDS protobuf grpc |
||||
) |
@ -1,5 +0,0 @@ |
||||
{ |
||||
"sdk": { |
||||
"version": "1.0.0" |
||||
} |
||||
} |
@ -0,0 +1,151 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_READER_H |
||||
#define GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_READER_H |
||||
|
||||
#include <type_traits> |
||||
|
||||
#include <grpc/impl/codegen/byte_buffer_reader.h> |
||||
#include <grpc/impl/codegen/grpc_types.h> |
||||
#include <grpc/impl/codegen/slice.h> |
||||
#include <grpcpp/impl/codegen/byte_buffer.h> |
||||
#include <grpcpp/impl/codegen/config_protobuf.h> |
||||
#include <grpcpp/impl/codegen/core_codegen_interface.h> |
||||
#include <grpcpp/impl/codegen/serialization_traits.h> |
||||
#include <grpcpp/impl/codegen/status.h> |
||||
|
||||
/// This header provides an object that reads bytes directly from a
|
||||
/// grpc::ByteBuffer, via the ZeroCopyInputStream interface
|
||||
|
||||
namespace grpc { |
||||
|
||||
extern CoreCodegenInterface* g_core_codegen_interface; |
||||
|
||||
/// This is a specialization of the protobuf class ZeroCopyInputStream
|
||||
/// The principle is to get one chunk of data at a time from the proto layer,
|
||||
/// with options to backup (re-see some bytes) or skip (forward past some bytes)
|
||||
///
|
||||
/// Read more about ZeroCopyInputStream interface here:
|
||||
/// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream
|
||||
class ProtoBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream { |
||||
public: |
||||
/// 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).
|
||||
explicit ProtoBufferReader(ByteBuffer* buffer) |
||||
: byte_count_(0), backup_count_(0), status_() { |
||||
/// Implemented through a grpc_byte_buffer_reader which iterates
|
||||
/// over the slices that make up a byte buffer
|
||||
if (!buffer->Valid() || |
||||
!g_core_codegen_interface->grpc_byte_buffer_reader_init( |
||||
&reader_, buffer->c_buffer())) { |
||||
status_ = Status(StatusCode::INTERNAL, |
||||
"Couldn't initialize byte buffer reader"); |
||||
} |
||||
} |
||||
|
||||
~ProtoBufferReader() { |
||||
if (status_.ok()) { |
||||
g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_); |
||||
} |
||||
} |
||||
|
||||
/// Give the proto library a chunk of data from the stream. The caller
|
||||
/// may safely read from data[0, size - 1].
|
||||
bool Next(const void** data, int* size) override { |
||||
if (!status_.ok()) { |
||||
return false; |
||||
} |
||||
/// If we have backed up previously, we need to return the backed-up slice
|
||||
if (backup_count_ > 0) { |
||||
*data = GRPC_SLICE_START_PTR(slice_) + GRPC_SLICE_LENGTH(slice_) - |
||||
backup_count_; |
||||
GPR_CODEGEN_ASSERT(backup_count_ <= INT_MAX); |
||||
*size = (int)backup_count_; |
||||
backup_count_ = 0; |
||||
return true; |
||||
} |
||||
/// Otherwise get the next slice from the byte buffer reader
|
||||
if (!g_core_codegen_interface->grpc_byte_buffer_reader_next(&reader_, |
||||
&slice_)) { |
||||
return false; |
||||
} |
||||
g_core_codegen_interface->grpc_slice_unref(slice_); |
||||
*data = GRPC_SLICE_START_PTR(slice_); |
||||
// On win x64, int is only 32bit
|
||||
GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX); |
||||
byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_); |
||||
return true; |
||||
} |
||||
|
||||
/// Returns the status of the buffer reader.
|
||||
Status status() const { return status_; } |
||||
|
||||
/// The proto library calls this to indicate that we should back up \a count
|
||||
/// bytes that have already been returned by the last call of Next.
|
||||
/// So do the backup and have that ready for a later Next.
|
||||
void BackUp(int count) override { |
||||
GPR_CODEGEN_ASSERT(count <= static_cast<int>(GRPC_SLICE_LENGTH(slice_))); |
||||
backup_count_ = count; |
||||
} |
||||
|
||||
/// The proto library calls this to skip over \a count bytes. Implement this
|
||||
/// using Next and BackUp combined.
|
||||
bool Skip(int count) override { |
||||
const void* data; |
||||
int size; |
||||
while (Next(&data, &size)) { |
||||
if (size >= count) { |
||||
BackUp(size - count); |
||||
return true; |
||||
} |
||||
// size < count;
|
||||
count -= size; |
||||
} |
||||
// error or we have too large count;
|
||||
return false; |
||||
} |
||||
|
||||
/// Returns the total number of bytes read since this object was created.
|
||||
grpc::protobuf::int64 ByteCount() const override { |
||||
return byte_count_ - backup_count_; |
||||
} |
||||
|
||||
// These protected members are needed to support internal optimizations.
|
||||
// they expose internal bits of grpc core that are NOT stable. If you have
|
||||
// a use case needs to use one of these functions, please send an email to
|
||||
// https://groups.google.com/forum/#!forum/grpc-io.
|
||||
protected: |
||||
void set_byte_count(int64_t byte_count) { byte_count_ = byte_count; } |
||||
int64_t backup_count() { return backup_count_; } |
||||
void set_backup_count(int64_t backup_count) { backup_count_ = backup_count; } |
||||
grpc_byte_buffer_reader* reader() { return &reader_; } |
||||
grpc_slice* slice() { return &slice_; } |
||||
|
||||
private: |
||||
int64_t byte_count_; ///< total bytes read since object creation
|
||||
int64_t backup_count_; ///< how far backed up in the stream we are
|
||||
grpc_byte_buffer_reader reader_; ///< internal object to read \a grpc_slice
|
||||
///< from the \a grpc_byte_buffer
|
||||
grpc_slice slice_; ///< current slice passed back to the caller
|
||||
Status status_; ///< status of the entire object
|
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_READER_H
|
@ -0,0 +1,167 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_WRITER_H |
||||
#define GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_WRITER_H |
||||
|
||||
#include <type_traits> |
||||
|
||||
#include <grpc/impl/codegen/grpc_types.h> |
||||
#include <grpc/impl/codegen/slice.h> |
||||
#include <grpcpp/impl/codegen/byte_buffer.h> |
||||
#include <grpcpp/impl/codegen/config_protobuf.h> |
||||
#include <grpcpp/impl/codegen/core_codegen_interface.h> |
||||
#include <grpcpp/impl/codegen/serialization_traits.h> |
||||
#include <grpcpp/impl/codegen/status.h> |
||||
|
||||
/// This header provides an object that writes bytes directly into a
|
||||
/// grpc::ByteBuffer, via the ZeroCopyOutputStream interface
|
||||
|
||||
namespace grpc { |
||||
|
||||
extern CoreCodegenInterface* g_core_codegen_interface; |
||||
|
||||
// Forward declaration for testing use only
|
||||
namespace internal { |
||||
class ProtoBufferWriterPeer; |
||||
} // namespace internal
|
||||
|
||||
const int kProtoBufferWriterMaxBufferLength = 1024 * 1024; |
||||
|
||||
/// This is a specialization of the protobuf class ZeroCopyOutputStream.
|
||||
/// The principle is to give the proto layer one buffer of bytes at a time
|
||||
/// that it can use to serialize the next portion of the message, with the
|
||||
/// option to "backup" if more buffer is given than required at the last buffer.
|
||||
///
|
||||
/// Read more about ZeroCopyOutputStream interface here:
|
||||
/// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyOutputStream
|
||||
class ProtoBufferWriter : public ::grpc::protobuf::io::ZeroCopyOutputStream { |
||||
public: |
||||
/// Constructor for this derived class
|
||||
///
|
||||
/// \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 total_size How many total bytes are required for this proto
|
||||
ProtoBufferWriter(ByteBuffer* byte_buffer, int block_size, int total_size) |
||||
: block_size_(block_size), |
||||
total_size_(total_size), |
||||
byte_count_(0), |
||||
have_backup_(false) { |
||||
GPR_CODEGEN_ASSERT(!byte_buffer->Valid()); |
||||
/// Create an empty raw byte buffer and look at its underlying slice buffer
|
||||
grpc_byte_buffer* bp = |
||||
g_core_codegen_interface->grpc_raw_byte_buffer_create(NULL, 0); |
||||
byte_buffer->set_buffer(bp); |
||||
slice_buffer_ = &bp->data.raw.slice_buffer; |
||||
} |
||||
|
||||
~ProtoBufferWriter() { |
||||
if (have_backup_) { |
||||
g_core_codegen_interface->grpc_slice_unref(backup_slice_); |
||||
} |
||||
} |
||||
|
||||
/// Give the proto library the next buffer of bytes and its size. It is
|
||||
/// safe for the caller to write from data[0, size - 1].
|
||||
bool Next(void** data, int* size) override { |
||||
// Protobuf should not ask for more memory than total_size_.
|
||||
GPR_CODEGEN_ASSERT(byte_count_ < total_size_); |
||||
// 1. Use the remaining backup slice if we have one
|
||||
// 2. Otherwise allocate a slice, up to the remaining length needed
|
||||
// or our maximum allocation size
|
||||
// 3. Provide the slice start and size available
|
||||
// 4. Add the slice being returned to the slice buffer
|
||||
size_t remain = total_size_ - byte_count_; |
||||
if (have_backup_) { |
||||
/// If we have a backup slice, we should use it first
|
||||
slice_ = backup_slice_; |
||||
have_backup_ = false; |
||||
if (GRPC_SLICE_LENGTH(slice_) > remain) { |
||||
GRPC_SLICE_SET_LENGTH(slice_, remain); |
||||
} |
||||
} else { |
||||
// When less than a whole block is needed, only allocate that much.
|
||||
// But make sure the allocated slice is not inlined.
|
||||
size_t allocate_length = |
||||
remain > static_cast<size_t>(block_size_) ? block_size_ : remain; |
||||
slice_ = g_core_codegen_interface->grpc_slice_malloc( |
||||
allocate_length > GRPC_SLICE_INLINED_SIZE |
||||
? allocate_length |
||||
: GRPC_SLICE_INLINED_SIZE + 1); |
||||
} |
||||
*data = GRPC_SLICE_START_PTR(slice_); |
||||
// On win x64, int is only 32bit
|
||||
GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX); |
||||
byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_); |
||||
g_core_codegen_interface->grpc_slice_buffer_add(slice_buffer_, slice_); |
||||
return true; |
||||
} |
||||
|
||||
/// Backup by \a count bytes because Next returned more bytes than needed
|
||||
/// (only used in the last buffer). \a count must be less than or equal too
|
||||
/// the last buffer returned from next.
|
||||
void BackUp(int count) override { |
||||
/// 1. Remove the partially-used last slice from the slice buffer
|
||||
/// 2. Split it into the needed (if any) and unneeded part
|
||||
/// 3. Add the needed part back to the slice buffer
|
||||
/// 4. Mark that we still have the remaining part (for later use/unref)
|
||||
GPR_CODEGEN_ASSERT(count <= static_cast<int>(GRPC_SLICE_LENGTH(slice_))); |
||||
g_core_codegen_interface->grpc_slice_buffer_pop(slice_buffer_); |
||||
if ((size_t)count == GRPC_SLICE_LENGTH(slice_)) { |
||||
backup_slice_ = slice_; |
||||
} else { |
||||
backup_slice_ = g_core_codegen_interface->grpc_slice_split_tail( |
||||
&slice_, GRPC_SLICE_LENGTH(slice_) - count); |
||||
g_core_codegen_interface->grpc_slice_buffer_add(slice_buffer_, slice_); |
||||
} |
||||
// It's dangerous to keep an inlined grpc_slice as the backup slice, since
|
||||
// on a following Next() call, a reference will be returned to this slice
|
||||
// via GRPC_SLICE_START_PTR, which will not be an address held by
|
||||
// slice_buffer_.
|
||||
have_backup_ = backup_slice_.refcount != NULL; |
||||
byte_count_ -= count; |
||||
} |
||||
|
||||
/// Returns the total number of bytes written since this object was created.
|
||||
grpc::protobuf::int64 ByteCount() const override { return byte_count_; } |
||||
|
||||
// These protected members are needed to support internal optimizations.
|
||||
// they expose internal bits of grpc core that are NOT stable. If you have
|
||||
// a use case needs to use one of these functions, please send an email to
|
||||
// https://groups.google.com/forum/#!forum/grpc-io.
|
||||
protected: |
||||
grpc_slice_buffer* slice_buffer() { return slice_buffer_; } |
||||
void set_byte_count(int64_t byte_count) { byte_count_ = byte_count; } |
||||
|
||||
private: |
||||
// friend for testing purposes only
|
||||
friend class internal::ProtoBufferWriterPeer; |
||||
const int block_size_; ///< size to alloc for each new \a grpc_slice needed
|
||||
const int total_size_; ///< byte size of proto being serialized
|
||||
int64_t byte_count_; ///< bytes written since this object was created
|
||||
grpc_slice_buffer* |
||||
slice_buffer_; ///< internal buffer of slices holding the serialized data
|
||||
bool have_backup_; ///< if we are holding a backup slice or not
|
||||
grpc_slice backup_slice_; ///< holds space we can still write to, if the
|
||||
///< caller has called BackUp
|
||||
grpc_slice slice_; ///< current slice passed back to the caller
|
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_WRITER_H
|
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_SUPPORT_PROTO_BUFFER_READER_H |
||||
#define GRPCPP_SUPPORT_PROTO_BUFFER_READER_H |
||||
|
||||
#include <grpcpp/impl/codegen/proto_buffer_reader.h> |
||||
|
||||
#endif // GRPCPP_SUPPORT_PROTO_BUFFER_READER_H
|
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_SUPPORT_PROTO_BUFFER_WRITER_H |
||||
#define GRPCPP_SUPPORT_PROTO_BUFFER_WRITER_H |
||||
|
||||
#include <grpcpp/impl/codegen/proto_buffer_writer.h> |
||||
|
||||
#endif // GRPCPP_SUPPORT_PROTO_BUFFER_WRITER_H
|
@ -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 @@ |
||||
/build |
@ -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> |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 4.7 KiB |
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 |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue