diff --git a/.gitmodules b/.gitmodules index 97b7197be32..557321001f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,4 +11,4 @@ branch = v3.0.0-alpha-1 [submodule "third_party/gflags"] path = third_party/gflags - url = https://code.google.com/p/gflags + url = https://github.com/gflags/gflags.git diff --git a/BUILD b/BUILD index 43017102a10..e69de29bb2d 100644 --- a/BUILD +++ b/BUILD @@ -1,567 +0,0 @@ -# GRPC Bazel BUILD file. -# This currently builds C and C++ code. - -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -licenses(["notice"]) # 3-clause BSD - - - -cc_library( - name = "gpr", - srcs = [ - "src/core/support/env.h", - "src/core/support/file.h", - "src/core/support/murmur_hash.h", - "src/core/support/string.h", - "src/core/support/string_win32.h", - "src/core/support/thd_internal.h", - "src/core/support/alloc.c", - "src/core/support/cancellable.c", - "src/core/support/cmdline.c", - "src/core/support/cpu_iphone.c", - "src/core/support/cpu_linux.c", - "src/core/support/cpu_posix.c", - "src/core/support/cpu_windows.c", - "src/core/support/env_linux.c", - "src/core/support/env_posix.c", - "src/core/support/env_win32.c", - "src/core/support/file.c", - "src/core/support/file_posix.c", - "src/core/support/file_win32.c", - "src/core/support/histogram.c", - "src/core/support/host_port.c", - "src/core/support/log.c", - "src/core/support/log_android.c", - "src/core/support/log_linux.c", - "src/core/support/log_posix.c", - "src/core/support/log_win32.c", - "src/core/support/murmur_hash.c", - "src/core/support/slice.c", - "src/core/support/slice_buffer.c", - "src/core/support/string.c", - "src/core/support/string_posix.c", - "src/core/support/string_win32.c", - "src/core/support/sync.c", - "src/core/support/sync_posix.c", - "src/core/support/sync_win32.c", - "src/core/support/thd_posix.c", - "src/core/support/thd_win32.c", - "src/core/support/time.c", - "src/core/support/time_posix.c", - "src/core/support/time_win32.c", - ], - hdrs = [ - "include/grpc/support/alloc.h", - "include/grpc/support/atm.h", - "include/grpc/support/atm_gcc_atomic.h", - "include/grpc/support/atm_gcc_sync.h", - "include/grpc/support/atm_win32.h", - "include/grpc/support/cancellable_platform.h", - "include/grpc/support/cmdline.h", - "include/grpc/support/cpu.h", - "include/grpc/support/histogram.h", - "include/grpc/support/host_port.h", - "include/grpc/support/log.h", - "include/grpc/support/log_win32.h", - "include/grpc/support/port_platform.h", - "include/grpc/support/slice.h", - "include/grpc/support/slice_buffer.h", - "include/grpc/support/sync.h", - "include/grpc/support/sync_generic.h", - "include/grpc/support/sync_posix.h", - "include/grpc/support/sync_win32.h", - "include/grpc/support/thd.h", - "include/grpc/support/time.h", - "include/grpc/support/useful.h", - ], - includes = [ - "include", - ".", - ], - deps = [ - ], -) - - - - -cc_library( - name = "grpc", - srcs = [ - "src/core/httpcli/format_request.h", - "src/core/httpcli/httpcli.h", - "src/core/httpcli/httpcli_security_context.h", - "src/core/httpcli/parser.h", - "src/core/security/auth.h", - "src/core/security/base64.h", - "src/core/security/credentials.h", - "src/core/security/json_token.h", - "src/core/security/secure_endpoint.h", - "src/core/security/secure_transport_setup.h", - "src/core/security/security_context.h", - "src/core/tsi/fake_transport_security.h", - "src/core/tsi/ssl_transport_security.h", - "src/core/tsi/transport_security.h", - "src/core/tsi/transport_security_interface.h", - "src/core/channel/census_filter.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/child_channel.h", - "src/core/channel/client_channel.h", - "src/core/channel/client_setup.h", - "src/core/channel/connected_channel.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/metadata_buffer.h", - "src/core/channel/noop_filter.h", - "src/core/compression/algorithm.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/iomgr/alarm.h", - "src/core/iomgr/alarm_heap.h", - "src/core/iomgr/alarm_internal.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_kick.h", - "src/core/iomgr/pollset_kick_posix.h", - "src/core/iomgr/pollset_kick_windows.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_log.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/statistics/census_tracing.h", - "src/core/statistics/hash_table.h", - "src/core/statistics/window_stats.h", - "src/core/surface/byte_buffer_queue.h", - "src/core/surface/call.h", - "src/core/surface/channel.h", - "src/core/surface/client.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_encoder.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/metadata.h", - "src/core/transport/stream_op.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/httpcli/format_request.c", - "src/core/httpcli/httpcli.c", - "src/core/httpcli/httpcli_security_context.c", - "src/core/httpcli/parser.c", - "src/core/security/auth.c", - "src/core/security/base64.c", - "src/core/security/credentials.c", - "src/core/security/credentials_posix.c", - "src/core/security/credentials_win32.c", - "src/core/security/factories.c", - "src/core/security/google_default_credentials.c", - "src/core/security/json_token.c", - "src/core/security/secure_endpoint.c", - "src/core/security/secure_transport_setup.c", - "src/core/security/security_context.c", - "src/core/security/server_secure_chttp2.c", - "src/core/surface/init_secure.c", - "src/core/surface/secure_channel_create.c", - "src/core/tsi/fake_transport_security.c", - "src/core/tsi/ssl_transport_security.c", - "src/core/tsi/transport_security.c", - "src/core/channel/call_op_string.c", - "src/core/channel/census_filter.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_stack.c", - "src/core/channel/child_channel.c", - "src/core/channel/client_channel.c", - "src/core/channel/client_setup.c", - "src/core/channel/connected_channel.c", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_filter.c", - "src/core/channel/http_server_filter.c", - "src/core/channel/metadata_buffer.c", - "src/core/channel/noop_filter.c", - "src/core/compression/algorithm.c", - "src/core/compression/message_compress.c", - "src/core/debug/trace.c", - "src/core/iomgr/alarm.c", - "src/core/iomgr/alarm_heap.c", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset_kick.c", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/json/json.c", - "src/core/json/json_reader.c", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/statistics/census_init.c", - "src/core/statistics/census_log.c", - "src/core/statistics/census_rpc_stats.c", - "src/core/statistics/census_tracing.c", - "src/core/statistics/hash_table.c", - "src/core/statistics/window_stats.c", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_queue.c", - "src/core/surface/byte_buffer_reader.c", - "src/core/surface/call.c", - "src/core/surface/call_details.c", - "src/core/surface/call_log_batch.c", - "src/core/surface/channel.c", - "src/core/surface/channel_create.c", - "src/core/surface/client.c", - "src/core/surface/completion_queue.c", - "src/core/surface/event_string.c", - "src/core/surface/init.c", - "src/core/surface/lame_client.c", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server_chttp2.c", - "src/core/surface/server_create.c", - "src/core/surface/surface_trace.c", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/stream_encoder.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/metadata.c", - "src/core/transport/stream_op.c", - "src/core/transport/transport.c", - ], - hdrs = [ - "include/grpc/grpc_security.h", - "include/grpc/byte_buffer.h", - "include/grpc/byte_buffer_reader.h", - "include/grpc/grpc.h", - "include/grpc/grpc_http.h", - "include/grpc/status.h", - ], - includes = [ - "include", - ".", - ], - deps = [ - ":gpr", - ], -) - - - - -cc_library( - name = "grpc_unsecure", - srcs = [ - "src/core/channel/census_filter.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/child_channel.h", - "src/core/channel/client_channel.h", - "src/core/channel/client_setup.h", - "src/core/channel/connected_channel.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/metadata_buffer.h", - "src/core/channel/noop_filter.h", - "src/core/compression/algorithm.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/iomgr/alarm.h", - "src/core/iomgr/alarm_heap.h", - "src/core/iomgr/alarm_internal.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_kick.h", - "src/core/iomgr/pollset_kick_posix.h", - "src/core/iomgr/pollset_kick_windows.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_log.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/statistics/census_tracing.h", - "src/core/statistics/hash_table.h", - "src/core/statistics/window_stats.h", - "src/core/surface/byte_buffer_queue.h", - "src/core/surface/call.h", - "src/core/surface/channel.h", - "src/core/surface/client.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_encoder.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/metadata.h", - "src/core/transport/stream_op.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/surface/init_unsecure.c", - "src/core/channel/call_op_string.c", - "src/core/channel/census_filter.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_stack.c", - "src/core/channel/child_channel.c", - "src/core/channel/client_channel.c", - "src/core/channel/client_setup.c", - "src/core/channel/connected_channel.c", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_filter.c", - "src/core/channel/http_server_filter.c", - "src/core/channel/metadata_buffer.c", - "src/core/channel/noop_filter.c", - "src/core/compression/algorithm.c", - "src/core/compression/message_compress.c", - "src/core/debug/trace.c", - "src/core/iomgr/alarm.c", - "src/core/iomgr/alarm_heap.c", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset_kick.c", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/json/json.c", - "src/core/json/json_reader.c", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/statistics/census_init.c", - "src/core/statistics/census_log.c", - "src/core/statistics/census_rpc_stats.c", - "src/core/statistics/census_tracing.c", - "src/core/statistics/hash_table.c", - "src/core/statistics/window_stats.c", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_queue.c", - "src/core/surface/byte_buffer_reader.c", - "src/core/surface/call.c", - "src/core/surface/call_details.c", - "src/core/surface/call_log_batch.c", - "src/core/surface/channel.c", - "src/core/surface/channel_create.c", - "src/core/surface/client.c", - "src/core/surface/completion_queue.c", - "src/core/surface/event_string.c", - "src/core/surface/init.c", - "src/core/surface/lame_client.c", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server_chttp2.c", - "src/core/surface/server_create.c", - "src/core/surface/surface_trace.c", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/stream_encoder.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/metadata.c", - "src/core/transport/stream_op.c", - "src/core/transport/transport.c", - ], - hdrs = [ - "include/grpc/byte_buffer.h", - "include/grpc/byte_buffer_reader.h", - "include/grpc/grpc.h", - "include/grpc/grpc_http.h", - "include/grpc/status.h", - ], - includes = [ - "include", - ".", - ], - deps = [ - ":gpr", - ], -) - - - - diff --git a/Makefile b/Makefile index cbf7c4dd40e..83e4e834b59 100644 --- a/Makefile +++ b/Makefile @@ -227,7 +227,6 @@ ifeq ($(HAS_CXX11),true) CXXFLAGS += -std=c++11 else CXXFLAGS += -std=c++0x -DEFINES += GRPC_OLD_CXX endif CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter LDFLAGS += -g @@ -285,7 +284,7 @@ E = @echo Q = @ endif -VERSION = 0.5.0.0 +VERSION = 0.6.0.0 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) @@ -456,7 +455,7 @@ endif .SECONDARY = %.pb.h %.pb.cc -PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin +PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin ifeq ($(DEP_MISSING),) all: static shared plugins dep_error: @@ -584,6 +583,7 @@ gpr_string_test: $(BINDIR)/$(CONFIG)/gpr_string_test gpr_sync_test: $(BINDIR)/$(CONFIG)/gpr_sync_test gpr_thd_test: $(BINDIR)/$(CONFIG)/gpr_thd_test gpr_time_test: $(BINDIR)/$(CONFIG)/gpr_time_test +gpr_tls_test: $(BINDIR)/$(CONFIG)/gpr_tls_test gpr_useful_test: $(BINDIR)/$(CONFIG)/gpr_useful_test grpc_base64_test: $(BINDIR)/$(CONFIG)/grpc_base64_test grpc_byte_buffer_reader_test: $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test @@ -632,6 +632,7 @@ end2end_test: $(BINDIR)/$(CONFIG)/end2end_test generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin +grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin interop_client: $(BINDIR)/$(CONFIG)/interop_client @@ -641,6 +642,7 @@ pubsub_client: $(BINDIR)/$(CONFIG)/pubsub_client pubsub_publisher_test: $(BINDIR)/$(CONFIG)/pubsub_publisher_test pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test qps_driver: $(BINDIR)/$(CONFIG)/qps_driver +qps_smoke_test: $(BINDIR)/$(CONFIG)/qps_smoke_test qps_worker: $(BINDIR)/$(CONFIG)/qps_worker status_test: $(BINDIR)/$(CONFIG)/status_test thread_pool_test: $(BINDIR)/$(CONFIG)/thread_pool_test @@ -1075,13 +1077,13 @@ privatelibs: privatelibs_c privatelibs_cxx privatelibs_c: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_thread_stress.a $(LIBDIR)/$(CONFIG)/libend2end_test_writes_done_hangs_with_pending_read.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_thread_stress_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_writes_done_hangs_with_pending_read_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a -privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libqps.a +privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libqps.a buildtests: buildtests_c buildtests_cxx -buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test +buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test -buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test +buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_smoke_test $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test test: test_c test_cxx @@ -1156,6 +1158,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/gpr_thd_test || ( echo test gpr_thd_test failed ; exit 1 ) $(E) "[RUN] Testing gpr_time_test" $(Q) $(BINDIR)/$(CONFIG)/gpr_time_test || ( echo test gpr_time_test failed ; exit 1 ) + $(E) "[RUN] Testing gpr_tls_test" + $(Q) $(BINDIR)/$(CONFIG)/gpr_tls_test || ( echo test gpr_tls_test failed ; exit 1 ) $(E) "[RUN] Testing gpr_useful_test" $(Q) $(BINDIR)/$(CONFIG)/gpr_useful_test || ( echo test gpr_useful_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_base64_test" @@ -2001,92 +2005,152 @@ endif ifeq ($(NO_PROTOC),true) $(GENDIR)/examples/pubsub/empty.pb.cc: protoc_dep_error +$(GENDIR)/examples/pubsub/empty.grpc.pb.cc: protoc_dep_error else $(GENDIR)/examples/pubsub/empty.pb.cc: examples/pubsub/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/examples/pubsub/empty.grpc.pb.cc: examples/pubsub/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/examples/pubsub/label.pb.cc: protoc_dep_error +$(GENDIR)/examples/pubsub/label.grpc.pb.cc: protoc_dep_error else $(GENDIR)/examples/pubsub/label.pb.cc: examples/pubsub/label.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/examples/pubsub/label.grpc.pb.cc: examples/pubsub/label.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/examples/pubsub/pubsub.pb.cc: protoc_dep_error +$(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: protoc_dep_error else $(GENDIR)/examples/pubsub/pubsub.pb.cc: examples/pubsub/pubsub.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: examples/pubsub/pubsub.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/interop/empty.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/interop/empty.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/interop/empty.pb.cc: test/cpp/interop/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/interop/empty.grpc.pb.cc: test/cpp/interop/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/interop/messages.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/interop/messages.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/interop/messages.pb.cc: test/cpp/interop/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/interop/messages.grpc.pb.cc: test/cpp/interop/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/interop/test.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/interop/test.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/interop/test.pb.cc: test/cpp/interop/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/interop/test.grpc.pb.cc: test/cpp/interop/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/qps/qpstest.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/qps/qpstest.pb.cc: test/cpp/qps/qpstest.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc: test/cpp/qps/qpstest.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/util/echo.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/util/echo.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/util/echo.pb.cc: test/cpp/util/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/util/echo.grpc.pb.cc: test/cpp/util/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc: test/cpp/util/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc: test/cpp/util/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/util/messages.pb.cc: protoc_dep_error +$(GENDIR)/test/cpp/util/messages.grpc.pb.cc: protoc_dep_error else $(GENDIR)/test/cpp/util/messages.pb.cc: test/cpp/util/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/test/cpp/util/messages.grpc.pb.cc: test/cpp/util/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif @@ -2163,10 +2227,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(prefix)/lib/gpr.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr-imp.a $(prefix)/lib/libgpr-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing libgpr.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so.0 $(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so endif endif @@ -2176,10 +2241,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(prefix)/lib/grpc.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc-imp.a $(prefix)/lib/libgrpc-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing libgrpc.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so.0 $(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so endif endif @@ -2189,10 +2255,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT) $(prefix)/lib/grpc_unsecure.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure-imp.a $(prefix)/lib/libgrpc_unsecure-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing libgrpc_unsecure.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so.0 $(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so endif endif @@ -2210,10 +2277,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT) $(prefix)/lib/grpc++.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++-imp.a $(prefix)/lib/libgrpc++-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing libgrpc++.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.0 $(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so endif endif @@ -2223,10 +2291,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/grpc++_unsecure.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure-imp.a $(prefix)/lib/libgrpc++_unsecure-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing libgrpc++_unsecure.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so.0 $(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so endif endif @@ -2244,10 +2313,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/grpc_csharp_ext.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext-imp.a $(prefix)/lib/libgrpc_csharp_ext-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing libgrpc_csharp_ext.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so.0 $(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so endif endif @@ -2266,6 +2336,8 @@ else $(Q) $(INSTALL) -d $(prefix)/bin $(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(prefix)/bin/grpc_cpp_plugin $(Q) $(INSTALL) -d $(prefix)/bin + $(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(prefix)/bin/grpc_objective_c_plugin + $(Q) $(INSTALL) -d $(prefix)/bin $(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_python_plugin $(prefix)/bin/grpc_python_plugin $(Q) $(INSTALL) -d $(prefix)/bin $(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin @@ -2334,6 +2406,7 @@ LIBGPR_SRC = \ src/core/support/sync.c \ src/core/support/sync_posix.c \ src/core/support/sync_win32.c \ + src/core/support/thd.c \ src/core/support/thd_posix.c \ src/core/support/thd_win32.c \ src/core/support/time.c \ @@ -2362,6 +2435,10 @@ PUBLIC_HEADERS_C += \ include/grpc/support/sync_win32.h \ include/grpc/support/thd.h \ include/grpc/support/time.h \ + include/grpc/support/tls.h \ + include/grpc/support/tls_gcc.h \ + include/grpc/support/tls_msvc.h \ + include/grpc/support/tls_pthread.h \ include/grpc/support/useful.h \ LIBGPR_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_SRC)))) @@ -2387,7 +2464,7 @@ $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT): $(LIBGPR_OBJS) $(ZLIB_DEP) $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) + $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgpr.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) else $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.0 -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(Q) ln -sf libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr.so.0 @@ -2428,6 +2505,7 @@ $(OBJDIR)/$(CONFIG)/src/core/support/string_win32.o: $(OBJDIR)/$(CONFIG)/src/core/support/sync.o: $(OBJDIR)/$(CONFIG)/src/core/support/sync_posix.o: $(OBJDIR)/$(CONFIG)/src/core/support/sync_win32.o: +$(OBJDIR)/$(CONFIG)/src/core/support/thd.o: $(OBJDIR)/$(CONFIG)/src/core/support/thd_posix.o: $(OBJDIR)/$(CONFIG)/src/core/support/thd_win32.o: $(OBJDIR)/$(CONFIG)/src/core/support/time.o: @@ -2778,7 +2856,7 @@ $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT): $(LIBGRPC_OBJS) $(ZLIB_DEP) $(LIBDIR $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr + $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr else $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr $(Q) ln -sf libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.so.0 @@ -3123,7 +3201,7 @@ $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS) $( $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) -lgpr + $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_unsecure.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) -lgpr else $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) -lgpr $(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.so.0 @@ -3281,6 +3359,12 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/rpc_method.h \ include/grpc++/impl/rpc_service_method.h \ include/grpc++/impl/service_type.h \ + include/grpc++/impl/sync.h \ + include/grpc++/impl/sync_cxx11.h \ + include/grpc++/impl/sync_no_cxx11.h \ + include/grpc++/impl/thd.h \ + include/grpc++/impl/thd_cxx11.h \ + include/grpc++/impl/thd_no_cxx11.h \ include/grpc++/server.h \ include/grpc++/server_builder.h \ include/grpc++/server_context.h \ @@ -3374,7 +3458,7 @@ $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT): $(LIBGRPC++_OBJS) $(ZLIB_DEP) $(LI $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc + $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc++.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc else $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc $(Q) ln -sf libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++.so.0 @@ -3421,9 +3505,9 @@ $(OBJDIR)/$(CONFIG)/src/cpp/util/time.o: LIBGRPC++_TEST_UTIL_SRC = \ - $(GENDIR)/test/cpp/util/messages.pb.cc \ - $(GENDIR)/test/cpp/util/echo.pb.cc \ - $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc \ + $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc \ + $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc \ + $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc \ test/cpp/util/cli_call.cc \ test/cpp/util/create_test_channel.cc \ @@ -3484,8 +3568,8 @@ endif -$(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc LIBGRPC++_UNSECURE_SRC = \ @@ -3532,6 +3616,12 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/rpc_method.h \ include/grpc++/impl/rpc_service_method.h \ include/grpc++/impl/service_type.h \ + include/grpc++/impl/sync.h \ + include/grpc++/impl/sync_cxx11.h \ + include/grpc++/impl/sync_no_cxx11.h \ + include/grpc++/impl/thd.h \ + include/grpc++/impl/thd_cxx11.h \ + include/grpc++/impl/thd_no_cxx11.h \ include/grpc++/server.h \ include/grpc++/server_builder.h \ include/grpc++/server_context.h \ @@ -3579,7 +3669,7 @@ $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS) $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure + $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc++_unsecure.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure else $(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure $(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.so.0 @@ -3621,6 +3711,7 @@ $(OBJDIR)/$(CONFIG)/src/cpp/util/time.o: LIBGRPC_PLUGIN_SUPPORT_SRC = \ src/compiler/cpp_generator.cc \ + src/compiler/objective_c_generator.cc \ src/compiler/python_generator.cc \ src/compiler/ruby_generator.cc \ @@ -3655,14 +3746,139 @@ ifneq ($(NO_DEPS),true) endif $(OBJDIR)/$(CONFIG)/src/compiler/cpp_generator.o: +$(OBJDIR)/$(CONFIG)/src/compiler/objective_c_generator.o: $(OBJDIR)/$(CONFIG)/src/compiler/python_generator.o: $(OBJDIR)/$(CONFIG)/src/compiler/ruby_generator.o: +LIBINTEROP_CLIENT_LIB_SRC = \ + $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \ + $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \ + $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \ + test/cpp/interop/client_helper.cc \ + test/cpp/interop/interop_client.cc \ + + +LIBINTEROP_CLIENT_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_CLIENT_LIB_SRC)))) + +ifeq ($(NO_SECURE),true) + +# You can't build secure libraries if you don't have OpenSSL with ALPN. + +$(LIBDIR)/$(CONFIG)/libinterop_client_lib.a: openssl_dep_error + + +else + +ifeq ($(NO_PROTOBUF),true) + +# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay. + +$(LIBDIR)/$(CONFIG)/libinterop_client_lib.a: protobuf_dep_error + + +else + +ifneq ($(OPENSSL_DEP),) +# This is to ensure the embedded OpenSSL is built beforehand, properly +# installing headers to their final destination on the drive. We need this +# otherwise parallel compilation will fail if a source is compiled first. +test/cpp/interop/empty.proto: $(OPENSSL_DEP) +test/cpp/interop/messages.proto: $(OPENSSL_DEP) +test/cpp/interop/test.proto: $(OPENSSL_DEP) +test/cpp/interop/client_helper.cc: $(OPENSSL_DEP) +test/cpp/interop/interop_client.cc: $(OPENSSL_DEP) +endif + +$(LIBDIR)/$(CONFIG)/libinterop_client_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_LIB_OBJS) + $(E) "[AR] Creating $@" + $(Q) mkdir -p `dirname $@` + $(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a + $(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a $(LIBINTEROP_CLIENT_LIB_OBJS) +ifeq ($(SYSTEM),Darwin) + $(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a +endif + + + + +endif + +endif + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(LIBINTEROP_CLIENT_LIB_OBJS:.o=.dep) +endif +endif + + + + +$(OBJDIR)/$(CONFIG)/test/cpp/interop/client_helper.o: $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_client.o: $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc + + +LIBINTEROP_SERVER_LIB_SRC = \ + test/cpp/interop/server_helper.cc \ + + +LIBINTEROP_SERVER_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_LIB_SRC)))) + +ifeq ($(NO_SECURE),true) + +# You can't build secure libraries if you don't have OpenSSL with ALPN. + +$(LIBDIR)/$(CONFIG)/libinterop_server_lib.a: openssl_dep_error + + +else + +ifeq ($(NO_PROTOBUF),true) + +# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay. + +$(LIBDIR)/$(CONFIG)/libinterop_server_lib.a: protobuf_dep_error + + +else + +ifneq ($(OPENSSL_DEP),) +# This is to ensure the embedded OpenSSL is built beforehand, properly +# installing headers to their final destination on the drive. We need this +# otherwise parallel compilation will fail if a source is compiled first. +test/cpp/interop/server_helper.cc: $(OPENSSL_DEP) +endif + +$(LIBDIR)/$(CONFIG)/libinterop_server_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_LIB_OBJS) + $(E) "[AR] Creating $@" + $(Q) mkdir -p `dirname $@` + $(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a + $(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBINTEROP_SERVER_LIB_OBJS) +ifeq ($(SYSTEM),Darwin) + $(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a +endif + + + + +endif + +endif + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(LIBINTEROP_SERVER_LIB_OBJS:.o=.dep) +endif +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/interop/server_helper.o: + + LIBPUBSUB_CLIENT_LIB_SRC = \ - $(GENDIR)/examples/pubsub/label.pb.cc \ - $(GENDIR)/examples/pubsub/empty.pb.cc \ - $(GENDIR)/examples/pubsub/pubsub.pb.cc \ + $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc \ + $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc \ + $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc \ examples/pubsub/publisher.cc \ examples/pubsub/subscriber.cc \ @@ -3723,13 +3939,14 @@ endif -$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher.o: $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/pubsub.pb.cc -$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o: $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/pubsub.pb.cc +$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher.o: $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o: $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc LIBQPS_SRC = \ - $(GENDIR)/test/cpp/qps/qpstest.pb.cc \ + $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc \ test/cpp/qps/driver.cc \ + test/cpp/qps/report.cc \ test/cpp/qps/timer.cc \ @@ -3759,6 +3976,7 @@ ifneq ($(OPENSSL_DEP),) # otherwise parallel compilation will fail if a source is compiled first. test/cpp/qps/qpstest.proto: $(OPENSSL_DEP) test/cpp/qps/driver.cc: $(OPENSSL_DEP) +test/cpp/qps/report.cc: $(OPENSSL_DEP) test/cpp/qps/timer.cc: $(OPENSSL_DEP) endif @@ -3785,8 +4003,9 @@ endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc LIBGRPC_CSHARP_EXT_SRC = \ @@ -3838,7 +4057,7 @@ $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS) $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) -lgpr -lgrpc + $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_csharp_ext.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) -lgpr -lgrpc else $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) -lgpr -lgrpc $(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.so.0 @@ -6762,6 +6981,37 @@ endif endif +GPR_TLS_TEST_SRC = \ + test/core/support/tls_test.c \ + +GPR_TLS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_TLS_TEST_SRC)))) + +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL with ALPN. + +$(BINDIR)/$(CONFIG)/gpr_tls_test: openssl_dep_error + +else + +$(BINDIR)/$(CONFIG)/gpr_tls_test: $(GPR_TLS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(GPR_TLS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_tls_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/support/tls_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_gpr_tls_test: $(GPR_TLS_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GPR_TLS_TEST_OBJS:.o=.dep) +endif +endif + + GPR_USEFUL_TEST_SRC = \ test/core/support/useful_test.c \ @@ -8337,6 +8587,36 @@ ifneq ($(NO_DEPS),true) endif +GRPC_OBJECTIVE_C_PLUGIN_SRC = \ + src/compiler/objective_c_plugin.cc \ + +GRPC_OBJECTIVE_C_PLUGIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_OBJECTIVE_C_PLUGIN_SRC)))) + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/grpc_objective_c_plugin: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/grpc_objective_c_plugin: $(PROTOBUF_DEP) $(GRPC_OBJECTIVE_C_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a + $(E) "[HOSTLD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_OBJECTIVE_C_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin + +endif + +$(OBJDIR)/$(CONFIG)/src/compiler/objective_c_plugin.o: $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a + +deps_grpc_objective_c_plugin: $(GRPC_OBJECTIVE_C_PLUGIN_OBJS:.o=.dep) + +ifneq ($(NO_DEPS),true) +-include $(GRPC_OBJECTIVE_C_PLUGIN_OBJS:.o=.dep) +endif + + GRPC_PYTHON_PLUGIN_SRC = \ src/compiler/python_plugin.cc \ @@ -8398,9 +8678,6 @@ endif INTEROP_CLIENT_SRC = \ - $(GENDIR)/test/cpp/interop/empty.pb.cc \ - $(GENDIR)/test/cpp/interop/messages.pb.cc \ - $(GENDIR)/test/cpp/interop/test.pb.cc \ test/cpp/interop/client.cc \ INTEROP_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_CLIENT_SRC)))) @@ -8422,19 +8699,16 @@ $(BINDIR)/$(CONFIG)/interop_client: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/interop_client: $(PROTOBUF_DEP) $(INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/interop_client: $(PROTOBUF_DEP) $(INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(INTEROP_CLIENT_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_client + $(Q) $(LDXX) $(LDFLAGS) $(INTEROP_CLIENT_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_client endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/interop/empty.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/interop/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/interop/test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/interop/client.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/interop/client.o: $(LIBDIR)/$(CONFIG)/libinterop_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_interop_client: $(INTEROP_CLIENT_OBJS:.o=.dep) @@ -8446,9 +8720,9 @@ endif INTEROP_SERVER_SRC = \ - $(GENDIR)/test/cpp/interop/empty.pb.cc \ - $(GENDIR)/test/cpp/interop/messages.pb.cc \ - $(GENDIR)/test/cpp/interop/test.pb.cc \ + $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \ + $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \ + $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \ test/cpp/interop/server.cc \ INTEROP_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_SERVER_SRC)))) @@ -8470,19 +8744,19 @@ $(BINDIR)/$(CONFIG)/interop_server: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/interop_server: $(PROTOBUF_DEP) $(INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/interop_server: $(PROTOBUF_DEP) $(INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(INTEROP_SERVER_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_server + $(Q) $(LDXX) $(LDFLAGS) $(INTEROP_SERVER_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_server endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/interop/empty.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/interop/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/interop/test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/interop/empty.o: $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/interop/messages.o: $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/interop/test.o: $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o: $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_interop_server: $(INTEROP_SERVER_OBJS:.o=.dep) @@ -8703,6 +8977,48 @@ endif endif +QPS_SMOKE_TEST_SRC = \ + test/cpp/qps/smoke_test.cc \ + +QPS_SMOKE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_SMOKE_TEST_SRC)))) + +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL with ALPN. + +$(BINDIR)/$(CONFIG)/qps_smoke_test: openssl_dep_error + +else + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/qps_smoke_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/qps_smoke_test: $(PROTOBUF_DEP) $(QPS_SMOKE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(QPS_SMOKE_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/qps_smoke_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/qps/smoke_test.o: $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_qps_smoke_test: $(QPS_SMOKE_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(QPS_SMOKE_TEST_OBJS:.o=.dep) +endif +endif + + QPS_WORKER_SRC = \ test/cpp/qps/client_async.cc \ test/cpp/qps/client_sync.cc \ diff --git a/README.md b/README.md index fa60b83d162..b78745f02c4 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ Copyright 2015 Google Inc. +#Documentation + +You can find more detailed documentation and examples in the [grpc-common repository](http://github.com/grpc/grpc-common). + #Installation See grpc/INSTALL for installation instructions for various platforms. @@ -25,10 +29,6 @@ of shared C core library [src/core] (src/core). Java source code is in [grpc-java] (http://github.com/grpc/grpc-java) repository. Go source code is in [grpc-go] (http://github.com/grpc/grpc-go) repository. -#Documentation - -You can find more detailed documentation and examples in the [grpc-common repository](http://github.com/grpc/grpc-common). - #Current Status of libraries Libraries in different languages are in different state of development. We are seeking contributions for all of these libraries. diff --git a/build.json b/build.json index fb81e34beb3..3f271392524 100644 --- a/build.json +++ b/build.json @@ -3,7 +3,7 @@ "#": "The public version number of the library.", "version": { "major": 0, - "minor": 5, + "minor": 6, "micro": 0, "build": 0 } @@ -29,6 +29,12 @@ "include/grpc++/impl/rpc_method.h", "include/grpc++/impl/rpc_service_method.h", "include/grpc++/impl/service_type.h", + "include/grpc++/impl/sync.h", + "include/grpc++/impl/sync_cxx11.h", + "include/grpc++/impl/sync_no_cxx11.h", + "include/grpc++/impl/thd.h", + "include/grpc++/impl/thd_cxx11.h", + "include/grpc++/impl/thd_no_cxx11.h", "include/grpc++/server.h", "include/grpc++/server_builder.h", "include/grpc++/server_context.h", @@ -298,6 +304,10 @@ "include/grpc/support/sync_win32.h", "include/grpc/support/thd.h", "include/grpc/support/time.h", + "include/grpc/support/tls.h", + "include/grpc/support/tls_gcc.h", + "include/grpc/support/tls_msvc.h", + "include/grpc/support/tls_pthread.h", "include/grpc/support/useful.h" ], "headers": [ @@ -338,6 +348,7 @@ "src/core/support/sync.c", "src/core/support/sync_posix.c", "src/core/support/sync_win32.c", + "src/core/support/thd.c", "src/core/support/thd_posix.c", "src/core/support/thd_win32.c", "src/core/support/time.c", @@ -465,6 +476,10 @@ "name": "grpc++", "build": "all", "language": "c++", + "headers": [ + "src/cpp/client/secure_credentials.h", + "src/cpp/server/secure_server_credentials.h" + ], "src": [ "src/cpp/client/secure_credentials.cc", "src/cpp/server/secure_server_credentials.cc" @@ -515,6 +530,8 @@ "src/compiler/cpp_generator.h", "src/compiler/cpp_generator_helpers.h", "src/compiler/generator_helpers.h", + "src/compiler/objective_c_generator.h", + "src/compiler/objective_c_generator_helpers.h", "src/compiler/python_generator.h", "src/compiler/ruby_generator.h", "src/compiler/ruby_generator_helpers-inl.h", @@ -523,12 +540,46 @@ ], "src": [ "src/compiler/cpp_generator.cc", + "src/compiler/objective_c_generator.cc", "src/compiler/python_generator.cc", "src/compiler/ruby_generator.cc" ], "deps": [], "secure": "no" }, + { + "name": "interop_client_lib", + "build": "private", + "language": "c++", + "src": [ + "test/cpp/interop/empty.proto", + "test/cpp/interop/messages.proto", + "test/cpp/interop/test.proto", + "test/cpp/interop/client_helper.cc", + "test/cpp/interop/interop_client.cc" + ], + "deps": [ + "grpc++_test_util", + "grpc_test_util", + "grpc++", + "grpc", + "gpr" + ] + }, + { + "name": "interop_server_lib", + "build": "private", + "language": "c++", + "src": [ + "test/cpp/interop/server_helper.cc" + ], + "deps": [ + "grpc_test_util", + "grpc++", + "grpc", + "gpr" + ] + }, { "name": "pubsub_client_lib", "build": "private", @@ -552,11 +603,13 @@ "language": "c++", "headers": [ "test/cpp/qps/driver.h", + "test/cpp/qps/report.h", "test/cpp/qps/timer.h" ], "src": [ "test/cpp/qps/qpstest.proto", "test/cpp/qps/driver.cc", + "test/cpp/qps/report.cc", "test/cpp/qps/timer.cc" ] }, @@ -1145,6 +1198,18 @@ "gpr" ] }, + { + "name": "gpr_tls_test", + "build": "test", + "language": "c", + "src": [ + "test/core/support/tls_test.c" + ], + "deps": [ + "gpr_test_util", + "gpr" + ] + }, { "name": "gpr_useful_test", "build": "test", @@ -1821,6 +1886,18 @@ ], "secure": "no" }, + { + "name": "grpc_objective_c_plugin", + "build": "protoc", + "language": "c++", + "src": [ + "src/compiler/objective_c_plugin.cc" + ], + "deps": [ + "grpc_plugin_support" + ], + "secure": "no" + }, { "name": "grpc_python_plugin", "build": "protoc", @@ -1851,12 +1928,10 @@ "run": false, "language": "c++", "src": [ - "test/cpp/interop/empty.proto", - "test/cpp/interop/messages.proto", - "test/cpp/interop/test.proto", "test/cpp/interop/client.cc" ], "deps": [ + "interop_client_lib", "grpc++_test_util", "grpc_test_util", "grpc++", @@ -1877,6 +1952,7 @@ "test/cpp/interop/server.cc" ], "deps": [ + "interop_server_lib", "grpc++_test_util", "grpc_test_util", "grpc++", @@ -1968,6 +2044,24 @@ "gpr" ] }, + { + "name": "qps_smoke_test", + "build": "test", + "run": false, + "language": "c++", + "src": [ + "test/cpp/qps/smoke_test.cc" + ], + "deps": [ + "qps", + "grpc++_test_util", + "grpc_test_util", + "grpc++", + "grpc", + "gpr_test_util", + "gpr" + ] + }, { "name": "qps_worker", "build": "test", diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md new file mode 100644 index 00000000000..3f5ce37e1ed --- /dev/null +++ b/doc/interop-test-descriptions.md @@ -0,0 +1,685 @@ +Interoperability Test Case Descriptions +======================================= + +Client and server use +[test.proto](https://github.com/grpc/grpc/blob/master/test/cpp/interop/test.proto) +and the [gRPC over HTTP/2 v2 +protocol](https://github.com/grpc/grpc-common/blob/master/PROTOCOL-HTTP2.md). + +Client +------ + +Clients implement test cases that test certain functionally. Each client is +provided the test case it is expected to run as a command-line parameter. Names +should be lowercase and without spaces. + +Clients should accept these arguments: +* --server_host=HOSTNAME + * The server host to connect to. For example, "localhost" or "127.0.0.1" +* --server_host_override=HOSTNAME + * The server host to claim to be connecting to, for use in TLS and HTTP/2 + :authority header. If unspecified, the value of --server_host will be + used +* --server_port=PORT + * The server port to connect to. For example, "8080" +* --test_case=TESTCASE + * The name of the test case to execute. For example, "empty_unary" +* --use_tls=BOOLEAN + * Whether to use a plaintext or encrypted connection +* --use_test_ca=BOOLEAN + * Whether to replace platform root CAs with + [ca.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/ca.pem) + as the CA root + +Clients must support TLS with ALPN. Clients must not disable certificate +checking. + +### empty_unary + +This test verifies that implementations support zero-size messages. Ideally, +client implementations would verify that the request and response were zero +bytes serialized, but this is generally prohibitive to perform, so is not +required. + +Server features: +* [EmptyCall][] + +Procedure: + 1. Client calls EmptyCall with the default Empty message + +Asserts: +* call was successful +* response is non-null + +*It may be possible to use UnaryCall instead of EmptyCall, but it is harder to +ensure that the proto serialized to zero bytes.* + +### large_unary + +This test verifies unary calls succeed in sending messages, and touches on flow +control (even if compression is enabled on the channel). + +Server features: +* [UnaryCall][] +* [Compressable Payload][] + +Procedure: + 1. Client calls UnaryCall with: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + +Asserts: +* call was successful +* response payload type is COMPRESSABLE +* response payload body is 314159 bytes in size +* clients are free to assert that the response payload body contents are zero + and comparing the entire response message against a golden response + +### client_streaming + +This test verifies that client-only streaming succeeds. + +Server features: +* [StreamingInputCall][] +* [Compressable Payload][] + +Procedure: + 1. Client calls StreamingInputCall + 2. Client sends: + + ``` + { + payload:{ + body: 27182 bytes of zeros + } + } + ``` + 3. Client then sends: + + ``` + { + payload:{ + body: 8 bytes of zeros + } + } + ``` + 4. Client then sends: + + ``` + { + payload:{ + body: 1828 bytes of zeros + } + } + ``` + 5. Client then sends: + + ``` + { + payload:{ + body: 45904 bytes of zeros + } + } + ``` + 6. Client halfCloses + +Asserts: +* call was successful +* response aggregated_payload_size is 74922 + +### server_streaming + +This test verifies that server-only streaming succeeds. + +Server features: +* [StreamingOutputCall][] +* [Compressable Payload][] + +Procedure: + 1. Client calls StreamingOutputCall with: + + ``` + { + response_type:COMPRESSABLE + response_parameters:{ + size: 31415 + } + response_parameters:{ + size: 9 + } + response_parameters:{ + size: 2653 + } + response_parameters:{ + size: 58979 + } + } + ``` + +Asserts: +* call was successful +* exactly four responses +* response payloads are COMPRESSABLE +* response payload bodies are sized (in order): 31415, 9, 2653, 58979 +* clients are free to assert that the response payload body contents are zero + and comparing the entire response messages against golden responses + +### ping_pong + +This test verifies that full duplex bidi is supported. + +Server features: +* [FullDuplexCall][] +* [Compressable Payload][] + +Procedure: + 1. Client calls FullDuplexCall with: + + ``` + { + response_type: COMPRESSABLE + response_parameters:{ + size: 31415 + } + payload:{ + body: 27182 bytes of zeros + } + } + ``` + 2. After getting a reply, it sends: + + ``` + { + response_type: COMPRESSABLE + response_parameters:{ + size: 9 + } + payload:{ + body: 8 bytes of zeros + } + } + ``` + 3. After getting a reply, it sends: + + ``` + { + response_type: COMPRESSABLE + response_parameters:{ + size: 2653 + } + payload:{ + body: 1828 bytes of zeros + } + } + ``` + 4. After getting a reply, it sends: + + ``` + { + response_type: COMPRESSABLE + response_parameters:{ + size: 58979 + } + payload:{ + body: 45904 bytes of zeros + } + } + ``` + +Asserts: +* call was successful +* exactly four responses +* response payloads are COMPRESSABLE +* response payload bodies are sized (in order): 31415, 9, 2653, 58979 +* clients are free to assert that the response payload body contents are zero + and comparing the entire response messages against golden responses + +### empty_stream + +This test verifies that streams support having zero-messages in both +directions. + +Server features: +* [FullDuplexCall][] + +Procedure: + 1. Client calls FullDuplexCall and then half-closes + +Asserts: +* call was successful +* exactly zero responses + +### compute_engine_creds + +Status: Not yet implementable + +This test is only for cloud-to-prod path. + +This test verifies unary calls succeed in sending messages while using Service +Credentials from GCE metadata server. The client instance needs to be created +with desired oauth scope. + +Server features: +* [UnaryCall][] +* [Compressable Payload][] +* SimpeResponse.username +* SimpleResponse.oauth_scope + +Procedure: + 1. Client sets flags default_service_account with GCE service account name and + oauth_scope with the oauth scope to use. + 2. Client configures channel to use GCECredentials + 3. Client calls UnaryCall on the channel with: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + fill_username: true + fill_oauth_scope: true + } + ``` + +Asserts: +* call was successful +* received SimpleResponse.username equals FLAGS_default_service_account +* received SimpleResponse.oauth_scope is in FLAGS_oauth_scope +* response payload body is 314159 bytes in size +* clients are free to assert that the response payload body contents are zero + and comparing the entire response message against a golden response + +### service_account_creds + +Status: Not yet implementable + +This test is only for cloud-to-prod path. + +This test verifies unary calls succeed in sending messages while using JWT +signing keys (redeemed for OAuth2 access tokens by the auth implementation) + +Server features: +* [UnaryCall][] +* [Compressable Payload][] +* SimpleResponse.username +* SimpleResponse.oauth_scope + +Procedure: + 1. Client sets flags service_account_key_file with the path to json key file, + oauth_scope to the oauth scope. + 2. Client configures the channel to use ServiceAccountCredentials. + 3. Client calls UnaryCall with: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + fill_username: true + fill_oauth_scope: true + } + ``` + +Asserts: +* call was successful +* received SimpleResponse.username is in the json key file read from + FLAGS_service_account_key_file +* received SimpleResponse.oauth_scope is in FLAGS_oauth_scope +* response payload body is 314159 bytes in size +* clients are free to assert that the response payload body contents are zero + and comparing the entire response message against a golden response + +### jwt_token_creds + +Status: Not yet implementable + +This test is only for cloud-to-prod path. + +This test verifies unary calls succeed in sending messages while using JWT +token (created by the project's key file) + +Server features: +* [UnaryCall][] +* [Compressable Payload][] +* SimpleResponse.username +* SimpleResponse.oauth_scope + +Procedure: + 1. Client sets flags service_account_key_file with the path to json key file + 2. Client configures the channel to use JWTTokenCredentials. + 3. Client calls UnaryCall with: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + fill_username: true + } + ``` + +Asserts: +* call was successful +* received SimpleResponse.username is in the json key file read from + FLAGS_service_account_key_file +* response payload body is 314159 bytes in size +* clients are free to assert that the response payload body contents are zero + and comparing the entire response message against a golden response + +### Metadata (TODO: fix name) + +Status: Not yet implementable + +This test verifies that custom metadata in either binary or ascii format can be +sent in header and trailer. + +Server features: +* [UnaryCall][] +* [Compressable Payload][] +* Ability to receive custom metadata from client in header and send custom data + back to client in both header and trailer. (TODO: this is not defined) + +Procedure: + 1. While sending custom metadata (ascii + binary) in the header, client calls UnaryCall with: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + +Asserts: +* call was successful +* custom metadata is echoed back in the response header. +* custom metadata is echoed back in the response trailer. + +### status_code_and_message + +Status: Not yet implementable + +This test verifies unary calls succeed in sending messages, and propagates back +status code and message sent along with the messages. + +Server features: +* [UnaryCall][] + +Procedure: + 1. Client calls UnaryCall with: + + ``` + { + response_status:{ + code: 2 + message: "test status message" + } + } + ``` + +Asserts: +* received status code is the same with sent code +* received status message is the same with sent message + +### unimplemented_method + +Status: Not yet implementable + +This test verifies calling unimplemented RPC method returns unimplemented +status. + +Procedure: +* Client calls UnimplementedCall with: + + ``` + { + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + +Asserts: +* received status code is 12 (UNIMPLEMENTED) +* received status message is empty or null/unset + +### cancel_after_begin + +This test verifies that a request can be cancelled after metadata has been sent +but before payloads are sent. + +Server features: +* [StreamingInputCall][] + +Procedure: + 1. Client starts StreamingInputCall + 2. Client immediately cancels request + +Asserts: +* Call completed with status CANCELLED + +### cancel_after_first_response + +This test verifies that a request can be cancelled after receiving a message +from the server. + +Server features: +* [FullDuplexCall][] +* [Compressable Payload][] + +Procedure: + 1. Client starts FullDuplexCall with + + ``` + { + response_type: COMPRESSABLE + response_parameters:{ + size: 31415 + } + payload:{ + body: 27182 bytes of zeros + } + } + ``` + 2. After receiving a response, client cancels request + +Asserts: +* Call completed with status CANCELLED + +### concurrent_large_unary + +Status: TODO + +Client performs 1000 large_unary tests in parallel on the same channel. + +### Flow control. Pushback at client for large messages (TODO: fix name) + +Status: TODO + +This test verifies that a client sending faster than a server can drain sees +pushback (i.e., attempts to send succeed only after appropriate delays). + +### TODO Tests + +High priority: + +Propagation of status code and message (yangg) + +Cancel after sent headers (ctiller - done) + +Cancel after received first message (ctiller - done) + +Timeout after expire (zhaoq) + +Zero-message streams (ejona) + +Multiple thousand simultaneous calls on same Channel (ctiller - done) + +OAuth2 tokens + Service Credentials from GCE metadata server (GCE->prod only) +(abhishek) + +OAuth2 tokens + JWT signing key (GCE->prod only) (abhishek) + +Metadata: client headers, server headers + trailers, binary+ascii (chenw) + +Normal priority: + +Cancel before start (ctiller) + +Cancel after sent first message (ctiller) + +Cancel after received headers (ctiller) + +Timeout but completed before expire (zhaoq) + +Multiple thousand simultaneous calls timeout on same Channel (ctiller) + +Lower priority: + +Flow control. Pushback at client for large messages (abhishek) + +Flow control. Pushback at server for large messages (abhishek) + +Going over max concurrent streams doesn't fail (client controls itself) +(abhishek) + +RPC method not implemented (yangg) + +Multiple thousand simultaneous calls on different Channels (ctiller) + +Failed TLS hostname verification (ejona?) + +To priorize: + +Start streaming RPC but don't send any requests, server responds + +### Postponed Tests + +Resilience to buggy servers: These tests would verify that a client application +isn't affected negatively by the responses put on the wire by a buggy server +(e.g. the client library won't make the application crash). + +Reconnect after transport failure + +Reconnect backoff + +Fuzz testing + + +Server +------ + +Servers implement various named features for clients to test with. Server +features are orthogonal. If a server implements a feature, it is always +available for clients. Names are simple descriptions for developer +communication and tracking. + +Servers should accept these arguments: + +* --port=PORT + + * The port to listen on. For example, "8080" + +* --use_tls=BOOLEAN + + * Whether to use a plaintext or encrypted connection + +Servers must support TLS with ALPN. They should use +[server1.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/server1.pem) +for their certificate. + +### EmptyCall +[EmptyCall]: #emptycall + +Server implements EmptyCall which immediately returns the empty message. + +### UnaryCall +[UnaryCall]: #unarycall + +Server implements UnaryCall which immediately returns a SimpleResponse with a +payload body of size SimpleRequest.response_size bytes and type as appropriate +for the SimpleRequest.response_type. If the server does not support the +response_type, then it should fail the RPC with INVALID_ARGUMENT. + +If the request sets fill_username, the server should return the client username +it sees in field SimpleResponse.username. If the request sets fill_oauth_scope, +the server should return the oauth scope of the rpc in the form of "xapi_zoo" +in field SimpleResponse.oauth_scope. + +### StreamingInputCall +[StreamingInputCall]: #streaminginputcall + +Server implements StreamingInputCall which upon half close immediately returns +a StreamingInputCallResponse where aggregated_payload_size is the sum of all +request payload bodies received. + +### StreamingOutputCall +[StreamingOutputCall]: #streamingoutputcall + +Server implements StreamingOutputCall by replying, in order, with one +StreamingOutputCallResponses for each ResponseParameters in +StreamingOutputCallRequest. Each StreamingOutputCallResponses should have a +payload body of size ResponseParameters.size bytes, as specified by its +respective ResponseParameters. After sending all responses, it closes with OK. + +### FullDuplexCall +[FullDuplexCall]: #fullduplexcall + +Server implements FullDuplexCall by replying, in order, with one +StreamingOutputCallResponses for each ResponseParameters in each +StreamingOutputCallRequest. Each StreamingOutputCallResponses should have a +payload body of size ResponseParameters.size bytes, as specified by its +respective ResponseParameters. After receiving half close and sending all +responses, it closes with OK. + +### Compressable Payload +[Compressable Payload]: #compressable-payload + +When the client requests COMPRESSABLE payload, the response includes a payload +of the size requested containing all zeros and the payload type is +COMPRESSABLE. + +### Observe ResponseParameters.interval_us +[Observe ResponseParameters.interval_us]: #observe-responseparametersinterval_us + +In StreamingOutputCall and FullDuplexCall, server delays sending a +StreamingOutputCallResponse by the ResponseParameters's interval_us for that +particular response, relative to the last response sent. That is, interval_us +acts like a sleep *before* sending the response and accumulates from one +response to the next. + +Interaction with flow control is unspecified. + +### Echo Auth Information + +Status: Pending + +If a SimpleRequest has fill_username=true and that request was successfully +authenticated, then the SimpleResponse should have username filled with the +canonical form of the authenticated source. The canonical form is dependent on +the authentication method, but is likely to be a base 10 integer identifier or +an email address. + +Discussion: + +Ideally, this would be communicated via metadata and not in the +request/response, but we want to use this test in code paths that don't yet +fully communicate metadata. diff --git a/examples/pubsub/publisher.h b/examples/pubsub/publisher.h index c90406ffef8..33bcf98df48 100644 --- a/examples/pubsub/publisher.h +++ b/examples/pubsub/publisher.h @@ -37,7 +37,7 @@ #include #include -#include "examples/pubsub/pubsub.pb.h" +#include "examples/pubsub/pubsub.grpc.pb.h" namespace grpc { namespace examples { diff --git a/examples/pubsub/subscriber.h b/examples/pubsub/subscriber.h index c587c01b825..40ab45471d5 100644 --- a/examples/pubsub/subscriber.h +++ b/examples/pubsub/subscriber.h @@ -37,7 +37,7 @@ #include #include -#include "examples/pubsub/pubsub.pb.h" +#include "examples/pubsub/pubsub.grpc.pb.h" namespace grpc { namespace examples { diff --git a/include/grpc++/config.h b/include/grpc++/config.h index 8ef5d71bfac..0f3d69289f3 100644 --- a/include/grpc++/config.h +++ b/include/grpc++/config.h @@ -34,11 +34,46 @@ #ifndef GRPCXX_CONFIG_H #define GRPCXX_CONFIG_H -#ifdef GRPC_OLD_CXX +#if !defined(GRPC_NO_AUTODETECT_PLATFORM) + +#ifdef _MSC_VER +// Visual Studio 2010 is 1600. +#if _MSC_VER < 1600 +#error "gRPC is only supported with Visual Studio starting at 2010" +// Visual Studio 2013 is 1800. +#elif _MSC_VER < 1800 +#define GRPC_CXX0X_NO_FINAL 1 +#define GRPC_CXX0X_NO_OVERRIDE 1 +#define GRPC_CXX0X_NO_CHRONO 1 +#define GRPC_CXX0X_NO_THREAD 1 +#endif +#endif // Visual Studio + +#ifndef __clang__ +#ifdef __GNUC__ +// nullptr was added in gcc 4.6 +#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406) +#define GRPC_CXX0X_NO_NULLPTR 1 +#endif +// final and override were added in gcc 4.7 +#if (__GNUC__ * 100 + __GNUC_MINOR__ < 407) +#define GRPC_CXX0X_NO_FINAL 1 +#define GRPC_CXX0X_NO_OVERRIDE 1 +#endif +#endif +#endif + +#endif + +#ifdef GRPC_CXX0X_NO_FINAL #define GRPC_FINAL -#define GRPC_OVERRIDE #else #define GRPC_FINAL final +#endif + +#ifdef GRPC_CXX0X_NO_OVERRIDE +#define GRPC_OVERRIDE +#else #define GRPC_OVERRIDE override #endif @@ -65,15 +100,7 @@ ::google::protobuf::io::ZeroCopyInputStream #endif -#ifndef __clang__ -#ifdef __GNUC__ -#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406) -#define GRPC_NO_NULLPTR -#endif -#endif -#endif - -#ifdef GRPC_NO_NULLPTR +#ifdef GRPC_CXX0X_NO_NULLPTR #include const class { public: diff --git a/include/grpc++/impl/sync.h b/include/grpc++/impl/sync.h new file mode 100644 index 00000000000..2f41d2bdebb --- /dev/null +++ b/include/grpc++/impl/sync.h @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_IMPL_SYNC_H +#define GRPCXX_IMPL_SYNC_H + +#include + +#ifdef GRPC_CXX0X_NO_THREAD +#include +#else +#include +#endif + +#endif // GRPCXX_IMPL_SYNC_H diff --git a/include/grpc++/impl/sync_cxx11.h b/include/grpc++/impl/sync_cxx11.h new file mode 100644 index 00000000000..4e6f1da3a61 --- /dev/null +++ b/include/grpc++/impl/sync_cxx11.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_IMPL_SYNC_CXX11_H +#define GRPCXX_IMPL_SYNC_CXX11_H + +#include +#include + +namespace grpc { + +using std::condition_variable; +using std::mutex; +using std::lock_guard; +using std::unique_lock; + +} // namespace grpc + +#endif // GRPCXX_IMPL_SYNC_CXX11_H diff --git a/include/grpc++/impl/sync_no_cxx11.h b/include/grpc++/impl/sync_no_cxx11.h new file mode 100644 index 00000000000..5636373b814 --- /dev/null +++ b/include/grpc++/impl/sync_no_cxx11.h @@ -0,0 +1,101 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_IMPL_SYNC_NO_CXX11_H +#define GRPCXX_IMPL_SYNC_NO_CXX11_H + +#include + +namespace grpc { + +template +class lock_guard; +class condition_variable; + +class mutex { + public: + mutex() { gpr_mu_init(&mu_); } + ~mutex() { gpr_mu_destroy(&mu_); } + private: + ::gpr_mu mu_; + template + friend class lock_guard; + friend class condition_variable; +}; + +template +class lock_guard { + public: + lock_guard(mutex &mu) : mu_(mu), locked(true) { gpr_mu_lock(&mu.mu_); } + ~lock_guard() { unlock_internal(); } + protected: + void lock_internal() { + if (!locked) gpr_mu_lock(&mu_.mu_); + locked = true; + } + void unlock_internal() { + if (locked) gpr_mu_unlock(&mu_.mu_); + locked = false; + } + private: + mutex &mu_; + bool locked; + friend class condition_variable; +}; + +template +class unique_lock : public lock_guard { + public: + unique_lock(mutex &mu) : lock_guard(mu) { } + void lock() { lock_internal(); } + void unlock() { unlock_internal(); } +}; + +class condition_variable { + public: + condition_variable() { gpr_cv_init(&cv_); } + ~condition_variable() { gpr_cv_destroy(&cv_); } + void wait(lock_guard &mu) { + mu.locked = false; + gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future); + mu.locked = true; + } + void notify_one() { gpr_cv_signal(&cv_); } + void notify_all() { gpr_cv_broadcast(&cv_); } + private: + gpr_cv cv_; +}; + +} // namespace grpc + +#endif // GRPCXX_IMPL_SYNC_NO_CXX11_H diff --git a/include/grpc++/impl/thd.h b/include/grpc++/impl/thd.h new file mode 100644 index 00000000000..4c4578a92da --- /dev/null +++ b/include/grpc++/impl/thd.h @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_IMPL_THD_H +#define GRPCXX_IMPL_THD_H + +#include + +#ifdef GRPC_CXX0X_NO_THREAD +#include +#else +#include +#endif + +#endif // GRPCXX_IMPL_THD_H diff --git a/include/grpc++/impl/thd_cxx11.h b/include/grpc++/impl/thd_cxx11.h new file mode 100644 index 00000000000..2055b1d5389 --- /dev/null +++ b/include/grpc++/impl/thd_cxx11.h @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_IMPL_THD_CXX11_H +#define GRPCXX_IMPL_THD_CXX11_H + +#include + +namespace grpc { + +using std::thread; + +} // namespace grpc + +#endif // GRPCXX_IMPL_THD_CXX11_H diff --git a/include/grpc++/impl/thd_no_cxx11.h b/include/grpc++/impl/thd_no_cxx11.h new file mode 100644 index 00000000000..a01b931df86 --- /dev/null +++ b/include/grpc++/impl/thd_no_cxx11.h @@ -0,0 +1,89 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_IMPL_THD_NO_CXX11_H +#define GRPCXX_IMPL_THD_NO_CXX11_H + +#include + +namespace grpc { + +class thread { + public: + template thread(void (T::*fptr)(), T *obj) { + func_ = new thread_function(fptr, obj); + joined_ = false; + start(); + } + ~thread() { + if (!joined_) std::terminate(); + delete func_; + } + void join() { + gpr_thd_join(thd_); + joined_ = true; + } + private: + void start() { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + gpr_thd_new(&thd_, thread_func, (void *) func_, &options); + } + static void thread_func(void *arg) { + thread_function_base *func = (thread_function_base *) arg; + func->call(); + } + class thread_function_base { + public: + virtual ~thread_function_base() { } + virtual void call() = 0; + }; + template + class thread_function : public thread_function_base { + public: + thread_function(void (T::*fptr)(), T *obj) + : fptr_(fptr) + , obj_(obj) { } + virtual void call() { (obj_->*fptr_)(); } + private: + void (T::*fptr_)(); + T *obj_; + }; + thread_function_base *func_; + gpr_thd_id thd_; + bool joined_; +}; + +} // namespace grpc + +#endif // GRPCXX_IMPL_THD_NO_CXX11_H diff --git a/include/grpc++/server.h b/include/grpc++/server.h index bddb4f62aa8..eb506115735 100644 --- a/include/grpc++/server.h +++ b/include/grpc++/server.h @@ -34,15 +34,14 @@ #ifndef GRPCXX_SERVER_H #define GRPCXX_SERVER_H -#include #include #include -#include #include #include #include #include +#include #include struct grpc_server; @@ -110,12 +109,12 @@ class Server GRPC_FINAL : private CallHook, CompletionQueue cq_; // Sever status - std::mutex mu_; + grpc::mutex mu_; bool started_; bool shutdown_; // The number of threads which are running callbacks. int num_running_cb_; - std::condition_variable callback_cv_; + grpc::condition_variable callback_cv_; std::list sync_methods_; diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h index 41185dbf640..0bb3e16c8d1 100644 --- a/include/grpc/support/port_platform.h +++ b/include/grpc/support/port_platform.h @@ -55,14 +55,17 @@ #define GPR_WINSOCK_SOCKET 1 #ifdef __GNUC__ #define GPR_GCC_ATOMIC 1 +#define GPR_GCC_TLS 1 #else #define GPR_WIN32_ATOMIC 1 +#define GPR_MSVC_TLS 1 #endif #elif defined(ANDROID) || defined(__ANDROID__) #define GPR_ANDROID 1 #define GPR_ARCH_32 1 #define GPR_CPU_LINUX 1 #define GPR_GCC_SYNC 1 +#define GPR_GCC_TLS 1 #define GPR_POSIX_MULTIPOLL_WITH_POLL 1 #define GPR_POSIX_WAKEUP_FD 1 #define GPR_LINUX_EVENTFD 1 @@ -88,6 +91,7 @@ #include #define GPR_CPU_LINUX 1 #define GPR_GCC_ATOMIC 1 +#define GPR_GCC_TLS 1 #define GPR_LINUX 1 #define GPR_LINUX_MULTIPOLL_WITH_EPOLL 1 #define GPR_POSIX_WAKEUP_FD 1 @@ -134,6 +138,32 @@ #define GPR_CPU_POSIX 1 #endif #define GPR_GCC_ATOMIC 1 +#define GPR_GCC_TLS 1 +#define GPR_POSIX_LOG 1 +#define GPR_POSIX_MULTIPOLL_WITH_POLL 1 +#define GPR_POSIX_WAKEUP_FD 1 +#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1 +#define GPR_POSIX_SOCKET 1 +#define GPR_POSIX_SOCKETADDR 1 +#define GPR_POSIX_SOCKETUTILS 1 +#define GPR_POSIX_ENV 1 +#define GPR_POSIX_FILE 1 +#define GPR_POSIX_STRING 1 +#define GPR_POSIX_SYNC 1 +#define GPR_POSIX_TIME 1 +#define GPR_GETPID_IN_UNISTD_H 1 +#ifdef _LP64 +#define GPR_ARCH_64 1 +#else /* _LP64 */ +#define GPR_ARCH_32 1 +#endif /* _LP64 */ +#elif defined(__FreeBSD__) +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#define GPR_CPU_POSIX 1 +#define GPR_GCC_ATOMIC 1 +#define GPR_GCC_TLS 1 #define GPR_POSIX_LOG 1 #define GPR_POSIX_MULTIPOLL_WITH_POLL 1 #define GPR_POSIX_WAKEUP_FD 1 @@ -190,16 +220,20 @@ #error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64 #endif -#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + defined(GPR_CPU_IPHONE) != 1 -#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE +#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + defined(GPR_CPU_IPHONE) + defined(GPR_CPU_CUSTOM) != 1 +#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE, GPR_CPU_CUSTOM #endif #if defined(GPR_POSIX_MULTIPOLL_WITH_POLL) && !defined(GPR_POSIX_SOCKET) #error Must define GPR_POSIX_SOCKET to use GPR_POSIX_MULTIPOLL_WITH_POLL #endif -#if defined(GPR_POSIX_SOCKET) + defined(GPR_WIN32) != 1 -#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WIN32 +#if defined(GPR_POSIX_SOCKET) + defined(GPR_WINSOCK_SOCKET) + defined(GPR_CUSTOM_SOCKET) != 1 +#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET +#endif + +#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + defined(GPR_CUSTOM_TLS) != 1 +#error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, defined(GPR_CUSTOM_TLS) #endif typedef int16_t gpr_int16; diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h index 35b2d12e774..1cdde1d2d04 100644 --- a/include/grpc/support/sync.h +++ b/include/grpc/support/sync.h @@ -60,7 +60,7 @@ #include #elif defined(GPR_WIN32) #include -#else +#elif !defined(GPR_CUSTOM_SYNC) #error Unable to determine platform for sync #endif diff --git a/include/grpc/support/thd.h b/include/grpc/support/thd.h index 64d5bed49a7..8126992d6b9 100644 --- a/include/grpc/support/thd.h +++ b/include/grpc/support/thd.h @@ -52,9 +52,8 @@ typedef gpr_uint64 gpr_thd_id; /* Thread creation options. */ typedef struct { - int flags; /* Flags below can be set here. Default value 0. */ + int flags; /* Opaque field. Get and set with accessors below. */ } gpr_thd_options; -/* No flags are currently defined. */ /* Create a new thread running (*thd_body)(arg) and place its thread identifier in *t, and return true. If there are insufficient resources, return false. @@ -66,9 +65,25 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, /* Return a gpr_thd_options struct with all fields set to defaults. */ gpr_thd_options gpr_thd_options_default(void); +/* Set the thread to become detached on startup - this is the default. */ +void gpr_thd_options_set_detached(gpr_thd_options *options); + +/* Set the thread to become joinable - mutually exclusive with detached. */ +void gpr_thd_options_set_joinable(gpr_thd_options *options); + +/* Returns non-zero if the option detached is set. */ +int gpr_thd_options_is_detached(const gpr_thd_options *options); + +/* Returns non-zero if the option joinable is set. */ +int gpr_thd_options_is_joinable(const gpr_thd_options *options); + /* Returns the identifier of the current thread. */ gpr_thd_id gpr_thd_currentid(void); +/* Blocks until the specified thread properly terminates. + Calling this on a detached thread has unpredictable results. */ +void gpr_thd_join(gpr_thd_id t); + #ifdef __cplusplus } #endif diff --git a/include/grpc/support/tls.h b/include/grpc/support/tls.h new file mode 100644 index 00000000000..1077fdec295 --- /dev/null +++ b/include/grpc/support/tls.h @@ -0,0 +1,77 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_SUPPORT_TLS_H +#define GRPC_SUPPORT_TLS_H + +#include "port_platform.h" + +/* Thread local storage. + + A minimal wrapper that should be implementable across many compilers, + and implementable efficiently across most modern compilers. + + Thread locals have type gpr_intptr. + + Declaring a thread local variable 'foo': + GPR_TLS_DECL(foo, initial_value); + Thread locals always have static scope. + + Initializing a thread local (must be done at library initialization + time): + gpr_tls_init(&foo); + + Destroying a thread local: + gpr_tls_destroy(&foo); + + Setting a thread local: + gpr_tls_set(&foo, new_value); + + Accessing a thread local: + current_value = gpr_tls_get(&foo, value); + + ALL functions here may be implemented as macros. */ + +#ifdef GPR_GCC_TLS +#include "tls_gcc.h" +#endif + +#ifdef GPR_MSVC_TLS +#include "tls_msvc.h" +#endif + +#ifdef GPR_PTHREAD_TLS +#include "tls_pthread.h" +#endif + +#endif diff --git a/include/grpc/support/tls_gcc.h b/include/grpc/support/tls_gcc.h new file mode 100644 index 00000000000..a078b104ea9 --- /dev/null +++ b/include/grpc/support/tls_gcc.h @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_SUPPORT_TLS_GCC_H +#define GRPC_SUPPORT_TLS_GCC_H + +/* Thread local storage based on gcc compiler primitives. + #include tls.h to use this - and see that file for documentation */ + +struct gpr_gcc_thread_local { + gpr_intptr value; +}; + +#define GPR_TLS_DECL(name) \ + static __thread struct gpr_gcc_thread_local name = {0} + +#define gpr_tls_init(tls) do {} while (0) +#define gpr_tls_destroy(tls) do {} while (0) +#define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value)) +#define gpr_tls_get(tls) ((tls)->value) + +#endif diff --git a/include/grpc/support/tls_msvc.h b/include/grpc/support/tls_msvc.h new file mode 100644 index 00000000000..e574c118844 --- /dev/null +++ b/include/grpc/support/tls_msvc.h @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_SUPPORT_TLS_GCC_H +#define GRPC_SUPPORT_TLS_GCC_H + +/* Thread local storage based on ms visual c compiler primitives. + #include tls.h to use this - and see that file for documentation */ + +struct gpr_msvc_thread_local { + gpr_intptr value; +}; + +#define GPR_TLS_DECL(name) \ + static __thread struct gpr_msvc_thread_local name = {0} + +#define gpr_tls_init(tls) do {} while (0) +#define gpr_tls_destroy(tls) do {} while (0) +#define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value)) +#define gpr_tls_get(tls) ((tls)->value) + +#endif diff --git a/include/grpc/support/tls_pthread.h b/include/grpc/support/tls_pthread.h new file mode 100644 index 00000000000..249c4d1cab6 --- /dev/null +++ b/include/grpc/support/tls_pthread.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_SUPPORT_TLS_PTHREAD_H +#define GRPC_SUPPORT_TLS_PTHREAD_H + +/* Thread local storage based on pthread library calls. + #include tls.h to use this - and see that file for documentation */ + +struct gpr_pthread_thread_local { + pthread_key_t key; +}; + +#define GPR_TLS_DECL(name) \ + static struct gpr_pthread_thread_local name = {0} + +#define gpr_tls_init(tls) GPR_ASSERT(0 == pthread_key_create(&(tls)->key, NULL)) +#define gpr_tls_destroy(tls) pthread_key_delete((tls)->key) +#define gpr_tls_set(tls, new_value) \ + GPR_ASSERT(pthread_setspecific((tls)->key, (void*)(new_value)) == 0) +#define gpr_tls_get(tls) ((gpr_intptr)pthread_getspecific((tls)->key)) + +#endif diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 0a84c735200..bd8bf65349a 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -109,8 +109,47 @@ bool HasBidiStreaming(const grpc::protobuf::FileDescriptor *file) { } return false; } + +grpc::string FilenameIdentifier(const grpc::string& filename) { + grpc::string result; + for (unsigned i = 0; i < filename.size(); i++) { + char c = filename[i]; + if (isalnum(c)) { + result.push_back(c); + } else { + static char hex[] = "0123456789abcdef"; + result.push_back('_'); + result.push_back(hex[(c >> 4) & 0xf]); + result.push_back(hex[c & 0xf]); + } + } + return result; +} } // namespace +grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms) { + grpc::string output; + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map vars; + + vars["filename"] = file->name(); + vars["filename_identifier"] = FilenameIdentifier(file->name()); + vars["filename_base"] = grpc_generator::StripProto(file->name()); + + printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n"); + printer.Print(vars, "// If you make any local change, they will be lost.\n"); + printer.Print(vars, "// source: $filename$\n"); + printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n"); + printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n"); + printer.Print(vars, "\n"); + printer.Print(vars, "#include \"$filename_base$.pb.h\"\n"); + printer.Print(vars, "\n"); + + return output; +} + grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file, const Parameters ¶ms) { grpc::string temp = @@ -156,17 +195,22 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file, "class ServerAsyncReaderWriter;\n"); } temp.append("} // namespace grpc\n"); - return temp; -} -grpc::string GetSourceIncludes(const Parameters ¶m) { - return "#include \n" - "#include \n" - "#include \n" - "#include \n" - "#include \n" - "#include \n" - "#include \n"; + temp.append("\n"); + + if (!file->package().empty()) { + std::vector parts = + grpc_generator::tokenize(file->package(), "."); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("namespace "); + temp.append(*part); + temp.append(" {\n"); + } + temp.append("\n"); + } + + return temp; } void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer, @@ -378,6 +422,83 @@ grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file, return output; } +grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms) { + grpc::string output; + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map vars; + + vars["filename"] = file->name(); + vars["filename_identifier"] = FilenameIdentifier(file->name()); + + if (!file->package().empty()) { + std::vector parts = + grpc_generator::tokenize(file->package(), "."); + + for (auto part = parts.rbegin(); part != parts.rend(); part++) { + vars["part"] = *part; + printer.Print(vars, "} // namespace $part$\n"); + } + printer.Print(vars, "\n"); + } + + printer.Print(vars, "\n"); + printer.Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n"); + + return output; +} + +grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms) { + grpc::string output; + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map vars; + + vars["filename"] = file->name(); + vars["filename_base"] = grpc_generator::StripProto(file->name()); + + printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n"); + printer.Print(vars, "// If you make any local change, they will be lost.\n"); + printer.Print(vars, "// source: $filename$\n\n"); + printer.Print(vars, "#include \"$filename_base$.pb.h\"\n"); + printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n"); + printer.Print(vars, "\n"); + + return output; +} + +grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶m) { + grpc::string output; + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map vars; + + printer.Print(vars, "#include \n"); + printer.Print(vars, "#include \n"); + printer.Print(vars, "#include \n"); + printer.Print(vars, "#include \n"); + printer.Print(vars, "#include \n"); + printer.Print(vars, "#include \n"); + printer.Print(vars, "#include \n"); + + if (!file->package().empty()) { + std::vector parts = + grpc_generator::tokenize(file->package(), "."); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer.Print(vars, "namespace $part$ {\n"); + } + } + + printer.Print(vars, "\n"); + + return output; +} + void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer, const grpc::protobuf::MethodDescriptor *method, std::map *vars) { @@ -741,4 +862,23 @@ grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file, return output; } +grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms) { + grpc::string temp; + + if (!file->package().empty()) { + std::vector parts = + grpc_generator::tokenize(file->package(), "."); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("} // namespace "); + temp.append(*part); + temp.append("\n"); + } + temp.append("\n"); + } + + return temp; +} + } // namespace grpc_cpp_generator diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h index 04ad71c0673..70c2e985f6b 100644 --- a/src/compiler/cpp_generator.h +++ b/src/compiler/cpp_generator.h @@ -44,12 +44,25 @@ struct Parameters { grpc::string services_namespace; }; +// Return the prologue of the generated header file. +grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms); + // Return the includes needed for generated header file. grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file, const Parameters ¶ms); // Return the includes needed for generated source file. -grpc::string GetSourceIncludes(const Parameters ¶ms); +grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms); + +// Return the epilogue of the generated header file. +grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms); + +// Return the prologue of the generated source file. +grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms); // Return the services for generated header file. grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file, @@ -59,6 +72,10 @@ grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file, grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file, const Parameters ¶ms); +// Return the epilogue of the generated source file. +grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file, + const Parameters ¶ms); + } // namespace grpc_cpp_generator #endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc index acbe128213a..88c704948ec 100644 --- a/src/compiler/cpp_plugin.cc +++ b/src/compiler/cpp_plugin.cc @@ -58,11 +58,6 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { return false; } - if (file->service_count() == 0) { - // No services. Do nothing. - return true; - } - grpc_cpp_generator::Parameters generator_parameters; if (!parameter.empty()) { @@ -84,16 +79,27 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc::string file_name = grpc_generator::StripProto(file->name()); - // Generate .pb.h - Insert(context, file_name + ".pb.h", "includes", - grpc_cpp_generator::GetHeaderIncludes(file, generator_parameters)); - Insert(context, file_name + ".pb.h", "namespace_scope", - grpc_cpp_generator::GetHeaderServices(file, generator_parameters)); - // Generate .pb.cc - Insert(context, file_name + ".pb.cc", "includes", - grpc_cpp_generator::GetSourceIncludes(generator_parameters)); - Insert(context, file_name + ".pb.cc", "namespace_scope", - grpc_cpp_generator::GetSourceServices(file, generator_parameters)); + grpc::string header_code = + grpc_cpp_generator::GetHeaderPrologue(file, generator_parameters) + + grpc_cpp_generator::GetHeaderIncludes(file, generator_parameters) + + grpc_cpp_generator::GetHeaderServices(file, generator_parameters) + + grpc_cpp_generator::GetHeaderEpilogue(file, generator_parameters); + std::unique_ptr header_output( + context->Open(file_name + ".grpc.pb.h")); + grpc::protobuf::io::CodedOutputStream header_coded_out( + header_output.get()); + header_coded_out.WriteRaw(header_code.data(), header_code.size()); + + grpc::string source_code = + grpc_cpp_generator::GetSourcePrologue(file, generator_parameters) + + grpc_cpp_generator::GetSourceIncludes(file, generator_parameters) + + grpc_cpp_generator::GetSourceServices(file, generator_parameters) + + grpc_cpp_generator::GetSourceEpilogue(file, generator_parameters); + std::unique_ptr source_output( + context->Open(file_name + ".grpc.pb.cc")); + grpc::protobuf::io::CodedOutputStream source_coded_out( + source_output.get()); + source_coded_out.WriteRaw(source_code.data(), source_code.size()); return true; } diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h index 30857891c77..374e1374cf4 100644 --- a/src/compiler/generator_helpers.h +++ b/src/compiler/generator_helpers.h @@ -95,6 +95,27 @@ inline std::vector tokenize(const grpc::string &input, } } +inline grpc::string CapitalizeFirstLetter(grpc::string s) { + if (s.empty()) { + return s; + } + s[0] = ::toupper(s[0]); + return s; +} + +inline grpc::string LowerUnderscoreToUpperCamel(grpc::string str) { + std::vector tokens = tokenize(str, "_"); + grpc::string result = ""; + for (unsigned int i = 0; i < tokens.size(); i++) { + result += CapitalizeFirstLetter(tokens[i]); + } + return result; +} + +inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) { + return LowerUnderscoreToUpperCamel(StripProto(file->name())); +} + } // namespace grpc_generator #endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc new file mode 100644 index 00000000000..c68c9c37c21 --- /dev/null +++ b/src/compiler/objective_c_generator.cc @@ -0,0 +1,236 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "src/compiler/objective_c_generator.h" +#include "src/compiler/objective_c_generator_helpers.h" + +#include "src/compiler/config.h" + +#include + +namespace grpc_objective_c_generator { +namespace { + +void PrintSimpleBlockSignature(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + (*vars)["method_name"] = method->name(); + (*vars)["request_type"] = PrefixedName(method->input_type()->name()); + (*vars)["response_type"] = PrefixedName(method->output_type()->name()); + + if (method->server_streaming()) { + printer->Print("// When the response stream finishes, the handler is " + "called with nil for both arguments.\n\n"); + } else { + printer->Print("// The handler is only called once.\n\n"); + } + printer->Print(*vars, "- (id)$method_name$WithRequest:" + "($request_type$)request completionHandler:(void(^)" + "($response_type$ *, NSError *))handler"); +} + +void PrintSimpleDelegateSignature(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + (*vars)["method_name"] = method->name(); + (*vars)["request_type"] = PrefixedName(method->input_type()->name()); + + printer->Print(*vars, "- (id)$method_name$WithRequest:" + "($request_type$)request delegate:(id)delegate"); +} + +void PrintAdvancedSignature(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + (*vars)["method_name"] = method->name(); + printer->Print(*vars, "- (GRXSource *)$method_name$WithRequest:" + "(id)request"); +} + +void PrintSourceMethodSimpleBlock(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + PrintSimpleBlockSignature(printer, method, vars); + + (*vars)["method_name"] = method->name(); + printer->Print(" {\n"); + printer->Indent(); + printer->Print(*vars, "return [[self $method_name$WithRequest:request] " + "connectHandler:^(id value, NSError *error) {\n"); + printer->Indent(); + printer->Print("handler(value, error);\n"); + printer->Outdent(); + printer->Print("}];\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +void PrintSourceMethodSimpleDelegate(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + PrintSimpleDelegateSignature(printer, method, vars); + + (*vars)["method_name"] = method->name(); + printer->Print(" {\n"); + printer->Indent(); + printer->Print(*vars, "return [[self $method_name$WithRequest:request]" + "connectToSink:delegate];\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +void PrintSourceMethodAdvanced(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + PrintAdvancedSignature(printer, method, vars); + + (*vars)["method_name"] = method->name(); + printer->Print(" {\n"); + printer->Indent(); + printer->Print(*vars, "return [self $method_name$WithRequest:request " + "client:[self newClient]];\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +void PrintSourceMethodHandler(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map *vars) { + (*vars)["method_name"] = method->name(); + (*vars)["response_type"] = PrefixedName(method->output_type()->name()); + (*vars)["caps_name"] = grpc_generator::CapitalizeFirstLetter(method->name()); + + printer->Print(*vars, "- (GRXSource *)$method_name$WithRequest:" + "(id)request client:(PBgRPCClient *)client {\n"); + printer->Indent(); + printer->Print(*vars, + "return [self responseWithMethod:$@\"$caps_name\"\n"); + printer->Print(*vars, + " class:[$response_type$ class]\n"); + printer->Print(" request:request\n"); + printer->Print(" client:client];\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +} + +grpc::string GetHeader(const grpc::protobuf::ServiceDescriptor *service, + const grpc::string message_header) { + grpc::string output; + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map vars; + printer.Print("#import \"PBgRPCClient.h\"\n"); + printer.Print("#import \"PBStub.h\"\n"); + vars["message_header"] = message_header; + printer.Print(vars, "#import \"$message_header$\"\n\n"); + printer.Print("@protocol GRXSource\n"); + printer.Print("@class GRXSource\n\n"); + vars["service_name"] = service->name(); + printer.Print("@protocol $service_name$Stub \n\n"); + printer.Print("#pragma mark Simple block handlers\n\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintSimpleBlockSignature(&printer, service->method(i), &vars); + printer.Print(";\n"); + } + printer.Print("\n"); + printer.Print("#pragma mark Simple delegate handlers.\n\n"); + printer.Print("# TODO(jcanizales): Use high-level snippets to remove this duplication."); + for (int i = 0; i < service->method_count(); i++) { + PrintSimpleDelegateSignature(&printer, service->method(i), &vars); + printer.Print(";\n"); + } + printer.Print("\n"); + printer.Print("#pragma mark Advanced handlers.\n\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintAdvancedSignature(&printer, service->method(i), &vars); + printer.Print(";\n"); + } + printer.Print("\n"); + printer.Print("@end\n\n"); + printer.Print("// Basic stub that only does marshalling and parsing\n"); + printer.Print(vars, "@interface $service_name$Stub :" + " PBStub<$service_name$Stub>\n"); + printer.Print("- (instancetype)initWithHost:(NSString *)host;\n"); + printer.Print("@end\n"); + return output; +} + +grpc::string GetSource(const grpc::protobuf::ServiceDescriptor *service) { + grpc::string output; + grpc::protobuf::io::StringOutputStream output_stream(&output); + grpc::protobuf::io::Printer printer(&output_stream, '$'); + std::map vars; + vars["service_name"] = service->name(); + printer.Print(vars, "#import \"$service_name$Stub.pb.h\"\n"); + printer.Print("#import \"PBGeneratedMessage+GRXSource.h\"\n\n"); + vars["full_name"] = service->full_name(); + printer.Print(vars, + "static NSString *const kInterface = @\"$full_name$\";\n"); + printer.Print("@implementation $service_name$Stub\n\n"); + printer.Print("- (instancetype)initWithHost:(NSString *)host {\n"); + printer.Indent(); + printer.Print("if ((self = [super initWithHost:host " + "interface:kInterface])) {\n"); + printer.Print("}\n"); + printer.Print("return self;\n"); + printer.Outdent(); + printer.Print("}\n\n"); + printer.Print("#pragma mark Simple block handlers.\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintSourceMethodSimpleBlock(&printer, service->method(i), &vars); + } + printer.Print("\n"); + printer.Print("#pragma mark Simple delegate handlers.\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintSourceMethodSimpleDelegate(&printer, service->method(i), &vars); + } + printer.Print("\n"); + printer.Print("#pragma mark Advanced handlers.\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintSourceMethodAdvanced(&printer, service->method(i), &vars); + } + printer.Print("\n"); + printer.Print("#pragma mark Handlers for subclasses " + "(stub wrappers) to override.\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintSourceMethodHandler(&printer, service->method(i), &vars); + } + printer.Print("@end\n"); + return output; +} + +} // namespace grpc_objective_c_generator diff --git a/src/ruby/ext/grpc/rb_event.h b/src/compiler/objective_c_generator.h similarity index 75% rename from src/ruby/ext/grpc/rb_event.h rename to src/compiler/objective_c_generator.h index 3105934b110..93c730b34e4 100644 --- a/src/ruby/ext/grpc/rb_event.h +++ b/src/compiler/objective_c_generator.h @@ -31,23 +31,18 @@ * */ -#ifndef GRPC_RB_EVENT_H_ -#define GRPC_RB_EVENT_H_ +#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H -#include -#include +#include "src/compiler/config.h" -/* rb_cEvent is the Event class whose instances proxy grpc_event. */ -extern VALUE rb_cEvent; +namespace grpc_objective_c_generator { -/* rb_cEventError is the ruby class that acts the exception thrown during rpc - event processing. */ -extern VALUE rb_eEventError; +grpc::string GetHeader(const grpc::protobuf::ServiceDescriptor *service, + const grpc::string message_header); -/* Used to create new ruby event objects */ -VALUE grpc_rb_new_event(grpc_event *ev); +grpc::string GetSource(const grpc::protobuf::ServiceDescriptor *service); -/* Initializes the Event and EventError classes. */ -void Init_grpc_event(); +} // namespace grpc_objective_c_generator -#endif /* GRPC_RB_EVENT_H_ */ +#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H diff --git a/src/compiler/objective_c_generator_helpers.h b/src/compiler/objective_c_generator_helpers.h new file mode 100644 index 00000000000..6a7c13991fd --- /dev/null +++ b/src/compiler/objective_c_generator_helpers.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H + +#include +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_objective_c_generator { + +const grpc::string prefix = "PBG"; + +inline grpc::string MessageHeaderName(const grpc::protobuf::FileDescriptor *file) { + return grpc_generator::FileNameInUpperCamel(file) + ".pb.h"; +} + +inline grpc::string StubFileName(grpc::string service_name) { + return prefix + service_name + "Stub"; +} + +inline grpc::string PrefixedName(grpc::string name) { + return prefix + name; +} + +} +#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc new file mode 100644 index 00000000000..eebce0cd20d --- /dev/null +++ b/src/compiler/objective_c_plugin.cc @@ -0,0 +1,98 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +// Generates Objective C gRPC service interface out of Protobuf IDL. + +#include + +#include "src/compiler/config.h" +#include "src/compiler/objective_c_generator.h" +#include "src/compiler/objective_c_generator_helpers.h" + +class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { + public: + ObjectiveCGrpcGenerator() {} + virtual ~ObjectiveCGrpcGenerator() {} + + virtual bool Generate(const grpc::protobuf::FileDescriptor *file, + const grpc::string ¶meter, + grpc::protobuf::compiler::GeneratorContext *context, + grpc::string *error) const { + + if (file->service_count() == 0) { + // No services. Do nothing. + return true; + } + + for (int i = 0; i < file->service_count(); i++) { + const grpc::protobuf::ServiceDescriptor *service = file->service(i); + grpc::string file_name = grpc_objective_c_generator::StubFileName( + service->name()); + + // Generate .pb.h + grpc::string header_code = grpc_objective_c_generator::GetHeader( + service, grpc_objective_c_generator::MessageHeaderName(file)); + std::unique_ptr header_output( + context->Open(file_name + ".pb.h")); + grpc::protobuf::io::CodedOutputStream header_coded_out( + header_output.get()); + header_coded_out.WriteRaw(header_code.data(), header_code.size()); + + // Generate .pb.m + grpc::string source_code = grpc_objective_c_generator::GetSource(service); + std::unique_ptr source_output( + context->Open(file_name + ".pb.m")); + grpc::protobuf::io::CodedOutputStream source_coded_out( + source_output.get()); + source_coded_out.WriteRaw(source_code.data(), source_code.size()); + } + + return true; + } + + private: + // Insert the given code into the given file at the given insertion point. + void Insert(grpc::protobuf::compiler::GeneratorContext *context, + const grpc::string &filename, const grpc::string &insertion_point, + const grpc::string &code) const { + std::unique_ptr output( + context->OpenForInsert(filename, insertion_point)); + grpc::protobuf::io::CodedOutputStream coded_out(output.get()); + coded_out.WriteRaw(code.data(), code.size()); + } +}; + +int main(int argc, char *argv[]) { + ObjectiveCGrpcGenerator generator; + return grpc::protobuf::compiler::PluginMain(argc, argv, &generator); +} diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc index d32213f7d5e..72149bc4e3a 100644 --- a/src/compiler/python_generator.cc +++ b/src/compiler/python_generator.cc @@ -354,6 +354,7 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name, "Service", service->name(), }); out->Print(dict, "def early_adopter_create_$Service$_stub(host, port," + " metadata_transformer=None," " secure=False, root_certificates=None, private_key=None," " certificate_chain=None, server_host_override=None):\n"); { @@ -423,7 +424,8 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name, out->Print( "return implementations.stub(" "\"$PackageQualifiedServiceName$\"," - " method_invocation_descriptions, host, port, secure=secure," + " method_invocation_descriptions, host, port," + " metadata_transformer=metadata_transformer, secure=secure," " root_certificates=root_certificates, private_key=private_key," " certificate_chain=certificate_chain," " server_host_override=server_host_override)\n", diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c index 7570ff18c59..bcef7c35b5d 100644 --- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c +++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c @@ -172,6 +172,9 @@ static int multipoll_with_poll_pollset_maybe_work( } r = poll(h->pfds, h->pfd_count, timeout); + + end_polling(pollset); + if (r < 0) { if (errno != EINTR) { gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); @@ -192,7 +195,6 @@ static int multipoll_with_poll_pollset_maybe_work( } } grpc_pollset_kick_post_poll(&pollset->kick_state); - end_polling(pollset); gpr_mu_lock(&pollset->mu); pollset->counter = 0; diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c index 0bb722e2b12..03fd94f1364 100644 --- a/src/core/iomgr/pollset_posix.c +++ b/src/core/iomgr/pollset_posix.c @@ -396,6 +396,9 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset, pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher); r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout); + + grpc_fd_end_poll(&fd_watcher); + if (r < 0) { if (errno != EINTR) { gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); @@ -415,7 +418,6 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset, } grpc_pollset_kick_post_poll(&pollset->kick_state); - grpc_fd_end_poll(&fd_watcher); gpr_mu_lock(&pollset->mu); pollset->counter = 0; diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h index 1e58901a7a6..66bb3ef7018 100644 --- a/src/core/iomgr/tcp_server.h +++ b/src/core/iomgr/tcp_server.h @@ -71,8 +71,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, up when grpc_tcp_server_destroy is called. */ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index); -void grpc_tcp_server_destroy(grpc_tcp_server *server, - void (*shutdown_done)(void *shutdown_done_arg), +void grpc_tcp_server_destroy(grpc_tcp_server *server, + void (*shutdown_done)(void *shutdown_done_arg), void *shutdown_done_arg); -#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */ diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c index 482166e2eb6..895f85fc682 100644 --- a/src/core/iomgr/tcp_server_posix.c +++ b/src/core/iomgr/tcp_server_posix.c @@ -154,13 +154,15 @@ static void destroyed_port(void *server, int success) { static void dont_care_about_shutdown_completion(void *ignored) {} -void grpc_tcp_server_destroy(grpc_tcp_server *s, - void (*shutdown_complete)(void *shutdown_complete_arg), - void *shutdown_complete_arg) { +void grpc_tcp_server_destroy( + grpc_tcp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg), + void *shutdown_complete_arg) { size_t i; gpr_mu_lock(&s->mu); - s->shutdown_complete = shutdown_complete ? shutdown_complete : dont_care_about_shutdown_completion; + s->shutdown_complete = shutdown_complete + ? shutdown_complete + : dont_care_about_shutdown_completion; s->shutdown_complete_arg = shutdown_complete_arg; /* shutdown all fd's */ diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index 896c9e5d08a..a43d5670a41 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -93,8 +93,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) { } void grpc_tcp_server_destroy(grpc_tcp_server *s, - void(*shutdown_done)(void *shutdown_done_arg), - void *shutdown_done_arg) { + void (*shutdown_done)(void *shutdown_done_arg), + void *shutdown_done_arg) { size_t i; gpr_mu_lock(&s->mu); /* shutdown all fd's */ @@ -116,13 +116,13 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s, gpr_free(s); if (shutdown_done) { - shutdown_done(shutdown_done_arg); + shutdown_done(shutdown_done_arg); } } /* Prepare a recently-created socket for listening. */ -static int prepare_socket(SOCKET sock, - const struct sockaddr *addr, int addr_len) { +static int prepare_socket(SOCKET sock, const struct sockaddr *addr, + int addr_len) { struct sockaddr_storage sockname_temp; socklen_t sockname_len; @@ -153,15 +153,15 @@ static int prepare_socket(SOCKET sock, } sockname_len = sizeof(sockname_temp); - if (getsockname(sock, (struct sockaddr *) &sockname_temp, &sockname_len) - == SOCKET_ERROR) { + if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) == + SOCKET_ERROR) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "getsockname: %s", utf8_message); gpr_free(utf8_message); goto error; } - return grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp); + return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); error: if (sock != INVALID_SOCKET) closesocket(sock); @@ -227,8 +227,7 @@ static void on_accept(void *arg, int success) { DWORD transfered_bytes = 0; DWORD flags; BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, - &transfered_bytes, FALSE, - &flags); + &transfered_bytes, FALSE, &flags); if (!wsa_success) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message); @@ -263,9 +262,9 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock, if (sock == INVALID_SOCKET) return -1; - status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, - &guid, sizeof(guid), &AcceptEx, sizeof(AcceptEx), - &ioctl_num_bytes, NULL, NULL); + status = + WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL); if (status != 0) { char *utf8_message = gpr_format_message(WSAGetLastError()); @@ -313,9 +312,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, for (i = 0; i < s->nports; i++) { sockname_len = sizeof(sockname_temp); if (0 == getsockname(s->ports[i].socket->socket, - (struct sockaddr *) &sockname_temp, - &sockname_len)) { - port = grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp); + (struct sockaddr *)&sockname_temp, &sockname_len)) { + port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { allocated_addr = malloc(addr_len); memcpy(allocated_addr, addr, addr_len); @@ -336,7 +334,7 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, if (grpc_sockaddr_is_wildcard(addr, &port)) { grpc_sockaddr_make_wildcard6(port, &wildcard); - addr = (struct sockaddr *) &wildcard; + addr = (struct sockaddr *)&wildcard; addr_len = sizeof(wildcard); } @@ -375,4 +373,4 @@ void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset, gpr_mu_unlock(&s->mu); } -#endif /* GPR_WINSOCK_SOCKET */ +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index d5b3a82b878..081272724cf 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -85,10 +85,10 @@ static void on_secure_transport_setup_done(void *statep, if (status == GRPC_SECURITY_OK) { gpr_mu_lock(&state->mu); if (!state->is_shutdown) { - grpc_create_chttp2_transport( - setup_transport, state->server, - grpc_server_get_channel_args(state->server), - secure_endpoint, NULL, 0, grpc_mdctx_create(), 0); + grpc_create_chttp2_transport(setup_transport, state->server, + grpc_server_get_channel_args(state->server), + secure_endpoint, NULL, 0, + grpc_mdctx_create(), 0); } else { /* We need to consume this here, because the server may already have gone * away. */ @@ -104,7 +104,8 @@ static void on_secure_transport_setup_done(void *statep, static void on_accept(void *statep, grpc_endpoint *tcp) { grpc_server_secure_state *state = statep; state_ref(state); - grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done, state); + grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done, + state); } /* Server callback: start listening on our ports */ @@ -120,12 +121,14 @@ static void destroy(grpc_server *server, void *statep) { grpc_server_secure_state *state = statep; gpr_mu_lock(&state->mu); state->is_shutdown = 1; - grpc_tcp_server_destroy(state->tcp, grpc_server_listener_destroy_done, server); + grpc_tcp_server_destroy(state->tcp, grpc_server_listener_destroy_done, + server); gpr_mu_unlock(&state->mu); state_unref(state); } -int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { +int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, + grpc_server_credentials *creds) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; grpc_server_secure_state *state = NULL; diff --git a/src/core/support/thd.c b/src/core/support/thd.c new file mode 100644 index 00000000000..ec308f3119e --- /dev/null +++ b/src/core/support/thd.c @@ -0,0 +1,66 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix implementation for gpr threads. */ + +#include + +#include + +enum { + GPR_THD_JOINABLE = 1 +}; + +gpr_thd_options gpr_thd_options_default(void) { + gpr_thd_options options; + memset(&options, 0, sizeof(options)); + return options; +} + +void gpr_thd_options_set_detached(gpr_thd_options *options) { + options->flags &= ~GPR_THD_JOINABLE; +} + +void gpr_thd_options_set_joinable(gpr_thd_options *options) { + options->flags |= GPR_THD_JOINABLE; +} + +int gpr_thd_options_is_detached(const gpr_thd_options *options) { + if (!options) return 1; + return (options->flags & GPR_THD_JOINABLE) == 0; +} + +int gpr_thd_options_is_joinable(const gpr_thd_options *options) { + if (!options) return 0; + return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE; +} diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c index f50ea583357..fa4eb505561 100644 --- a/src/core/support/thd_posix.c +++ b/src/core/support/thd_posix.c @@ -68,7 +68,11 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, a->arg = arg; GPR_ASSERT(pthread_attr_init(&attr) == 0); - GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); + if (gpr_thd_options_is_detached(options)) { + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); + } else { + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); + } thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0); GPR_ASSERT(pthread_attr_destroy(&attr) == 0); if (!thread_started) { @@ -78,14 +82,12 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, return thread_started; } -gpr_thd_options gpr_thd_options_default(void) { - gpr_thd_options options; - memset(&options, 0, sizeof(options)); - return options; -} - gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } +void gpr_thd_join(gpr_thd_id t) { + pthread_join((pthread_t)t, NULL); +} + #endif /* GPR_POSIX_SYNC */ diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c index 347cad57e3a..3cc798293ac 100644 --- a/src/core/support/thd_win32.c +++ b/src/core/support/thd_win32.c @@ -31,7 +31,7 @@ * */ -/* Posix implementation for gpr threads. */ +/* Windows implementation for gpr threads. */ #include @@ -40,47 +40,81 @@ #include #include #include +#include #include -struct thd_arg { +#if defined(_MSC_VER) +#define thread_local __declspec(thread) +#elif defined(__GNUC__) +#define thread_local __thread +#else +#error "Unknown compiler - please file a bug report" +#endif + +struct thd_info { void (*body)(void *arg); /* body of a thread */ void *arg; /* argument to a thread */ + HANDLE join_event; /* if joinable, the join event */ + int joinable; /* true if not detached */ }; +static thread_local struct thd_info *g_thd_info; + +/* Destroys a thread info */ +static void destroy_thread(struct thd_info *t) { + if (t->joinable) CloseHandle(t->join_event); + gpr_free(t); +} + /* Body of every thread started via gpr_thd_new. */ static DWORD WINAPI thread_body(void *v) { - struct thd_arg a = *(struct thd_arg *)v; - gpr_free(v); - (*a.body)(a.arg); + g_thd_info = (struct thd_info *)v; + g_thd_info->body(g_thd_info->arg); + if (g_thd_info->joinable) { + BOOL ret = SetEvent(g_thd_info->join_event); + GPR_ASSERT(ret); + } else { + destroy_thread(g_thd_info); + } return 0; } int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, const gpr_thd_options *options) { HANDLE handle; - DWORD thread_id; - struct thd_arg *a = gpr_malloc(sizeof(*a)); - a->body = thd_body; - a->arg = arg; + struct thd_info *info = gpr_malloc(sizeof(*info)); + info->body = thd_body; + info->arg = arg; *t = 0; - handle = CreateThread(NULL, 64 * 1024, thread_body, a, 0, &thread_id); + if (gpr_thd_options_is_joinable(options)) { + info->joinable = 1; + info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (info->join_event == NULL) { + gpr_free(info); + return 0; + } + } else { + info->joinable = 0; + } + handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL); if (handle == NULL) { - gpr_free(a); + destroy_thread(info); } else { - CloseHandle(handle); /* threads are "detached" */ + *t = (gpr_thd_id)info; + CloseHandle(handle); } - *t = (gpr_thd_id)thread_id; return handle != NULL; } -gpr_thd_options gpr_thd_options_default(void) { - gpr_thd_options options; - memset(&options, 0, sizeof(options)); - return options; +gpr_thd_id gpr_thd_currentid(void) { + return (gpr_thd_id)g_thd_info; } -gpr_thd_id gpr_thd_currentid(void) { - return (gpr_thd_id)GetCurrentThreadId(); +void gpr_thd_join(gpr_thd_id t) { + struct thd_info *info = (struct thd_info *)t; + DWORD ret = WaitForSingleObject(info->join_event, INFINITE); + GPR_ASSERT(ret == WAIT_OBJECT_0); + destroy_thread(info); } #endif /* GPR_WIN32 */ diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index b08bd93693e..24f4a05071a 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -436,6 +436,7 @@ grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc) { gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); grpc_pollset_kick(&cc->pollset); - grpc_pollset_work(&cc->pollset, gpr_time_add(gpr_now(), gpr_time_from_millis(100))); + grpc_pollset_work(&cc->pollset, + gpr_time_add(gpr_now(), gpr_time_from_millis(100))); gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); } diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h index 3e9e2d186ef..3a7cc99dda9 100644 --- a/src/core/surface/completion_queue.h +++ b/src/core/surface/completion_queue.h @@ -116,4 +116,4 @@ grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc); -#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */ diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 2e013ea7421..17cba9a505b 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -592,9 +592,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } static const grpc_channel_filter server_surface_filter = { - call_op, channel_op, sizeof(call_data), - init_call_elem, destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "server", + call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, "server", }; static void addcq(grpc_server *server, grpc_completion_queue *cq) { @@ -737,7 +736,8 @@ grpc_transport_setup_result grpc_server_setup_transport( channel = grpc_channel_create_from_filters(filters, num_filters, s->channel_args, mdctx, 0); chand = (channel_data *)grpc_channel_stack_element( - grpc_channel_get_channel_stack(channel), 0)->channel_data; + grpc_channel_get_channel_stack(channel), 0) + ->channel_data; chand->server = s; server_ref(s); chand->channel = channel; @@ -758,7 +758,7 @@ grpc_transport_setup_result grpc_server_setup_transport( method = grpc_mdstr_from_string(mdctx, rm->method); hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash); for (probes = 0; chand->registered_methods[(hash + probes) % slots] - .server_registered_method != NULL; + .server_registered_method != NULL; probes++) ; if (probes > max_probes) max_probes = probes; @@ -927,7 +927,8 @@ void grpc_server_destroy(grpc_server *server) { gpr_mu_lock(&server->mu); } - gpr_cv_wait(&server->cv, &server->mu, gpr_time_add(gpr_now(), gpr_time_from_millis(100))); + gpr_cv_wait(&server->cv, &server->mu, + gpr_time_add(gpr_now(), gpr_time_from_millis(100))); } while (server->listeners) { diff --git a/src/core/surface/server.h b/src/core/surface/server.h index 548a16c6c96..2cfa38fa436 100644 --- a/src/core/surface/server.h +++ b/src/core/surface/server.h @@ -48,7 +48,8 @@ grpc_server *grpc_server_create_from_filters(grpc_completion_queue *cq, and when it shuts down, it will call destroy */ void grpc_server_add_listener(grpc_server *server, void *listener, void (*start)(grpc_server *server, void *arg, - grpc_pollset **pollsets, size_t npollsets), + grpc_pollset **pollsets, + size_t npollsets), void (*destroy)(grpc_server *server, void *arg)); void grpc_server_listener_destroy_done(void *server); @@ -62,4 +63,4 @@ grpc_transport_setup_result grpc_server_setup_transport( const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); -#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */ diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c index 9a23125752a..f3b9219f8b0 100644 --- a/src/core/surface/server_chttp2.c +++ b/src/core/surface/server_chttp2.c @@ -66,7 +66,8 @@ static void new_transport(void *server, grpc_endpoint *tcp) { } /* Server callback: start listening on our ports */ -static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, size_t pollset_count) { +static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, + size_t pollset_count) { grpc_tcp_server *tcp = tcpp; grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server); } diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index d6f9acc6755..0a73b2c0f67 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -31,38 +31,23 @@ * */ -#include #include #include -#include -#include #include "src/cpp/client/channel.h" +#include "src/cpp/client/secure_credentials.h" namespace grpc { -class SecureCredentials GRPC_FINAL : public Credentials { - public: - explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {} - ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); } - grpc_credentials* GetRawCreds() { return c_creds_; } - - std::shared_ptr CreateChannel( - const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE { - grpc_channel_args channel_args; - args.SetChannelArgs(&channel_args); - return std::shared_ptr(new Channel( - args.GetSslTargetNameOverride().empty() - ? target - : args.GetSslTargetNameOverride(), - grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args))); - } - - SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; } - - private: - grpc_credentials* const c_creds_; -}; +std::shared_ptr SecureCredentials::CreateChannel( + const string& target, const grpc::ChannelArguments& args) { + grpc_channel_args channel_args; + args.SetChannelArgs(&channel_args); + return std::shared_ptr(new Channel( + args.GetSslTargetNameOverride().empty() ? target + : args.GetSslTargetNameOverride(), + grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args))); +} namespace { std::unique_ptr WrapCredentials(grpc_credentials* creds) { diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h new file mode 100644 index 00000000000..77d575813ea --- /dev/null +++ b/src/cpp/client/secure_credentials.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H +#define GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H + +#include + +#include +#include + +namespace grpc { + +class SecureCredentials GRPC_FINAL : public Credentials { + public: + explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {} + ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); } + grpc_credentials* GetRawCreds() { return c_creds_; } + + std::shared_ptr CreateChannel( + const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE; + SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; } + + private: + grpc_credentials* const c_creds_; +}; + +} // namespace grpc + +#endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H + diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index 49d69a3fb9a..3e262dd74f7 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -31,39 +31,22 @@ * */ -#include - -#include +#include "src/cpp/server/secure_server_credentials.h" namespace grpc { -namespace { -class SecureServerCredentials GRPC_FINAL : public ServerCredentials { - public: - explicit SecureServerCredentials(grpc_server_credentials* creds) - : creds_(creds) {} - ~SecureServerCredentials() GRPC_OVERRIDE { - grpc_server_credentials_release(creds_); - } - - int AddPortToServer(const grpc::string& addr, - grpc_server* server) GRPC_OVERRIDE { - return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); - } - - private: - grpc_server_credentials* const creds_; -}; -} // namespace +int SecureServerCredentials::AddPortToServer( + const grpc::string& addr, grpc_server* server) { + return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); +} std::shared_ptr SslServerCredentials( const SslServerCredentialsOptions& options) { std::vector pem_key_cert_pairs; for (auto key_cert_pair = options.pem_key_cert_pairs.begin(); - key_cert_pair != options.pem_key_cert_pairs.end(); - key_cert_pair++) { + key_cert_pair != options.pem_key_cert_pairs.end(); key_cert_pair++) { grpc_ssl_pem_key_cert_pair p = {key_cert_pair->private_key.c_str(), - key_cert_pair->cert_chain.c_str()}; + key_cert_pair->cert_chain.c_str()}; pem_key_cert_pairs.push_back(p); } grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create( diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h new file mode 100644 index 00000000000..b9803f107e5 --- /dev/null +++ b/src/cpp/server/secure_server_credentials.h @@ -0,0 +1,60 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H +#define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H + +#include + +#include + +namespace grpc { + +class SecureServerCredentials GRPC_FINAL : public ServerCredentials { + public: + explicit SecureServerCredentials(grpc_server_credentials* creds) + : creds_(creds) {} + ~SecureServerCredentials() GRPC_OVERRIDE { + grpc_server_credentials_release(creds_); + } + + int AddPortToServer(const grpc::string& addr, + grpc_server* server) GRPC_OVERRIDE; + + private: + grpc_server_credentials* const creds_; +}; + +} // namespace grpc + +#endif // GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc index bd0a23739c3..046133c5eb1 100644 --- a/src/cpp/server/server.cc +++ b/src/cpp/server/server.cc @@ -183,7 +183,7 @@ Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned) Server::~Server() { { - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); if (started_ && !shutdown_) { lock.unlock(); Shutdown(); @@ -259,7 +259,7 @@ bool Server::Start() { } void Server::Shutdown() { - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); if (started_ && !shutdown_) { shutdown_ = true; grpc_server_shutdown(server_); @@ -273,7 +273,7 @@ void Server::Shutdown() { } void Server::Wait() { - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); while (num_running_cb_ != 0) { callback_cv_.wait(lock); } @@ -405,7 +405,7 @@ void Server::RequestAsyncGenericCall(GenericServerContext* context, void Server::ScheduleCallback() { { - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); num_running_cb_++; } thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this)); @@ -426,7 +426,7 @@ void Server::RunRpc() { } { - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); num_running_cb_--; if (shutdown_) { callback_cv_.notify_all(); diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index bb3c2d1405f..ffd6d30d5d4 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -33,9 +33,8 @@ #include -#include - #include +#include #include #include #include "src/cpp/util/time.h" @@ -57,14 +56,14 @@ class ServerContext::CompletionOp GRPC_FINAL : public CallOpBuffer { void Unref(); private: - std::mutex mu_; + grpc::mutex mu_; int refs_; bool finalized_; bool cancelled_; }; void ServerContext::CompletionOp::Unref() { - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); if (--refs_ == 0) { lock.unlock(); delete this; @@ -73,13 +72,13 @@ void ServerContext::CompletionOp::Unref() { bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) { cq->TryPluck(this); - std::lock_guard g(mu_); + grpc::lock_guard g(mu_); return finalized_ ? cancelled_ : false; } bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) { GPR_ASSERT(CallOpBuffer::FinalizeResult(tag, status)); - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); finalized_ = true; if (!*status) cancelled_ = true; if (--refs_ == 0) { diff --git a/src/cpp/server/thread_pool.cc b/src/cpp/server/thread_pool.cc index 80c96111b1f..e8d0e89ed21 100644 --- a/src/cpp/server/thread_pool.cc +++ b/src/cpp/server/thread_pool.cc @@ -31,6 +31,9 @@ * */ +#include +#include + #include "src/cpp/server/thread_pool.h" namespace grpc { @@ -38,7 +41,7 @@ namespace grpc { void ThreadPool::ThreadFunc() { for (;;) { // Wait until work is available or we are shutting down. - std::unique_lock lock(mu_); + grpc::unique_lock lock(mu_); if (!shutdown_ && callbacks_.empty()) { cv_.wait(lock); } @@ -57,13 +60,13 @@ void ThreadPool::ThreadFunc() { ThreadPool::ThreadPool(int num_threads) : shutdown_(false) { for (int i = 0; i < num_threads; i++) { - threads_.push_back(std::thread(&ThreadPool::ThreadFunc, this)); + threads_.push_back(grpc::thread(&ThreadPool::ThreadFunc, this)); } } ThreadPool::~ThreadPool() { { - std::lock_guard lock(mu_); + grpc::lock_guard lock(mu_); shutdown_ = true; cv_.notify_all(); } @@ -73,7 +76,7 @@ ThreadPool::~ThreadPool() { } void ThreadPool::ScheduleCallback(const std::function& callback) { - std::lock_guard lock(mu_); + grpc::lock_guard lock(mu_); callbacks_.push(callback); cv_.notify_one(); } diff --git a/src/cpp/server/thread_pool.h b/src/cpp/server/thread_pool.h index 41e2009ff16..0f24d6e9b32 100644 --- a/src/cpp/server/thread_pool.h +++ b/src/cpp/server/thread_pool.h @@ -35,11 +35,11 @@ #define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H #include + +#include +#include #include -#include -#include -#include #include #include @@ -53,11 +53,11 @@ class ThreadPool GRPC_FINAL : public ThreadPoolInterface { void ScheduleCallback(const std::function& callback) GRPC_OVERRIDE; private: - std::mutex mu_; - std::condition_variable cv_; + grpc::mutex mu_; + grpc::condition_variable cv_; bool shutdown_; std::queue> callbacks_; - std::vector threads_; + std::vector threads_; void ThreadFunc(); }; diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs index e4328806ad4..e0f04742451 100644 --- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec index af8a8869ca1..f2032522c90 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.nuspec +++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec @@ -7,7 +7,7 @@ Core C# implementation of gRPC - an RPC library and framework. See project site for more info. This is an experimental release, not ready to use. - 0.1.0 + 0.2.0 Google Inc. jtattermusch https://github.com/grpc/grpc/blob/master/LICENSE diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs index 168939cf8c5..81218cb67e2 100644 --- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs @@ -9,6 +9,6 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] [assembly: InternalsVisibleTo("Grpc.Core.Tests")] diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index f5956bd33e0..ca7683d399f 100644 --- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs +++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs @@ -46,11 +46,15 @@ namespace math MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel); MathExamples.DivExample(stub); - MathExamples.FibExample(stub); + MathExamples.DivAsyncExample(stub).Wait(); - MathExamples.SumExample(stub); + MathExamples.FibExample(stub).Wait(); - MathExamples.DivManyExample(stub); + MathExamples.SumExample(stub).Wait(); + + MathExamples.DivManyExample(stub).Wait(); + + MathExamples.DependendRequestsExample(stub).Wait(); } GrpcEnvironment.Shutdown(); diff --git a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs index 11fc099a954..1989ca84308 100644 --- a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.Examples.MathServer/.gitignore b/src/csharp/Grpc.Examples.MathServer/.gitignore new file mode 100644 index 00000000000..1746e3269ed --- /dev/null +++ b/src/csharp/Grpc.Examples.MathServer/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj new file mode 100644 index 00000000000..3f7e6c07680 --- /dev/null +++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj @@ -0,0 +1,52 @@ + + + + Debug + x86 + 10.0.0 + 2.0 + {BF62FE08-373A-43D6-9D73-41CAA38B7011} + Exe + Grpc.Examples.MathServer + Grpc.Examples.MathServer + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + x86 + + + full + true + bin\Release + prompt + 4 + true + x86 + + + + + + + + + + + + {CCC4440E-49F7-4790-B0AF-FEABB0837AE7} + Grpc.Core + + + {7DC1433E-3225-42C7-B7EA-546D56E27A4B} + Grpc.Examples + + + \ No newline at end of file diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs new file mode 100644 index 00000000000..884a84d0a6c --- /dev/null +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -0,0 +1,61 @@ +#region Copyright notice and license +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using Grpc.Core; + +namespace math +{ + class MainClass + { + public static void Main(string[] args) + { + String host = "0.0.0.0"; + + GrpcEnvironment.Initialize(); + + Server server = new Server(); + server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); + int port = server.AddListeningPort(host + ":0"); + server.Start(); + + Console.WriteLine("MathServer listening on port " + port); + + Console.WriteLine("Press any key to stop the server..."); + Console.ReadKey(); + + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } + } +} diff --git a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..6b3d0516b90 --- /dev/null +++ b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs @@ -0,0 +1,12 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Grpc.Examples.MathServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Google Inc. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyVersion("0.1.*")] diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj index cf5a6400796..f9c1caf700d 100644 --- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj +++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj @@ -37,6 +37,18 @@ ..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 85f213cb391..fa5d6688a6b 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -33,6 +33,7 @@ using System; using System.Collections.Generic; +using System.Reactive.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; @@ -120,14 +121,12 @@ namespace math.Tests [Test] public void Sum() { - var res = client.Sum(); - foreach (var num in new long[] { 10, 20, 30 }) - { - res.Inputs.OnNext(Num.CreateBuilder().SetNum_(num).Build()); - } - res.Inputs.OnCompleted(); + var clientStreamingResult = client.Sum(); + var numList = new List { 10, 20, 30 }.ConvertAll( + n => Num.CreateBuilder().SetNum_(n).Build()); + numList.Subscribe(clientStreamingResult.Inputs); - Assert.AreEqual(60, res.Task.Result.Num_); + Assert.AreEqual(60, clientStreamingResult.Task.Result.Num_); } [Test] @@ -142,13 +141,7 @@ namespace math.Tests var recorder = new RecordingObserver(); var requestObserver = client.DivMany(recorder); - - foreach (var arg in divArgsList) - { - requestObserver.OnNext(arg); - } - requestObserver.OnCompleted(); - + divArgsList.Subscribe(requestObserver); var result = recorder.ToList().Result; CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); diff --git a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs index 43c7616ac3a..d78e9210c09 100644 --- a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config index 51c17bcd5e7..06c5e6a4ebe 100644 --- a/src/csharp/Grpc.Examples.Tests/packages.config +++ b/src/csharp/Grpc.Examples.Tests/packages.config @@ -1,5 +1,10 @@ - - - - + + + + + + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs index b8bb7eacbd0..032372b2a11 100644 --- a/src/csharp/Grpc.Examples/MathExamples.cs +++ b/src/csharp/Grpc.Examples/MathExamples.cs @@ -45,51 +45,45 @@ namespace math Console.WriteLine("Div Result: " + result); } - public static void DivAsyncExample(MathGrpc.IMathServiceClient stub) + public static async Task DivAsyncExample(MathGrpc.IMathServiceClient stub) { - Task call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); - DivReply result = call.Result; - Console.WriteLine(result); + Task resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); + DivReply result = await resultTask; + Console.WriteLine("DivAsync Result: " + result); } - public static void DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub) + public static async Task DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub) { - Task call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); - DivReply result = call.Result; + Task resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); + DivReply result = await resultTask; Console.WriteLine(result); } - public static void FibExample(MathGrpc.IMathServiceClient stub) + public static async Task FibExample(MathGrpc.IMathServiceClient stub) { var recorder = new RecordingObserver(); stub.Fib(new FibArgs.Builder { Limit = 5 }.Build(), recorder); - - List numbers = recorder.ToList().Result; - Console.WriteLine("Fib Result: " + string.Join("|", recorder.ToList().Result)); + List result = await recorder.ToList(); + Console.WriteLine("Fib Result: " + string.Join("|", result)); } - public static void SumExample(MathGrpc.IMathServiceClient stub) + public static async Task SumExample(MathGrpc.IMathServiceClient stub) { - List numbers = new List + var numbers = new List { new Num.Builder { Num_ = 1 }.Build(), new Num.Builder { Num_ = 2 }.Build(), new Num.Builder { Num_ = 3 }.Build() }; - var res = stub.Sum(); - foreach (var num in numbers) - { - res.Inputs.OnNext(num); - } - res.Inputs.OnCompleted(); - - Console.WriteLine("Sum Result: " + res.Task.Result); + var clientStreamingResult = stub.Sum(); + numbers.Subscribe(clientStreamingResult.Inputs); + Console.WriteLine("Sum Result: " + await clientStreamingResult.Task); } - public static void DivManyExample(MathGrpc.IMathServiceClient stub) + public static async Task DivManyExample(MathGrpc.IMathServiceClient stub) { - List divArgsList = new List + var divArgsList = new List { new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(), new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), @@ -97,26 +91,27 @@ namespace math }; var recorder = new RecordingObserver(); - var inputs = stub.DivMany(recorder); - foreach (var input in divArgsList) - { - inputs.OnNext(input); - } - inputs.OnCompleted(); - - Console.WriteLine("DivMany Result: " + string.Join("|", recorder.ToList().Result)); + divArgsList.Subscribe(inputs); + var result = await recorder.ToList(); + Console.WriteLine("DivMany Result: " + string.Join("|", result)); } - public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub) + public static async Task DependendRequestsExample(MathGrpc.IMathServiceClient stub) { - var numberList = new List + var numbers = new List { - new Num.Builder { Num_ = 1 }.Build(), - new Num.Builder { Num_ = 2 }.Build(), new Num.Builder { Num_ = 3 }.Build() + new Num.Builder { Num_ = 1 }.Build(), + new Num.Builder { Num_ = 2 }.Build(), + new Num.Builder { Num_ = 3 }.Build() }; - numberList.ToObservable(); + var clientStreamingResult = stub.Sum(); + numbers.Subscribe(clientStreamingResult.Inputs); + Num sum = await clientStreamingResult.Task; + + DivReply result = await stub.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build()); + Console.WriteLine("Avg Result: " + result); } } } diff --git a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs index b55d24166cc..fd1cdbbc1c2 100644 --- a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs index c93dd1eb2f3..d9d36f03e42 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs index f3def1aea44..b0b163b8838 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs index f09a448e9e2..fe6c8a8aed4 100644 --- a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs @@ -9,4 +9,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("0.1.*")] +[assembly: AssemblyVersion("0.2.*")] diff --git a/src/csharp/Grpc.nuspec b/src/csharp/Grpc.nuspec index 96a6aaf6b72..4c106a2ca2e 100644 --- a/src/csharp/Grpc.nuspec +++ b/src/csharp/Grpc.nuspec @@ -7,7 +7,7 @@ C# implementation of gRPC - an RPC library and framework. See project site for more info. This is an experimental release, not ready to use. - 0.1.0 + 0.2.0 Google Inc. jtattermusch https://github.com/grpc/grpc/blob/master/LICENSE @@ -17,7 +17,7 @@ Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 - + diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index 2e6d2886993..2f8c2e17190 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Cli EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.csproj", "{A654F3B8-E859-4E6A-B30D-227527DBEF0D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{BF62FE08-373A-43D6-9D73-41CAA38B7011}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -47,6 +49,10 @@ Global {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86 {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86 {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86 + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86 + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86 + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86 + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86 {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86 {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86 {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86 diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 9a1c908d11b..e182468d9b0 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -731,7 +731,7 @@ grpcsharp_ssl_credentials_create(const char *pem_root_certs, } } -GPR_EXPORT void grpcsharp_credentials_release(grpc_credentials *creds) { +GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *creds) { grpc_credentials_release(creds); } @@ -765,7 +765,7 @@ grpcsharp_ssl_server_credentials_create( return creds; } -GPR_EXPORT void grpcsharp_server_credentials_release( +GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_credentials_release( grpc_server_credentials *creds) { grpc_server_credentials_release(creds); } diff --git a/src/node/binding.gyp b/src/node/binding.gyp index 7ef3bdf4bde..83f72fabcac 100644 --- a/src/node/binding.gyp +++ b/src/node/binding.gyp @@ -18,12 +18,29 @@ ], 'link_settings': { 'libraries': [ - '-lrt', '-lpthread', '-lgrpc', '-lgpr' - ], + ] }, + "conditions": [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9', + 'OTHER_CFLAGS': [ + '-std=c++11', + '-stdlib=libc++' + ] + } + }], + ['OS != "mac"', { + 'link_settings': { + 'libraries': [ + '-lrt' + ] + } + }] + ], "target_name": "grpc", "sources": [ "ext/byte_buffer.cc", diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc index 82b54b518c0..01bd92ea523 100644 --- a/src/node/ext/byte_buffer.cc +++ b/src/node/ext/byte_buffer.cc @@ -32,7 +32,6 @@ */ #include -#include #include #include diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index 787e274973f..d37bf763ddc 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -31,8 +31,6 @@ * */ -#include - #include #include diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc index e47bac833bd..3c2396b8101 100644 --- a/src/node/ext/server.cc +++ b/src/node/ext/server.cc @@ -38,8 +38,6 @@ #include #include -#include - #include #include "grpc/grpc.h" #include "grpc/grpc_security.h" diff --git a/src/ruby/lib/grpc/core/event.rb b/src/php/bin/generate_proto_php.sh old mode 100644 new mode 100755 similarity index 83% rename from src/ruby/lib/grpc/core/event.rb rename to src/php/bin/generate_proto_php.sh index 194aa8ecac9..16f93747ab8 --- a/src/ruby/lib/grpc/core/event.rb +++ b/src/php/bin/generate_proto_php.sh @@ -1,3 +1,4 @@ +#!/bin/sh # Copyright 2015, Google Inc. # All rights reserved. # @@ -27,18 +28,13 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -require 'grpc' -# GRPC contains the General RPC module. -module GRPC - module Core - # Event is a class defined in the c extension - # - # Here, we add an inspect method. - class Event - def inspect - "<#{self.class}: type:#{type}, tag:#{tag} result:#{result}>" - end - end - end -end +set +e +cd $(dirname $0) + +gen_code='../tests/generated_code' +interop='../tests/interop' + +protoc-gen-php -i $gen_code -o $gen_code $gen_code/math.proto + +protoc-gen-php -i $interop -o $interop $interop/test.proto diff --git a/src/php/composer.json b/src/php/composer.json index dca61a9889a..3c0cb37231f 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -1,7 +1,7 @@ { "name": "grpc/grpc", "description": "gRPC library for PHP", - "version": "0.2.0", + "version": "0.5.0", "homepage": "http://grpc.io", "license": "BSD-3-Clause", "require": { diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c index 6bc65b53679..b1525e9246a 100644 --- a/src/php/ext/grpc/call.c +++ b/src/php/ext/grpc/call.c @@ -443,8 +443,9 @@ PHP_METHOD(Call, startBatch) { add_property_bool(result, "send_status", true); break; case GRPC_OP_RECV_INITIAL_METADATA: - add_property_zval(result, "metadata", - grpc_parse_metadata_array(&recv_metadata)); + array = grpc_parse_metadata_array(&recv_metadata); + add_property_zval(result, "metadata", array); + Z_DELREF_P(array); break; case GRPC_OP_RECV_MESSAGE: byte_buffer_to_string(message, &message_str, &message_len); @@ -458,11 +459,13 @@ PHP_METHOD(Call, startBatch) { case GRPC_OP_RECV_STATUS_ON_CLIENT: MAKE_STD_ZVAL(recv_status); object_init(recv_status); - add_property_zval(recv_status, "metadata", - grpc_parse_metadata_array(&recv_trailing_metadata)); + array = grpc_parse_metadata_array(&recv_trailing_metadata); + add_property_zval(recv_status, "metadata", array); + Z_DELREF_P(array); add_property_long(recv_status, "code", status); add_property_string(recv_status, "details", status_details, true); add_property_zval(result, "status", recv_status); + Z_DELREF_P(recv_status); break; case GRPC_OP_RECV_CLOSE_ON_SERVER: add_property_bool(result, "cancelled", cancelled); diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index 51a3eae0f4e..b8262db162b 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -62,6 +62,7 @@ void free_wrapped_grpc_channel(void *object TSRMLS_DC) { if (channel->wrapped != NULL) { grpc_channel_destroy(channel->wrapped); } + efree(channel->target); efree(channel); } diff --git a/src/python/README.md b/src/python/README.md index c8057be38b3..82bc7767322 100644 --- a/src/python/README.md +++ b/src/python/README.md @@ -42,7 +42,14 @@ $ tools/run_tests/run_python.sh Installing ----------------------- -- [Install the gRPC core](https://github.com/grpc/grpc/blob/master/INSTALL) +- Install the gRPC core + - [Debian package](https://github.com/grpc/grpc/releases) + ``` + $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc_0.5.0_amd64.deb + $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc-dev_0.5.0_amd64.deb + $ sudo dpkg -i libgrpc_0.5.0_amd64.deb libgrpc-dev_0.5.0_amd64.deb + ``` + - [From source](https://github.com/grpc/grpc/blob/master/INSTALL) - Install gRPC Python's dependencies ``` @@ -53,3 +60,16 @@ $ pip install -r src/python/requirements.txt ``` $ pip install src/python/src ``` + +Packaging to PyPI +----------------------- + +- Install packaging dependencies +``` +$ pip install setuptools twine +``` + +- Push to PyPI +``` +$ ../../tools/distrib/python/submit.py +``` diff --git a/src/python/interop/interop/_interop_test_case.py b/src/python/interop/interop/_interop_test_case.py index fec8f1915d5..cd6a574e90d 100644 --- a/src/python/interop/interop/_interop_test_case.py +++ b/src/python/interop/interop/_interop_test_case.py @@ -40,16 +40,16 @@ class InteropTestCase(object): """ def testEmptyUnary(self): - methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub) + methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub, None) def testLargeUnary(self): - methods.TestCase.LARGE_UNARY.test_interoperability(self.stub) + methods.TestCase.LARGE_UNARY.test_interoperability(self.stub, None) def testServerStreaming(self): - methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub) + methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub, None) def testClientStreaming(self): - methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub) + methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub, None) def testPingPong(self): - methods.TestCase.PING_PONG.test_interoperability(self.stub) + methods.TestCase.PING_PONG.test_interoperability(self.stub, None) diff --git a/src/python/interop/interop/client.py b/src/python/interop/interop/client.py index 85a0dcd9983..bae5e174604 100644 --- a/src/python/interop/interop/client.py +++ b/src/python/interop/interop/client.py @@ -30,6 +30,7 @@ """The Python implementation of the GRPC interoperability test client.""" import argparse +from oauth2client import client as oauth2client_client from grpc.early_adopter import implementations @@ -43,9 +44,6 @@ def _args(): parser = argparse.ArgumentParser() parser.add_argument( '--server_host', help='the host to which to connect', type=str) - parser.add_argument( - '--server_host_override', - help='the server host to which to claim to connect', type=str) parser.add_argument( '--server_port', help='the port to which to connect', type=int) parser.add_argument( @@ -56,10 +54,25 @@ def _args(): parser.add_argument( '--use_test_ca', help='replace platform root CAs with ca.pem', action='store_true') + parser.add_argument( + '--server_host_override', + help='the server host to which to claim to connect', type=str) + parser.add_argument('--oauth_scope', help='scope for OAuth tokens', type=str) + parser.add_argument( + '--default_service_account', + help='email address of the default service account', type=str) return parser.parse_args() +def _oauth_access_token(args): + credentials = client.GoogleCredentials.get_application_default() + scoped_credentials = credentials.create_scoped([args.oauth_scope]) + return scoped_credentials.get_access_token().access_token def _stub(args): + if args.oauth_scope: + metadata_transformer = lambda x: [('Authorization', 'Bearer %s' % _oauth_access_token(args))] + else: + metadata_transformer = lambda x: [] if args.use_tls: if args.use_test_ca: root_certificates = resources.test_root_certificates() @@ -68,7 +81,8 @@ def _stub(args): stub = implementations.stub( methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host, - args.server_port, secure=True, root_certificates=root_certificates, + args.server_port, metadata_transformer=metadata_transformer, + secure=True, root_certificates=root_certificates, server_host_override=args.server_host_override) else: stub = implementations.stub( @@ -89,7 +103,7 @@ def _test_interoperability(): args = _args() stub = _stub(args) test_case = _test_case_from_arg(args.test_case) - test_case.test_interoperability(stub) + test_case.test_interoperability(stub, args) if __name__ == '__main__': diff --git a/src/python/interop/interop/empty_pb2.py b/src/python/interop/interop/empty_pb2.py index 732a358a369..8c1ce2f13e8 100644 --- a/src/python/interop/interop/empty_pb2.py +++ b/src/python/interop/interop/empty_pb2.py @@ -57,6 +57,7 @@ Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), d _sym_db.RegisterMessage(Empty) -from grpc.framework.face import demonstration as _face_testing -from grpc.framework.face import interfaces as _face_interfaces +import abc +from grpc.early_adopter import implementations +from grpc.framework.alpha import utilities # @@protoc_insertion_point(module_scope) diff --git a/src/python/interop/interop/messages_pb2.py b/src/python/interop/interop/messages_pb2.py index d449a991404..0bf3d86a312 100644 --- a/src/python/interop/interop/messages_pb2.py +++ b/src/python/interop/interop/messages_pb2.py @@ -441,6 +441,7 @@ StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('Streamin _sym_db.RegisterMessage(StreamingOutputCallResponse) -from grpc.framework.face import demonstration as _face_testing -from grpc.framework.face import interfaces as _face_interfaces +import abc +from grpc.early_adopter import implementations +from grpc.framework.alpha import utilities # @@protoc_insertion_point(module_scope) diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py index 79550a37893..c69771dff1e 100644 --- a/src/python/interop/interop/methods.py +++ b/src/python/interop/interop/methods.py @@ -30,8 +30,12 @@ """Implementations of interoperability test methods.""" import enum +import json +import os import threading +from oauth2client import client as oauth2client_client + from grpc.framework.alpha import utilities from interop import empty_pb2 @@ -150,19 +154,12 @@ SERVER_METHODS = { } -def _empty_unary(stub): - with stub: - response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT) - if not isinstance(response, empty_pb2.Empty): - raise TypeError( - 'response is of type "%s", not empty_pb2.Empty!', type(response)) - - -def _large_unary(stub): +def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope): with stub: request = messages_pb2.SimpleRequest( response_type=messages_pb2.COMPRESSABLE, response_size=314159, - payload=messages_pb2.Payload(body=b'\x00' * 271828)) + payload=messages_pb2.Payload(body=b'\x00' * 271828), + fill_username=fill_username, fill_oauth_scope=fill_oauth_scope) response_future = stub.UnaryCall.async(request, _TIMEOUT) response = response_future.result() if response.payload.type is not messages_pb2.COMPRESSABLE: @@ -171,6 +168,19 @@ def _large_unary(stub): if len(response.payload.body) != 314159: raise ValueError( 'response body of incorrect size %d!' % len(response.payload.body)) + return response + + +def _empty_unary(stub): + with stub: + response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT) + if not isinstance(response, empty_pb2.Empty): + raise TypeError( + 'response is of type "%s", not empty_pb2.Empty!', type(response)) + + +def _large_unary(stub): + _large_unary_common_behavior(stub, False, False) def _client_streaming(stub): @@ -266,6 +276,28 @@ def _ping_pong(stub): pipe.close() +def _compute_engine_creds(stub, args): + response = _large_unary_common_behavior(stub, True, True) + if args.default_service_account != response.username: + raise ValueError( + 'expected username %s, got %s' % (args.default_service_account, + response.username)) + + +def _service_account_creds(stub, args): + json_key_filename = os.environ[ + oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS] + wanted_email = json.load(open(json_key_filename, 'rb'))['client_email'] + response = _large_unary_common_behavior(stub, True, True) + if wanted_email != response.username: + raise ValueError( + 'expected username %s, got %s' % (wanted_email, response.username)) + if response.oauth_scope in args.oauth_scope: + raise ValueError( + 'expected to find oauth scope "%s" in received "%s"' % + (response.oauth_scope, args.oauth_scope)) + + @enum.unique class TestCase(enum.Enum): EMPTY_UNARY = 'empty_unary' @@ -273,8 +305,10 @@ class TestCase(enum.Enum): SERVER_STREAMING = 'server_streaming' CLIENT_STREAMING = 'client_streaming' PING_PONG = 'ping_pong' + COMPUTE_ENGINE_CREDS = 'compute_engine_creds' + SERVICE_ACCOUNT_CREDS = 'service_account_creds' - def test_interoperability(self, stub): + def test_interoperability(self, stub, args): if self is TestCase.EMPTY_UNARY: _empty_unary(stub) elif self is TestCase.LARGE_UNARY: @@ -285,5 +319,9 @@ class TestCase(enum.Enum): _client_streaming(stub) elif self is TestCase.PING_PONG: _ping_pong(stub) + elif self is TestCase.COMPUTE_ENGINE_CREDS: + _compute_engine_creds(stub, args) + elif self is TestCase.SERVICE_ACCOUNT_CREDS: + _service_account_creds(stub, args) else: raise NotImplementedError('Test case "%s" not implemented!' % self.name) diff --git a/src/python/interop/interop/test_pb2.py b/src/python/interop/interop/test_pb2.py index e86094611b1..71325d5a9f0 100644 --- a/src/python/interop/interop/test_pb2.py +++ b/src/python/interop/interop/test_pb2.py @@ -29,121 +29,150 @@ _sym_db.RegisterFileDescriptor(DESCRIPTOR) -from grpc.framework.face import demonstration as _face_testing -from grpc.framework.face import interfaces as _face_interfaces -class TestServiceService(object): +import abc +from grpc.early_adopter import implementations +from grpc.framework.alpha import utilities +class EarlyAdopterTestServiceServicer(object): """""" - def __init__(self): - pass -class TestServiceServicer(object): - """""" - def EmptyCall(self, arg): + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def EmptyCall(self, request, context): + raise NotImplementedError() + @abc.abstractmethod + def UnaryCall(self, request, context): raise NotImplementedError() - def UnaryCall(self, arg): + @abc.abstractmethod + def StreamingOutputCall(self, request, context): raise NotImplementedError() - def StreamingOutputCall(self, arg): + @abc.abstractmethod + def StreamingInputCall(self, request_iterator, context): raise NotImplementedError() - def StreamingInputCall(self, arg): + @abc.abstractmethod + def FullDuplexCall(self, request_iterator, context): raise NotImplementedError() - def FullDuplexCall(self, arg): + @abc.abstractmethod + def HalfDuplexCall(self, request_iterator, context): + raise NotImplementedError() +class EarlyAdopterTestServiceServer(object): + """""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def start(self): raise NotImplementedError() - def HalfDuplexCall(self, arg): + @abc.abstractmethod + def stop(self): raise NotImplementedError() -class TestServiceStub(object): +class EarlyAdopterTestServiceStub(object): """""" - def EmptyCall(self, arg): + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def EmptyCall(self, request): raise NotImplementedError() EmptyCall.async = None - def UnaryCall(self, arg): + @abc.abstractmethod + def UnaryCall(self, request): raise NotImplementedError() UnaryCall.async = None - def StreamingOutputCall(self, arg): + @abc.abstractmethod + def StreamingOutputCall(self, request): raise NotImplementedError() StreamingOutputCall.async = None - def StreamingInputCall(self, arg): + @abc.abstractmethod + def StreamingInputCall(self, request_iterator): raise NotImplementedError() StreamingInputCall.async = None - def FullDuplexCall(self, arg): + @abc.abstractmethod + def FullDuplexCall(self, request_iterator): raise NotImplementedError() FullDuplexCall.async = None - def HalfDuplexCall(self, arg): + @abc.abstractmethod + def HalfDuplexCall(self, request_iterator): raise NotImplementedError() HalfDuplexCall.async = None -class _TestServiceStub(TestServiceStub): - def __init__(self, face_stub, default_timeout): - self._face_stub = face_stub - self._default_timeout = default_timeout - stub_self = self - class EmptyCall(object): - def __call__(self, arg): - return stub_self._face_stub.blocking_value_in_value_out("EmptyCall", arg, stub_self._default_timeout) - def async(self, arg): - return stub_self._face_stub.future_value_in_value_out("EmptyCall", arg, stub_self._default_timeout) - self.EmptyCall = EmptyCall() - class UnaryCall(object): - def __call__(self, arg): - return stub_self._face_stub.blocking_value_in_value_out("UnaryCall", arg, stub_self._default_timeout) - def async(self, arg): - return stub_self._face_stub.future_value_in_value_out("UnaryCall", arg, stub_self._default_timeout) - self.UnaryCall = UnaryCall() - class StreamingOutputCall(object): - def __call__(self, arg): - return stub_self._face_stub.inline_value_in_stream_out("StreamingOutputCall", arg, stub_self._default_timeout) - def async(self, arg): - return stub_self._face_stub.inline_value_in_stream_out("StreamingOutputCall", arg, stub_self._default_timeout) - self.StreamingOutputCall = StreamingOutputCall() - class StreamingInputCall(object): - def __call__(self, arg): - return stub_self._face_stub.blocking_stream_in_value_out("StreamingInputCall", arg, stub_self._default_timeout) - def async(self, arg): - return stub_self._face_stub.future_stream_in_value_out("StreamingInputCall", arg, stub_self._default_timeout) - self.StreamingInputCall = StreamingInputCall() - class FullDuplexCall(object): - def __call__(self, arg): - return stub_self._face_stub.inline_stream_in_stream_out("FullDuplexCall", arg, stub_self._default_timeout) - def async(self, arg): - return stub_self._face_stub.inline_stream_in_stream_out("FullDuplexCall", arg, stub_self._default_timeout) - self.FullDuplexCall = FullDuplexCall() - class HalfDuplexCall(object): - def __call__(self, arg): - return stub_self._face_stub.inline_stream_in_stream_out("HalfDuplexCall", arg, stub_self._default_timeout) - def async(self, arg): - return stub_self._face_stub.inline_stream_in_stream_out("HalfDuplexCall", arg, stub_self._default_timeout) - self.HalfDuplexCall = HalfDuplexCall() -def mock_TestService(servicer, default_timeout): - value_in_value_out = {} - value_in_stream_out = {} - stream_in_value_out = {} - stream_in_stream_out = {} - class EmptyCall(_face_interfaces.InlineValueInValueOutMethod): - def service(self, request, context): - return servicer.EmptyCall(request) - value_in_value_out['EmptyCall'] = EmptyCall() - class UnaryCall(_face_interfaces.InlineValueInValueOutMethod): - def service(self, request, context): - return servicer.UnaryCall(request) - value_in_value_out['UnaryCall'] = UnaryCall() - class StreamingOutputCall(_face_interfaces.InlineValueInStreamOutMethod): - def service(self, request, context): - return servicer.StreamingOutputCall(request) - value_in_stream_out['StreamingOutputCall'] = StreamingOutputCall() - class StreamingInputCall(_face_interfaces.InlineStreamInValueOutMethod): - def service(self, request, context): - return servicer.StreamingInputCall(request) - stream_in_value_out['StreamingInputCall'] = StreamingInputCall() - class FullDuplexCall(_face_interfaces.InlineStreamInStreamOutMethod): - def service(self, request, context): - return servicer.FullDuplexCall(request) - stream_in_stream_out['FullDuplexCall'] = FullDuplexCall() - class HalfDuplexCall(_face_interfaces.InlineStreamInStreamOutMethod): - def service(self, request, context): - return servicer.HalfDuplexCall(request) - stream_in_stream_out['HalfDuplexCall'] = HalfDuplexCall() - face_linked_pair = _face_testing.server_and_stub(default_timeout,inline_value_in_value_out_methods=value_in_value_out,inline_value_in_stream_out_methods=value_in_stream_out,inline_stream_in_value_out_methods=stream_in_value_out,inline_stream_in_stream_out_methods=stream_in_stream_out) - class LinkedPair(object): - def __init__(self, server, stub): - self.server = server - self.stub = stub - stub = _TestServiceStub(face_linked_pair.stub, default_timeout) - return LinkedPair(None, stub) +def early_adopter_create_TestService_server(servicer, port, private_key=None, certificate_chain=None): + import test.cpp.interop.empty_pb2 + import test.cpp.interop.empty_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + method_service_descriptions = { + "EmptyCall": utilities.unary_unary_service_description( + servicer.EmptyCall, + test.cpp.interop.empty_pb2.Empty.FromString, + test.cpp.interop.empty_pb2.Empty.SerializeToString, + ), + "FullDuplexCall": utilities.stream_stream_service_description( + servicer.FullDuplexCall, + test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString, + test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString, + ), + "HalfDuplexCall": utilities.stream_stream_service_description( + servicer.HalfDuplexCall, + test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString, + test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString, + ), + "StreamingInputCall": utilities.stream_unary_service_description( + servicer.StreamingInputCall, + test.cpp.interop.messages_pb2.StreamingInputCallRequest.FromString, + test.cpp.interop.messages_pb2.StreamingInputCallResponse.SerializeToString, + ), + "StreamingOutputCall": utilities.unary_stream_service_description( + servicer.StreamingOutputCall, + test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString, + test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString, + ), + "UnaryCall": utilities.unary_unary_service_description( + servicer.UnaryCall, + test.cpp.interop.messages_pb2.SimpleRequest.FromString, + test.cpp.interop.messages_pb2.SimpleResponse.SerializeToString, + ), + } + return implementations.server("grpc.testing.TestService", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain) +def early_adopter_create_TestService_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None): + import test.cpp.interop.empty_pb2 + import test.cpp.interop.empty_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + import test.cpp.interop.messages_pb2 + method_invocation_descriptions = { + "EmptyCall": utilities.unary_unary_invocation_description( + test.cpp.interop.empty_pb2.Empty.SerializeToString, + test.cpp.interop.empty_pb2.Empty.FromString, + ), + "FullDuplexCall": utilities.stream_stream_invocation_description( + test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString, + test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString, + ), + "HalfDuplexCall": utilities.stream_stream_invocation_description( + test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString, + test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString, + ), + "StreamingInputCall": utilities.stream_unary_invocation_description( + test.cpp.interop.messages_pb2.StreamingInputCallRequest.SerializeToString, + test.cpp.interop.messages_pb2.StreamingInputCallResponse.FromString, + ), + "StreamingOutputCall": utilities.unary_stream_invocation_description( + test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString, + test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString, + ), + "UnaryCall": utilities.unary_unary_invocation_description( + test.cpp.interop.messages_pb2.SimpleRequest.SerializeToString, + test.cpp.interop.messages_pb2.SimpleResponse.FromString, + ), + } + return implementations.stub("grpc.testing.TestService", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override) # @@protoc_insertion_point(module_scope) diff --git a/src/python/interop/setup.py b/src/python/interop/setup.py index 6db54350903..502fcbedd84 100644 --- a/src/python/interop/setup.py +++ b/src/python/interop/setup.py @@ -29,7 +29,7 @@ """A setup module for the GRPC Python interop testing package.""" -from distutils import core as _core +import setuptools _PACKAGES = ( 'interop', @@ -45,9 +45,13 @@ _PACKAGE_DATA = { 'credentials/server1.pem',] } -_INSTALL_REQUIRES = ['grpc-2015>=0.0.1'] +_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.4.0a4'] -_core.setup( - name='interop', version='0.0.1', packages=_PACKAGES, - package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA, - install_requires=_INSTALL_REQUIRES) +setuptools.setup( + name='interop', + version='0.0.1', + packages=_PACKAGES, + package_dir=_PACKAGE_DIRECTORIES, + package_data=_PACKAGE_DATA, + install_requires=_INSTALL_REQUIRES +) diff --git a/src/python/src/.gitignore b/src/python/src/.gitignore new file mode 100644 index 00000000000..bc15a52cf1e --- /dev/null +++ b/src/python/src/.gitignore @@ -0,0 +1,3 @@ +MANIFEST +grpcio.egg-info/ +dist/ diff --git a/src/python/src/MANIFEST.in b/src/python/src/MANIFEST.in new file mode 100644 index 00000000000..6f32db05488 --- /dev/null +++ b/src/python/src/MANIFEST.in @@ -0,0 +1 @@ +graft grpc diff --git a/src/python/src/README.rst b/src/python/src/README.rst new file mode 100644 index 00000000000..bc1815febc3 --- /dev/null +++ b/src/python/src/README.rst @@ -0,0 +1,27 @@ +gRPC Python +=========== + +Package for GRPC Python. + +Dependencies +------------ + +Ensure that you have installed GRPC core. + +On debian linux systems, install from our released deb package: + +:: + + $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc_0.5.0_amd64.deb + $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc-dev_0.5.0_amd64.deb + $ sudo dpkg -i libgrpc_0.5.0_amd64.deb libgrpc-dev_0.5.0_amd64.deb + +Otherwise, install from source: + +:: + + git clone https://github.com/grpc/grpc.git + cd grpc + ./configure + make && make install + diff --git a/src/python/src/grpc/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py index cfdcc2c4bc9..4987be389a9 100644 --- a/src/python/src/grpc/_adapter/_links_test.py +++ b/src/python/src/grpc/_adapter/_links_test.py @@ -43,6 +43,14 @@ _IDENTITY = lambda x: x _TIMEOUT = 2 +# TODO(nathaniel): End-to-end metadata testing. +def _transform_metadata(unused_metadata): + return ( + ('one unused key', 'one unused value'), + ('another unused key', 'another unused value'), +) + + class RoundTripTest(unittest.TestCase): def setUp(self): @@ -76,7 +84,8 @@ class RoundTripTest(unittest.TestCase): rear_link = rear.RearLink( 'localhost', port, self.rear_link_pool, {test_method: None}, - {test_method: None}, False, None, None, None) + {test_method: None}, False, None, None, None, + metadata_transformer=_transform_metadata) rear_link.join_fore_link(test_fore_link) test_fore_link.join_rear_link(rear_link) rear_link.start() diff --git a/src/python/src/grpc/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py index f19321c4266..2b93aa63314 100644 --- a/src/python/src/grpc/_adapter/rear.py +++ b/src/python/src/grpc/_adapter/rear.py @@ -93,7 +93,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated): def __init__( self, host, port, pool, request_serializers, response_deserializers, secure, root_certificates, private_key, certificate_chain, - server_host_override=None): + metadata_transformer=None, server_host_override=None): """Constructor. Args: @@ -111,6 +111,9 @@ class RearLink(base_interfaces.RearLink, activated.Activated): key should be used. certificate_chain: The PEM-encoded certificate chain to use or None if no certificate chain should be used. + metadata_transformer: A function that given a metadata object produces + another metadata to be used in the underlying communication on the + wire. server_host_override: (For testing only) the target name used for SSL host name checking. """ @@ -134,6 +137,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated): self._root_certificates = root_certificates self._private_key = private_key self._certificate_chain = certificate_chain + self._metadata_transformer = metadata_transformer self._server_host_override = server_host_override def _on_write_event(self, operation_id, event, rpc_state): @@ -243,6 +247,10 @@ class RearLink(base_interfaces.RearLink, activated.Activated): """ request_serializer = self._request_serializers[name] call = _low.Call(self._channel, name, self._host, time.time() + timeout) + if self._metadata_transformer is not None: + metadata = self._metadata_transformer([]) + for metadata_key, metadata_value in metadata: + call.add_metadata(metadata_key, metadata_value) call.invoke(self._completion_queue, operation_id, operation_id) outstanding = set(_INVOCATION_EVENT_KINDS) diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py index 7d3d29f06ca..35456d38c6b 100644 --- a/src/python/src/grpc/early_adopter/implementations.py +++ b/src/python/src/grpc/early_adopter/implementations.py @@ -114,7 +114,7 @@ class _Stub(interfaces.Stub): def __init__( self, breakdown, host, port, secure, root_certificates, private_key, - certificate_chain, server_host_override=None): + certificate_chain, metadata_transformer=None, server_host_override=None): self._lock = threading.Lock() self._breakdown = breakdown self._host = host @@ -123,6 +123,7 @@ class _Stub(interfaces.Stub): self._root_certificates = root_certificates self._private_key = private_key self._certificate_chain = certificate_chain + self._metadata_transformer = metadata_transformer self._server_host_override = server_host_override self._pool = None @@ -141,6 +142,7 @@ class _Stub(interfaces.Stub): self._breakdown.request_serializers, self._breakdown.response_deserializers, self._secure, self._root_certificates, self._private_key, self._certificate_chain, + metadata_transformer=self._metadata_transformer, server_host_override=self._server_host_override) self._front.join_rear_link(self._rear_link) self._rear_link.join_fore_link(self._front) @@ -189,8 +191,9 @@ class _Stub(interfaces.Stub): def stub( - service_name, methods, host, port, secure=False, root_certificates=None, - private_key=None, certificate_chain=None, server_host_override=None): + service_name, methods, host, port, metadata_transformer=None, secure=False, + root_certificates=None, private_key=None, certificate_chain=None, + server_host_override=None): """Constructs an interfaces.Stub. Args: @@ -201,6 +204,9 @@ def stub( not qualified by the service name or decorated in any other way. host: The host to which to connect for RPC service. port: The port to which to connect for RPC service. + metadata_transformer: A callable that given a metadata object produces + another metadata object to be used in the underlying communication on the + wire. secure: Whether or not to construct the stub with a secure connection. root_certificates: The PEM-encoded root certificates or None to ask for them to be retrieved from a default location. diff --git a/src/python/src/setup.py b/src/python/src/setup.py index bd70634b8fe..32ac41e2856 100644 --- a/src/python/src/setup.py +++ b/src/python/src/setup.py @@ -30,6 +30,8 @@ """A setup module for the GRPC Python package.""" from distutils import core as _core +import setuptools +import sys _EXTENSION_SOURCES = ( 'grpc/_adapter/_c.c', @@ -49,8 +51,9 @@ _EXTENSION_INCLUDE_DIRECTORIES = ( _EXTENSION_LIBRARIES = ( 'grpc', 'gpr', - 'rt', ) +if not "darwin" in sys.platform: + _EXTENSION_LIBRARIES += ('rt',) _EXTENSION_MODULE = _core.Extension( 'grpc._adapter._c', sources=list(_EXTENSION_SOURCES), @@ -80,7 +83,15 @@ _PACKAGE_DIRECTORIES = { 'grpc.framework': 'grpc/framework', } -_core.setup( - name='grpc-2015', version='0.4.0', - ext_modules=[_EXTENSION_MODULE], packages=list(_PACKAGES), - package_dir=_PACKAGE_DIRECTORIES) +setuptools.setup( + name='grpcio', + version='0.5.0a0', + ext_modules=[_EXTENSION_MODULE], + packages=list(_PACKAGES), + package_dir=_PACKAGE_DIRECTORIES, + install_requires=[ + 'enum34==1.0.4', + 'futures==2.2.0', + 'protobuf==3.0.0-alpha-1' + ] +) diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c index ff5a114de58..e3a5277f544 100644 --- a/src/ruby/ext/grpc/rb_byte_buffer.c +++ b/src/ruby/ext/grpc/rb_byte_buffer.c @@ -39,203 +39,29 @@ #include #include "rb_grpc.h" -/* grpc_rb_byte_buffer wraps a grpc_byte_buffer. It provides a peer ruby - * object, 'mark' to minimize copying when a byte_buffer is created from - * ruby. */ -typedef struct grpc_rb_byte_buffer { - /* Holder of ruby objects involved in constructing the status */ - VALUE mark; - /* The actual status */ - grpc_byte_buffer *wrapped; -} grpc_rb_byte_buffer; - -/* Destroys ByteBuffer instances. */ -static void grpc_rb_byte_buffer_free(void *p) { - grpc_rb_byte_buffer *bb = NULL; - if (p == NULL) { - return; - }; - bb = (grpc_rb_byte_buffer *)p; - - /* Deletes the wrapped object if the mark object is Qnil, which indicates - * that no other object is the actual owner. */ - if (bb->wrapped != NULL && bb->mark == Qnil) { - grpc_byte_buffer_destroy(bb->wrapped); - } - - xfree(p); -} - -/* Protects the mark object from GC */ -static void grpc_rb_byte_buffer_mark(void *p) { - grpc_rb_byte_buffer *bb = NULL; - if (p == NULL) { - return; - } - bb = (grpc_rb_byte_buffer *)p; - - /* If it's not already cleaned up, mark the mark object */ - if (bb->mark != Qnil && BUILTIN_TYPE(bb->mark) != T_NONE) { - rb_gc_mark(bb->mark); - } +grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) { + gpr_slice slice = gpr_slice_from_copied_buffer(string, length); + grpc_byte_buffer *buffer = grpc_byte_buffer_create(&slice, 1); + gpr_slice_unref(slice); + return buffer; } -/* id_source is the name of the hidden ivar the preserves the original - * byte_buffer source string */ -static ID id_source; - -/* Allocates ByteBuffer instances. - - Provides safe default values for the byte_buffer fields. */ -static VALUE grpc_rb_byte_buffer_alloc(VALUE cls) { - grpc_rb_byte_buffer *wrapper = ALLOC(grpc_rb_byte_buffer); - wrapper->wrapped = NULL; - wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_byte_buffer_mark, - grpc_rb_byte_buffer_free, wrapper); -} - -/* Clones ByteBuffer instances. - - Gives ByteBuffer a consistent implementation of Ruby's object copy/dup - protocol. */ -static VALUE grpc_rb_byte_buffer_init_copy(VALUE copy, VALUE orig) { - grpc_rb_byte_buffer *orig_bb = NULL; - grpc_rb_byte_buffer *copy_bb = NULL; - - if (copy == orig) { - return copy; - } - - /* Raise an error if orig is not a metadata object or a subclass. */ - if (TYPE(orig) != T_DATA || - RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_byte_buffer_free) { - rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cByteBuffer)); - } - - Data_Get_Struct(orig, grpc_rb_byte_buffer, orig_bb); - Data_Get_Struct(copy, grpc_rb_byte_buffer, copy_bb); - - /* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper - * object. */ - MEMCPY(copy_bb, orig_bb, grpc_rb_byte_buffer, 1); - return copy; -} - -/* id_empty is used to return the empty string from to_s when necessary. */ -static ID id_empty; - -static VALUE grpc_rb_byte_buffer_to_s(VALUE self) { - grpc_rb_byte_buffer *wrapper = NULL; - grpc_byte_buffer *bb = NULL; - grpc_byte_buffer_reader *reader = NULL; - char *output = NULL; +VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) { size_t length = 0; + char *string = NULL; size_t offset = 0; - VALUE output_obj = Qnil; + grpc_byte_buffer_reader *reader = NULL; gpr_slice next; + if (buffer == NULL) { + return Qnil; - Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper); - output_obj = rb_ivar_get(wrapper->mark, id_source); - if (output_obj != Qnil) { - /* From ruby, ByteBuffers are immutable so if a source is set, return that - * as the to_s value */ - return output_obj; - } - - /* Read the bytes. */ - bb = wrapper->wrapped; - if (bb == NULL) { - return rb_id2str(id_empty); - } - length = grpc_byte_buffer_length(bb); - if (length == 0) { - return rb_id2str(id_empty); } - reader = grpc_byte_buffer_reader_create(bb); - output = xmalloc(length); + length = grpc_byte_buffer_length(buffer); + string = xmalloc(length + 1); + reader = grpc_byte_buffer_reader_create(buffer); while (grpc_byte_buffer_reader_next(reader, &next) != 0) { - memcpy(output + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); + memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); offset += GPR_SLICE_LENGTH(next); } - output_obj = rb_str_new(output, length); - - /* Save a references to the computed string in the mark object so that the - * calling to_s does not do any allocations. */ - wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject); - rb_ivar_set(wrapper->mark, id_source, output_obj); - - return output_obj; -} - -/* Initializes ByteBuffer instances. */ -static VALUE grpc_rb_byte_buffer_init(VALUE self, VALUE src) { - gpr_slice a_slice; - grpc_rb_byte_buffer *wrapper = NULL; - grpc_byte_buffer *byte_buffer = NULL; - - if (TYPE(src) != T_STRING) { - rb_raise(rb_eTypeError, "bad byte_buffer arg: got <%s>, want ", - rb_obj_classname(src)); - return Qnil; - } - Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper); - a_slice = gpr_slice_malloc(RSTRING_LEN(src)); - memcpy(GPR_SLICE_START_PTR(a_slice), RSTRING_PTR(src), RSTRING_LEN(src)); - byte_buffer = grpc_byte_buffer_create(&a_slice, 1); - gpr_slice_unref(a_slice); - - if (byte_buffer == NULL) { - rb_raise(rb_eArgError, "could not create a byte_buffer, not sure why"); - return Qnil; - } - wrapper->wrapped = byte_buffer; - - /* Save a references to the original string in the mark object so that the - * pointers used there is valid for the lifetime of the object. */ - wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject); - rb_ivar_set(wrapper->mark, id_source, src); - - return self; -} - -/* rb_cByteBuffer is the ruby class that proxies grpc_byte_buffer. */ -VALUE rb_cByteBuffer = Qnil; - -void Init_grpc_byte_buffer() { - rb_cByteBuffer = - rb_define_class_under(rb_mGrpcCore, "ByteBuffer", rb_cObject); - - /* Allocates an object managed by the ruby runtime */ - rb_define_alloc_func(rb_cByteBuffer, grpc_rb_byte_buffer_alloc); - - /* Provides a ruby constructor and support for dup/clone. */ - rb_define_method(rb_cByteBuffer, "initialize", grpc_rb_byte_buffer_init, 1); - rb_define_method(rb_cByteBuffer, "initialize_copy", - grpc_rb_byte_buffer_init_copy, 1); - - /* Provides a to_s method that returns the buffer value */ - rb_define_method(rb_cByteBuffer, "to_s", grpc_rb_byte_buffer_to_s, 0); - - id_source = rb_intern("__source"); - id_empty = rb_intern(""); -} - -VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer *bb) { - grpc_rb_byte_buffer *byte_buffer = NULL; - if (bb == NULL) { - return Qnil; - } - byte_buffer = ALLOC(grpc_rb_byte_buffer); - byte_buffer->wrapped = bb; - byte_buffer->mark = mark; - return Data_Wrap_Struct(rb_cByteBuffer, grpc_rb_byte_buffer_mark, - grpc_rb_byte_buffer_free, byte_buffer); -} - -/* Gets the wrapped byte_buffer from the ruby wrapper */ -grpc_byte_buffer *grpc_rb_get_wrapped_byte_buffer(VALUE v) { - grpc_rb_byte_buffer *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_byte_buffer, wrapper); - return wrapper->wrapped; + return rb_str_new(string, length); } diff --git a/src/ruby/ext/grpc/rb_byte_buffer.h b/src/ruby/ext/grpc/rb_byte_buffer.h index 6ef72f3e757..96b9009dae9 100644 --- a/src/ruby/ext/grpc/rb_byte_buffer.h +++ b/src/ruby/ext/grpc/rb_byte_buffer.h @@ -37,18 +37,10 @@ #include #include -/* rb_cByteBuffer is the ByteBuffer class whose instances proxy - grpc_byte_buffer. */ -extern VALUE rb_cByteBuffer; +/* Converts a char* with a length to a grpc_byte_buffer */ +grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length); -/* Initializes the ByteBuffer class. */ -void Init_grpc_byte_buffer(); - -/* grpc_rb_byte_buffer_create_with_mark creates a grpc_rb_byte_buffer with a - * ruby mark object that will be kept alive while the byte_buffer is alive. */ -VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb); - -/* Gets the wrapped byte_buffer from its ruby object. */ -grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v); +/* Converts a grpc_byte_buffer to a ruby string */ +VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer); #endif /* GRPC_RB_BYTE_BUFFER_H_ */ diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index b5a256d5a67..18cb4ec4f2b 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -36,11 +36,19 @@ #include #include +#include + #include "rb_byte_buffer.h" #include "rb_completion_queue.h" -#include "rb_metadata.h" #include "rb_grpc.h" +/* rb_sBatchResult is struct class used to hold the results of a batch call */ +static VALUE rb_sBatchResult; + +/* rb_cMdAry is the MetadataArray class whose instances proxy + * grpc_metadata_array. */ +static VALUE rb_cMdAry; + /* id_cq is the name of the hidden ivar that preserves a reference to a * completion queue */ static ID id_cq; @@ -62,6 +70,15 @@ static ID id_metadata; * received by the call and subsequently saved on it. */ static ID id_status; +/* sym_* are the symbol for attributes of rb_sBatchResult. */ +static VALUE sym_send_message; +static VALUE sym_send_metadata; +static VALUE sym_send_close; +static VALUE sym_send_status; +static VALUE sym_message; +static VALUE sym_status; +static VALUE sym_cancelled; + /* hash_all_calls is a hash of Call address -> reference count that is used to * track the creation and destruction of rb_call instances. */ @@ -101,84 +118,6 @@ const char *grpc_call_error_detail_of(grpc_call_error err) { return detail; } -/* grpc_rb_call_add_metadata_hash_cb is the hash iteration callback used by - grpc_rb_call_add_metadata. -*/ -int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) { - grpc_call *call = NULL; - grpc_metadata *md = NULL; - VALUE md_obj = Qnil; - VALUE md_obj_args[2]; - VALUE flags = rb_ivar_get(call_obj, id_flags); - grpc_call_error err; - int array_length; - int i; - - /* Construct a metadata object from key and value and add it */ - Data_Get_Struct(call_obj, grpc_call, call); - md_obj_args[0] = key; - - if (TYPE(val) == T_ARRAY) { - /* If the value is an array, add each value in the array separately */ - array_length = RARRAY_LEN(val); - for (i = 0; i < array_length; i++) { - md_obj_args[1] = rb_ary_entry(val, i); - md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata); - md = grpc_rb_get_wrapped_metadata(md_obj); - err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)", - grpc_call_error_detail_of(err), err); - return ST_STOP; - } - } - } else { - md_obj_args[1] = val; - md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata); - md = grpc_rb_get_wrapped_metadata(md_obj); - err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)", - grpc_call_error_detail_of(err), err); - return ST_STOP; - } - } - - return ST_CONTINUE; -} - -/* - call-seq: - call.add_metadata(completion_queue, hash_elements, flags=nil) - - Add metadata elements to the call from a ruby hash, to be sent upon - invocation. flags is a bit-field combination of the write flags defined - above. REQUIRES: grpc_call_invoke/grpc_call_accept have not been - called on this call. Produces no events. */ - -static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) { - VALUE metadata; - VALUE flags = Qnil; - ID id_size = rb_intern("size"); - - /* "11" == 1 mandatory args, 1 (flags) is optional */ - rb_scan_args(argc, argv, "11", &metadata, &flags); - if (NIL_P(flags)) { - flags = UINT2NUM(0); /* Default to no flags */ - } - if (TYPE(metadata) != T_HASH) { - rb_raise(rb_eTypeError, "add metadata failed: metadata should be a hash"); - return Qnil; - } - if (NUM2UINT(rb_funcall(metadata, id_size, 0)) == 0) { - return Qnil; - } - rb_ivar_set(self, id_flags, flags); - rb_ivar_set(self, id_input_md, metadata); - rb_hash_foreach(metadata, grpc_rb_call_add_metadata_hash_cb, self); - return Qnil; -} - /* Called by clients to cancel an RPC on the server. Can be called multiple times, from any thread. */ static VALUE grpc_rb_call_cancel(VALUE self) { @@ -196,75 +135,18 @@ static VALUE grpc_rb_call_cancel(VALUE self) { /* call-seq: - call.invoke(completion_queue, tag, flags=nil) - - Invoke the RPC. Starts sending metadata and request headers on the wire. - flags is a bit-field combination of the write flags defined above. - REQUIRES: Can be called at most once per call. - Can only be called on the client. - Produces a GRPC_INVOKE_ACCEPTED event on completion. */ -static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) { - VALUE cqueue = Qnil; - VALUE metadata_read_tag = Qnil; - VALUE finished_tag = Qnil; - VALUE flags = Qnil; - grpc_call *call = NULL; - grpc_completion_queue *cq = NULL; - grpc_call_error err; + status = call.status - /* "31" == 3 mandatory args, 1 (flags) is optional */ - rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag, - &flags); - if (NIL_P(flags)) { - flags = UINT2NUM(0); /* Default to no flags */ - } - cq = grpc_rb_get_wrapped_completion_queue(cqueue); - Data_Get_Struct(self, grpc_call, call); - err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag), - ROBJECT(finished_tag), NUM2UINT(flags)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "invoke failed: %s (code=%d)", - grpc_call_error_detail_of(err), err); - } - - /* Add the completion queue as an instance attribute, prevents it from being - * GCed until this call object is GCed */ - rb_ivar_set(self, id_cq, cqueue); - - return Qnil; -} - -/* Initiate a read on a call. Output event contains a byte buffer with the - result of the read. - REQUIRES: No other reads are pending on the call. It is only safe to start - the next read after the corresponding read event is received. */ -static VALUE grpc_rb_call_start_read(VALUE self, VALUE tag) { - grpc_call *call = NULL; - grpc_call_error err; - Data_Get_Struct(self, grpc_call, call); - err = grpc_call_start_read_old(call, ROBJECT(tag)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "start read failed: %s (code=%d)", - grpc_call_error_detail_of(err), err); - } - - return Qnil; -} - -/* - call-seq: - status = call.status - - Gets the status object saved the call. */ + Gets the status object saved the call. */ static VALUE grpc_rb_call_get_status(VALUE self) { return rb_ivar_get(self, id_status); } /* call-seq: - call.status = status + call.status = status - Saves a status object on the call. */ + Saves a status object on the call. */ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) { if (!NIL_P(status) && rb_obj_class(status) != rb_sStatus) { rb_raise(rb_eTypeError, "bad status: got:<%s> want: ", @@ -277,18 +159,18 @@ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) { /* call-seq: - metadata = call.metadata + metadata = call.metadata - Gets the metadata object saved the call. */ + Gets the metadata object saved the call. */ static VALUE grpc_rb_call_get_metadata(VALUE self) { return rb_ivar_get(self, id_metadata); } /* call-seq: - call.metadata = metadata + call.metadata = metadata - Saves the metadata hash on the call. */ + Saves the metadata hash on the call. */ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) { if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) { rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: ", @@ -299,147 +181,402 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) { return rb_ivar_set(self, id_metadata, metadata); } -/* - call-seq: - call.start_write(byte_buffer, tag, flags=nil) - - Queue a byte buffer for writing. - flags is a bit-field combination of the write flags defined above. - A write with byte_buffer null is allowed, and will not send any bytes on the - wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides - a mechanism to flush any previously buffered writes to outgoing flow control. - REQUIRES: No other writes are pending on the call. It is only safe to - start the next write after the corresponding write_accepted event - is received. - GRPC_INVOKE_ACCEPTED must have been received by the application - prior to calling this on the client. On the server, - grpc_call_accept must have been called successfully. - Produces a GRPC_WRITE_ACCEPTED event. */ -static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) { - VALUE byte_buffer = Qnil; - VALUE tag = Qnil; - VALUE flags = Qnil; - grpc_call *call = NULL; - grpc_byte_buffer *bfr = NULL; - grpc_call_error err; +/* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used + to fill grpc_metadata_array. + + it's capacity should have been computed via a prior call to + grpc_rb_md_ary_fill_hash_cb +*/ +int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { + grpc_metadata_array *md_ary = NULL; + int array_length; + int i; + + /* Construct a metadata object from key and value and add it */ + Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary); - /* "21" == 2 mandatory args, 1 (flags) is optional */ - rb_scan_args(argc, argv, "21", &byte_buffer, &tag, &flags); - if (NIL_P(flags)) { - flags = UINT2NUM(0); /* Default to no flags */ + if (TYPE(val) == T_ARRAY) { + /* If the value is an array, add capacity for each value in the array */ + array_length = RARRAY_LEN(val); + for (i = 0; i < array_length; i++) { + if (TYPE(key) == T_SYMBOL) { + md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key)); + } else { /* StringValueCStr does all other type exclusions for us */ + md_ary->metadata[md_ary->count].key = StringValueCStr(key); + } + md_ary->metadata[md_ary->count].value = RSTRING_PTR(rb_ary_entry(val, i)); + md_ary->metadata[md_ary->count].value_length = + RSTRING_LEN(rb_ary_entry(val, i)); + md_ary->count += 1; + } + } else { + if (TYPE(key) == T_SYMBOL) { + md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key)); + } else { /* StringValueCStr does all other type exclusions for us */ + md_ary->metadata[md_ary->count].key = StringValueCStr(key); + } + md_ary->metadata[md_ary->count].value = RSTRING_PTR(val); + md_ary->metadata[md_ary->count].value_length = RSTRING_LEN(val); + md_ary->count += 1; } - bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer); - Data_Get_Struct(self, grpc_call, call); - err = grpc_call_start_write_old(call, bfr, ROBJECT(tag), NUM2UINT(flags)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "start write failed: %s (code=%d)", - grpc_call_error_detail_of(err), err); + + return ST_CONTINUE; +} + +/* grpc_rb_md_ary_capacity_hash_cb is the hash iteration callback used + to pre-compute the capacity a grpc_metadata_array. +*/ +int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { + grpc_metadata_array *md_ary = NULL; + + /* Construct a metadata object from key and value and add it */ + Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary); + + if (TYPE(val) == T_ARRAY) { + /* If the value is an array, add capacity for each value in the array */ + md_ary->capacity += RARRAY_LEN(val); + } else { + md_ary->capacity += 1; + } + return ST_CONTINUE; +} + +/* grpc_rb_md_ary_convert converts a ruby metadata hash into + a grpc_metadata_array. +*/ +void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary) { + VALUE md_ary_obj = Qnil; + if (md_ary_hash == Qnil) { + return; /* Do nothing if the expected has value is nil */ + } + if (TYPE(md_ary_hash) != T_HASH) { + rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want ", + rb_obj_classname(md_ary_hash)); + return; } - return Qnil; + /* Initialize the array, compute it's capacity, then fill it. */ + grpc_metadata_array_init(md_ary); + md_ary_obj = Data_Wrap_Struct(rb_cMdAry, GC_NOT_MARKED, GC_DONT_FREE, md_ary); + rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj); + md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata)); + rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj); } -/* Queue a status for writing. - - call-seq: - tag = Object.new - call.write_status(200, "OK", tag) - - REQUIRES: No other writes are pending on the call. It is only safe to - start the next write after the corresponding write_accepted event - is received. - GRPC_INVOKE_ACCEPTED must have been received by the application - prior to calling this. - Only callable on the server. - Produces a GRPC_FINISHED event when the status is sent and the stream is - fully closed */ -static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code, - VALUE status, VALUE tag) { - grpc_call *call = NULL; - grpc_call_error err; - Data_Get_Struct(self, grpc_call, call); - err = grpc_call_start_write_status_old(call, NUM2UINT(code), - StringValueCStr(status), ROBJECT(tag)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "start write status: %s (code=%d)", - grpc_call_error_detail_of(err), err); +/* Converts a metadata array to a hash. */ +VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) { + VALUE key = Qnil; + VALUE new_ary = Qnil; + VALUE value = Qnil; + VALUE result = rb_hash_new(); + size_t i; + + for (i = 0; i < md_ary->count; i++) { + key = rb_str_new2(md_ary->metadata[i].key); + value = rb_hash_aref(result, key); + if (value == Qnil) { + value = rb_str_new(md_ary->metadata[i].value, + md_ary->metadata[i].value_length); + rb_hash_aset(result, key, value); + } else if (TYPE(value) == T_ARRAY) { + /* Add the string to the returned array */ + rb_ary_push(value, + rb_str_new(md_ary->metadata[i].value, + md_ary->metadata[i].value_length)); + } else { + /* Add the current value with this key and the new one to an array */ + new_ary = rb_ary_new(); + rb_ary_push(new_ary, value); + rb_ary_push(new_ary, + rb_str_new(md_ary->metadata[i].value, + md_ary->metadata[i].value_length)); + rb_hash_aset(result, key, new_ary); + } } + return result; +} - return Qnil; +/* grpc_rb_call_check_op_keys_hash_cb is a hash iteration func that checks + each key of an ops hash is valid. +*/ +int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val, VALUE ops_ary) { + /* Update the capacity; the value is an array, add capacity for each value in + * the array */ + if (TYPE(key) != T_FIXNUM) { + rb_raise(rb_eTypeError, "invalid operation : got <%s>, want ", + rb_obj_classname(key)); + return ST_STOP; + } + switch(NUM2INT(key)) { + case GRPC_OP_SEND_INITIAL_METADATA: + case GRPC_OP_SEND_MESSAGE: + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + case GRPC_OP_SEND_STATUS_FROM_SERVER: + case GRPC_OP_RECV_INITIAL_METADATA: + case GRPC_OP_RECV_MESSAGE: + case GRPC_OP_RECV_STATUS_ON_CLIENT: + case GRPC_OP_RECV_CLOSE_ON_SERVER: + rb_ary_push(ops_ary, key); + return ST_CONTINUE; + default: + rb_raise(rb_eTypeError, "invalid operation : bad value %d", + NUM2INT(key)); + }; + return ST_STOP; } -/* No more messages to send. - REQUIRES: No other writes are pending on the call. */ -static VALUE grpc_rb_call_writes_done(VALUE self, VALUE tag) { - grpc_call *call = NULL; - grpc_call_error err; - Data_Get_Struct(self, grpc_call, call); - err = grpc_call_writes_done_old(call, ROBJECT(tag)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "writes done: %s (code=%d)", - grpc_call_error_detail_of(err), err); +/* grpc_rb_op_update_status_from_server adds the values in a ruby status + struct to the 'send_status_from_server' portion of an op. +*/ +void grpc_rb_op_update_status_from_server(grpc_op *op, + grpc_metadata_array* md_ary, + VALUE status) { + VALUE code = rb_struct_aref(status, sym_code); + VALUE details = rb_struct_aref(status, sym_details); + VALUE metadata_hash = rb_struct_aref(status, sym_metadata); + + /* TODO: add check to ensure status is the correct struct type */ + if (TYPE(code) != T_FIXNUM) { + rb_raise(rb_eTypeError, "invalid code : got <%s>, want ", + rb_obj_classname(code)); + return; + } + if (TYPE(details) != T_STRING) { + rb_raise(rb_eTypeError, "invalid details : got <%s>, want ", + rb_obj_classname(code)); + return; } + op->data.send_status_from_server.status = NUM2INT(code); + op->data.send_status_from_server.status_details = StringValueCStr(details); + grpc_rb_md_ary_convert(metadata_hash, md_ary); + op->data.send_status_from_server.trailing_metadata_count = md_ary->count; + op->data.send_status_from_server.trailing_metadata = md_ary->metadata; +} - return Qnil; +/* run_batch_stack holds various values used by the + * grpc_rb_call_run_batch function */ +typedef struct run_batch_stack { + /* The batch ops */ + grpc_op ops[8]; /* 8 is the maximum number of operations */ + size_t op_num; /* tracks the last added operation */ + + /* Data being sent */ + grpc_metadata_array send_metadata; + grpc_metadata_array send_trailing_metadata; + + /* Data being received */ + grpc_byte_buffer *recv_message; + grpc_metadata_array recv_metadata; + grpc_metadata_array recv_trailing_metadata; + int recv_cancelled; + grpc_status_code recv_status; + char *recv_status_details; + size_t recv_status_details_capacity; +} run_batch_stack; + +/* grpc_run_batch_stack_init ensures the run_batch_stack is properly + * initialized */ +static void grpc_run_batch_stack_init(run_batch_stack* st) { + MEMZERO(st, run_batch_stack, 1); + grpc_metadata_array_init(&st->send_metadata); + grpc_metadata_array_init(&st->send_trailing_metadata); + grpc_metadata_array_init(&st->recv_metadata); + grpc_metadata_array_init(&st->recv_trailing_metadata); + st->op_num = 0; } -/* call-seq: - call.server_end_initial_metadata(flag) - - Only to be called on servers, before sending messages. - flags is a bit-field combination of the write flags defined above. - - REQUIRES: Can be called at most once per call. - Can only be called on the server, must be called after - grpc_call_server_accept - Produces no events */ -static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv, - VALUE self) { - VALUE flags = Qnil; - grpc_call *call = NULL; - grpc_call_error err; +/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly + * cleaned up */ +static void grpc_run_batch_stack_cleanup(run_batch_stack* st) { + grpc_metadata_array_destroy(&st->send_metadata); + grpc_metadata_array_destroy(&st->send_trailing_metadata); + grpc_metadata_array_destroy(&st->recv_metadata); + grpc_metadata_array_destroy(&st->recv_trailing_metadata); + if (st->recv_status_details != NULL) { + gpr_free(st->recv_status_details); + } +} - /* "01" == 1 (flags) is optional */ - rb_scan_args(argc, argv, "01", &flags); - if (NIL_P(flags)) { - flags = UINT2NUM(0); /* Default to no flags */ +/* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from + * ops_hash */ +static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) { + VALUE this_op = Qnil; + VALUE this_value = Qnil; + VALUE ops_ary = rb_ary_new(); + size_t i = 0; + + /* Create a ruby array with just the operation keys */ + rb_hash_foreach(ops_hash, grpc_rb_call_check_op_keys_hash_cb, ops_ary); + + /* Fill the ops array */ + for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) { + this_op = rb_ary_entry(ops_ary, i); + this_value = rb_hash_aref(ops_hash, this_op); + switch(NUM2INT(this_op)) { + case GRPC_OP_SEND_INITIAL_METADATA: + /* N.B. later there is no need to explicitly delete the metadata keys + * and values, they are references to data in ruby objects. */ + grpc_rb_md_ary_convert(this_value, &st->send_metadata); + st->ops[st->op_num].data.send_initial_metadata.count = + st->send_metadata.count; + st->ops[st->op_num].data.send_initial_metadata.metadata = + st->send_metadata.metadata; + break; + case GRPC_OP_SEND_MESSAGE: + st->ops[st->op_num].data.send_message = + grpc_rb_s_to_byte_buffer(RSTRING_PTR(this_value), + RSTRING_LEN(this_value)); + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + /* N.B. later there is no need to explicitly delete the metadata keys + * and values, they are references to data in ruby objects. */ + grpc_rb_op_update_status_from_server(&st->ops[st->op_num], + &st->send_trailing_metadata, + this_value); + break; + case GRPC_OP_RECV_INITIAL_METADATA: + st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata; + break; + case GRPC_OP_RECV_MESSAGE: + st->ops[st->op_num].data.recv_message = &st->recv_message; + break; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + st->ops[st->op_num].data.recv_status_on_client.trailing_metadata = + &st->recv_trailing_metadata; + st->ops[st->op_num].data.recv_status_on_client.status = + &st->recv_status; + st->ops[st->op_num].data.recv_status_on_client.status_details = + &st->recv_status_details; + st->ops[st->op_num].data.recv_status_on_client.status_details_capacity = + &st->recv_status_details_capacity; + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + st->ops[st->op_num].data.recv_close_on_server.cancelled = + &st->recv_cancelled; + break; + default: + grpc_run_batch_stack_cleanup(st); + rb_raise(rb_eTypeError, "invalid operation : bad value %d", + NUM2INT(this_op)); + }; + st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op); + st->op_num++; } - Data_Get_Struct(self, grpc_call, call); - err = grpc_call_server_end_initial_metadata_old(call, NUM2UINT(flags)); - if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "end_initial_metadata failed: %s (code=%d)", - grpc_call_error_detail_of(err), err); +} + +/* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct + after the results have run */ +static VALUE grpc_run_batch_stack_build_result(run_batch_stack* st) { + size_t i = 0; + VALUE result = rb_struct_new(rb_sBatchResult, Qnil, Qnil, Qnil, Qnil, Qnil, + Qnil, Qnil, Qnil, NULL); + for (i = 0; i < st->op_num; i++) { + switch(st->ops[i].op) { + case GRPC_OP_SEND_INITIAL_METADATA: + rb_struct_aset(result, sym_send_metadata, Qtrue); + break; + case GRPC_OP_SEND_MESSAGE: + rb_struct_aset(result, sym_send_message, Qtrue); + grpc_byte_buffer_destroy(st->ops[i].data.send_message); + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + rb_struct_aset(result, sym_send_close, Qtrue); + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + rb_struct_aset(result, sym_send_status, Qtrue); + break; + case GRPC_OP_RECV_INITIAL_METADATA: + rb_struct_aset(result, sym_metadata, + grpc_rb_md_ary_to_h(&st->recv_metadata)); + case GRPC_OP_RECV_MESSAGE: + rb_struct_aset(result, sym_message, + grpc_rb_byte_buffer_to_s(st->recv_message)); + break; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + rb_struct_aset( + result, + sym_status, + rb_struct_new(rb_sStatus, + UINT2NUM(st->recv_status), + (st->recv_status_details == NULL + ? Qnil + : rb_str_new2(st->recv_status_details)), + grpc_rb_md_ary_to_h(&st->recv_trailing_metadata), + NULL)); + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + rb_struct_aset(result, sym_send_close, Qtrue); + break; + default: + break; + } } - return Qnil; + return result; } /* call-seq: - call.server_accept(completion_queue, finished_tag) - - Accept an incoming RPC, binding a completion queue to it. - To be called before sending or receiving messages. - - REQUIRES: Can be called at most once per call. - Can only be called on the server. - Produces a GRPC_FINISHED event with finished_tag when the call has been - completed (there may be other events for the call pending at this - time) */ -static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue, - VALUE finished_tag) { + cq = CompletionQueue.new + ops = { + GRPC::Core::CallOps::SEND_INITIAL_METADATA => , + GRPC::Core::CallOps::SEND_MESSAGE => , + ... + } + tag = Object.new + timeout = 10 + call.start_batch(cqueue, tag, timeout, ops) + + Start a batch of operations defined in the array ops; when complete, post a + completion of type 'tag' to the completion queue bound to the call. + + Also waits for the batch to complete, until timeout is reached. + The order of ops specified in the batch has no significance. + Only one operation of each type can be active at once in any given + batch */ +static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag, + VALUE timeout, VALUE ops_hash) { + run_batch_stack st; grpc_call *call = NULL; - grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue); + grpc_event *ev = NULL; grpc_call_error err; + VALUE result = Qnil; Data_Get_Struct(self, grpc_call, call); - err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag)); + + /* Validate the ops args, adding them to a ruby array */ + if (TYPE(ops_hash) != T_HASH) { + rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash"); + return Qnil; + } + grpc_run_batch_stack_init(&st); + grpc_run_batch_stack_fill_ops(&st, ops_hash); + + /* call grpc_call_start_batch, then wait for it to complete using + * pluck_event */ + err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag)); if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)", + grpc_run_batch_stack_cleanup(&st); + rb_raise(rb_eCallError, "grpc_call_start_batch failed with %s (code=%d)", grpc_call_error_detail_of(err), err); + return; + } + ev = grpc_rb_completion_queue_pluck_event(cqueue, tag, timeout); + if (ev == NULL) { + grpc_run_batch_stack_cleanup(&st); + rb_raise(rb_eOutOfTime, "grpc_call_start_batch timed out"); + return; + } + if (ev->data.op_complete != GRPC_OP_OK) { + grpc_run_batch_stack_cleanup(&st); + rb_raise(rb_eCallError, "start_batch completion failed, (code=%d)", + ev->data.op_complete); + return; } - /* Add the completion queue as an instance attribute, prevents it from being - * GCed until this call object is GCed */ - rb_ivar_set(self, id_cq, cqueue); - return Qnil; + /* Build and return the BatchResult struct result */ + result = grpc_run_batch_stack_build_result(&st); + grpc_run_batch_stack_cleanup(&st); + return result; } /* rb_cCall is the ruby class that proxies grpc_call. */ @@ -449,6 +586,10 @@ VALUE rb_cCall = Qnil; operations; */ VALUE rb_eCallError = Qnil; +/* rb_eOutOfTime is the ruby class of the exception thrown to indicate + a timeout. */ +VALUE rb_eOutOfTime = Qnil; + void Init_grpc_error_codes() { /* Constants representing the error codes of grpc_call_error in grpc.h */ VALUE rb_RpcErrors = rb_define_module_under(rb_mGrpcCore, "RpcErrors"); @@ -500,11 +641,35 @@ void Init_grpc_error_codes() { rb_obj_freeze(rb_error_code_details); } +void Init_grpc_op_codes() { + /* Constants representing operation type codes in grpc.h */ + VALUE rb_CallOps = rb_define_module_under(rb_mGrpcCore, "CallOps"); + rb_define_const(rb_CallOps, "SEND_INITIAL_METADATA", + UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA)); + rb_define_const(rb_CallOps, "SEND_MESSAGE", UINT2NUM(GRPC_OP_SEND_MESSAGE)); + rb_define_const(rb_CallOps, "SEND_CLOSE_FROM_CLIENT", + UINT2NUM(GRPC_OP_SEND_CLOSE_FROM_CLIENT)); + rb_define_const(rb_CallOps, "SEND_STATUS_FROM_SERVER", + UINT2NUM(GRPC_OP_SEND_STATUS_FROM_SERVER)); + rb_define_const(rb_CallOps, "RECV_INITIAL_METADATA", + UINT2NUM(GRPC_OP_RECV_INITIAL_METADATA)); + rb_define_const(rb_CallOps, "RECV_MESSAGE", + UINT2NUM(GRPC_OP_RECV_MESSAGE)); + rb_define_const(rb_CallOps, "RECV_STATUS_ON_CLIENT", + UINT2NUM(GRPC_OP_RECV_STATUS_ON_CLIENT)); + rb_define_const(rb_CallOps, "RECV_CLOSE_ON_SERVER", + UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER)); +} + void Init_grpc_call() { /* CallError inherits from Exception to signal that it is non-recoverable */ rb_eCallError = rb_define_class_under(rb_mGrpcCore, "CallError", rb_eException); + rb_eOutOfTime = + rb_define_class_under(rb_mGrpcCore, "OutOfTime", rb_eException); rb_cCall = rb_define_class_under(rb_mGrpcCore, "Call", rb_cObject); + rb_cMdAry = rb_define_class_under(rb_mGrpcCore, "MetadataArray", + rb_cObject); /* Prevent allocation or inialization of the Call class */ rb_define_alloc_func(rb_cCall, grpc_rb_cannot_alloc); @@ -512,17 +677,8 @@ void Init_grpc_call() { rb_define_method(rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy, 1); /* Add ruby analogues of the Call methods. */ - rb_define_method(rb_cCall, "server_accept", grpc_rb_call_server_accept, 2); - rb_define_method(rb_cCall, "server_end_initial_metadata", - grpc_rb_call_server_end_initial_metadata, -1); - rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1); + rb_define_method(rb_cCall, "run_batch", grpc_rb_call_run_batch, 4); rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0); - rb_define_method(rb_cCall, "invoke", grpc_rb_call_invoke, -1); - rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1); - rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1); - rb_define_method(rb_cCall, "start_write_status", - grpc_rb_call_start_write_status, 3); - rb_define_method(rb_cCall, "writes_done", grpc_rb_call_writes_done, 1); rb_define_method(rb_cCall, "status", grpc_rb_call_get_status, 0); rb_define_method(rb_cCall, "status=", grpc_rb_call_set_status, 1); rb_define_method(rb_cCall, "metadata", grpc_rb_call_get_metadata, 0); @@ -537,12 +693,35 @@ void Init_grpc_call() { id_flags = rb_intern("__flags"); id_input_md = rb_intern("__input_md"); + /* Ids used in constructing the batch result. */ + sym_send_message = ID2SYM(rb_intern("send_message")); + sym_send_metadata = ID2SYM(rb_intern("send_metadata")); + sym_send_close = ID2SYM(rb_intern("send_close")); + sym_send_status = ID2SYM(rb_intern("send_status")); + sym_message = ID2SYM(rb_intern("message")); + sym_status = ID2SYM(rb_intern("status")); + sym_cancelled = ID2SYM(rb_intern("cancelled")); + + /* The Struct used to return the run_batch result. */ + rb_sBatchResult = rb_struct_define( + "BatchResult", + "send_message", + "send_metadata", + "send_close", + "send_status", + "message", + "metadata", + "status", + "cancelled", + NULL); + /* The hash for reference counting calls, to ensure they can't be destroyed * more than once */ hash_all_calls = rb_hash_new(); rb_define_const(rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls); Init_grpc_error_codes(); + Init_grpc_op_codes(); } /* Gets the call from the ruby object */ diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h index bb51759a467..03e570863c2 100644 --- a/src/ruby/ext/grpc/rb_call.h +++ b/src/ruby/ext/grpc/rb_call.h @@ -46,13 +46,20 @@ VALUE grpc_rb_wrap_call(grpc_call* c); /* Provides the details of an call error */ const char* grpc_call_error_detail_of(grpc_call_error err); +/* Converts a metadata array to a hash. */ +VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary); + /* rb_cCall is the Call class whose instances proxy grpc_call. */ extern VALUE rb_cCall; -/* rb_cCallError is the ruby class of the exception thrown during call +/* rb_eCallError is the ruby class of the exception thrown during call operations. */ extern VALUE rb_eCallError; +/* rb_eOutOfTime is the ruby class of the exception thrown to indicate + a timeout. */ +extern VALUE rb_eOutOfTime; + /* Initializes the Call class. */ void Init_grpc_call(); diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 2a48f46ce2e..76a65fe6fe0 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -49,10 +49,16 @@ static ID id_channel; /* id_target is the name of the hidden ivar that preserves a reference to the - * target string used to create the call, preserved so that is does not get + * target string used to create the call, preserved so that it does not get * GCed before the channel */ static ID id_target; +/* id_cqueue is the name of the hidden ivar that preserves a reference to the + * completion queue used to create the call, preserved so that it does not get + * GCed before the channel */ +static ID id_cqueue; + + /* Used during the conversion of a hash to channel args during channel setup */ static VALUE rb_cChannelArgs; @@ -142,6 +148,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { if (ch == NULL) { rb_raise(rb_eRuntimeError, "could not create an rpc channel to target:%s", target_chars); + return Qnil; } rb_ivar_set(self, id_target, target); wrapper->wrapped = ch; @@ -164,6 +171,7 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) { if (TYPE(orig) != T_DATA || RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_free) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cChannel)); + return Qnil; } Data_Get_Struct(orig, grpc_rb_channel, orig_ch); @@ -177,34 +185,42 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) { /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ -static VALUE grpc_rb_channel_create_call(VALUE self, VALUE method, VALUE host, - VALUE deadline) { +static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method, + VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; - grpc_channel *ch = NULL; grpc_call *call = NULL; + grpc_channel *ch = NULL; + grpc_completion_queue *cq = NULL; char *method_chars = StringValueCStr(method); char *host_chars = StringValueCStr(host); + cq = grpc_rb_get_wrapped_completion_queue(cqueue); Data_Get_Struct(self, grpc_rb_channel, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); + return Qnil; } call = - grpc_channel_create_call_old(ch, method_chars, host_chars, - grpc_rb_time_timeval(deadline, - /* absolute time */ 0)); + grpc_channel_create_call(ch, cq, method_chars, host_chars, + grpc_rb_time_timeval(deadline, + /* absolute time */ 0)); if (call == NULL) { rb_raise(rb_eRuntimeError, "cannot create call with method %s", method_chars); + return Qnil; } res = grpc_rb_wrap_call(call); - /* Make this channel an instance attribute of the call so that is is not GCed + /* Make this channel an instance attribute of the call so that it is not GCed * before the call. */ rb_ivar_set(res, id_channel, self); + + /* Make the completion queue an instance attribute of the call so that it is + * not GCed before the call. */ + rb_ivar_set(res, id_cqueue, cqueue); return res; } @@ -240,11 +256,12 @@ void Init_grpc_channel() { 1); /* Add ruby analogues of the Channel methods. */ - rb_define_method(rb_cChannel, "create_call", grpc_rb_channel_create_call, 3); + rb_define_method(rb_cChannel, "create_call", grpc_rb_channel_create_call, 4); rb_define_method(rb_cChannel, "destroy", grpc_rb_channel_destroy, 0); rb_define_alias(rb_cChannel, "close", "destroy"); id_channel = rb_intern("__channel"); + id_cqueue = rb_intern("__cqueue"); id_target = rb_intern("__target"); rb_define_const(rb_cChannel, "SSL_TARGET", ID2SYM(rb_intern(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG))); diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index 3fdbdd837a7..688db94851b 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -38,7 +38,6 @@ #include #include #include "rb_grpc.h" -#include "rb_event.h" /* Used to allow grpc_completion_queue_next call to release the GIL */ typedef struct next_call_stack { @@ -140,8 +139,19 @@ static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) { /* Blocks until the next event for given tag is available, and returns the * event. */ -static VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag, - VALUE timeout) { +VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag, + VALUE timeout) { + grpc_event *ev = grpc_rb_completion_queue_pluck_event(self, tag, timeout); + if (ev == NULL) { + return Qnil; + } + return grpc_rb_new_event(ev); +} + +/* Blocks until the next event for given tag is available, and returns the + * event. */ +grpc_event* grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag, + VALUE timeout) { next_call_stack next_call; MEMZERO(&next_call, next_call_stack, 1); Data_Get_Struct(self, grpc_completion_queue, next_call.cq); @@ -151,9 +161,9 @@ static VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag, rb_thread_call_without_gvl(grpc_rb_completion_queue_pluck_no_gil, (void *)&next_call, NULL, NULL); if (next_call.event == NULL) { - return Qnil; + return NULL; } - return grpc_rb_new_event(next_call.event); + return next_call.event; } /* rb_cCompletionQueue is the ruby class that proxies grpc_completion_queue. */ diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h index 38025ea2d2e..13715ccaa75 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.h +++ b/src/ruby/ext/grpc/rb_completion_queue.h @@ -40,6 +40,14 @@ /* Gets the wrapped completion queue from the ruby wrapper */ grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v); +/** + * Makes the implementation of CompletionQueue#pluck available in other files + * + * This avoids having code that holds the GIL repeated at multiple sites. + */ +grpc_event* grpc_rb_completion_queue_pluck_event(VALUE cqueue, VALUE tag, + VALUE timeout); + /* rb_cCompletionQueue is the CompletionQueue class whose instances proxy grpc_completion_queue. */ extern VALUE rb_cCompletionQueue; diff --git a/src/ruby/ext/grpc/rb_event.c b/src/ruby/ext/grpc/rb_event.c deleted file mode 100644 index 2e64af4c847..00000000000 --- a/src/ruby/ext/grpc/rb_event.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "rb_event.h" - -#include - -#include -#include "rb_grpc.h" -#include "rb_byte_buffer.h" -#include "rb_call.h" -#include "rb_metadata.h" - -/* grpc_rb_event wraps a grpc_event. It provides a peer ruby object, - * 'mark' to minimize copying when an event is created from ruby. */ -typedef struct grpc_rb_event { - /* Holder of ruby objects involved in constructing the channel */ - VALUE mark; - /* The actual event */ - grpc_event *wrapped; -} grpc_rb_event; - -/* rb_mCompletionType is a ruby module that holds the completion type values */ -VALUE rb_mCompletionType = Qnil; - -/* Destroys Event instances. */ -static void grpc_rb_event_free(void *p) { - grpc_rb_event *ev = NULL; - if (p == NULL) { - return; - }; - ev = (grpc_rb_event *)p; - - /* Deletes the wrapped object if the mark object is Qnil, which indicates - * that no other object is the actual owner. */ - if (ev->wrapped != NULL && ev->mark == Qnil) { - grpc_event_finish(ev->wrapped); - rb_warning("event gc: destroyed the c event"); - } else { - rb_warning("event gc: did not destroy the c event"); - } - - xfree(p); -} - -/* Protects the mark object from GC */ -static void grpc_rb_event_mark(void *p) { - grpc_rb_event *event = NULL; - if (p == NULL) { - return; - } - event = (grpc_rb_event *)p; - if (event->mark != Qnil) { - rb_gc_mark(event->mark); - } -} - -static VALUE grpc_rb_event_result(VALUE self); - -/* Obtains the type of an event. */ -static VALUE grpc_rb_event_type(VALUE self) { - grpc_event *event = NULL; - grpc_rb_event *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_event, wrapper); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, "finished!"); - return Qnil; - } - - event = wrapper->wrapped; - switch (event->type) { - case GRPC_QUEUE_SHUTDOWN: - return rb_const_get(rb_mCompletionType, rb_intern("QUEUE_SHUTDOWN")); - - case GRPC_READ: - return rb_const_get(rb_mCompletionType, rb_intern("READ")); - - case GRPC_WRITE_ACCEPTED: - grpc_rb_event_result(self); /* validates the result */ - return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED")); - - case GRPC_FINISH_ACCEPTED: - grpc_rb_event_result(self); /* validates the result */ - return rb_const_get(rb_mCompletionType, rb_intern("FINISH_ACCEPTED")); - - case GRPC_CLIENT_METADATA_READ: - return rb_const_get(rb_mCompletionType, - rb_intern("CLIENT_METADATA_READ")); - - case GRPC_FINISHED: - return rb_const_get(rb_mCompletionType, rb_intern("FINISHED")); - - case GRPC_SERVER_RPC_NEW: - return rb_const_get(rb_mCompletionType, rb_intern("SERVER_RPC_NEW")); - - default: - rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d", - event->type); - } - return Qnil; /* should not be reached */ -} - -/* Obtains the tag associated with an event. */ -static VALUE grpc_rb_event_tag(VALUE self) { - grpc_event *event = NULL; - grpc_rb_event *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_event, wrapper); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, "finished!"); - return Qnil; - } - - event = wrapper->wrapped; - if (event->tag == NULL) { - return Qnil; - } - return (VALUE)event->tag; -} - -/* Obtains the call associated with an event. */ -static VALUE grpc_rb_event_call(VALUE self) { - grpc_event *event = NULL; - grpc_rb_event *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_event, wrapper); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, "finished!"); - return Qnil; - } - - event = wrapper->wrapped; - if (event->call != NULL) { - return grpc_rb_wrap_call(event->call); - } - return Qnil; -} - -/* Obtains the metadata associated with an event. */ -static VALUE grpc_rb_event_metadata(VALUE self) { - grpc_event *event = NULL; - grpc_rb_event *wrapper = NULL; - grpc_metadata *metadata = NULL; - VALUE key = Qnil; - VALUE new_ary = Qnil; - VALUE result = Qnil; - VALUE value = Qnil; - size_t count = 0; - size_t i = 0; - Data_Get_Struct(self, grpc_rb_event, wrapper); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, "finished!"); - return Qnil; - } - - /* Figure out which metadata to read. */ - event = wrapper->wrapped; - switch (event->type) { - case GRPC_CLIENT_METADATA_READ: - count = event->data.client_metadata_read.count; - metadata = event->data.client_metadata_read.elements; - break; - - case GRPC_FINISHED: - count = event->data.finished.metadata_count; - metadata = event->data.finished.metadata_elements; - break; - - case GRPC_SERVER_RPC_NEW: - count = event->data.server_rpc_new.metadata_count; - metadata = event->data.server_rpc_new.metadata_elements; - break; - - default: - rb_raise(rb_eRuntimeError, - "bug: bad event type metadata. got %d; want %d|%d:%d", - event->type, GRPC_CLIENT_METADATA_READ, GRPC_FINISHED, - GRPC_SERVER_RPC_NEW); - return Qnil; - } - - result = rb_hash_new(); - for (i = 0; i < count; i++) { - key = rb_str_new2(metadata[i].key); - value = rb_hash_aref(result, key); - if (value == Qnil) { - value = rb_str_new(metadata[i].value, metadata[i].value_length); - rb_hash_aset(result, key, value); - } else if (TYPE(value) == T_ARRAY) { - /* Add the string to the returned array */ - rb_ary_push(value, - rb_str_new(metadata[i].value, metadata[i].value_length)); - } else { - /* Add the current value with this key and the new one to an array */ - new_ary = rb_ary_new(); - rb_ary_push(new_ary, value); - rb_ary_push(new_ary, - rb_str_new(metadata[i].value, metadata[i].value_length)); - rb_hash_aset(result, key, new_ary); - } - } - return result; -} - -/* Obtains the data associated with an event. */ -static VALUE grpc_rb_event_result(VALUE self) { - grpc_event *event = NULL; - grpc_rb_event *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_event, wrapper); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, "finished!"); - return Qnil; - } - event = wrapper->wrapped; - - switch (event->type) { - case GRPC_QUEUE_SHUTDOWN: - return Qnil; - - case GRPC_READ: - return grpc_rb_byte_buffer_create_with_mark(self, event->data.read); - - case GRPC_FINISH_ACCEPTED: - if (event->data.finish_accepted == GRPC_OP_OK) { - return Qnil; - } - rb_raise(rb_eEventError, "finish failed, not sure why (code=%d)", - event->data.finish_accepted); - break; - - case GRPC_WRITE_ACCEPTED: - if (event->data.write_accepted == GRPC_OP_OK) { - return Qnil; - } - rb_raise(rb_eEventError, "write failed, not sure why (code=%d)", - event->data.write_accepted); - break; - - case GRPC_CLIENT_METADATA_READ: - return grpc_rb_event_metadata(self); - - case GRPC_FINISHED: - return rb_struct_new(rb_sStatus, UINT2NUM(event->data.finished.status), - (event->data.finished.details == NULL - ? Qnil - : rb_str_new2(event->data.finished.details)), - grpc_rb_event_metadata(self), NULL); - break; - - case GRPC_SERVER_RPC_NEW: - return rb_struct_new( - rb_sNewServerRpc, rb_str_new2(event->data.server_rpc_new.method), - rb_str_new2(event->data.server_rpc_new.host), - Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE, - (void *)&event->data.server_rpc_new.deadline), - grpc_rb_event_metadata(self), NULL); - - default: - rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d", - event->type); - } - - return Qfalse; -} - -static VALUE grpc_rb_event_finish(VALUE self) { - grpc_event *event = NULL; - grpc_rb_event *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_event, wrapper); - if (wrapper->wrapped == NULL) { /* already closed */ - return Qnil; - } - event = wrapper->wrapped; - grpc_event_finish(event); - wrapper->wrapped = NULL; - wrapper->mark = Qnil; - return Qnil; -} - -/* rb_cEvent is the Event class whose instances proxy grpc_event */ -VALUE rb_cEvent = Qnil; - -/* rb_eEventError is the ruby class of the exception thrown on failures during - rpc event processing. */ -VALUE rb_eEventError = Qnil; - -void Init_grpc_event() { - rb_eEventError = - rb_define_class_under(rb_mGrpcCore, "EventError", rb_eStandardError); - rb_cEvent = rb_define_class_under(rb_mGrpcCore, "Event", rb_cObject); - - /* Prevent allocation or inialization from ruby. */ - rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc); - rb_define_method(rb_cEvent, "initialize", grpc_rb_cannot_init, 0); - rb_define_method(rb_cEvent, "initialize_copy", grpc_rb_cannot_init_copy, 1); - - /* Accessors for the data available in an event. */ - rb_define_method(rb_cEvent, "call", grpc_rb_event_call, 0); - rb_define_method(rb_cEvent, "result", grpc_rb_event_result, 0); - rb_define_method(rb_cEvent, "tag", grpc_rb_event_tag, 0); - rb_define_method(rb_cEvent, "type", grpc_rb_event_type, 0); - rb_define_method(rb_cEvent, "finish", grpc_rb_event_finish, 0); - rb_define_alias(rb_cEvent, "close", "finish"); - - /* Constants representing the completion types */ - rb_mCompletionType = - rb_define_module_under(rb_mGrpcCore, "CompletionType"); - rb_define_const(rb_mCompletionType, "QUEUE_SHUTDOWN", - INT2NUM(GRPC_QUEUE_SHUTDOWN)); - rb_define_const(rb_mCompletionType, "OP_COMPLETE", INT2NUM(GRPC_OP_COMPLETE)); - rb_define_const(rb_mCompletionType, "READ", INT2NUM(GRPC_READ)); - rb_define_const(rb_mCompletionType, "WRITE_ACCEPTED", - INT2NUM(GRPC_WRITE_ACCEPTED)); - rb_define_const(rb_mCompletionType, "FINISH_ACCEPTED", - INT2NUM(GRPC_FINISH_ACCEPTED)); - rb_define_const(rb_mCompletionType, "CLIENT_METADATA_READ", - INT2NUM(GRPC_CLIENT_METADATA_READ)); - rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED)); - rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW", - INT2NUM(GRPC_SERVER_RPC_NEW)); - rb_define_const(rb_mCompletionType, "SERVER_SHUTDOWN", - INT2NUM(GRPC_SERVER_SHUTDOWN)); - rb_define_const(rb_mCompletionType, "RESERVED", - INT2NUM(GRPC_COMPLETION_DO_NOT_USE)); -} - -VALUE grpc_rb_new_event(grpc_event *ev) { - grpc_rb_event *wrapper = ALLOC(grpc_rb_event); - wrapper->wrapped = ev; - wrapper->mark = Qnil; - return Data_Wrap_Struct(rb_cEvent, grpc_rb_event_mark, grpc_rb_event_free, - wrapper); -} diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 400efd0dfad..d4335dd1bad 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -39,12 +39,9 @@ #include #include -#include "rb_byte_buffer.h" #include "rb_call.h" #include "rb_channel.h" #include "rb_completion_queue.h" -#include "rb_event.h" -#include "rb_metadata.h" #include "rb_server.h" #include "rb_credentials.h" #include "rb_server_credentials.h" @@ -195,7 +192,7 @@ static ID id_inspect; /* id_to_s is the to_s method found on various ruby objects. */ static ID id_to_s; -/* Converts `a wrapped time constant to a standard time. */ +/* Converts a wrapped time constant to a standard time. */ VALUE grpc_rb_time_val_to_time(VALUE self) { gpr_timespec *time_const = NULL; Data_Get_Struct(self, gpr_timespec, time_const); @@ -257,16 +254,16 @@ void Init_grpc() { rb_mGRPC = rb_define_module("GRPC"); rb_mGrpcCore = rb_define_module_under(rb_mGRPC, "Core"); rb_sNewServerRpc = rb_struct_define("NewServerRpc", "method", "host", - "deadline", "metadata", NULL); + "deadline", "metadata", "call", NULL); rb_sStatus = rb_struct_define("Status", "code", "details", "metadata", NULL); + sym_code = ID2SYM(rb_intern("code")); + sym_details = ID2SYM(rb_intern("details")); + sym_metadata = ID2SYM(rb_intern("metadata")); - Init_grpc_byte_buffer(); - Init_grpc_event(); Init_grpc_channel(); Init_grpc_completion_queue(); Init_grpc_call(); Init_grpc_credentials(); - Init_grpc_metadata(); Init_grpc_server(); Init_grpc_server_credentials(); Init_grpc_status_codes(); diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h index 851f5ee69fa..4ff9b7f6e90 100644 --- a/src/ruby/ext/grpc/rb_grpc.h +++ b/src/ruby/ext/grpc/rb_grpc.h @@ -50,6 +50,15 @@ extern VALUE rb_sNewServerRpc; /* rb_sStruct is the struct that holds status details. */ extern VALUE rb_sStatus; +/* sym_code is the symbol for the code attribute of rb_sStatus. */ +VALUE sym_code; + +/* sym_details is the symbol for the details attribute of rb_sStatus. */ +VALUE sym_details; + +/* sym_metadata is the symbol for the metadata attribute of rb_sStatus. */ +VALUE sym_metadata; + /* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the wrapped struct does not need to participate in ruby gc. */ extern const RUBY_DATA_FUNC GC_NOT_MARKED; diff --git a/src/ruby/ext/grpc/rb_metadata.c b/src/ruby/ext/grpc/rb_metadata.c deleted file mode 100644 index 7622a8c57ed..00000000000 --- a/src/ruby/ext/grpc/rb_metadata.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "rb_metadata.h" - -#include -#include - -#include -#include "rb_grpc.h" - -/* grpc_rb_metadata wraps a grpc_metadata. It provides a peer ruby object, - * 'mark' to minimize copying when a metadata is created from ruby. */ -typedef struct grpc_rb_metadata { - /* Holder of ruby objects involved in constructing the metadata */ - VALUE mark; - /* The actual metadata */ - grpc_metadata *wrapped; -} grpc_rb_metadata; - -/* Destroys Metadata instances. */ -static void grpc_rb_metadata_free(void *p) { - if (p == NULL) { - return; - }; - - /* Because metadata is only created during a call to grpc_call_add_metadata, - * and the call takes ownership of the metadata, this does not free the - * wrapped struct, only the wrapper */ - xfree(p); -} - -/* Protects the mark object from GC */ -static void grpc_rb_metadata_mark(void *p) { - grpc_rb_metadata *md = NULL; - if (p == NULL) { - return; - } - - md = (grpc_rb_metadata *)p; - /* If it's not already cleaned up, mark the mark object */ - if (md->mark != Qnil && BUILTIN_TYPE(md->mark) != T_NONE) { - rb_gc_mark(md->mark); - } -} - -/* Allocates Metadata instances. - - Provides safe default values for the Metadata fields. */ -static VALUE grpc_rb_metadata_alloc(VALUE cls) { - grpc_rb_metadata *wrapper = ALLOC(grpc_rb_metadata); - wrapper->wrapped = NULL; - wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_metadata_mark, grpc_rb_metadata_free, - wrapper); -} - -/* id_key and id_value are the names of the hidden ivars that preserve the - * original byte_buffer source string */ -static ID id_key; -static ID id_value; - -/* Initializes Metadata instances. */ -static VALUE grpc_rb_metadata_init(VALUE self, VALUE key, VALUE value) { - grpc_rb_metadata *wrapper = NULL; - grpc_metadata *md = ALLOC(grpc_metadata); - - /* Use direct pointers to the strings wrapped by the ruby object to avoid - * copying */ - Data_Get_Struct(self, grpc_rb_metadata, wrapper); - wrapper->wrapped = md; - if (TYPE(key) == T_SYMBOL) { - md->key = (char *)rb_id2name(SYM2ID(key)); - } else { /* StringValueCStr does all other type exclusions for us */ - md->key = StringValueCStr(key); - } - md->value = RSTRING_PTR(value); - md->value_length = RSTRING_LEN(value); - - /* Save references to the original values on the mark object so that the - * pointers used there are valid for the lifetime of the object. */ - wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject); - rb_ivar_set(wrapper->mark, id_key, key); - rb_ivar_set(wrapper->mark, id_value, value); - - return self; -} - -/* Clones Metadata instances. - - Gives Metadata a consistent implementation of Ruby's object copy/dup - protocol. */ -static VALUE grpc_rb_metadata_init_copy(VALUE copy, VALUE orig) { - grpc_rb_metadata *orig_md = NULL; - grpc_rb_metadata *copy_md = NULL; - - if (copy == orig) { - return copy; - } - - /* Raise an error if orig is not a metadata object or a subclass. */ - if (TYPE(orig) != T_DATA || - RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_metadata_free) { - rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cMetadata)); - } - - Data_Get_Struct(orig, grpc_rb_metadata, orig_md); - Data_Get_Struct(copy, grpc_rb_metadata, copy_md); - - /* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper - * object. */ - MEMCPY(copy_md, orig_md, grpc_rb_metadata, 1); - return copy; -} - -/* Gets the key from a metadata instance. */ -static VALUE grpc_rb_metadata_key(VALUE self) { - VALUE key = Qnil; - grpc_rb_metadata *wrapper = NULL; - grpc_metadata *md = NULL; - - Data_Get_Struct(self, grpc_rb_metadata, wrapper); - if (wrapper->mark != Qnil) { - key = rb_ivar_get(wrapper->mark, id_key); - if (key != Qnil) { - return key; - } - } - - md = wrapper->wrapped; - if (md == NULL || md->key == NULL) { - return Qnil; - } - return rb_str_new2(md->key); -} - -/* Gets the value from a metadata instance. */ -static VALUE grpc_rb_metadata_value(VALUE self) { - VALUE val = Qnil; - grpc_rb_metadata *wrapper = NULL; - grpc_metadata *md = NULL; - - Data_Get_Struct(self, grpc_rb_metadata, wrapper); - if (wrapper->mark != Qnil) { - val = rb_ivar_get(wrapper->mark, id_value); - if (val != Qnil) { - return val; - } - } - - md = wrapper->wrapped; - if (md == NULL || md->value == NULL) { - return Qnil; - } - return rb_str_new2(md->value); -} - -/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */ -VALUE rb_cMetadata = Qnil; -void Init_grpc_metadata() { - rb_cMetadata = - rb_define_class_under(rb_mGrpcCore, "Metadata", rb_cObject); - - /* Allocates an object managed by the ruby runtime */ - rb_define_alloc_func(rb_cMetadata, grpc_rb_metadata_alloc); - - /* Provides a ruby constructor and support for dup/clone. */ - rb_define_method(rb_cMetadata, "initialize", grpc_rb_metadata_init, 2); - rb_define_method(rb_cMetadata, "initialize_copy", grpc_rb_metadata_init_copy, - 1); - - /* Provides accessors for the code and details. */ - rb_define_method(rb_cMetadata, "key", grpc_rb_metadata_key, 0); - rb_define_method(rb_cMetadata, "value", grpc_rb_metadata_value, 0); - - id_key = rb_intern("__key"); - id_value = rb_intern("__value"); -} - -/* Gets the wrapped metadata from the ruby wrapper */ -grpc_metadata *grpc_rb_get_wrapped_metadata(VALUE v) { - grpc_rb_metadata *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_metadata, wrapper); - return wrapper->wrapped; -} diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index c54f02e87af..9a49285db28 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -46,6 +46,9 @@ /* rb_cServer is the ruby class that proxies grpc_server. */ VALUE rb_cServer = Qnil; +/* id_at is the constructor method of the ruby standard Time class. */ +static ID id_at; + /* grpc_rb_server wraps a grpc_server. It provides a peer ruby object, 'mark' to minimize copying when a server is created from ruby. */ typedef struct grpc_rb_server { @@ -152,18 +155,89 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) { return copy; } -static VALUE grpc_rb_server_request_call(VALUE self, VALUE tag_new) { - grpc_call_error err; +/* request_call_stack holds various values used by the + * grpc_rb_server_request_call function */ +typedef struct request_call_stack { + grpc_call_details details; + grpc_metadata_array md_ary; +} request_call_stack; + +/* grpc_request_call_stack_init ensures the request_call_stack is properly + * initialized */ +static void grpc_request_call_stack_init(request_call_stack* st) { + MEMZERO(st, request_call_stack, 1); + grpc_metadata_array_init(&st->md_ary); + grpc_call_details_init(&st->details); + st->details.method = NULL; + st->details.host = NULL; +} + +/* grpc_request_call_stack_cleanup ensures the request_call_stack is properly + * cleaned up */ +static void grpc_request_call_stack_cleanup(request_call_stack* st) { + grpc_metadata_array_destroy(&st->md_ary); + grpc_call_details_destroy(&st->details); +} + +/* call-seq: + cq = CompletionQueue.new + tag = Object.new + timeout = 10 + server.request_call(cqueue, tag, timeout) + + Requests notification of a new call on a server. */ +static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, + VALUE tag_new, VALUE timeout) { grpc_rb_server *s = NULL; + grpc_call *call = NULL; + grpc_event *ev = NULL; + grpc_call_error err; + request_call_stack st; + VALUE result; Data_Get_Struct(self, grpc_rb_server, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); + return Qnil; } else { - err = grpc_server_request_call_old(s->wrapped, ROBJECT(tag_new)); + grpc_request_call_stack_init(&st); + /* call grpc_server_request_call, then wait for it to complete using + * pluck_event */ + err = grpc_server_request_call( + s->wrapped, &call, &st.details, &st.md_ary, + grpc_rb_get_wrapped_completion_queue(cqueue), + ROBJECT(tag_new)); if (err != GRPC_CALL_OK) { - rb_raise(rb_eCallError, "server request failed: %s (code=%d)", + grpc_request_call_stack_cleanup(&st); + rb_raise(rb_eCallError, "grpc_server_request_call failed: %s (code=%d)", grpc_call_error_detail_of(err), err); + return Qnil; } + ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout); + if (ev == NULL) { + grpc_request_call_stack_cleanup(&st); + return Qnil; + } + if (ev->data.op_complete != GRPC_OP_OK) { + grpc_request_call_stack_cleanup(&st); + grpc_event_finish(ev); + rb_raise(rb_eCallError, "request_call completion failed: (code=%d)", + ev->data.op_complete); + return Qnil; + } + + /* build the NewServerRpc struct result */ + result = rb_struct_new( + rb_sNewServerRpc, + rb_str_new2(st.details.method), + rb_str_new2(st.details.host), + rb_funcall(rb_cTime, id_at, 2, INT2NUM(st.details.deadline.tv_sec), + INT2NUM(st.details.deadline.tv_nsec)), + grpc_rb_md_ary_to_h(&st.md_ary), + grpc_rb_wrap_call(call), + NULL); + grpc_event_finish(ev); + grpc_request_call_stack_cleanup(&st); + return result; } return Qnil; } @@ -249,12 +323,13 @@ void Init_grpc_server() { rb_define_method(rb_cServer, "initialize_copy", grpc_rb_server_init_copy, 1); /* Add the server methods. */ - rb_define_method(rb_cServer, "request_call", grpc_rb_server_request_call, 1); + rb_define_method(rb_cServer, "request_call", grpc_rb_server_request_call, 3); rb_define_method(rb_cServer, "start", grpc_rb_server_start, 0); rb_define_method(rb_cServer, "destroy", grpc_rb_server_destroy, 0); rb_define_alias(rb_cServer, "close", "destroy"); rb_define_method(rb_cServer, "add_http2_port", grpc_rb_server_add_http2_port, -1); + id_at = rb_intern("at"); } /* Gets the wrapped server from the ruby wrapper */ diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb index dd02ef7666a..b0f68035cd6 100644 --- a/src/ruby/lib/grpc.rb +++ b/src/ruby/lib/grpc.rb @@ -31,7 +31,6 @@ require 'grpc/errors' require 'grpc/grpc' require 'grpc/logconfig' require 'grpc/version' -require 'grpc/core/event' require 'grpc/core/time_consts' require 'grpc/generic/active_call' require 'grpc/generic/client_stub' diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb index 58944872b54..b23793730f7 100644 --- a/src/ruby/lib/grpc/errors.rb +++ b/src/ruby/lib/grpc/errors.rb @@ -31,10 +31,6 @@ require 'grpc' # GRPC contains the General RPC module. module GRPC - # OutOfTime is an exception class that indicates that an RPC exceeded its - # deadline. - OutOfTime = Class.new(StandardError) - # BadStatus is an exception class that indicates that an error occurred at # either end of a GRPC connection. When raised, it indicates that a status # error should be returned to the other end of a GRPC connection; when diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 6256330e88e..489349c2c99 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -30,20 +30,14 @@ require 'forwardable' require 'grpc/generic/bidi_call' -def assert_event_type(ev, want) - fail OutOfTime if ev.nil? - got = ev.type - fail "Unexpected rpc event: got #{got}, want #{want}" unless got == want -end - # GRPC contains the General RPC module. module GRPC # The ActiveCall class provides simple methods for sending marshallable # data to a call class ActiveCall - include Core::CompletionType include Core::StatusCodes include Core::TimeConsts + include Core::CallOps attr_reader(:deadline) # client_invoke begins a client invocation. @@ -61,15 +55,14 @@ module GRPC # @param q [CompletionQueue] the completion queue # @param deadline [Fixnum,TimeSpec] the deadline def self.client_invoke(call, q, _deadline, **kw) - fail(ArgumentError, 'not a call') unless call.is_a? Core::Call + fail(TypeError, '!Core::Call') unless call.is_a? Core::Call unless q.is_a? Core::CompletionQueue - fail(ArgumentError, 'not a CompletionQueue') + fail(TypeError, '!Core::CompletionQueue') end - call.add_metadata(kw) if kw.length > 0 - client_metadata_read = Object.new - finished_tag = Object.new - call.invoke(q, client_metadata_read, finished_tag) - [finished_tag, client_metadata_read] + metadata_tag = Object.new + call.run_batch(q, metadata_tag, INFINITE_FUTURE, + SEND_INITIAL_METADATA => kw) + metadata_tag end # Creates an ActiveCall. @@ -91,25 +84,21 @@ module GRPC # @param marshal [Function] f(obj)->string that marshal requests # @param unmarshal [Function] f(string)->obj that unmarshals responses # @param deadline [Fixnum] the deadline for the call to complete - # @param finished_tag [Object] the object used as the call's finish tag, - # if the call has begun - # @param read_metadata_tag [Object] the object used as the call's finish - # tag, if the call has begun + # @param metadata_tag [Object] the object use obtain metadata for clients # @param started [true|false] indicates if the call has begun - def initialize(call, q, marshal, unmarshal, deadline, finished_tag: nil, - read_metadata_tag: nil, started: true) - fail(ArgumentError, 'not a call') unless call.is_a? Core::Call + def initialize(call, q, marshal, unmarshal, deadline, started: true, + metadata_tag: nil) + fail(TypeError, '!Core::Call') unless call.is_a? Core::Call unless q.is_a? Core::CompletionQueue - fail(ArgumentError, 'not a CompletionQueue') + fail(TypeError, '!Core::CompletionQueue') end @call = call @cq = q @deadline = deadline - @finished_tag = finished_tag - @read_metadata_tag = read_metadata_tag @marshal = marshal @started = started @unmarshal = unmarshal + @metadata_tag = metadata_tag end # Obtains the status of the call. @@ -176,51 +165,38 @@ module GRPC # writes_done indicates that all writes are completed. # - # It blocks until the remote endpoint acknowledges by sending a FINISHED - # event, unless assert_finished is set to false. Any calls to - # #remote_send after this call will fail. + # It blocks until the remote endpoint acknowledges with at status unless + # assert_finished is set to false. Any calls to #remote_send after this + # call will fail. # # @param assert_finished [true, false] when true(default), waits for # FINISHED. def writes_done(assert_finished = true) - @call.writes_done(self) - ev = @cq.pluck(self, INFINITE_FUTURE) - begin - assert_event_type(ev, FINISH_ACCEPTED) - logger.debug("Writes done: waiting for finish? #{assert_finished}") - ensure - ev.close - end - + ops = { + SEND_CLOSE_FROM_CLIENT => nil + } + ops[RECV_STATUS_ON_CLIENT] = nil if assert_finished + @call.run_batch(@cq, self, INFINITE_FUTURE, ops) return unless assert_finished - ev = @cq.pluck(@finished_tag, INFINITE_FUTURE) - fail 'unexpected nil event' if ev.nil? - ev.close @call.status end - # finished waits until the call is completed. + # finished waits until a client call is completed. # - # It blocks until the remote endpoint acknowledges by sending a FINISHED - # event. + # It blocks until the remote endpoint acknowledges by sending a status. def finished - ev = @cq.pluck(@finished_tag, INFINITE_FUTURE) - begin - fail "unexpected event: #{ev.inspect}" unless ev.type == FINISHED - if @call.metadata.nil? - @call.metadata = ev.result.metadata - else - @call.metadata.merge!(ev.result.metadata) - end - - if ev.result.code != Core::StatusCodes::OK - fail BadStatus.new(ev.result.code, ev.result.details) - end - res = ev.result - ensure - ev.close + batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, + RECV_STATUS_ON_CLIENT => nil) + if @call.metadata.nil? + @call.metadata = batch_result.metadata + elsif !batch_result.metadata.nil? + @call.metadata.merge!(batch_result.metadata) end - res + if batch_result.status.code != Core::StatusCodes::OK + fail BadStatus.new(batch_result.status.code, + batch_result.status.details) + end + batch_result end # remote_send sends a request to the remote endpoint. @@ -232,72 +208,50 @@ module GRPC # @param marshalled [false, true] indicates if the object is already # marshalled. def remote_send(req, marshalled = false) - assert_queue_is_ready logger.debug("sending #{req.inspect}, marshalled? #{marshalled}") if marshalled payload = req else payload = @marshal.call(req) end - @call.start_write(Core::ByteBuffer.new(payload), self) - - # call queue#pluck, and wait for WRITE_ACCEPTED, so as not to return - # until the flow control allows another send on this call. - ev = @cq.pluck(self, INFINITE_FUTURE) - begin - assert_event_type(ev, WRITE_ACCEPTED) - ensure - ev.close - end + @call.run_batch(@cq, self, INFINITE_FUTURE, SEND_MESSAGE => payload) end - # send_status sends a status to the remote endpoint + # send_status sends a status to the remote endpoint. # # @param code [int] the status code to send # @param details [String] details # @param assert_finished [true, false] when true(default), waits for # FINISHED. def send_status(code = OK, details = '', assert_finished = false) - assert_queue_is_ready - @call.start_write_status(code, details, self) - ev = @cq.pluck(self, INFINITE_FUTURE) - begin - assert_event_type(ev, FINISH_ACCEPTED) - ensure - ev.close - end - logger.debug("Status sent: #{code}:'#{details}'") - return finished if assert_finished + ops = { + SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details) + } + ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished + @call.run_batch(@cq, self, INFINITE_FUTURE, ops) nil end # remote_read reads a response from the remote endpoint. # - # It blocks until the remote endpoint sends a READ or FINISHED event. On - # a READ, it returns the response after unmarshalling it. On - # FINISHED, it returns nil if the status is OK, otherwise raising - # BadStatus + # It blocks until the remote endpoint replies with a message or status. + # On receiving a message, it returns the response after unmarshalling it. + # On receiving a status, it returns nil if the status is OK, otherwise + # raising BadStatus def remote_read - if @call.metadata.nil? && !@read_metadata_tag.nil? - ev = @cq.pluck(@read_metadata_tag, INFINITE_FUTURE) - assert_event_type(ev, CLIENT_METADATA_READ) - @call.metadata = ev.result - @read_metadata_tag = nil + ops = { RECV_MESSAGE => nil } + ops[RECV_INITIAL_METADATA] = nil unless @metadata_tag.nil? + batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops) + unless @metadata_tag.nil? + @call.metadata = batch_result.metadata + @metadata_tag = nil end - - @call.start_read(self) - ev = @cq.pluck(self, INFINITE_FUTURE) - begin - assert_event_type(ev, READ) - logger.debug("received req: #{ev.result.inspect}") - unless ev.result.nil? - logger.debug("received req.to_s: #{ev.result}") - res = @unmarshal.call(ev.result.to_s) - logger.debug("received_req (unmarshalled): #{res.inspect}") - return res - end - ensure - ev.close + logger.debug("received req: #{batch_result}") + unless batch_result.nil? || batch_result.message.nil? + logger.debug("received req.to_s: #{batch_result.message}") + res = @unmarshal.call(batch_result.message) + logger.debug("received_req (unmarshalled): #{res.inspect}") + return res end logger.debug('found nil; the final response has been sent') nil @@ -324,7 +278,6 @@ module GRPC return enum_for(:each_remote_read) unless block_given? loop do resp = remote_read - break if resp.is_a? Struct::Status # is an OK status break if resp.nil? # the last response was received yield resp end @@ -461,8 +414,7 @@ module GRPC # @return [Enumerator, nil] a response Enumerator def bidi_streamer(requests, **kw, &blk) start_call(**kw) unless @started - bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline, - @finished_tag) + bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline) bd.run_on_client(requests, &blk) end @@ -478,8 +430,7 @@ module GRPC # # @param gen_each_reply [Proc] generates the BiDi stream replies def run_server_bidi(gen_each_reply) - bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline, - @finished_tag) + bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline) bd.run_on_server(gen_each_reply) end @@ -516,21 +467,5 @@ module GRPC # a Operation on the client. Operation = view_class(:cancel, :cancelled, :deadline, :execute, :metadata, :status) - - # confirms that no events are enqueued, and that the queue is not - # shutdown. - def assert_queue_is_ready - ev = nil - begin - ev = @cq.pluck(self, ZERO) - fail "unexpected event #{ev.inspect}" unless ev.nil? - rescue OutOfTime - logging.debug('timed out waiting for next event') - # expected, nothing should be on the queue and the deadline was ZERO, - # except things using another tag - ensure - ev.close unless ev.nil? - end - end end end diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb index c66deaae608..1c1b3b0db78 100644 --- a/src/ruby/lib/grpc/generic/bidi_call.rb +++ b/src/ruby/lib/grpc/generic/bidi_call.rb @@ -30,18 +30,12 @@ require 'forwardable' require 'grpc/grpc' -def assert_event_type(ev, want) - fail OutOfTime if ev.nil? - got = ev.type - fail("Unexpected rpc event: got #{got}, want #{want}") unless got == want -end - # GRPC contains the General RPC module. module GRPC # The BiDiCall class orchestrates exection of a BiDi stream on a client or # server. class BidiCall - include Core::CompletionType + include Core::CallOps include Core::StatusCodes include Core::TimeConsts @@ -63,8 +57,7 @@ module GRPC # @param marshal [Function] f(obj)->string that marshal requests # @param unmarshal [Function] f(string)->obj that unmarshals responses # @param deadline [Fixnum] the deadline for the call to complete - # @param finished_tag [Object] the object used as the call's finish tag, - def initialize(call, q, marshal, unmarshal, deadline, finished_tag) + def initialize(call, q, marshal, unmarshal, deadline) fail(ArgumentError, 'not a call') unless call.is_a? Core::Call unless q.is_a? Core::CompletionQueue fail(ArgumentError, 'not a CompletionQueue') @@ -72,7 +65,6 @@ module GRPC @call = call @cq = q @deadline = deadline - @finished_tag = finished_tag @marshal = marshal @readq = Queue.new @unmarshal = unmarshal @@ -146,30 +138,14 @@ module GRPC requests.each do |req| count += 1 payload = @marshal.call(req) - @call.start_write(Core::ByteBuffer.new(payload), write_tag) - ev = @cq.pluck(write_tag, INFINITE_FUTURE) - begin - assert_event_type(ev, WRITE_ACCEPTED) - ensure - ev.close - end + @call.run_batch(@cq, write_tag, INFINITE_FUTURE, + SEND_MESSAGE => payload) end if is_client - @call.writes_done(write_tag) - ev = @cq.pluck(write_tag, INFINITE_FUTURE) - begin - assert_event_type(ev, FINISH_ACCEPTED) - ensure - ev.close - end logger.debug("bidi-client: sent #{count} reqs, waiting to finish") - ev = @cq.pluck(@finished_tag, INFINITE_FUTURE) - begin - assert_event_type(ev, FINISHED) - ensure - ev.close - end - logger.debug('bidi-client: finished received') + @call.run_batch(@cq, write_tag, INFINITE_FUTURE, + SEND_CLOSE_FROM_CLIENT => nil, + RECV_STATUS_ON_CLIENT => nil) end rescue StandardError => e logger.warn('bidi: write_loop failed') @@ -189,25 +165,20 @@ module GRPC loop do logger.debug("waiting for read #{count}") count += 1 - @call.start_read(read_tag) - ev = @cq.pluck(read_tag, INFINITE_FUTURE) - begin - assert_event_type(ev, READ) - - # handle the next event. - if ev.result.nil? - @readq.push(END_OF_READS) - logger.debug('done reading!') - break - end - - # push the latest read onto the queue and continue reading - logger.debug("received req: #{ev.result}") - res = @unmarshal.call(ev.result.to_s) - @readq.push(res) - ensure - ev.close + # TODO: ensure metadata is read if available, currently it's not + batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE, + RECV_MESSAGE => nil) + # handle the next message + if batch_result.message.nil? + @readq.push(END_OF_READS) + logger.debug('done reading!') + break end + + # push the latest read onto the queue and continue reading + logger.debug("received req: #{batch_result.message}") + res = @unmarshal.call(batch_result.message) + @readq.push(res) end rescue StandardError => e diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index 01328d4a5bc..6547a1499ec 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -35,9 +35,10 @@ module GRPC # ClientStub represents an endpoint used to send requests to GRPC servers. class ClientStub include Core::StatusCodes + include Core::TimeConsts - # Default deadline is 5 seconds. - DEFAULT_DEADLINE = 5 + # Default timeout is 5 seconds. + DEFAULT_TIMEOUT = 5 # setup_channel is used by #initialize to constuct a channel from its # arguments. @@ -76,8 +77,8 @@ module GRPC # present the host and arbitrary keyword arg areignored, and the RPC # connection uses this channel. # - # - :deadline - # when present, this is the default deadline used for calls + # - :timeout + # when present, this is the default timeout used for calls # # - :update_metadata # when present, this a func that takes a hash and returns a hash @@ -87,13 +88,13 @@ module GRPC # @param host [String] the host the stub connects to # @param q [Core::CompletionQueue] used to wait for events # @param channel_override [Core::Channel] a pre-created channel - # @param deadline [Number] the default deadline to use in requests + # @param timeout [Number] the default timeout to use in requests # @param creds [Core::Credentials] the channel # @param update_metadata a func that updates metadata as described above # @param kw [KeywordArgs]the channel arguments def initialize(host, q, channel_override: nil, - deadline: DEFAULT_DEADLINE, + timeout: nil, creds: nil, update_metadata: nil, **kw) @@ -103,7 +104,7 @@ module GRPC @update_metadata = ClientStub.check_update_metadata(update_metadata) alt_host = kw[Core::Channel::SSL_TARGET] @host = alt_host.nil? ? host : alt_host - @deadline = deadline + @timeout = timeout.nil? ? DEFAULT_TIMEOUT : timeout end # request_response sends a request to a GRPC server, and returns the @@ -140,12 +141,12 @@ module GRPC # @param req [Object] the request sent to the server # @param marshal [Function] f(obj)->string that marshals requests # @param unmarshal [Function] f(string)->obj that unmarshals responses - # @param deadline [Numeric] (optional) the max completion time in seconds + # @param timeout [Numeric] (optional) the max completion time in seconds # @param return_op [true|false] return an Operation if true # @return [Object] the response received from the server - def request_response(method, req, marshal, unmarshal, deadline = nil, + def request_response(method, req, marshal, unmarshal, timeout = nil, return_op: false, **kw) - c = new_active_call(method, marshal, unmarshal, deadline || @deadline) + c = new_active_call(method, marshal, unmarshal, timeout) md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone) return c.request_response(req, **md) unless return_op @@ -197,12 +198,12 @@ module GRPC # @param requests [Object] an Enumerable of requests to send # @param marshal [Function] f(obj)->string that marshals requests # @param unmarshal [Function] f(string)->obj that unmarshals responses - # @param deadline [Numeric] the max completion time in seconds + # @param timeout [Numeric] the max completion time in seconds # @param return_op [true|false] return an Operation if true # @return [Object|Operation] the response received from the server - def client_streamer(method, requests, marshal, unmarshal, deadline = nil, + def client_streamer(method, requests, marshal, unmarshal, timeout = nil, return_op: false, **kw) - c = new_active_call(method, marshal, unmarshal, deadline || @deadline) + c = new_active_call(method, marshal, unmarshal, timeout) md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone) return c.client_streamer(requests, **md) unless return_op @@ -262,13 +263,13 @@ module GRPC # @param req [Object] the request sent to the server # @param marshal [Function] f(obj)->string that marshals requests # @param unmarshal [Function] f(string)->obj that unmarshals responses - # @param deadline [Numeric] the max completion time in seconds + # @param timeout [Numeric] the max completion time in seconds # @param return_op [true|false]return an Operation if true # @param blk [Block] when provided, is executed for each response # @return [Enumerator|Operation|nil] as discussed above - def server_streamer(method, req, marshal, unmarshal, deadline = nil, + def server_streamer(method, req, marshal, unmarshal, timeout = nil, return_op: false, **kw, &blk) - c = new_active_call(method, marshal, unmarshal, deadline || @deadline) + c = new_active_call(method, marshal, unmarshal, timeout) md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone) return c.server_streamer(req, **md, &blk) unless return_op @@ -367,13 +368,13 @@ module GRPC # @param requests [Object] an Enumerable of requests to send # @param marshal [Function] f(obj)->string that marshals requests # @param unmarshal [Function] f(string)->obj that unmarshals responses - # @param deadline [Numeric] (optional) the max completion time in seconds + # @param timeout [Numeric] (optional) the max completion time in seconds # @param blk [Block] when provided, is executed for each response # @param return_op [true|false] return an Operation if true # @return [Enumerator|nil|Operation] as discussed above - def bidi_streamer(method, requests, marshal, unmarshal, deadline = nil, + def bidi_streamer(method, requests, marshal, unmarshal, timeout = nil, return_op: false, **kw, &blk) - c = new_active_call(method, marshal, unmarshal, deadline || @deadline) + c = new_active_call(method, marshal, unmarshal, timeout) md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone) return c.bidi_streamer(requests, **md, &blk) unless return_op @@ -390,15 +391,14 @@ module GRPC # Creates a new active stub # - # @param ch [GRPC::Channel] the channel used to create the stub. + # @param method [string] the method being called. # @param marshal [Function] f(obj)->string that marshals requests # @param unmarshal [Function] f(string)->obj that unmarshals responses - # @param deadline [TimeConst] - def new_active_call(ch, marshal, unmarshal, deadline = nil) - absolute_deadline = Core::TimeConsts.from_relative_time(deadline) - call = @ch.create_call(ch, @host, absolute_deadline) - ActiveCall.new(call, @queue, marshal, unmarshal, absolute_deadline, - started: false) + # @param timeout [TimeConst] + def new_active_call(method, marshal, unmarshal, timeout = nil) + deadline = from_relative_time(timeout.nil? ? @timeout : timeout) + call = @ch.create_call(@queue, method, @host, deadline) + ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false) end end end diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb index 2cb3d2eebf4..3e48b8e51d7 100644 --- a/src/ruby/lib/grpc/generic/rpc_desc.rb +++ b/src/ruby/lib/grpc/generic/rpc_desc.rb @@ -81,7 +81,6 @@ module GRPC active_call.run_server_bidi(mth) end send_status(active_call, OK, 'OK') - active_call.finished rescue BadStatus => e # this is raised by handlers that want GRPC to send an application # error code and detail message. @@ -91,15 +90,11 @@ module GRPC # This is raised by GRPC internals but should rarely, if ever happen. # Log it, but don't notify the other endpoint.. logger.warn("failed call: #{active_call}\n#{e}") - rescue OutOfTime + rescue Core::OutOfTime # This is raised when active_call#method.call exceeeds the deadline # event. Send a status of deadline exceeded logger.warn("late call: #{active_call}") send_status(active_call, DEADLINE_EXCEEDED, 'late') - rescue Core::EventError => e - # This is raised by GRPC internals but should rarely, if ever happen. - # Log it, but don't notify the other endpoint.. - logger.warn("failed call: #{active_call}\n#{e}") rescue StandardError => e # This will usuaally be an unhandled error in the handling code. # Send back a UNKNOWN status to the client @@ -142,7 +137,7 @@ module GRPC def send_status(active_client, code, details) details = 'Not sure why' if details.nil? - active_client.send_status(code, details) + active_client.send_status(code, details, code == OK) rescue StandardError => e logger.warn("Could not send status #{code}:#{details}") logger.warn(e) diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb index 35e84023be9..30a4bf15325 100644 --- a/src/ruby/lib/grpc/generic/rpc_server.rb +++ b/src/ruby/lib/grpc/generic/rpc_server.rb @@ -38,7 +38,7 @@ module GRPC # RpcServer hosts a number of services and makes them available on the # network. class RpcServer - include Core::CompletionType + include Core::CallOps include Core::TimeConsts extend ::Forwardable @@ -202,20 +202,14 @@ module GRPC end @pool.start @server.start - server_tag = Object.new + request_call_tag = Object.new until stopped? - @server.request_call(server_tag) - ev = @cq.pluck(server_tag, @poll_period) - next if ev.nil? - if ev.type != SERVER_RPC_NEW - logger.warn("bad evt: got:#{ev.type}, want:#{SERVER_RPC_NEW}") - ev.close - next - end - c = new_active_server_call(ev.call, ev.result) + deadline = from_relative_time(@poll_period) + an_rpc = @server.request_call(@cq, request_call_tag, deadline) + next if an_rpc.nil? + c = new_active_server_call(an_rpc) unless c.nil? - mth = ev.result.method.to_sym - ev.close + mth = an_rpc.method.to_sym @pool.schedule(c) do |call| rpc_descs[mth].run_server_method(call, rpc_handlers[mth]) end @@ -224,46 +218,49 @@ module GRPC @running = false end - def new_active_server_call(call, new_server_rpc) - # Accept the call. This is necessary even if a status is to be sent - # back immediately - finished_tag = Object.new - call_queue = Core::CompletionQueue.new - call.metadata = new_server_rpc.metadata # store the metadata - call.server_accept(call_queue, finished_tag) - call.server_end_initial_metadata - - # Send UNAVAILABLE if there are too many unprocessed jobs + # Sends UNAVAILABLE if there are too many unprocessed jobs + def available?(an_rpc) jobs_count, max = @pool.jobs_waiting, @max_waiting_requests logger.info("waiting: #{jobs_count}, max: #{max}") - if @pool.jobs_waiting > @max_waiting_requests - logger.warn("NOT AVAILABLE: too many jobs_waiting: #{new_server_rpc}") - noop = proc { |x| x } - c = ActiveCall.new(call, call_queue, noop, noop, - new_server_rpc.deadline, - finished_tag: finished_tag) - c.send_status(StatusCodes::UNAVAILABLE, '') - return nil - end + return an_rpc if @pool.jobs_waiting <= @max_waiting_requests + logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}") + noop = proc { |x| x } + c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline) + c.send_status(StatusCodes::UNAVAILABLE, '') + nil + end - # Send NOT_FOUND if the method does not exist - mth = new_server_rpc.method.to_sym - unless rpc_descs.key?(mth) - logger.warn("NOT_FOUND: #{new_server_rpc}") - noop = proc { |x| x } - c = ActiveCall.new(call, call_queue, noop, noop, - new_server_rpc.deadline, - finished_tag: finished_tag) - c.send_status(StatusCodes::NOT_FOUND, '') - return nil - end + # Sends NOT_FOUND if the method can't be found + def found?(an_rpc) + mth = an_rpc.method.to_sym + return an_rpc if rpc_descs.key?(mth) + logger.warn("NOT_FOUND: #{an_rpc}") + noop = proc { |x| x } + c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline) + c.send_status(StatusCodes::NOT_FOUND, '') + nil + end + + def new_active_server_call(an_rpc) + # Accept the call. This is necessary even if a status is to be sent + # back immediately + return nil if an_rpc.nil? || an_rpc.call.nil? + + # allow the metadata to be accessed from the call + handle_call_tag = Object.new + an_rpc.call.metadata = an_rpc.metadata + # TODO: add a hook to send md + an_rpc.call.run_batch(@cq, handle_call_tag, INFINITE_FUTURE, + SEND_INITIAL_METADATA => nil) + return nil unless available?(an_rpc) + return nil unless found?(an_rpc) # Create the ActiveCall - rpc_desc = rpc_descs[mth] - logger.info("deadline is #{new_server_rpc.deadline}; (now=#{Time.now})") - ActiveCall.new(call, call_queue, + logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})") + rpc_desc = rpc_descs[an_rpc.method.to_sym] + ActiveCall.new(an_rpc.call, @cq, rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input), - new_server_rpc.deadline, finished_tag: finished_tag) + an_rpc.deadline) end # Pool is a simple thread pool for running server requests. diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 513a53724f3..bfd0cbb3936 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '0.5.0' + VERSION = '0.6.0' end diff --git a/src/ruby/spec/alloc_spec.rb b/src/ruby/spec/alloc_spec.rb deleted file mode 100644 index 88e7e2b3e7a..00000000000 --- a/src/ruby/spec/alloc_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -require 'grpc' - -describe 'Wrapped classes where .new cannot create an instance' do - describe GRPC::Core::Event do - it 'should fail .new fail with a runtime error' do - expect { GRPC::Core::Event.new }.to raise_error(TypeError) - end - end - - describe GRPC::Core::Call do - it 'should fail .new fail with a runtime error' do - expect { GRPC::Core::Event.new }.to raise_error(TypeError) - end - end -end diff --git a/src/ruby/spec/byte_buffer_spec.rb b/src/ruby/spec/byte_buffer_spec.rb deleted file mode 100644 index e1833ebb3a0..00000000000 --- a/src/ruby/spec/byte_buffer_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -require 'grpc' - -describe GRPC::Core::ByteBuffer do - describe '#new' do - it 'is constructed from a string' do - expect { GRPC::Core::ByteBuffer.new('#new') }.not_to raise_error - end - - it 'can be constructed from the empty string' do - expect { GRPC::Core::ByteBuffer.new('') }.not_to raise_error - end - - it 'cannot be constructed from nil' do - expect { GRPC::Core::ByteBuffer.new(nil) }.to raise_error TypeError - end - - it 'cannot be constructed from non-strings' do - [1, Object.new, :a_symbol].each do |x| - expect { GRPC::Core::ByteBuffer.new(x) }.to raise_error TypeError - end - end - end - - describe '#to_s' do - it 'is the string value the ByteBuffer was constructed with' do - expect(GRPC::Core::ByteBuffer.new('#to_s').to_s).to eq('#to_s') - end - end - - describe '#dup' do - it 'makes an instance whose #to_s is the original string value' do - bb = GRPC::Core::ByteBuffer.new('#dup') - a_copy = bb.dup - expect(a_copy.to_s).to eq('#dup') - expect(a_copy.dup.to_s).to eq('#dup') - end - end -end diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb index 26175645719..4977c10a7e1 100644 --- a/src/ruby/spec/call_spec.rb +++ b/src/ruby/spec/call_spec.rb @@ -66,51 +66,34 @@ describe GRPC::Core::RpcErrors do end end -describe GRPC::Core::Call do +describe GRPC::Core::CallOps do before(:each) do - @tag = Object.new - @client_queue = GRPC::Core::CompletionQueue.new - fake_host = 'localhost:10101' - @ch = GRPC::Core::Channel.new(fake_host, nil) - end - - describe '#start_read' do - xit 'should fail if called immediately' do - blk = proc { make_test_call.start_read(@tag) } - expect(&blk).to raise_error GRPC::Core::CallError - end - end - - describe '#start_write' do - xit 'should fail if called immediately' do - bytes = GRPC::Core::ByteBuffer.new('test string') - blk = proc { make_test_call.start_write(bytes, @tag) } - expect(&blk).to raise_error GRPC::Core::CallError - end + @known_types = { + SEND_INITIAL_METADATA: 0, + SEND_MESSAGE: 1, + SEND_CLOSE_FROM_CLIENT: 2, + SEND_STATUS_FROM_SERVER: 3, + RECV_INITIAL_METADATA: 4, + RECV_MESSAGE: 5, + RECV_STATUS_ON_CLIENT: 6, + RECV_CLOSE_ON_SERVER: 7 + } end - describe '#start_write_status' do - xit 'should fail if called immediately' do - blk = proc { make_test_call.start_write_status(153, 'x', @tag) } - expect(&blk).to raise_error GRPC::Core::CallError - end + it 'should have symbols for all the known operation types' do + m = GRPC::Core::CallOps + syms_and_codes = m.constants.collect { |c| [c, m.const_get(c)] } + expect(Hash[syms_and_codes]).to eq(@known_types) end +end - describe '#writes_done' do - xit 'should fail if called immediately' do - blk = proc { make_test_call.writes_done(Object.new) } - expect(&blk).to raise_error GRPC::Core::CallError - end - end +describe GRPC::Core::Call do + let(:client_queue) { GRPC::Core::CompletionQueue.new } + let(:test_tag) { Object.new } + let(:fake_host) { 'localhost:10101' } - describe '#add_metadata' do - it 'adds metadata to a call without fail' do - call = make_test_call - n = 37 - one_md = proc { |x| [sprintf('key%d', x), sprintf('value%d', x)] } - metadata = Hash[n.times.collect { |i| one_md.call i }] - expect { call.add_metadata(metadata) }.to_not raise_error - end + before(:each) do + @ch = GRPC::Core::Channel.new(fake_host, nil) end describe '#status' do @@ -154,7 +137,7 @@ describe GRPC::Core::Call do end def make_test_call - @ch.create_call('dummy_method', 'dummy_host', deadline) + @ch.create_call(client_queue, 'dummy_method', 'dummy_host', deadline) end def deadline diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb index af73294abe4..31e38d71b81 100644 --- a/src/ruby/spec/channel_spec.rb +++ b/src/ruby/spec/channel_spec.rb @@ -36,16 +36,13 @@ def load_test_certs end describe GRPC::Core::Channel do - FAKE_HOST = 'localhost:0' + let(:fake_host) { 'localhost:0' } + let(:cq) { GRPC::Core::CompletionQueue.new } def create_test_cert GRPC::Core::Credentials.new(load_test_certs[0]) end - before(:each) do - @cq = GRPC::Core::CompletionQueue.new - end - shared_examples '#new' do it 'take a host name without channel args' do expect { GRPC::Core::Channel.new('dummy_host', nil) }.not_to raise_error @@ -115,25 +112,23 @@ describe GRPC::Core::Channel do describe '#create_call' do it 'creates a call OK' do - host = FAKE_HOST - ch = GRPC::Core::Channel.new(host, nil) + ch = GRPC::Core::Channel.new(fake_host, nil) deadline = Time.now + 5 blk = proc do - ch.create_call('dummy_method', 'dummy_host', deadline) + ch.create_call(cq, 'dummy_method', 'dummy_host', deadline) end expect(&blk).to_not raise_error end it 'raises an error if called on a closed channel' do - host = FAKE_HOST - ch = GRPC::Core::Channel.new(host, nil) + ch = GRPC::Core::Channel.new(fake_host, nil) ch.close deadline = Time.now + 5 blk = proc do - ch.create_call('dummy_method', 'dummy_host', deadline) + ch.create_call(cq, 'dummy_method', 'dummy_host', deadline) end expect(&blk).to raise_error(RuntimeError) end @@ -141,15 +136,13 @@ describe GRPC::Core::Channel do describe '#destroy' do it 'destroys a channel ok' do - host = FAKE_HOST - ch = GRPC::Core::Channel.new(host, nil) + ch = GRPC::Core::Channel.new(fake_host, nil) blk = proc { ch.destroy } expect(&blk).to_not raise_error end it 'can be called more than once without error' do - host = FAKE_HOST - ch = GRPC::Core::Channel.new(host, nil) + ch = GRPC::Core::Channel.new(fake_host, nil) blk = proc { ch.destroy } blk.call expect(&blk).to_not raise_error @@ -164,15 +157,13 @@ describe GRPC::Core::Channel do describe '#close' do it 'closes a channel ok' do - host = FAKE_HOST - ch = GRPC::Core::Channel.new(host, nil) + ch = GRPC::Core::Channel.new(fake_host, nil) blk = proc { ch.close } expect(&blk).to_not raise_error end it 'can be called more than once without error' do - host = FAKE_HOST - ch = GRPC::Core::Channel.new(host, nil) + ch = GRPC::Core::Channel.new(fake_host, nil) blk = proc { ch.close } blk.call expect(&blk).to_not raise_error diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index 49a2d3bb4df..1a2afbe1f9a 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -30,7 +30,6 @@ require 'grpc' require 'spec_helper' -include GRPC::Core::CompletionType include GRPC::Core def load_test_certs @@ -40,6 +39,8 @@ def load_test_certs end shared_context 'setup: tags' do + let(:sent_message) { 'sent message' } + let(:reply_text) { 'the reply' } before(:example) do @server_finished_tag = Object.new @client_finished_tag = Object.new @@ -52,153 +53,136 @@ shared_context 'setup: tags' do Time.now + 2 end - def expect_next_event_on(queue, type, tag) - ev = queue.pluck(tag, deadline) - if type.nil? - expect(ev).to be_nil - else - expect(ev).to_not be_nil - expect(ev.type).to be(type) - end - ev - end - def server_allows_client_to_proceed - @server.request_call(@server_tag) - ev = @server_queue.pluck(@server_tag, deadline) - expect(ev).not_to be_nil - expect(ev.type).to be(SERVER_RPC_NEW) - server_call = ev.call - server_call.server_accept(@server_queue, @server_finished_tag) - server_call.server_end_initial_metadata + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + server_call = recvd_rpc.call + ops = { CallOps::SEND_INITIAL_METADATA => {} } + svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, ops) + expect(svr_batch.send_metadata).to be true server_call end - def server_responds_with(server_call, reply_text) - reply = ByteBuffer.new(reply_text) - server_call.start_read(@server_tag) - ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) - expect(ev.type).to be(READ) - server_call.start_write(reply, @server_tag) - ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) - expect(ev).not_to be_nil - expect(ev.type).to be(WRITE_ACCEPTED) - end - - def client_sends(call, sent = 'a message') - req = ByteBuffer.new(sent) - call.start_write(req, @tag) - ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE) - expect(ev).not_to be_nil - expect(ev.type).to be(WRITE_ACCEPTED) - sent - end - def new_client_call - @ch.create_call('/method', 'foo.test.google.fr', deadline) + @ch.create_call(@client_queue, '/method', 'foo.test.google.fr', deadline) end end shared_examples 'basic GRPC message delivery is OK' do + include GRPC::Core include_context 'setup: tags' - it 'servers receive requests from clients and start responding' do - reply = ByteBuffer.new('the server payload') + it 'servers receive requests from clients and can respond' do call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) - - # check the server rpc new was received - # @server.request_call(@server_tag) - # ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - - # accept the call - # server_call = ev.call - # server_call.server_accept(@server_queue, @server_finished_tag) - # server_call.server_end_initial_metadata - server_call = server_allows_client_to_proceed - - # client sends a message - msg = client_sends(call) + client_ops = { + CallOps::SEND_INITIAL_METADATA => {}, + CallOps::SEND_MESSAGE => sent_message + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.send_metadata).to be true + expect(batch_result.send_message).to be true # confirm the server can read the inbound message - server_call.start_read(@server_tag) - ev = expect_next_event_on(@server_queue, READ, @server_tag) - expect(ev.result.to_s).to eq(msg) - - # the server response - server_call.start_write(reply, @server_tag) - expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag) + server_call = server_allows_client_to_proceed + server_ops = { + CallOps::RECV_MESSAGE => nil + } + svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, + server_ops) + expect(svr_batch.message).to eq(sent_message) end it 'responses written by servers are received by the client' do call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) - server_call = server_allows_client_to_proceed - client_sends(call) - server_responds_with(server_call, 'server_response') + client_ops = { + CallOps::SEND_INITIAL_METADATA => {}, + CallOps::SEND_MESSAGE => sent_message + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.send_metadata).to be true + expect(batch_result.send_message).to be true - call.start_read(@tag) - ev = expect_next_event_on(@client_queue, READ, @tag) - expect(ev.result.to_s).to eq('server_response') + # confirm the server can read the inbound message + server_call = server_allows_client_to_proceed + server_ops = { + CallOps::RECV_MESSAGE => nil, + CallOps::SEND_MESSAGE => reply_text + } + svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, + server_ops) + expect(svr_batch.message).to eq(sent_message) + expect(svr_batch.send_message).to be true end it 'servers can ignore a client write and send a status' do call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) - - # check the server rpc new was received - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - expect(ev.tag).to be(@server_tag) - - # accept the call - need to do this to sent status. - server_call = ev.call - server_call.server_accept(@server_queue, @server_finished_tag) - server_call.server_end_initial_metadata - server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found', - @server_tag) - - # Client sends some data - client_sends(call) - - # client gets an empty response for the read, preceeded by some metadata. - call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, - @client_metadata_tag) - ev = expect_next_event_on(@client_queue, READ, @tag) - expect(ev.tag).to be(@tag) - expect(ev.result.to_s).to eq('') - - # finally, after client sends writes_done, they get the finished. - call.writes_done(@tag) - expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag) - ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag) - expect(ev.result.code).to eq(StatusCodes::NOT_FOUND) + client_ops = { + CallOps::SEND_INITIAL_METADATA => {}, + CallOps::SEND_MESSAGE => sent_message + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.send_metadata).to be true + expect(batch_result.send_message).to be true + + # confirm the server can read the inbound message + the_status = Struct::Status.new(StatusCodes::OK, 'OK') + server_call = server_allows_client_to_proceed + server_ops = { + CallOps::SEND_STATUS_FROM_SERVER => the_status + } + svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, + server_ops) + expect(svr_batch.message).to eq nil + expect(svr_batch.send_status).to be true end it 'completes calls by sending status to client and server' do call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) + client_ops = { + CallOps::SEND_INITIAL_METADATA => {}, + CallOps::SEND_MESSAGE => sent_message + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.send_metadata).to be true + expect(batch_result.send_message).to be true + + # confirm the server can read the inbound message and respond + the_status = Struct::Status.new(StatusCodes::OK, 'OK', {}) server_call = server_allows_client_to_proceed - client_sends(call) - server_responds_with(server_call, 'server_response') - server_call.start_write_status(10_101, 'status code is 10101', @server_tag) - - # first the client says writes are done - call.start_read(@tag) - expect_next_event_on(@client_queue, READ, @tag) - call.writes_done(@tag) - - # but nothing happens until the server sends a status - expect_next_event_on(@server_queue, FINISH_ACCEPTED, @server_tag) - ev = expect_next_event_on(@server_queue, FINISHED, @server_finished_tag) - expect(ev.result).to be_a(Struct::Status) - - # client gets FINISHED - expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag) - ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag) - expect(ev.result.details).to eq('status code is 10101') - expect(ev.result.code).to eq(10_101) + server_ops = { + CallOps::RECV_MESSAGE => nil, + CallOps::SEND_MESSAGE => reply_text, + CallOps::SEND_STATUS_FROM_SERVER => the_status + } + svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, + server_ops) + expect(svr_batch.message).to eq sent_message + expect(svr_batch.send_status).to be true + expect(svr_batch.send_message).to be true + + # confirm the client can receive the server response and status. + client_ops = { + CallOps::SEND_CLOSE_FROM_CLIENT => nil, + CallOps::RECV_MESSAGE => nil, + CallOps::RECV_STATUS_ON_CLIENT => nil + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.send_close).to be true + expect(batch_result.message).to eq reply_text + expect(batch_result.status).to eq the_status + + # confirm the server can receive the client close. + server_ops = { + CallOps::RECV_CLOSE_ON_SERVER => nil + } + svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, + server_ops) + expect(svr_batch.send_close).to be true end end @@ -224,25 +208,33 @@ shared_examples 'GRPC metadata delivery works OK' do it 'raises an exception if a metadata key is invalid' do @bad_keys.each do |md| call = new_client_call - expect { call.add_metadata(md) }.to raise_error + client_ops = { + CallOps::SEND_INITIAL_METADATA => md + } + blk = proc do + call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + end + expect(&blk).to raise_error end end it 'sends all the metadata pairs when keys and values are valid' do @valid_metadata.each do |md| call = new_client_call - call.add_metadata(md) - - # Client begins a call OK - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) - - # ... server has all metadata available even though the client did not - # send a write - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) + client_ops = { + CallOps::SEND_INITIAL_METADATA => md + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.send_metadata).to be true + + # confirm the server can receive the client metadata + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + recvd_md = recvd_rpc.metadata replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }] - result = ev.result.metadata - expect(result.merge(replace_symbols)).to eq(result) + expect(recvd_md).to eq(recvd_md.merge(replace_symbols)) end end end @@ -266,55 +258,81 @@ shared_examples 'GRPC metadata delivery works OK' do it 'raises an exception if a metadata key is invalid' do @bad_keys.each do |md| call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) + # client signals that it's done sending metadata to allow server to + # respond + client_ops = { + CallOps::SEND_INITIAL_METADATA => nil + } + call.run_batch(@client_queue, @client_tag, deadline, client_ops) # server gets the invocation - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - expect { ev.call.add_metadata(md) }.to raise_error + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + server_ops = { + CallOps::SEND_INITIAL_METADATA => md + } + blk = proc do + recvd_rpc.call.run_batch(@server_queue, @server_tag, deadline, + server_ops) + end + expect(&blk).to raise_error end end - it 'sends a hash that contains the status when no metadata is added' do + it 'sends an empty hash if no metadata is added' do call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) - - # server gets the invocation - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - server_call = ev.call - - # ... server accepts the call without adding metadata - server_call.server_accept(@server_queue, @server_finished_tag) - server_call.server_end_initial_metadata - - # there is the HTTP status metadata, though there should not be any - # TODO: update this with the bug number to be resolved - ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, - @client_metadata_tag) - expect(ev.result).to eq({}) + # client signals that it's done sending metadata to allow server to + # respond + client_ops = { + CallOps::SEND_INITIAL_METADATA => nil + } + call.run_batch(@client_queue, @client_tag, deadline, client_ops) + + # server gets the invocation but sends no metadata back + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + server_call = recvd_rpc.call + server_ops = { + CallOps::SEND_INITIAL_METADATA => nil + } + server_call.run_batch(@server_queue, @server_tag, deadline, server_ops) + + # client receives nothing as expected + client_ops = { + CallOps::RECV_INITIAL_METADATA => nil + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) + expect(batch_result.metadata).to eq({}) end it 'sends all the pairs when keys and values are valid' do @valid_metadata.each do |md| call = new_client_call - call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) - - # server gets the invocation - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - server_call = ev.call - - # ... server adds metadata and accepts the call - server_call.add_metadata(md) - server_call.server_accept(@server_queue, @server_finished_tag) - server_call.server_end_initial_metadata - - # Now the client can read the metadata - ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, - @client_metadata_tag) + # client signals that it's done sending metadata to allow server to + # respond + client_ops = { + CallOps::SEND_INITIAL_METADATA => nil + } + call.run_batch(@client_queue, @client_tag, deadline, client_ops) + + # server gets the invocation but sends no metadata back + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + server_call = recvd_rpc.call + server_ops = { + CallOps::SEND_INITIAL_METADATA => md + } + server_call.run_batch(@server_queue, @server_tag, deadline, server_ops) + + # client receives nothing as expected + client_ops = { + CallOps::RECV_INITIAL_METADATA => nil + } + batch_result = call.run_batch(@client_queue, @client_tag, deadline, + client_ops) replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }] - expect(ev.result).to eq(replace_symbols) + expect(batch_result.metadata).to eq(replace_symbols) end end end diff --git a/src/ruby/spec/event_spec.rb b/src/ruby/spec/event_spec.rb deleted file mode 100644 index 7d92fcd7928..00000000000 --- a/src/ruby/spec/event_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -require 'grpc' - -describe GRPC::Core::CompletionType do - before(:each) do - @known_types = { - QUEUE_SHUTDOWN: 0, - OP_COMPLETE: 1, - READ: 2, - WRITE_ACCEPTED: 3, - FINISH_ACCEPTED: 4, - CLIENT_METADATA_READ: 5, - FINISHED: 6, - SERVER_RPC_NEW: 7, - SERVER_SHUTDOWN: 8, - RESERVED: 9 - } - end - - it 'should have all the known types' do - mod = GRPC::Core::CompletionType - blk = proc { Hash[mod.constants.collect { |c| [c, mod.const_get(c)] }] } - expect(blk.call).to eq(@known_types) - end -end diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 96e07cacb44..575871afb11 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -34,12 +34,11 @@ include GRPC::Core::StatusCodes describe GRPC::ActiveCall do ActiveCall = GRPC::ActiveCall Call = GRPC::Core::Call - CompletionType = GRPC::Core::CompletionType + CallOps = GRPC::Core::CallOps before(:each) do @pass_through = proc { |x| x } @server_tag = Object.new - @server_done_tag = Object.new @tag = Object.new @client_queue = GRPC::Core::CompletionQueue.new @@ -48,7 +47,7 @@ describe GRPC::ActiveCall do @server = GRPC::Core::Server.new(@server_queue, nil) server_port = @server.add_http2_port(host) @server.start - @ch = GRPC::Core::Channel.new("localhost:#{server_port}", nil) + @ch = GRPC::Core::Channel.new("0.0.0.0:#{server_port}", nil) end after(:each) do @@ -58,12 +57,10 @@ describe GRPC::ActiveCall do describe 'restricted view methods' do before(:each) do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) @client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) end describe '#multi_req_view' do @@ -90,48 +87,45 @@ describe GRPC::ActiveCall do describe '#remote_send' do it 'allows a client to send a payload to the server' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) @client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) msg = 'message is a string' @client_call.remote_send(msg) # check that server rpc new was received - @server.request_call(@server_tag) - ev = @server_queue.next(deadline) - expect(ev.type).to be(CompletionType::SERVER_RPC_NEW) - expect(ev.call).to be_a(Call) - expect(ev.tag).to be(@server_tag) + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + recvd_call = recvd_rpc.call # Accept the call, and verify that the server reads the response ok. - ev.call.server_accept(@client_queue, @server_tag) - ev.call.server_end_initial_metadata - server_call = ActiveCall.new(ev.call, @client_queue, @pass_through, + server_ops = { + CallOps::SEND_INITIAL_METADATA => {} + } + recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops) + server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through, @pass_through, deadline) expect(server_call.remote_read).to eq(msg) end it 'marshals the payload using the marshal func' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + ActiveCall.client_invoke(call, @client_queue, deadline) marshal = proc { |x| 'marshalled:' + x } client_call = ActiveCall.new(call, @client_queue, marshal, - @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + @pass_through, deadline) msg = 'message is a string' client_call.remote_send(msg) # confirm that the message was marshalled - @server.request_call(@server_tag) - ev = @server_queue.next(deadline) - ev.call.server_accept(@client_queue, @server_tag) - ev.call.server_end_initial_metadata - server_call = ActiveCall.new(ev.call, @client_queue, @pass_through, + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + recvd_call = recvd_rpc.call + server_ops = { + CallOps::SEND_INITIAL_METADATA => nil + } + recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops) + server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through, @pass_through, deadline) expect(server_call.remote_read).to eq('marshalled:' + msg) end @@ -142,23 +136,22 @@ describe GRPC::ActiveCall do call = make_test_call ActiveCall.client_invoke(call, @client_queue, deadline, k1: 'v1', k2: 'v2') - @server.request_call(@server_tag) - ev = @server_queue.next(deadline) - expect(ev).to_not be_nil - expect(ev.result.metadata['k1']).to eq('v1') - expect(ev.result.metadata['k2']).to eq('v2') + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + recvd_call = recvd_rpc.call + expect(recvd_call).to_not be_nil + expect(recvd_rpc.metadata).to_not be_nil + expect(recvd_rpc.metadata['k1']).to eq('v1') + expect(recvd_rpc.metadata['k2']).to eq('v2') end end describe '#remote_read' do it 'reads the response sent by a server' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) server_call = expect_server_to_receive(msg) @@ -168,12 +161,10 @@ describe GRPC::ActiveCall do it 'saves no metadata when the server adds no metadata' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) server_call = expect_server_to_receive(msg) @@ -185,12 +176,10 @@ describe GRPC::ActiveCall do it 'saves metadata add by the server' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) server_call = expect_server_to_receive(msg, k1: 'v1', k2: 'v2') @@ -203,12 +192,10 @@ describe GRPC::ActiveCall do it 'get a nil msg before a status when an OK status is sent' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) client_call.writes_done(false) @@ -222,13 +209,11 @@ describe GRPC::ActiveCall do it 'unmarshals the response using the unmarshal func' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) unmarshal = proc { |x| 'unmarshalled:' + x } client_call = ActiveCall.new(call, @client_queue, @pass_through, unmarshal, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) # confirm the client receives the unmarshalled message msg = 'message is a string' @@ -249,13 +234,11 @@ describe GRPC::ActiveCall do it 'the returns an enumerator that can read n responses' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) - msg = 'message is 4a string' + metadata_tag: md_tag) + msg = 'message is a string' reply = 'server_response' client_call.remote_send(msg) server_call = expect_server_to_receive(msg) @@ -269,12 +252,10 @@ describe GRPC::ActiveCall do it 'the returns an enumerator that stops after an OK Status' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - read_metadata_tag: meta_tag, - finished_tag: done_tag) + metadata_tag: md_tag) msg = 'message is a string' reply = 'server_response' client_call.remote_send(msg) @@ -294,12 +275,10 @@ describe GRPC::ActiveCall do describe '#writes_done' do it 'finishes ok if the server sends a status response' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - finished_tag: done_tag, - read_metadata_tag: meta_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) expect { client_call.writes_done(false) }.to_not raise_error @@ -312,12 +291,10 @@ describe GRPC::ActiveCall do it 'finishes ok if the server sends an early status response' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - read_metadata_tag: meta_tag, - finished_tag: done_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) server_call = expect_server_to_receive(msg) @@ -330,12 +307,10 @@ describe GRPC::ActiveCall do it 'finishes ok if writes_done is true' do call = make_test_call - done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + md_tag = ActiveCall.client_invoke(call, @client_queue, deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, - read_metadata_tag: meta_tag, - finished_tag: done_tag) + metadata_tag: md_tag) msg = 'message is a string' client_call.remote_send(msg) server_call = expect_server_to_receive(msg) @@ -353,21 +328,20 @@ describe GRPC::ActiveCall do end def expect_server_to_be_invoked(**kw) - @server.request_call(@server_tag) - ev = @server_queue.next(deadline) - ev.call.add_metadata(kw) - ev.call.server_accept(@client_queue, @server_done_tag) - ev.call.server_end_initial_metadata - ActiveCall.new(ev.call, @client_queue, @pass_through, - @pass_through, deadline, - finished_tag: @server_done_tag) + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + expect(recvd_rpc).to_not eq nil + recvd_call = recvd_rpc.call + recvd_call.run_batch(@server_queue, @server_tag, deadline, + CallOps::SEND_INITIAL_METADATA => kw) + ActiveCall.new(recvd_call, @server_queue, @pass_through, + @pass_through, deadline) end def make_test_call - @ch.create_call('dummy_method', 'dummy_host', deadline) + @ch.create_call(@client_queue, '/method', 'a.dummy.host', deadline) end def deadline - Time.now + 1 # in 1 second; arbitrary + Time.now + 2 # in 2 seconds; arbitrary end end diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 0c98fc40d91..193c5f2a038 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -30,15 +30,41 @@ require 'grpc' require 'xray/thread_dump_signal_handler' -NOOP = proc { |x| x } -FAKE_HOST = 'localhost:0' +# Notifier is useful high-level synchronization primitive. +class Notifier + attr_reader :payload, :notified + alias_method :notified?, :notified + + def initialize + @mutex = Mutex.new + @cvar = ConditionVariable.new + @notified = false + @payload = nil + end + + def wait + @mutex.synchronize do + @cvar.wait(@mutex) until notified? + end + end + + def notify(payload) + @mutex.synchronize do + return Error.new('already notified') if notified? + @payload = payload + @notified = true + @cvar.signal + return nil + end + end +end def wakey_thread(&blk) - awake_mutex, awake_cond = Mutex.new, ConditionVariable.new + n = Notifier.new t = Thread.new do - blk.call(awake_mutex, awake_cond) + blk.call(n) end - awake_mutex.synchronize { awake_cond.wait(awake_mutex) } + n.wait t end @@ -50,8 +76,11 @@ end include GRPC::Core::StatusCodes include GRPC::Core::TimeConsts +include GRPC::Core::CallOps describe 'ClientStub' do + let(:noop) { proc { |x| x } } + before(:each) do Thread.abort_on_exception = true @server = nil @@ -66,61 +95,56 @@ describe 'ClientStub' do end describe '#new' do + let(:fake_host) { 'localhost:0' } it 'can be created from a host and args' do - host = FAKE_HOST opts = { a_channel_arg: 'an_arg' } blk = proc do - GRPC::ClientStub.new(host, @cq, **opts) + GRPC::ClientStub.new(fake_host, @cq, **opts) end expect(&blk).not_to raise_error end it 'can be created with a default deadline' do - host = FAKE_HOST opts = { a_channel_arg: 'an_arg', deadline: 5 } blk = proc do - GRPC::ClientStub.new(host, @cq, **opts) + GRPC::ClientStub.new(fake_host, @cq, **opts) end expect(&blk).not_to raise_error end it 'can be created with an channel override' do - host = FAKE_HOST opts = { a_channel_arg: 'an_arg', channel_override: @ch } blk = proc do - GRPC::ClientStub.new(host, @cq, **opts) + GRPC::ClientStub.new(fake_host, @cq, **opts) end expect(&blk).not_to raise_error end it 'cannot be created with a bad channel override' do - host = FAKE_HOST blk = proc do opts = { a_channel_arg: 'an_arg', channel_override: Object.new } - GRPC::ClientStub.new(host, @cq, **opts) + GRPC::ClientStub.new(fake_host, @cq, **opts) end expect(&blk).to raise_error end it 'cannot be created with bad credentials' do - host = FAKE_HOST blk = proc do opts = { a_channel_arg: 'an_arg', creds: Object.new } - GRPC::ClientStub.new(host, @cq, **opts) + GRPC::ClientStub.new(fake_host, @cq, **opts) end expect(&blk).to raise_error end it 'can be created with test test credentials' do certs = load_test_certs - host = FAKE_HOST blk = proc do opts = { GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr', a_channel_arg: 'an_arg', creds: GRPC::Core::Credentials.new(certs[0], nil, nil) } - GRPC::ClientStub.new(host, @cq, **opts) + GRPC::ClientStub.new(fake_host, @cq, **opts) end expect(&blk).to_not raise_error end @@ -187,7 +211,7 @@ describe 'ClientStub' do describe 'without a call operation' do def get_response(stub) - stub.request_response(@method, @sent_msg, NOOP, NOOP, + stub.request_response(@method, @sent_msg, noop, noop, k1: 'v1', k2: 'v2') end @@ -196,7 +220,7 @@ describe 'ClientStub' do describe 'via a call operation' do def get_response(stub) - op = stub.request_response(@method, @sent_msg, NOOP, NOOP, + op = stub.request_response(@method, @sent_msg, noop, noop, return_op: true, k1: 'v1', k2: 'v2') expect(op).to be_a(GRPC::ActiveCall::Operation) op.execute @@ -259,7 +283,7 @@ describe 'ClientStub' do describe 'without a call operation' do def get_response(stub) - stub.client_streamer(@method, @sent_msgs, NOOP, NOOP, + stub.client_streamer(@method, @sent_msgs, noop, noop, k1: 'v1', k2: 'v2') end @@ -268,7 +292,7 @@ describe 'ClientStub' do describe 'via a call operation' do def get_response(stub) - op = stub.client_streamer(@method, @sent_msgs, NOOP, NOOP, + op = stub.client_streamer(@method, @sent_msgs, noop, noop, return_op: true, k1: 'v1', k2: 'v2') expect(op).to be_a(GRPC::ActiveCall::Operation) op.execute @@ -333,7 +357,7 @@ describe 'ClientStub' do describe 'without a call operation' do def get_responses(stub) - e = stub.server_streamer(@method, @sent_msg, NOOP, NOOP, + e = stub.server_streamer(@method, @sent_msg, noop, noop, k1: 'v1', k2: 'v2') expect(e).to be_a(Enumerator) e @@ -344,7 +368,7 @@ describe 'ClientStub' do describe 'via a call operation' do def get_responses(stub) - op = stub.server_streamer(@method, @sent_msg, NOOP, NOOP, + op = stub.server_streamer(@method, @sent_msg, noop, noop, return_op: true, k1: 'v1', k2: 'v2') expect(op).to be_a(GRPC::ActiveCall::Operation) e = op.execute @@ -361,34 +385,30 @@ describe 'ClientStub' do before(:each) do @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s } @replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s } + server_port = create_test_server + @host = "localhost:#{server_port}" end it 'supports sending all the requests first', bidi: true do - server_port = create_test_server - host = "localhost:#{server_port}" th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys, @pass) - stub = GRPC::ClientStub.new(host, @cq) + stub = GRPC::ClientStub.new(@host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@replys) th.join end it 'supports client-initiated ping pong', bidi: true do - server_port = create_test_server - host = "localhost:#{server_port}" th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true) - stub = GRPC::ClientStub.new(host, @cq) + stub = GRPC::ClientStub.new(@host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) th.join end it 'supports a server-initiated ping pong', bidi: true do - server_port = create_test_server - host = "localhost:#{server_port}" th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false) - stub = GRPC::ClientStub.new(host, @cq) + stub = GRPC::ClientStub.new(@host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) th.join @@ -397,7 +417,7 @@ describe 'ClientStub' do describe 'without a call operation' do def get_responses(stub) - e = stub.bidi_streamer(@method, @sent_msgs, NOOP, NOOP) + e = stub.bidi_streamer(@method, @sent_msgs, noop, noop) expect(e).to be_a(Enumerator) e end @@ -407,7 +427,7 @@ describe 'ClientStub' do describe 'via a call operation' do def get_responses(stub) - op = stub.bidi_streamer(@method, @sent_msgs, NOOP, NOOP, + op = stub.bidi_streamer(@method, @sent_msgs, noop, noop, return_op: true) expect(op).to be_a(GRPC::ActiveCall::Operation) e = op.execute @@ -421,8 +441,8 @@ describe 'ClientStub' do def run_server_streamer(expected_input, replys, status, **kw) wanted_metadata = kw.clone - wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(mtx, cnd) + wakey_thread do |notifier| + c = expect_server_to_be_invoked(notifier) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end @@ -434,8 +454,8 @@ describe 'ClientStub' do def run_bidi_streamer_handle_inputs_first(expected_inputs, replys, status) - wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(mtx, cnd) + wakey_thread do |notifier| + c = expect_server_to_be_invoked(notifier) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } replys.each { |r| c.remote_send(r) } c.send_status(status, status == @pass ? 'OK' : 'NOK', true) @@ -443,8 +463,8 @@ describe 'ClientStub' do end def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts) - wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(mtx, cnd) + wakey_thread do |notifier| + c = expect_server_to_be_invoked(notifier) expected_inputs.each do |i| if client_starts expect(c.remote_read).to eq(i) @@ -460,8 +480,8 @@ describe 'ClientStub' do def run_client_streamer(expected_inputs, resp, status, **kw) wanted_metadata = kw.clone - wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(mtx, cnd) + wakey_thread do |notifier| + c = expect_server_to_be_invoked(notifier) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) @@ -473,8 +493,8 @@ describe 'ClientStub' do def run_request_response(expected_input, resp, status, **kw) wanted_metadata = kw.clone - wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(mtx, cnd) + wakey_thread do |notifier| + c = expect_server_to_be_invoked(notifier) expect(c.remote_read).to eq(expected_input) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) @@ -490,24 +510,16 @@ describe 'ClientStub' do @server.add_http2_port('0.0.0.0:0') end - def start_test_server(awake_mutex, awake_cond) + def expect_server_to_be_invoked(notifier) @server.start - @server_tag = Object.new - @server.request_call(@server_tag) - awake_mutex.synchronize { awake_cond.signal } - end - - def expect_server_to_be_invoked(awake_mutex, awake_cond) - start_test_server(awake_mutex, awake_cond) - ev = @server_queue.pluck(@server_tag, INFINITE_FUTURE) - fail OutOfTime if ev.nil? - server_call = ev.call - server_call.metadata = ev.result.metadata - finished_tag = Object.new - server_call.server_accept(@server_queue, finished_tag) - server_call.server_end_initial_metadata - GRPC::ActiveCall.new(server_call, @server_queue, NOOP, NOOP, - INFINITE_FUTURE, - finished_tag: finished_tag) + notifier.notify(nil) + server_tag = Object.new + recvd_rpc = @server.request_call(@server_queue, server_tag, + INFINITE_FUTURE) + recvd_call = recvd_rpc.call + recvd_call.metadata = recvd_rpc.metadata + recvd_call.run_batch(@server_queue, server_tag, Time.now + 2, + SEND_INITIAL_METADATA => nil) + GRPC::ActiveCall.new(recvd_call, @server_queue, noop, noop, INFINITE_FUTURE) end end diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb index 39d1e83748b..a68299465ce 100644 --- a/src/ruby/spec/generic/rpc_desc_spec.rb +++ b/src/ruby/spec/generic/rpc_desc_spec.rb @@ -37,7 +37,6 @@ describe GRPC::RpcDesc do INTERNAL = GRPC::Core::StatusCodes::INTERNAL UNKNOWN = GRPC::Core::StatusCodes::UNKNOWN CallError = GRPC::Core::CallError - EventError = GRPC::Core::EventError before(:each) do @request_response = RpcDesc.new('rr', Object.new, Object.new, 'encode', @@ -63,24 +62,17 @@ describe GRPC::RpcDesc do it 'sends the specified status if BadStatus is raised' do expect(@call).to receive(:remote_read).once.and_return(Object.new) - expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK') + expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false) @request_response.run_server_method(@call, method(:bad_status)) end it 'sends status UNKNOWN if other StandardErrors are raised' do expect(@call).to receive(:remote_read).once.and_return(Object.new) - expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason) + expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, + false) @request_response.run_server_method(@call, method(:other_error)) end - it 'absorbs EventError with no further action' do - expect(@call).to receive(:remote_read).once.and_raise(EventError) - blk = proc do - @request_response.run_server_method(@call, method(:fake_reqresp)) - end - expect(&blk).to_not raise_error - end - it 'absorbs CallError with no further action' do expect(@call).to receive(:remote_read).once.and_raise(CallError) blk = proc do @@ -93,8 +85,7 @@ describe GRPC::RpcDesc do req = Object.new expect(@call).to receive(:remote_read).once.and_return(req) expect(@call).to receive(:remote_send).once.with(@ok_response) - expect(@call).to receive(:send_status).once.with(OK, 'OK') - expect(@call).to receive(:finished).once + expect(@call).to receive(:send_status).once.with(OK, 'OK', true) @request_response.run_server_method(@call, method(:fake_reqresp)) end end @@ -107,23 +98,16 @@ describe GRPC::RpcDesc do end it 'sends the specified status if BadStatus is raised' do - expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK') + expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false) @client_streamer.run_server_method(@call, method(:bad_status_alt)) end it 'sends status UNKNOWN if other StandardErrors are raised' do - expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason) + expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, + false) @client_streamer.run_server_method(@call, method(:other_error_alt)) end - it 'absorbs EventError with no further action' do - expect(@call).to receive(:remote_send).once.and_raise(EventError) - blk = proc do - @client_streamer.run_server_method(@call, method(:fake_clstream)) - end - expect(&blk).to_not raise_error - end - it 'absorbs CallError with no further action' do expect(@call).to receive(:remote_send).once.and_raise(CallError) blk = proc do @@ -134,8 +118,7 @@ describe GRPC::RpcDesc do it 'sends a response and closes the stream if there no errors' do expect(@call).to receive(:remote_send).once.with(@ok_response) - expect(@call).to receive(:send_status).once.with(OK, 'OK') - expect(@call).to receive(:finished).once + expect(@call).to receive(:send_status).once.with(OK, 'OK', true) @client_streamer.run_server_method(@call, method(:fake_clstream)) end end @@ -149,24 +132,17 @@ describe GRPC::RpcDesc do it 'sends the specified status if BadStatus is raised' do expect(@call).to receive(:remote_read).once.and_return(Object.new) - expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK') + expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false) @server_streamer.run_server_method(@call, method(:bad_status)) end it 'sends status UNKNOWN if other StandardErrors are raised' do expect(@call).to receive(:remote_read).once.and_return(Object.new) - expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason) + expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason, + false) @server_streamer.run_server_method(@call, method(:other_error)) end - it 'absorbs EventError with no further action' do - expect(@call).to receive(:remote_read).once.and_raise(EventError) - blk = proc do - @server_streamer.run_server_method(@call, method(:fake_svstream)) - end - expect(&blk).to_not raise_error - end - it 'absorbs CallError with no further action' do expect(@call).to receive(:remote_read).once.and_raise(CallError) blk = proc do @@ -179,8 +155,7 @@ describe GRPC::RpcDesc do req = Object.new expect(@call).to receive(:remote_read).once.and_return(req) expect(@call).to receive(:remote_send).twice.with(@ok_response) - expect(@call).to receive(:send_status).once.with(OK, 'OK') - expect(@call).to receive(:finished).once + expect(@call).to receive(:send_status).once.with(OK, 'OK', true) @server_streamer.run_server_method(@call, method(:fake_svstream)) end end @@ -197,20 +172,20 @@ describe GRPC::RpcDesc do it 'sends the specified status if BadStatus is raised' do e = GRPC::BadStatus.new(@bs_code, 'NOK') expect(@call).to receive(:run_server_bidi).and_raise(e) - expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK') + expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false) @bidi_streamer.run_server_method(@call, method(:bad_status_alt)) end it 'sends status UNKNOWN if other StandardErrors are raised' do expect(@call).to receive(:run_server_bidi).and_raise(StandardError) - expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason) + expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason, + false) @bidi_streamer.run_server_method(@call, method(:other_error_alt)) end it 'closes the stream if there no errors' do expect(@call).to receive(:run_server_bidi) - expect(@call).to receive(:send_status).once.with(OK, 'OK') - expect(@call).to receive(:finished).once + expect(@call).to receive(:send_status).once.with(OK, 'OK', true) @bidi_streamer.run_server_method(@call, method(:fake_bidistream)) end end diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index 34e5cdcd04c..f409d73e2fe 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -364,7 +364,7 @@ describe GRPC::RpcServer do @srv.wait_till_running req = EchoMsg.new stub = SlowStub.new(@host, **@client_opts) - deadline = service.delay + 0.5 # wait for long enough + deadline = service.delay + 1.0 # wait for long enough expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg) wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }] expect(service.received_md).to eq(wanted_md) diff --git a/src/ruby/spec/metadata_spec.rb b/src/ruby/spec/metadata_spec.rb deleted file mode 100644 index 24728666921..00000000000 --- a/src/ruby/spec/metadata_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -require 'grpc' - -describe GRPC::Core::Metadata do - describe '#new' do - it 'should create instances' do - expect { GRPC::Core::Metadata.new('a key', 'a value') }.to_not raise_error - end - end - - describe '#key' do - md = GRPC::Core::Metadata.new('a key', 'a value') - it 'should be the constructor value' do - expect(md.key).to eq('a key') - end - end - - describe '#value' do - md = GRPC::Core::Metadata.new('a key', 'a value') - it 'should be the constuctor value' do - expect(md.value).to eq('a value') - end - end - - describe '#dup' do - it 'should create a copy that returns the correct key' do - md = GRPC::Core::Metadata.new('a key', 'a value') - expect(md.dup.key).to eq('a key') - end - - it 'should create a copy that returns the correct value' do - md = GRPC::Core::Metadata.new('a key', 'a value') - expect(md.dup.value).to eq('a value') - end - end -end diff --git a/templates/BUILD.template b/templates/BUILD.template index 997c55b1c89..8303b9f8e96 100644 --- a/templates/BUILD.template +++ b/templates/BUILD.template @@ -32,38 +32,79 @@ licenses(["notice"]) # 3-clause BSD +package(default_visibility = ["//visibility:public"]) + +<%! +def get_deps(target_dict): + deps = [] + if target_dict.get('secure', 'no') == 'yes': + deps = [ + "//external:libssl", + ] + if target_dict.get('build', None) == 'protoc': + deps.append("//external:protobuf_compiler") + if target_dict['name'] == 'grpc++_unsecure' or target_dict['name'] == 'grpc++': + deps.append("//external:protobuf_clib") + for d in target_dict.get('deps', []): + if d.find('//') == 0 or d[0] == ':': + deps.append(d) + else: + deps.append(':%s' % (d)) + return deps +%> + % for lib in libs: -% if lib.build == "all" and lib.language == 'c': -${makelib(lib)} +% if lib.build != "private": +${cc_library(lib)} % endif % endfor -<%def name="makelib(lib)"> +% for tgt in targets: +% if tgt.build == 'protoc': +${cc_binary(tgt)} +% endif +% endfor +<%def name="cc_library(lib)"> cc_library( - name = "${lib.name}", - srcs = [ + name = "${lib.name}", + srcs = [ % for hdr in lib.get("headers", []): - "${hdr}", + "${hdr}", % endfor % for src in lib.src: - "${src}", + "${src}", % endfor - ], - hdrs = [ + ], + hdrs = [ % for hdr in lib.get("public_headers", []): - "${hdr}", + "${hdr}", % endfor - ], - includes = [ - "include", - ".", - ], - deps = [ -% for dep in lib.get("deps", []): - ":${dep}", + ], + includes = [ + "include", + ".", + ], + deps = [ +% for dep in get_deps(lib): + "${dep}", % endfor - ], + ], ) + +<%def name="cc_binary(tgt)"> +cc_binary( + name = "${tgt.name}", + srcs = [ +% for src in tgt.src: + "${src}", +% endfor + ], + deps = [ +% for dep in get_deps(tgt): + "${dep}", +% endfor + ], +) diff --git a/templates/Makefile.template b/templates/Makefile.template index 340cf235992..2cfbfa36ec9 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -35,17 +35,11 @@ proto_re = re.compile('(.*)\\.proto') - def excluded(filename, exclude_res): - for r in exclude_res: - if r.match(filename): - return True - return False - def proto_to_cc(filename): m = proto_re.match(filename) if not m: return filename - return '$(GENDIR)/' + m.group(1) + '.pb.cc' + return '$(GENDIR)/' + m.group(1) + '.pb.cc $(GENDIR)/' + m.group(1) + '.grpc.pb.cc' %> @@ -244,7 +238,6 @@ ifeq ($(HAS_CXX11),true) CXXFLAGS += -std=c++11 else CXXFLAGS += -std=c++0x -DEFINES += GRPC_OLD_CXX endif CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter LDFLAGS += -g @@ -841,11 +834,17 @@ endif % for p in protos: ifeq ($(NO_PROTOC),true) $(GENDIR)/${p}.pb.cc: protoc_dep_error +$(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error else $(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(E) "[PROTOC] Generating protobuf CC file from $<" $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< + $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< + +$(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) + $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" + $(Q) mkdir -p `dirname $@` + $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< endif % endfor @@ -927,10 +926,11 @@ ifeq ($(SYSTEM),MINGW32) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT) $(prefix)/lib/${lib.name}.$(SHARED_EXT) $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a else -ifneq ($(SYSTEM),Darwin) $(E) "[INSTALL] Installing lib${lib.name}.$(SHARED_EXT)" $(Q) $(INSTALL) -d $(prefix)/lib $(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.$(SHARED_EXT) +ifneq ($(SYSTEM),Darwin) + $(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major} $(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so endif endif @@ -1167,7 +1167,7 @@ ${out_libbase}.$(SHARED_EXT): $(LIB${lib.name.upper()}_OBJS) ${lib_deps} $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` ifeq ($(SYSTEM),Darwin) - $(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs} + $(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name lib${lib.name}.$(SHARED_EXT) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs} else $(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs} $(Q) ln -sf lib${lib.name}.$(SHARED_EXT) ${out_libbase}.so.${settings.version.major} diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c index 326321f4e21..592dfd415f9 100644 --- a/test/core/end2end/tests/cancel_after_invoke.c +++ b/test/core/end2end/tests/cancel_after_invoke.c @@ -110,7 +110,8 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config, grpc_op ops[6]; grpc_op *op; grpc_call *c; - grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, mode, NULL, NULL); + grpc_end2end_test_fixture f = + begin_test(config, __FUNCTION__, mode, NULL, NULL); gpr_timespec deadline = five_seconds_time(); cq_verifier *v_client = cq_verifier_create(f.client_cq); grpc_metadata_array initial_metadata_recv; diff --git a/test/core/end2end/tests/cancel_test_helpers.h b/test/core/end2end/tests/cancel_test_helpers.h index 3d92b64ae49..0d680fcfe11 100644 --- a/test/core/end2end/tests/cancel_test_helpers.h +++ b/test/core/end2end/tests/cancel_test_helpers.h @@ -47,6 +47,8 @@ static grpc_call_error wait_for_deadline(grpc_call *call) { static const cancellation_mode cancellation_modes[] = { {"cancel", grpc_call_cancel, GRPC_STATUS_CANCELLED, ""}, - {"deadline", wait_for_deadline, GRPC_STATUS_DEADLINE_EXCEEDED, "Deadline Exceeded"}, }; + {"deadline", wait_for_deadline, GRPC_STATUS_DEADLINE_EXCEEDED, + "Deadline Exceeded"}, +}; -#endif /* GRPC_TEST_CORE_END2END_TESTS_CANCEL_TEST_HELPERS_H */ +#endif /* GRPC_TEST_CORE_END2END_TESTS_CANCEL_TEST_HELPERS_H */ diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c index 6b80ee1ee8c..1c02c4b2f80 100644 --- a/test/core/iomgr/tcp_server_posix_test.c +++ b/test/core/iomgr/tcp_server_posix_test.c @@ -38,6 +38,7 @@ #include #include "test/core/util/test_config.h" +#include #include #include #include diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c index c03a905d2af..bb3d54a2627 100644 --- a/test/core/support/thd_test.c +++ b/test/core/support/thd_test.c @@ -60,12 +60,16 @@ static void thd_body(void *v) { gpr_mu_unlock(&t->mu); } +static void thd_body_joinable(void *v) { } + /* Test that we can create a number of threads and wait for them. */ static void test(void) { int i; gpr_thd_id thd; + gpr_thd_id thds[1000]; struct test t; int n = 1000; + gpr_thd_options options = gpr_thd_options_default(); gpr_mu_init(&t.mu); gpr_cv_init(&t.done_cv); t.n = n; @@ -79,6 +83,13 @@ static void test(void) { } gpr_mu_unlock(&t.mu); GPR_ASSERT(t.n == 0); + gpr_thd_options_set_joinable(&options); + for (i = 0; i < n; i++) { + GPR_ASSERT(gpr_thd_new(&thds[i], &thd_body_joinable, NULL, &options)); + } + for (i = 0; i < n; i++) { + gpr_thd_join(thds[i]); + } } /* ------------------------------------------------- */ diff --git a/test/core/support/tls_test.c b/test/core/support/tls_test.c new file mode 100644 index 00000000000..8632fd44901 --- /dev/null +++ b/test/core/support/tls_test.c @@ -0,0 +1,82 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Test of gpr thread local storage support. */ + +#include +#include +#include +#include +#include +#include +#include "test/core/util/test_config.h" + +#define NUM_THREADS 100 + +GPR_TLS_DECL(test_var); + +static void thd_body(void *arg) { + gpr_intptr i; + + GPR_ASSERT(gpr_tls_get(&test_var) == 0); + + for (i = 0; i < 10000000; i++) { + gpr_tls_set(&test_var, i); + GPR_ASSERT(gpr_tls_get(&test_var) == i); + } +} + +/* ------------------------------------------------- */ + +int main(int argc, char *argv[]) { + gpr_thd_options opt = gpr_thd_options_default(); + int i; + gpr_thd_id threads[NUM_THREADS]; + + grpc_test_init(argc, argv); + + gpr_tls_init(&test_var); + + gpr_thd_options_set_joinable(&opt); + + for (i = 0; i < NUM_THREADS; i++) { + gpr_thd_new(&threads[i], thd_body, NULL, &opt); + } + for (i = 0; i < NUM_THREADS; i++) { + gpr_thd_join(threads[i]); + } + + gpr_tls_destroy(&test_var); + + return 0; +} diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 9938fcf12eb..dd294d95163 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -35,8 +35,8 @@ #include #include "test/core/util/test_config.h" -#include "test/cpp/util/echo_duplicate.pb.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo_duplicate.grpc.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include "src/cpp/util/time.h" #include #include diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 0d5db046df4..f96051cafac 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -35,8 +35,8 @@ #include #include "test/core/util/test_config.h" -#include "test/cpp/util/echo_duplicate.pb.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo_duplicate.grpc.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include "src/cpp/util/time.h" #include "src/cpp/server/thread_pool.h" #include diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc index 9cdd8c94d12..eb6f5369a92 100644 --- a/test/cpp/end2end/generic_end2end_test.cc +++ b/test/cpp/end2end/generic_end2end_test.cc @@ -38,7 +38,7 @@ #include "src/cpp/util/time.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include #include #include diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc index de6c6b7b77e..189cdeb0eed 100644 --- a/test/cpp/interop/client.cc +++ b/test/cpp/interop/client.cc @@ -31,29 +31,19 @@ * */ -#include -#include #include -#include -#include -#include #include #include #include #include -#include #include #include -#include -#include #include #include -#include "test/cpp/util/create_test_channel.h" -#include "test/cpp/interop/test.pb.h" -#include "test/cpp/interop/empty.pb.h" -#include "test/cpp/interop/messages.pb.h" +#include "test/cpp/interop/client_helper.h" +#include "test/cpp/interop/interop_client.h" DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls."); DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google"); @@ -81,21 +71,8 @@ DEFINE_string(service_account_key_file, "", "Path to service account json key file."); DEFINE_string(oauth_scope, "", "Scope for OAuth tokens."); -using grpc::ChannelInterface; -using grpc::ClientContext; -using grpc::ComputeEngineCredentials; -using grpc::CreateTestChannel; -using grpc::Credentials; -using grpc::JWTCredentials; -using grpc::ServiceAccountCredentials; -using grpc::testing::ResponseParameters; -using grpc::testing::SimpleRequest; -using grpc::testing::SimpleResponse; -using grpc::testing::StreamingInputCallRequest; -using grpc::testing::StreamingInputCallResponse; -using grpc::testing::StreamingOutputCallRequest; -using grpc::testing::StreamingOutputCallResponse; -using grpc::testing::TestService; +using grpc::testing::CreateChannelForTestCase; +using grpc::testing::GetServiceAccountJsonKey; // In some distros, gflags is in the namespace google, and in some others, // in gflags. This hack is enabling us to find both. @@ -104,362 +81,48 @@ namespace gflags {} using namespace google; using namespace gflags; -namespace { -// The same value is defined by the Java client. -const std::vector request_stream_sizes = {27182, 8, 1828, 45904}; -const std::vector response_stream_sizes = {31415, 9, 2653, 58979}; -const int kNumResponseMessages = 2000; -const int kResponseMessageSize = 1030; -const int kReceiveDelayMilliSeconds = 20; -const int kLargeRequestSize = 314159; -const int kLargeResponseSize = 271812; -} // namespace - -grpc::string GetServiceAccountJsonKey() { - static grpc::string json_key; - if (json_key.empty()) { - std::ifstream json_key_file(FLAGS_service_account_key_file); - std::stringstream key_stream; - key_stream << json_key_file.rdbuf(); - json_key = key_stream.str(); - } - return json_key; -} - -std::shared_ptr CreateChannelForTestCase( - const grpc::string& test_case) { - GPR_ASSERT(FLAGS_server_port); - const int host_port_buf_size = 1024; - char host_port[host_port_buf_size]; - snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(), - FLAGS_server_port); - - if (test_case == "service_account_creds") { - std::unique_ptr creds; - GPR_ASSERT(FLAGS_enable_ssl); - grpc::string json_key = GetServiceAccountJsonKey(); - creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope, - std::chrono::hours(1)); - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); - } else if (test_case == "compute_engine_creds") { - std::unique_ptr creds; - GPR_ASSERT(FLAGS_enable_ssl); - creds = ComputeEngineCredentials(); - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); - } else if (test_case == "jwt_token_creds") { - std::unique_ptr creds; - GPR_ASSERT(FLAGS_enable_ssl); - grpc::string json_key = GetServiceAccountJsonKey(); - creds = JWTCredentials(json_key, std::chrono::hours(1)); - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); - } else { - return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots); - } -} - -void AssertOkOrPrintErrorStatus(const grpc::Status& s) { - if (s.IsOk()) { - return; - } - gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(), - s.details().c_str()); - GPR_ASSERT(0); -} - -void DoEmpty() { - gpr_log(GPR_INFO, "Sending an empty rpc..."); - std::shared_ptr channel = - CreateChannelForTestCase("empty_unary"); - std::unique_ptr stub(TestService::NewStub(channel)); - - grpc::testing::Empty request = grpc::testing::Empty::default_instance(); - grpc::testing::Empty response = grpc::testing::Empty::default_instance(); - ClientContext context; - - grpc::Status s = stub->EmptyCall(&context, request, &response); - AssertOkOrPrintErrorStatus(s); - - gpr_log(GPR_INFO, "Empty rpc done."); -} - -// Shared code to set large payload, make rpc and check response payload. -void PerformLargeUnary(std::shared_ptr channel, - SimpleRequest* request, SimpleResponse* response) { - std::unique_ptr stub(TestService::NewStub(channel)); - - ClientContext context; - request->set_response_type(grpc::testing::PayloadType::COMPRESSABLE); - request->set_response_size(kLargeResponseSize); - grpc::string payload(kLargeRequestSize, '\0'); - request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize); - - grpc::Status s = stub->UnaryCall(&context, *request, response); - - AssertOkOrPrintErrorStatus(s); - GPR_ASSERT(response->payload().type() == - grpc::testing::PayloadType::COMPRESSABLE); - GPR_ASSERT(response->payload().body() == - grpc::string(kLargeResponseSize, '\0')); -} - -void DoComputeEngineCreds() { - gpr_log(GPR_INFO, - "Sending a large unary rpc with compute engine credentials ..."); - std::shared_ptr channel = - CreateChannelForTestCase("compute_engine_creds"); - SimpleRequest request; - SimpleResponse response; - request.set_fill_username(true); - request.set_fill_oauth_scope(true); - PerformLargeUnary(channel, &request, &response); - gpr_log(GPR_INFO, "Got username %s", response.username().c_str()); - gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str()); - GPR_ASSERT(!response.username().empty()); - GPR_ASSERT(response.username().c_str() == FLAGS_default_service_account); - GPR_ASSERT(!response.oauth_scope().empty()); - const char* oauth_scope_str = response.oauth_scope().c_str(); - GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos); - gpr_log(GPR_INFO, "Large unary with compute engine creds done."); -} - -void DoServiceAccountCreds() { - gpr_log(GPR_INFO, - "Sending a large unary rpc with service account credentials ..."); - std::shared_ptr channel = - CreateChannelForTestCase("service_account_creds"); - SimpleRequest request; - SimpleResponse response; - request.set_fill_username(true); - request.set_fill_oauth_scope(true); - PerformLargeUnary(channel, &request, &response); - GPR_ASSERT(!response.username().empty()); - GPR_ASSERT(!response.oauth_scope().empty()); - grpc::string json_key = GetServiceAccountJsonKey(); - GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos); - const char* oauth_scope_str = response.oauth_scope().c_str(); - GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos); - gpr_log(GPR_INFO, "Large unary with service account creds done."); -} - -void DoJwtTokenCreds() { - gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ..."); - std::shared_ptr channel = - CreateChannelForTestCase("jwt_token_creds"); - SimpleRequest request; - SimpleResponse response; - request.set_fill_username(true); - PerformLargeUnary(channel, &request, &response); - GPR_ASSERT(!response.username().empty()); - grpc::string json_key = GetServiceAccountJsonKey(); - GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos); - gpr_log(GPR_INFO, "Large unary with JWT token creds done."); -} - -void DoLargeUnary() { - gpr_log(GPR_INFO, "Sending a large unary rpc..."); - std::shared_ptr channel = - CreateChannelForTestCase("large_unary"); - SimpleRequest request; - SimpleResponse response; - PerformLargeUnary(channel, &request, &response); - gpr_log(GPR_INFO, "Large unary done."); -} - -void DoRequestStreaming() { - gpr_log(GPR_INFO, "Sending request steaming rpc ..."); - std::shared_ptr channel = - CreateChannelForTestCase("client_streaming"); - std::unique_ptr stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - StreamingInputCallRequest request; - StreamingInputCallResponse response; - - std::unique_ptr> stream( - stub->StreamingInputCall(&context, &response)); - - int aggregated_payload_size = 0; - for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { - grpc::testing::Payload* payload = request.mutable_payload(); - payload->set_body(grpc::string(request_stream_sizes[i], '\0')); - GPR_ASSERT(stream->Write(request)); - aggregated_payload_size += request_stream_sizes[i]; - } - stream->WritesDone(); - grpc::Status s = stream->Finish(); - - GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size); - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Request streaming done."); -} - -void DoResponseStreaming() { - gpr_log(GPR_INFO, "Receiving response steaming rpc ..."); - std::shared_ptr channel = - CreateChannelForTestCase("server_streaming"); - std::unique_ptr stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - StreamingOutputCallRequest request; - for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { - ResponseParameters* response_parameter = request.add_response_parameters(); - response_parameter->set_size(response_stream_sizes[i]); - } - StreamingOutputCallResponse response; - std::unique_ptr> stream( - stub->StreamingOutputCall(&context, request)); - - unsigned int i = 0; - while (stream->Read(&response)) { - GPR_ASSERT(response.payload().body() == - grpc::string(response_stream_sizes[i], '\0')); - ++i; - } - GPR_ASSERT(response_stream_sizes.size() == i); - grpc::Status s = stream->Finish(); - - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Response streaming done."); -} - -void DoResponseStreamingWithSlowConsumer() { - gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ..."); - std::shared_ptr channel = - CreateChannelForTestCase("slow_consumer"); - std::unique_ptr stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - StreamingOutputCallRequest request; - - for (int i = 0; i < kNumResponseMessages; ++i) { - ResponseParameters* response_parameter = request.add_response_parameters(); - response_parameter->set_size(kResponseMessageSize); - } - StreamingOutputCallResponse response; - std::unique_ptr> stream( - stub->StreamingOutputCall(&context, request)); - - int i = 0; - while (stream->Read(&response)) { - GPR_ASSERT(response.payload().body() == - grpc::string(kResponseMessageSize, '\0')); - gpr_log(GPR_INFO, "received message %d", i); - usleep(kReceiveDelayMilliSeconds * 1000); - ++i; - } - GPR_ASSERT(kNumResponseMessages == i); - grpc::Status s = stream->Finish(); - - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Response streaming done."); -} - -void DoHalfDuplex() { - gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ..."); - std::shared_ptr channel = - CreateChannelForTestCase("half_duplex"); - std::unique_ptr stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - std::unique_ptr> - stream(stub->HalfDuplexCall(&context)); - - StreamingOutputCallRequest request; - ResponseParameters* response_parameter = request.add_response_parameters(); - for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { - response_parameter->set_size(response_stream_sizes[i]); - GPR_ASSERT(stream->Write(request)); - } - stream->WritesDone(); - - unsigned int i = 0; - StreamingOutputCallResponse response; - while (stream->Read(&response)) { - GPR_ASSERT(response.payload().has_body()); - GPR_ASSERT(response.payload().body() == - grpc::string(response_stream_sizes[i], '\0')); - ++i; - } - GPR_ASSERT(response_stream_sizes.size() == i); - grpc::Status s = stream->Finish(); - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Half-duplex streaming rpc done."); -} - -void DoPingPong() { - gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ..."); - std::shared_ptr channel = - CreateChannelForTestCase("ping_pong"); - std::unique_ptr stub(TestService::NewStub(channel)); - - grpc::ClientContext context; - std::unique_ptr> - stream(stub->FullDuplexCall(&context)); - - StreamingOutputCallRequest request; - request.set_response_type(grpc::testing::PayloadType::COMPRESSABLE); - ResponseParameters* response_parameter = request.add_response_parameters(); - grpc::testing::Payload* payload = request.mutable_payload(); - StreamingOutputCallResponse response; - for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { - response_parameter->set_size(response_stream_sizes[i]); - payload->set_body(grpc::string(request_stream_sizes[i], '\0')); - GPR_ASSERT(stream->Write(request)); - GPR_ASSERT(stream->Read(&response)); - GPR_ASSERT(response.payload().has_body()); - GPR_ASSERT(response.payload().body() == - grpc::string(response_stream_sizes[i], '\0')); - } - - stream->WritesDone(); - GPR_ASSERT(!stream->Read(&response)); - grpc::Status s = stream->Finish(); - AssertOkOrPrintErrorStatus(s); - gpr_log(GPR_INFO, "Ping pong streaming done."); -} - int main(int argc, char** argv) { grpc_init(); ParseCommandLineFlags(&argc, &argv, true); + grpc::testing::InteropClient client( + CreateChannelForTestCase(FLAGS_test_case)); if (FLAGS_test_case == "empty_unary") { - DoEmpty(); + client.DoEmpty(); } else if (FLAGS_test_case == "large_unary") { - DoLargeUnary(); + client.DoLargeUnary(); } else if (FLAGS_test_case == "client_streaming") { - DoRequestStreaming(); + client.DoRequestStreaming(); } else if (FLAGS_test_case == "server_streaming") { - DoResponseStreaming(); + client.DoResponseStreaming(); } else if (FLAGS_test_case == "slow_consumer") { - DoResponseStreamingWithSlowConsumer(); + client.DoResponseStreamingWithSlowConsumer(); } else if (FLAGS_test_case == "half_duplex") { - DoHalfDuplex(); + client.DoHalfDuplex(); } else if (FLAGS_test_case == "ping_pong") { - DoPingPong(); + client.DoPingPong(); } else if (FLAGS_test_case == "service_account_creds") { - DoServiceAccountCreds(); + grpc::string json_key = GetServiceAccountJsonKey(); + client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope); } else if (FLAGS_test_case == "compute_engine_creds") { - DoComputeEngineCreds(); + client.DoComputeEngineCreds(FLAGS_default_service_account, + FLAGS_oauth_scope); } else if (FLAGS_test_case == "jwt_token_creds") { - DoJwtTokenCreds(); + grpc::string json_key = GetServiceAccountJsonKey(); + client.DoJwtTokenCreds(json_key); } else if (FLAGS_test_case == "all") { - DoEmpty(); - DoLargeUnary(); - DoRequestStreaming(); - DoResponseStreaming(); - DoHalfDuplex(); - DoPingPong(); + client.DoEmpty(); + client.DoLargeUnary(); + client.DoRequestStreaming(); + client.DoResponseStreaming(); + client.DoHalfDuplex(); + client.DoPingPong(); // service_account_creds and jwt_token_creds can only run with ssl. if (FLAGS_enable_ssl) { - DoServiceAccountCreds(); - DoJwtTokenCreds(); + grpc::string json_key = GetServiceAccountJsonKey(); + client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope); + client.DoJwtTokenCreds(json_key); } // compute_engine_creds only runs in GCE. } else { @@ -470,6 +133,7 @@ int main(int argc, char** argv) { "service_account_creds|compute_engine_creds|jwt_token_creds", FLAGS_test_case.c_str()); } + client.Reset(nullptr); grpc_shutdown(); return 0; diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc new file mode 100644 index 00000000000..362e6af353b --- /dev/null +++ b/test/cpp/interop/client_helper.cc @@ -0,0 +1,119 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/interop/client_helper.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "test/cpp/util/create_test_channel.h" + +DECLARE_bool(enable_ssl); +DECLARE_bool(use_prod_roots); +DECLARE_int32(server_port); +DECLARE_string(server_host); +DECLARE_string(server_host_override); +DECLARE_string(test_case); +DECLARE_string(default_service_account); +DECLARE_string(service_account_key_file); +DECLARE_string(oauth_scope); + +// In some distros, gflags is in the namespace google, and in some others, +// in gflags. This hack is enabling us to find both. +namespace google {} +namespace gflags {} +using namespace google; +using namespace gflags; + +namespace grpc { +namespace testing { + +grpc::string GetServiceAccountJsonKey() { + static grpc::string json_key; + if (json_key.empty()) { + std::ifstream json_key_file(FLAGS_service_account_key_file); + std::stringstream key_stream; + key_stream << json_key_file.rdbuf(); + json_key = key_stream.str(); + } + return json_key; +} + +std::shared_ptr CreateChannelForTestCase( + const grpc::string& test_case) { + GPR_ASSERT(FLAGS_server_port); + const int host_port_buf_size = 1024; + char host_port[host_port_buf_size]; + snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(), + FLAGS_server_port); + + if (test_case == "service_account_creds") { + std::unique_ptr creds; + GPR_ASSERT(FLAGS_enable_ssl); + grpc::string json_key = GetServiceAccountJsonKey(); + creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope, + std::chrono::hours(1)); + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); + } else if (test_case == "compute_engine_creds") { + std::unique_ptr creds; + GPR_ASSERT(FLAGS_enable_ssl); + creds = ComputeEngineCredentials(); + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); + } else if (test_case == "jwt_token_creds") { + std::unique_ptr creds; + GPR_ASSERT(FLAGS_enable_ssl); + grpc::string json_key = GetServiceAccountJsonKey(); + creds = JWTCredentials(json_key, std::chrono::hours(1)); + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); + } else { + return CreateTestChannel(host_port, FLAGS_server_host_override, + FLAGS_enable_ssl, FLAGS_use_prod_roots); + } +} + +} // namespace testing +} // namespace grpc diff --git a/src/ruby/ext/grpc/rb_metadata.h b/test/cpp/interop/client_helper.h similarity index 71% rename from src/ruby/ext/grpc/rb_metadata.h rename to test/cpp/interop/client_helper.h index 251072f658d..897f974026f 100644 --- a/src/ruby/ext/grpc/rb_metadata.h +++ b/test/cpp/interop/client_helper.h @@ -31,23 +31,23 @@ * */ -#ifndef GRPC_RB_METADATA_H_ -#define GRPC_RB_METADATA_H_ +#ifndef GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H +#define GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H -#include -#include +#include -/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */ -extern VALUE rb_cMetadata; +#include +#include -/* grpc_rb_metadata_create_with_mark creates a grpc_rb_metadata with a ruby mark - * object that will be kept alive while the metadata is alive. */ -extern VALUE grpc_rb_metadata_create_with_mark(VALUE mark, grpc_metadata* md); +namespace grpc { +namespace testing { -/* Gets the wrapped metadata from the ruby wrapper */ -grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v); +grpc::string GetServiceAccountJsonKey(); -/* Initializes the Metadata class. */ -void Init_grpc_metadata(); +std::shared_ptr CreateChannelForTestCase( + const grpc::string& test_case); -#endif /* GRPC_RB_METADATA_H_ */ +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc new file mode 100644 index 00000000000..fd9c2e024ab --- /dev/null +++ b/test/cpp/interop/interop_client.cc @@ -0,0 +1,311 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/interop/interop_client.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include "test/cpp/interop/test.grpc.pb.h" +#include "test/cpp/interop/empty.grpc.pb.h" +#include "test/cpp/interop/messages.grpc.pb.h" + +namespace grpc { +namespace testing { + +namespace { +// The same value is defined by the Java client. +const std::vector request_stream_sizes = {27182, 8, 1828, 45904}; +const std::vector response_stream_sizes = {31415, 9, 2653, 58979}; +const int kNumResponseMessages = 2000; +const int kResponseMessageSize = 1030; +const int kReceiveDelayMilliSeconds = 20; +const int kLargeRequestSize = 314159; +const int kLargeResponseSize = 271812; +} // namespace + +InteropClient::InteropClient(std::shared_ptr channel) + : channel_(channel) {} + +void InteropClient::AssertOkOrPrintErrorStatus(const Status& s) { + if (s.IsOk()) { + return; + } + gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(), + s.details().c_str()); + GPR_ASSERT(0); +} + +void InteropClient::DoEmpty() { + gpr_log(GPR_INFO, "Sending an empty rpc..."); + std::unique_ptr stub(TestService::NewStub(channel_)); + + Empty request = Empty::default_instance(); + Empty response = Empty::default_instance(); + ClientContext context; + + Status s = stub->EmptyCall(&context, request, &response); + AssertOkOrPrintErrorStatus(s); + + gpr_log(GPR_INFO, "Empty rpc done."); +} + +// Shared code to set large payload, make rpc and check response payload. +void InteropClient::PerformLargeUnary(SimpleRequest* request, + SimpleResponse* response) { + std::unique_ptr stub(TestService::NewStub(channel_)); + + ClientContext context; + request->set_response_type(PayloadType::COMPRESSABLE); + request->set_response_size(kLargeResponseSize); + grpc::string payload(kLargeRequestSize, '\0'); + request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize); + + Status s = stub->UnaryCall(&context, *request, response); + + AssertOkOrPrintErrorStatus(s); + GPR_ASSERT(response->payload().type() == PayloadType::COMPRESSABLE); + GPR_ASSERT(response->payload().body() == + grpc::string(kLargeResponseSize, '\0')); +} + +void InteropClient::DoComputeEngineCreds( + const grpc::string& default_service_account, + const grpc::string& oauth_scope) { + gpr_log(GPR_INFO, + "Sending a large unary rpc with compute engine credentials ..."); + SimpleRequest request; + SimpleResponse response; + request.set_fill_username(true); + request.set_fill_oauth_scope(true); + PerformLargeUnary(&request, &response); + gpr_log(GPR_INFO, "Got username %s", response.username().c_str()); + gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str()); + GPR_ASSERT(!response.username().empty()); + GPR_ASSERT(response.username().c_str() == default_service_account); + GPR_ASSERT(!response.oauth_scope().empty()); + const char* oauth_scope_str = response.oauth_scope().c_str(); + GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos); + gpr_log(GPR_INFO, "Large unary with compute engine creds done."); +} + +void InteropClient::DoServiceAccountCreds(const grpc::string& username, + const grpc::string& oauth_scope) { + gpr_log(GPR_INFO, + "Sending a large unary rpc with service account credentials ..."); + SimpleRequest request; + SimpleResponse response; + request.set_fill_username(true); + request.set_fill_oauth_scope(true); + PerformLargeUnary(&request, &response); + GPR_ASSERT(!response.username().empty()); + GPR_ASSERT(!response.oauth_scope().empty()); + GPR_ASSERT(username.find(response.username()) != grpc::string::npos); + const char* oauth_scope_str = response.oauth_scope().c_str(); + GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos); + gpr_log(GPR_INFO, "Large unary with service account creds done."); +} + +void InteropClient::DoJwtTokenCreds(const grpc::string& username) { + gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ..."); + SimpleRequest request; + SimpleResponse response; + request.set_fill_username(true); + PerformLargeUnary(&request, &response); + GPR_ASSERT(!response.username().empty()); + GPR_ASSERT(username.find(response.username()) != grpc::string::npos); + gpr_log(GPR_INFO, "Large unary with JWT token creds done."); +} + +void InteropClient::DoLargeUnary() { + gpr_log(GPR_INFO, "Sending a large unary rpc..."); + SimpleRequest request; + SimpleResponse response; + PerformLargeUnary(&request, &response); + gpr_log(GPR_INFO, "Large unary done."); +} + +void InteropClient::DoRequestStreaming() { + gpr_log(GPR_INFO, "Sending request steaming rpc ..."); + std::unique_ptr stub(TestService::NewStub(channel_)); + + ClientContext context; + StreamingInputCallRequest request; + StreamingInputCallResponse response; + + std::unique_ptr> stream( + stub->StreamingInputCall(&context, &response)); + + int aggregated_payload_size = 0; + for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { + Payload* payload = request.mutable_payload(); + payload->set_body(grpc::string(request_stream_sizes[i], '\0')); + GPR_ASSERT(stream->Write(request)); + aggregated_payload_size += request_stream_sizes[i]; + } + stream->WritesDone(); + Status s = stream->Finish(); + + GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size); + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Request streaming done."); +} + +void InteropClient::DoResponseStreaming() { + gpr_log(GPR_INFO, "Receiving response steaming rpc ..."); + std::unique_ptr stub(TestService::NewStub(channel_)); + + ClientContext context; + StreamingOutputCallRequest request; + for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { + ResponseParameters* response_parameter = request.add_response_parameters(); + response_parameter->set_size(response_stream_sizes[i]); + } + StreamingOutputCallResponse response; + std::unique_ptr> stream( + stub->StreamingOutputCall(&context, request)); + + unsigned int i = 0; + while (stream->Read(&response)) { + GPR_ASSERT(response.payload().body() == + grpc::string(response_stream_sizes[i], '\0')); + ++i; + } + GPR_ASSERT(response_stream_sizes.size() == i); + Status s = stream->Finish(); + + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Response streaming done."); +} + +void InteropClient::DoResponseStreamingWithSlowConsumer() { + gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ..."); + std::unique_ptr stub(TestService::NewStub(channel_)); + + ClientContext context; + StreamingOutputCallRequest request; + + for (int i = 0; i < kNumResponseMessages; ++i) { + ResponseParameters* response_parameter = request.add_response_parameters(); + response_parameter->set_size(kResponseMessageSize); + } + StreamingOutputCallResponse response; + std::unique_ptr> stream( + stub->StreamingOutputCall(&context, request)); + + int i = 0; + while (stream->Read(&response)) { + GPR_ASSERT(response.payload().body() == + grpc::string(kResponseMessageSize, '\0')); + gpr_log(GPR_INFO, "received message %d", i); + usleep(kReceiveDelayMilliSeconds * 1000); + ++i; + } + GPR_ASSERT(kNumResponseMessages == i); + Status s = stream->Finish(); + + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Response streaming done."); +} + +void InteropClient::DoHalfDuplex() { + gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ..."); + std::unique_ptr stub(TestService::NewStub(channel_)); + + ClientContext context; + std::unique_ptr> + stream(stub->HalfDuplexCall(&context)); + + StreamingOutputCallRequest request; + ResponseParameters* response_parameter = request.add_response_parameters(); + for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) { + response_parameter->set_size(response_stream_sizes[i]); + GPR_ASSERT(stream->Write(request)); + } + stream->WritesDone(); + + unsigned int i = 0; + StreamingOutputCallResponse response; + while (stream->Read(&response)) { + GPR_ASSERT(response.payload().has_body()); + GPR_ASSERT(response.payload().body() == + grpc::string(response_stream_sizes[i], '\0')); + ++i; + } + GPR_ASSERT(response_stream_sizes.size() == i); + Status s = stream->Finish(); + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Half-duplex streaming rpc done."); +} + +void InteropClient::DoPingPong() { + gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ..."); + std::unique_ptr stub(TestService::NewStub(channel_)); + + ClientContext context; + std::unique_ptr> + stream(stub->FullDuplexCall(&context)); + + StreamingOutputCallRequest request; + request.set_response_type(PayloadType::COMPRESSABLE); + ResponseParameters* response_parameter = request.add_response_parameters(); + Payload* payload = request.mutable_payload(); + StreamingOutputCallResponse response; + for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) { + response_parameter->set_size(response_stream_sizes[i]); + payload->set_body(grpc::string(request_stream_sizes[i], '\0')); + GPR_ASSERT(stream->Write(request)); + GPR_ASSERT(stream->Read(&response)); + GPR_ASSERT(response.payload().has_body()); + GPR_ASSERT(response.payload().body() == + grpc::string(response_stream_sizes[i], '\0')); + } + + stream->WritesDone(); + GPR_ASSERT(!stream->Read(&response)); + Status s = stream->Finish(); + AssertOkOrPrintErrorStatus(s); + gpr_log(GPR_INFO, "Ping pong streaming done."); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h new file mode 100644 index 00000000000..b0ab320f8dc --- /dev/null +++ b/test/cpp/interop/interop_client.h @@ -0,0 +1,79 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H +#define GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H +#include + +#include +#include +#include +#include "test/cpp/interop/messages.grpc.pb.h" + +namespace grpc { +namespace testing { + +class InteropClient { + public: + explicit InteropClient(std::shared_ptr channel); + ~InteropClient() {} + + void Reset(std::shared_ptr channel) { channel_ = channel; } + + void DoEmpty(); + void DoLargeUnary(); + void DoPingPong(); + void DoHalfDuplex(); + void DoRequestStreaming(); + void DoResponseStreaming(); + void DoResponseStreamingWithSlowConsumer(); + // Auth tests. + // username is a string containing the user email + void DoJwtTokenCreds(const grpc::string& username); + void DoComputeEngineCreds(const grpc::string& default_service_account, + const grpc::string& oauth_scope); + // username is a string containing the user email + void DoServiceAccountCreds(const grpc::string& username, + const grpc::string& oauth_scope); + + private: + void PerformLargeUnary(SimpleRequest* request, SimpleResponse* response); + void AssertOkOrPrintErrorStatus(const Status& s); + + std::shared_ptr channel_; +}; + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc index 780a7370acb..d87493b8132 100644 --- a/test/cpp/interop/server.cc +++ b/test/cpp/interop/server.cc @@ -41,7 +41,6 @@ #include #include #include -#include "test/core/end2end/data/ssl_test_data.h" #include #include #include @@ -49,9 +48,10 @@ #include #include #include -#include "test/cpp/interop/test.pb.h" -#include "test/cpp/interop/empty.pb.h" -#include "test/cpp/interop/messages.pb.h" +#include "test/cpp/interop/test.grpc.pb.h" +#include "test/cpp/interop/empty.grpc.pb.h" +#include "test/cpp/interop/messages.grpc.pb.h" +#include "test/cpp/interop/server_helper.h" DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls."); DEFINE_int32(port, 0, "Server port."); @@ -211,15 +211,8 @@ void RunServer() { ServerBuilder builder; builder.RegisterService(&service); - std::shared_ptr creds = grpc::InsecureServerCredentials(); - if (FLAGS_enable_ssl) { - SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, - test_server1_cert}; - SslServerCredentialsOptions ssl_opts; - ssl_opts.pem_root_certs = ""; - ssl_opts.pem_key_cert_pairs.push_back(pkcp); - creds = grpc::SslServerCredentials(ssl_opts); - } + std::shared_ptr creds = + grpc::testing::CreateInteropServerCredentials(); builder.AddListeningPort(server_address.str(), creds); std::unique_ptr server(builder.BuildAndStart()); gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str()); diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc new file mode 100644 index 00000000000..56597c83c4c --- /dev/null +++ b/test/cpp/interop/server_helper.cc @@ -0,0 +1,69 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/interop/server_helper.h" + +#include + +#include +#include "test/core/end2end/data/ssl_test_data.h" +#include +#include + +DECLARE_bool(enable_ssl); + +// In some distros, gflags is in the namespace google, and in some others, +// in gflags. This hack is enabling us to find both. +namespace google {} +namespace gflags {} +using namespace google; +using namespace gflags; + +namespace grpc { +namespace testing { + +std::shared_ptr CreateInteropServerCredentials() { + if (FLAGS_enable_ssl) { + SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, + test_server1_cert}; + SslServerCredentialsOptions ssl_opts; + ssl_opts.pem_root_certs = ""; + ssl_opts.pem_key_cert_pairs.push_back(pkcp); + return SslServerCredentials(ssl_opts); + } else { + return InsecureServerCredentials(); + } +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h new file mode 100644 index 00000000000..f98e67bb673 --- /dev/null +++ b/test/cpp/interop/server_helper.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H +#define GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H + +#include + +#include + +namespace grpc { +namespace testing { + +std::shared_ptr CreateInteropServerCredentials(); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index cae7f44537c..2dc5b3860f3 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -36,7 +36,7 @@ #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/timer.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include #include @@ -104,7 +104,7 @@ class Client { void EndThreads() { threads_.clear(); } - virtual void ThreadFunc(Histogram* histogram, size_t thread_idx) = 0; + virtual bool ThreadFunc(Histogram* histogram, size_t thread_idx) = 0; private: class Thread { @@ -113,20 +113,24 @@ class Client { : done_(false), new_(nullptr), impl_([this, idx, client]() { - for (;;) { - // run the loop body - client->ThreadFunc(&histogram_, idx); - // lock, see if we're done - std::lock_guard g(mu_); - if (done_) {return;} - // check if we're marking, swap out the histogram if so - if (new_) { - new_->Swap(&histogram_); - new_ = nullptr; - cv_.notify_one(); + for (;;) { + // run the loop body + bool thread_still_ok = client->ThreadFunc(&histogram_, idx); + // lock, see if we're done + std::lock_guard g(mu_); + if (!thread_still_ok) { + gpr_log(GPR_ERROR, "Finishing client thread due to RPC error"); + done_ = true; + } + if (done_) {return;} + // check if we're marking, swap out the histogram if so + if (new_) { + new_->Swap(&histogram_); + new_ = nullptr; + cv_.notify_one(); + } } - } - }) {} + }) {} ~Thread() { { diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index 1ed3c7157fc..0a6d9beeca6 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -48,7 +48,7 @@ #include #include #include "test/cpp/util/create_test_channel.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/timer.h" #include "test/cpp/qps/client.h" @@ -137,13 +137,7 @@ class AsyncUnaryClient GRPC_FINAL : public Client { cli_cqs_.emplace_back(new CompletionQueue); } - auto payload_size = config.payload_size(); - auto check_done = [payload_size](grpc::Status s, SimpleResponse* response) { - GPR_ASSERT(s.IsOk() && (response->payload().type() == - grpc::testing::PayloadType::COMPRESSABLE) && - (response->payload().body().length() == - static_cast(payload_size))); - }; + auto check_done = [](grpc::Status s, SimpleResponse* response) {}; int t = 0; for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) { @@ -179,10 +173,14 @@ class AsyncUnaryClient GRPC_FINAL : public Client { } } - void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { void* got_tag; bool ok; - cli_cqs_[thread_idx]->Next(&got_tag, &ok); + switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) { + case CompletionQueue::SHUTDOWN: return false; + case CompletionQueue::TIMEOUT: return true; + case CompletionQueue::GOT_EVENT: break; + } ClientRpcContext* ctx = ClientRpcContext::detag(got_tag); if (ctx->RunNextState(ok, histogram) == false) { @@ -191,6 +189,8 @@ class AsyncUnaryClient GRPC_FINAL : public Client { ctx->StartNewClone(); delete ctx; } + + return true; } std::vector> cli_cqs_; @@ -270,13 +270,7 @@ class AsyncStreamingClient GRPC_FINAL : public Client { cli_cqs_.emplace_back(new CompletionQueue); } - auto payload_size = config.payload_size(); - auto check_done = [payload_size](grpc::Status s, SimpleResponse *response) { - GPR_ASSERT(s.IsOk() && (response->payload().type() == - grpc::testing::PayloadType::COMPRESSABLE) && - (response->payload().body().length() == - static_cast(payload_size))); - }; + auto check_done = [](grpc::Status s, SimpleResponse* response) {}; int t = 0; for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) { @@ -313,10 +307,14 @@ class AsyncStreamingClient GRPC_FINAL : public Client { } } - void ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE { void *got_tag; bool ok; - cli_cqs_[thread_idx]->Next(&got_tag, &ok); + switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) { + case CompletionQueue::SHUTDOWN: return false; + case CompletionQueue::TIMEOUT: return true; + case CompletionQueue::GOT_EVENT: break; + } ClientRpcContext *ctx = ClientRpcContext::detag(got_tag); if (ctx->RunNextState(ok, histogram) == false) { @@ -325,6 +323,8 @@ class AsyncStreamingClient GRPC_FINAL : public Client { ctx->StartNewClone(); delete ctx; } + + return true; } std::vector> cli_cqs_; diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index 77da1725ffa..aea5a0fb27a 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -55,7 +55,7 @@ #include #include "test/cpp/util/create_test_channel.h" #include "test/cpp/qps/client.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/timer.h" @@ -83,13 +83,14 @@ class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient { SynchronousClient(config) {StartThreads(num_threads_);} ~SynchronousUnaryClient() {} - void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); double start = Timer::Now(); grpc::ClientContext context; grpc::Status s = stub->UnaryCall(&context, request_, &responses_[thread_idx]); histogram->Add((Timer::Now() - start) * 1e9); + return s.IsOk(); } }; @@ -111,11 +112,13 @@ class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient { } } - void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { + bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { double start = Timer::Now(); - EXPECT_TRUE(stream_->Write(request_)); - EXPECT_TRUE(stream_->Read(&responses_[thread_idx])); - histogram->Add((Timer::Now() - start) * 1e9); + if (stream_->Write(request_) && stream_->Read(&responses_[thread_idx])) { + histogram->Add((Timer::Now() - start) * 1e9); + return true; + } + return false; } private: grpc::ClientContext context_; diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 64a53496aed..f44883783dd 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -74,7 +74,9 @@ static vector get_hosts(const string& name) { ScenarioResult RunScenario(const ClientConfig& initial_client_config, size_t num_clients, const ServerConfig& server_config, - size_t num_servers) { + size_t num_servers, + int warmup_seconds, + int benchmark_seconds) { // ClientContext allocator (all are destroyed at scope exit) list contexts; auto alloc_context = [&contexts]() { @@ -146,7 +148,7 @@ ScenarioResult RunScenario(const ClientConfig& initial_client_config, // Let everything warmup gpr_log(GPR_INFO, "Warming up"); gpr_timespec start = gpr_now(); - gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(5))); + gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(warmup_seconds))); // Start a run gpr_log(GPR_INFO, "Starting"); @@ -171,7 +173,7 @@ ScenarioResult RunScenario(const ClientConfig& initial_client_config, // Wait some time gpr_log(GPR_INFO, "Running"); - gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(15))); + gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(benchmark_seconds))); // Finish a run ScenarioResult result; diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h index d87e80dc552..b3a8bf8cc4a 100644 --- a/test/cpp/qps/driver.h +++ b/test/cpp/qps/driver.h @@ -35,7 +35,7 @@ #define TEST_QPS_DRIVER_H #include "test/cpp/qps/histogram.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" namespace grpc { namespace testing { @@ -54,7 +54,10 @@ struct ScenarioResult { ScenarioResult RunScenario(const grpc::testing::ClientConfig& client_config, size_t num_clients, const grpc::testing::ServerConfig& server_config, - size_t num_servers); + size_t num_servers, + int warmup_seconds, + int benchmark_seconds); + } // namespace testing } // namespace grpc diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h index 7ba00e94c39..0547b7283a7 100644 --- a/test/cpp/qps/histogram.h +++ b/test/cpp/qps/histogram.h @@ -35,7 +35,7 @@ #define TEST_QPS_HISTOGRAM_H #include -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" namespace grpc { namespace testing { @@ -50,10 +50,10 @@ class Histogram { void Merge(Histogram* h) { gpr_histogram_merge(impl_, h->impl_); } void Add(double value) { gpr_histogram_add(impl_, value); } - double Percentile(double pctile) { + double Percentile(double pctile) const { return gpr_histogram_percentile(impl_, pctile); } - double Count() { return gpr_histogram_count(impl_); } + double Count() const { return gpr_histogram_count(impl_); } void Swap(Histogram* other) { std::swap(impl_, other->impl_); } void FillProto(HistogramData* p) { size_t n; diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc index f7aa8e2aba6..220f826118f 100644 --- a/test/cpp/qps/qps_driver.cc +++ b/test/cpp/qps/qps_driver.cc @@ -35,11 +35,14 @@ #include #include "test/cpp/qps/driver.h" -#include "test/cpp/qps/stats.h" +#include "test/cpp/qps/report.h" DEFINE_int32(num_clients, 1, "Number of client binaries"); DEFINE_int32(num_servers, 1, "Number of server binaries"); +DEFINE_int32(warmup_seconds, 5, "Warmup time (in seconds)"); +DEFINE_int32(benchmark_seconds, 30, "Benchmark time (in seconds)"); + // Common config DEFINE_bool(enable_ssl, false, "Use SSL"); DEFINE_string(rpc_type, "UNARY", "Type of RPC: UNARY or STREAMING"); @@ -62,7 +65,6 @@ using grpc::testing::ClientType; using grpc::testing::ServerType; using grpc::testing::RpcType; using grpc::testing::ResourceUsage; -using grpc::testing::sum; // In some distros, gflags is in the namespace google, and in some others, // in gflags. This hack is enabling us to find both. @@ -98,40 +100,13 @@ int main(int argc, char** argv) { server_config.set_threads(FLAGS_server_threads); server_config.set_enable_ssl(FLAGS_enable_ssl); - auto result = RunScenario(client_config, FLAGS_num_clients, server_config, - FLAGS_num_servers); - - gpr_log(GPR_INFO, "QPS: %.1f", - result.latencies.Count() / - average(result.client_resources, - [](ResourceUsage u) { return u.wall_time; })); - - gpr_log(GPR_INFO, "Latencies (50/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f us", - result.latencies.Percentile(50) / 1000, - result.latencies.Percentile(95) / 1000, - result.latencies.Percentile(99) / 1000, - result.latencies.Percentile(99.9) / 1000); - - gpr_log(GPR_INFO, "Server system time: %.2f%%", - 100.0 * sum(result.server_resources, - [](ResourceUsage u) { return u.system_time; }) / - sum(result.server_resources, - [](ResourceUsage u) { return u.wall_time; })); - gpr_log(GPR_INFO, "Server user time: %.2f%%", - 100.0 * sum(result.server_resources, - [](ResourceUsage u) { return u.user_time; }) / - sum(result.server_resources, - [](ResourceUsage u) { return u.wall_time; })); - gpr_log(GPR_INFO, "Client system time: %.2f%%", - 100.0 * sum(result.client_resources, - [](ResourceUsage u) { return u.system_time; }) / - sum(result.client_resources, - [](ResourceUsage u) { return u.wall_time; })); - gpr_log(GPR_INFO, "Client user time: %.2f%%", - 100.0 * sum(result.client_resources, - [](ResourceUsage u) { return u.user_time; }) / - sum(result.client_resources, - [](ResourceUsage u) { return u.wall_time; })); + auto result = RunScenario(client_config, FLAGS_num_clients, + server_config, FLAGS_num_servers, + FLAGS_warmup_seconds, FLAGS_benchmark_seconds); + + ReportQPSPerCore(result, server_config); + ReportLatency(result); + ReportTimes(result); grpc_shutdown(); return 0; diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc new file mode 100644 index 00000000000..29d88da344a --- /dev/null +++ b/test/cpp/qps/report.cc @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/qps/report.h" + +#include +#include "test/cpp/qps/stats.h" + +namespace grpc { +namespace testing { + +// QPS: XXX +void ReportQPS(const ScenarioResult& result) { + gpr_log(GPR_INFO, "QPS: %.1f", + result.latencies.Count() / + average(result.client_resources, + [](ResourceUsage u) { return u.wall_time; })); +} + +// QPS: XXX (YYY/server core) +void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& server_config) { + auto qps = + result.latencies.Count() / + average(result.client_resources, + [](ResourceUsage u) { return u.wall_time; }); + + gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps, qps/server_config.threads()); +} + +// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us +void ReportLatency(const ScenarioResult& result) { + gpr_log(GPR_INFO, "Latencies (50/90/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f/%.1f us", + result.latencies.Percentile(50) / 1000, + result.latencies.Percentile(90) / 1000, + result.latencies.Percentile(95) / 1000, + result.latencies.Percentile(99) / 1000, + result.latencies.Percentile(99.9) / 1000); +} + +void ReportTimes(const ScenarioResult& result) { + gpr_log(GPR_INFO, "Server system time: %.2f%%", + 100.0 * sum(result.server_resources, + [](ResourceUsage u) { return u.system_time; }) / + sum(result.server_resources, + [](ResourceUsage u) { return u.wall_time; })); + gpr_log(GPR_INFO, "Server user time: %.2f%%", + 100.0 * sum(result.server_resources, + [](ResourceUsage u) { return u.user_time; }) / + sum(result.server_resources, + [](ResourceUsage u) { return u.wall_time; })); + gpr_log(GPR_INFO, "Client system time: %.2f%%", + 100.0 * sum(result.client_resources, + [](ResourceUsage u) { return u.system_time; }) / + sum(result.client_resources, + [](ResourceUsage u) { return u.wall_time; })); + gpr_log(GPR_INFO, "Client user time: %.2f%%", + 100.0 * sum(result.client_resources, + [](ResourceUsage u) { return u.user_time; }) / + sum(result.client_resources, + [](ResourceUsage u) { return u.wall_time; })); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h new file mode 100644 index 00000000000..343e426ca4a --- /dev/null +++ b/test/cpp/qps/report.h @@ -0,0 +1,57 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TEST_QPS_REPORT_H +#define TEST_QPS_REPORT_H + +#include "test/cpp/qps/driver.h" + +namespace grpc { +namespace testing { + +// QPS: XXX +void ReportQPS(const ScenarioResult& result); +// QPS: XXX (YYY/server core) +void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& config); +// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us +void ReportLatency(const ScenarioResult& result); +// Server system time: XX% +// Server user time: XX% +// Client system time: XX% +// Client user time: XX% +void ReportTimes(const ScenarioResult& result); + +} // namespace testing +} // namespace grpc + +#endif diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h index ef71cb94d00..68e01154101 100644 --- a/test/cpp/qps/server.h +++ b/test/cpp/qps/server.h @@ -35,7 +35,7 @@ #define TEST_QPS_SERVER_H #include "test/cpp/qps/timer.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" namespace grpc { namespace testing { diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 65c170af811..b19c443c823 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -52,7 +52,7 @@ #include #include #include "src/cpp/server/thread_pool.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/server.h" #include @@ -97,15 +97,15 @@ class AsyncQpsServerTest : public Server { bool ok; void* got_tag; while (srv_cq_.Next(&got_tag, &ok)) { - ServerRpcContext* ctx = detag(got_tag); - // The tag is a pointer to an RPC context to invoke - if (ctx->RunNextState(ok) == false) { - // this RPC context is done, so refresh it + ServerRpcContext* ctx = detag(got_tag); + // The tag is a pointer to an RPC context to invoke + if (ctx->RunNextState(ok) == false) { + // this RPC context is done, so refresh it std::lock_guard g(shutdown_mutex_); if (!shutdown_) { ctx->Reset(); } - } + } } return; })); @@ -175,8 +175,9 @@ class AsyncQpsServerTest : public Server { private: bool finisher(bool) { return false; } bool invoker(bool ok) { - if (!ok) - return false; + if (!ok) { + return false; + } ResponseType response; @@ -230,8 +231,9 @@ class AsyncQpsServerTest : public Server { private: bool request_done(bool ok) { - if (!ok) - return false; + if (!ok) { + return false; + } stream_.Read(&req_, AsyncQpsServerTest::tag(this)); next_state_ = &ServerRpcContextStreamingImpl::read_done; return true; diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index 99644299010..2770233a7c0 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -47,7 +47,7 @@ #include #include #include "src/cpp/server/thread_pool.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/server.h" #include "test/cpp/qps/timer.h" diff --git a/test/cpp/qps/smoke_test.cc b/test/cpp/qps/smoke_test.cc new file mode 100644 index 00000000000..c9d321f133c --- /dev/null +++ b/test/cpp/qps/smoke_test.cc @@ -0,0 +1,149 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "test/cpp/qps/driver.h" +#include "test/cpp/qps/report.h" + +namespace grpc { +namespace testing { + +static const int WARMUP = 5; +static const int BENCHMARK = 10; + +static void RunSynchronousUnaryPingPong() { + gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(SYNCHRONOUS_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_payload_size(1); + client_config.set_rpc_type(UNARY); + + ServerConfig server_config; + server_config.set_server_type(SYNCHRONOUS_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(1); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPS(result); + ReportLatency(result); +} + +static void RunSynchronousStreamingPingPong() { + gpr_log(GPR_INFO, "Running Synchronous Streaming Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(SYNCHRONOUS_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_payload_size(1); + client_config.set_rpc_type(STREAMING); + + ServerConfig server_config; + server_config.set_server_type(SYNCHRONOUS_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(1); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPS(result); + ReportLatency(result); +} + +static void RunAsyncUnaryPingPong() { + gpr_log(GPR_INFO, "Running Async Unary Ping Pong"); + + ClientConfig client_config; + client_config.set_client_type(ASYNC_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1); + client_config.set_client_channels(1); + client_config.set_payload_size(1); + client_config.set_async_client_threads(1); + client_config.set_rpc_type(UNARY); + + ServerConfig server_config; + server_config.set_server_type(ASYNC_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(1); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPS(result); + ReportLatency(result); +} + +static void RunQPS() { + gpr_log(GPR_INFO, "Running QPS test"); + + ClientConfig client_config; + client_config.set_client_type(ASYNC_CLIENT); + client_config.set_enable_ssl(false); + client_config.set_outstanding_rpcs_per_channel(1000); + client_config.set_client_channels(8); + client_config.set_payload_size(1); + client_config.set_async_client_threads(8); + client_config.set_rpc_type(UNARY); + + ServerConfig server_config; + server_config.set_server_type(ASYNC_SERVER); + server_config.set_enable_ssl(false); + server_config.set_threads(4); + + auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK); + + ReportQPSPerCore(result, server_config); + ReportLatency(result); +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc_init(); + + using namespace grpc::testing; + RunSynchronousStreamingPingPong(); + RunSynchronousUnaryPingPong(); + RunAsyncUnaryPingPong(); + RunQPS(); + + grpc_shutdown(); + return 0; +} diff --git a/test/cpp/qps/smoke_test.sh b/test/cpp/qps/smoke_test.sh new file mode 100755 index 00000000000..ba7f0a4f27d --- /dev/null +++ b/test/cpp/qps/smoke_test.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# performs a single qps run with one client and one server + +set -ex + +cd $(dirname $0)/../../.. + +killall qps_worker || true + +config=opt + +NUMCPUS=`python2.7 -c 'import multiprocessing; print multiprocessing.cpu_count()'` + +make CONFIG=$config qps_worker qps_smoke_test -j$NUMCPUS + +bins/$config/qps_worker -driver_port 10000 -server_port 10001 & +PID1=$! +bins/$config/qps_worker -driver_port 10010 -server_port 10011 & +PID2=$! + +export QPS_WORKERS="localhost:10000,localhost:10010" + +bins/$config/qps_smoke_test $* + +kill -2 $PID1 $PID2 +wait + diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc index b6830cc0557..101eb9f9694 100644 --- a/test/cpp/qps/worker.cc +++ b/test/cpp/qps/worker.cc @@ -55,7 +55,7 @@ #include #include "test/core/util/grpc_profiler.h" #include "test/cpp/util/create_test_channel.h" -#include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/qpstest.grpc.pb.h" #include "test/cpp/qps/client.h" #include "test/cpp/qps/server.h" diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 91fc40c31f0..32ef392cc4c 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -33,7 +33,7 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/cli_call.h" -#include "test/cpp/util/echo.pb.h" +#include "test/cpp/util/echo.grpc.pb.h" #include "src/cpp/server/thread_pool.h" #include #include diff --git a/third_party/openssl b/third_party/openssl index 3df69d3aefd..4ac03295828 160000 --- a/third_party/openssl +++ b/third_party/openssl @@ -1 +1 @@ -Subproject commit 3df69d3aefde7671053d4e3c242b228e5d79c83f +Subproject commit 4ac0329582829f5378d8078c8d314ad37db87736 diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh index 7a12440db2c..45f08df38fe 100755 --- a/tools/buildgen/generate_projects.sh +++ b/tools/buildgen/generate_projects.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # Copyright 2015, Google Inc. # All rights reserved. # @@ -31,7 +31,7 @@ set -e -if [ "x$TEST" == "x" ] ; then +if [ "x$TEST" = "x" ] ; then TEST=false fi @@ -61,12 +61,12 @@ for dir in . ; do out=${out%.*} # strip template extension json_files="build.json $end2end_test_build" data=`for i in $json_files; do echo -n "-d $i "; done` - if [ $TEST == true ] ; then + if [ "x$TEST" = "xtrue" ] ; then actual_out=$out out=`mktemp /tmp/gentXXXXXX` fi $mako_renderer $plugins $data -o $out $file - if [ $TEST == true ] ; then + if [ "x$TEST" = "xtrue" ] ; then diff -q $out $actual_out rm $out fi diff --git a/tools/distpackages/build_deb_packages.sh b/tools/distpackages/build_deb_packages.sh index 7dff8e37437..0beb41ed0a5 100755 --- a/tools/distpackages/build_deb_packages.sh +++ b/tools/distpackages/build_deb_packages.sh @@ -30,9 +30,13 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Where to put resulting .deb packages. +set -x deb_dest="/tmp/deb_out" mkdir -p $deb_dest +# Where the grpc disto is +grpc_root="/var/local/git/grpc" + # Update version from default values if the file /version.txt exists # # - when present, /version.txt will added by the docker build. @@ -41,7 +45,13 @@ if [ -f /version.txt ]; then pkg_version=$(cat /version.txt) fi version="${pkg_version}.0" -echo "Target release => $pkg_version" +release_tag="release-${pkg_version//./_}" +echo "Target release => $pkg_version, will checkout tag $release_tag" + +# Switch grpc_root to the release tag +pushd $grpc_root +git checkout $release_tag || { echo "bad release tag ${release_tag}"; exit 1; } +popd if [ -f /.dockerinit ]; then # We're in Docker where uname -p returns "unknown". @@ -71,7 +81,9 @@ do if [ $pkg_name == "libgrpc" ] then # Copy shared libraries - (cd ../..; make install-shared_c prefix=$tmp_dir/$pkg_name/usr/lib) + pushd $grpc_root + make install-shared_c prefix=$tmp_dir/$pkg_name/usr/lib + popd mv $tmp_dir/$pkg_name/usr/lib/lib $arch_lib_dir # non-dev package should contain so.0 symlinks @@ -84,7 +96,10 @@ do if [ $pkg_name == "libgrpc-dev" ] then # Copy headers and static libraries - (cd ../..; make install-headers_c install-static_c prefix=$tmp_dir/$pkg_name/usr/lib) + pushd $grpc_root + make install-headers_c install-static_c prefix=$tmp_dir/$pkg_name/usr/lib + popd + mv $tmp_dir/$pkg_name/usr/lib/include $tmp_dir/$pkg_name/usr/include mv $tmp_dir/$pkg_name/usr/lib/lib $arch_lib_dir diff --git a/tools/distpackages/templates/libgrpc/DEBIAN/control b/tools/distpackages/templates/libgrpc/DEBIAN/control index 417a8258274..5854b1f4a19 100644 --- a/tools/distpackages/templates/libgrpc/DEBIAN/control +++ b/tools/distpackages/templates/libgrpc/DEBIAN/control @@ -2,7 +2,8 @@ Package: libgrpc Version: 0.5.0 Architecture: amd64 Maintainer: Jan Tattermusch -Depends: libc6 +Depends: libc6, openssl (1.0.2-1) +Build-Depends-Indep: openssl (1.0.2-1) Section: libs Priority: optional Homepage: https://github.com/grpc/grpc diff --git a/tools/distrib/python/submit.py b/tools/distrib/python/submit.py new file mode 100755 index 00000000000..79ebb93e573 --- /dev/null +++ b/tools/distrib/python/submit.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +import argparse +import os +import shutil +import subprocess + +parser = argparse.ArgumentParser( + description='Submit the package to a PyPI repository.') +parser.add_argument( + '--repository', '-r', metavar='r', type=str, default='pypi', + help='The repository to push the package to. ' + 'Ensure the value appears in your .pypirc file. ' + 'Defaults to "pypi".' +) +parser.add_argument( + '--identity', '-i', metavar='i', type=str, + help='GPG identity to sign the files with.' +) +parser.add_argument( + '--username', '-u', metavar='u', type=str, + help='Username to authenticate with the repository. Not needed if you have ' + 'configured your .pypirc to include your username.' +) +parser.add_argument( + '--password', '-p', metavar='p', type=str, + help='Password to authenticate with the repository. Not needed if you have ' + 'configured your .pypirc to include your password.' +) +args = parser.parse_args() + +# Move to the root directory of Python GRPC. +pkgdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), + '../../../src/python/src') +# Remove previous distributions; they somehow confuse twine. +try: + shutil.rmtree(os.path.join(pkgdir, 'dist/')) +except: + pass + +# Make the push. +cmd = ['python', 'setup.py', 'sdist'] +subprocess.call(cmd, cwd=pkgdir) + +cmd = ['twine', 'upload', '-r', args.repository] +if args.identity is not None: + cmd.extend(['-i', args.identity]) +if args.username is not None: + cmd.extend(['-u', args.username]) +if args.password is not None: + cmd.extend(['-p', args.password]) +cmd.append('dist/*') + +subprocess.call(cmd, cwd=pkgdir) diff --git a/tools/dockerfile/grpc_build_deb/Dockerfile b/tools/dockerfile/grpc_build_deb/Dockerfile index 24ffc7379cf..7f025b67125 100644 --- a/tools/dockerfile/grpc_build_deb/Dockerfile +++ b/tools/dockerfile/grpc_build_deb/Dockerfile @@ -30,8 +30,17 @@ # Dockerfile to build Debian packages for gRPC C core. FROM grpc/base +# Add the file containing the gRPC version +ADD version.txt version.txt + +# Add the update-to-date distpackages folder +ADD distpackages distpackages + # Install dependencies -RUN apt-get update && apt-get install -y lintian +RUN echo 'deb http://http.debian.net/debian experimental main contrib non-free' >> /etc/apt/sources.list +RUN apt-get update \ + && apt-get -t experimental install -y openssl=1.0.2-1 \ + && apt-get install -y lintian # Get the source from GitHub RUN git clone https://github.com/grpc/grpc.git /var/local/git/grpc @@ -39,4 +48,4 @@ RUN cd /var/local/git/grpc && \ git pull --recurse-submodules && \ git submodule update --init --recursive -RUN /bin/bash -l -c 'cd /var/local/git/grpc/tools/distpackages && ./build_deb_packages.sh' +RUN /bin/bash -l -c 'cd /distpackages && ./build_deb_packages.sh' diff --git a/tools/dockerfile/grpc_build_deb/version.txt b/tools/dockerfile/grpc_build_deb/version.txt new file mode 100644 index 00000000000..a918a2aa18d --- /dev/null +++ b/tools/dockerfile/grpc_build_deb/version.txt @@ -0,0 +1 @@ +0.6.0 diff --git a/tools/dockerfile/grpc_dist_proto/version.txt b/tools/dockerfile/grpc_dist_proto/version.txt index 8f0916f768f..a918a2aa18d 100644 --- a/tools/dockerfile/grpc_dist_proto/version.txt +++ b/tools/dockerfile/grpc_dist_proto/version.txt @@ -1 +1 @@ -0.5.0 +0.6.0 diff --git a/tools/dockerfile/grpc_python/Dockerfile b/tools/dockerfile/grpc_python/Dockerfile index 62ef785a318..aa29685beee 100644 --- a/tools/dockerfile/grpc_python/Dockerfile +++ b/tools/dockerfile/grpc_python/Dockerfile @@ -66,5 +66,8 @@ RUN cd /var/local/git/grpc \ # Add a cacerts directory containing the Google root pem file, allowing the interop client to access the production test instance ADD cacerts cacerts +# Add a service_account directory containing the auth creds file +ADD service_account service_account + # Specify the default command such that the interop server runs on its known testing port CMD ["/bin/bash", "-l", "-c", "python2.7 -m interop.server --use_tls --port 8050"] diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index 497112ce399..c68903b8164 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -673,7 +673,7 @@ _grpc_build_proto_bins_args() { } # grpc_build_proto_bins -# +# # - rebuilds the dist_proto docker image # * doing this builds the protoc and the ruby, python and cpp bins statically # @@ -693,11 +693,11 @@ grpc_build_proto_bins() { gce_has_instance $grpc_project $host || return 1; local project_opt="--project $grpc_project" local zone_opt="--zone $grpc_zone" - + # rebuild the dist_proto image local label='dist_proto' grpc_update_image -- -h $host $label || return 1 - + # run a command to copy the generated archive to the docker host local docker_prefix='sudo docker run -v /tmp:/tmp/proto_bins_out' local tar_name='proto-bins*.tar.gz' @@ -715,6 +715,63 @@ grpc_build_proto_bins() { gcloud compute copy-files $rmt_tar $local_copy $project_opt $zone_opt || return 1 } +_grpc_build_debs_args() { + [[ -n $1 ]] && { # host + host=$1 + shift + } || { + host='grpc-docker-builder' + } +} + +# grpc_build_debs +# +# - rebuilds the build_debs +# * doing this builds a deb package for release debs +# +# - runs a docker command that copies the debs from the docker instance to its +# host +# - copies the debs from the host to the local machine +grpc_build_debs() { + _grpc_ensure_gcloud_ssh || return 1; + + # declare vars local so that they don't pollute the shell environment + # where this func is used. + local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone + # set by _grpc_build_debs_args + local host + + # set the project zone and check that all necessary args are provided + _grpc_set_project_and_zone -f _grpc_build_debs_args "$@" || return 1 + gce_has_instance $grpc_project $host || return 1; + local project_opt="--project $grpc_project" + local zone_opt="--zone $grpc_zone" + + # Update the remote distpackages_dir + local src_dist_dir='tools/distpackages' + local rmt_dist_dir="$host:~" + gcloud compute copy-files $src_dist_dir $rmt_dist_dir $project_opt $zone_opt || return 1 + + # rebuild the build_deb image + local label='build_deb' + grpc_update_image -- -h $host $label || return 1 + + # run a command to copy the debs from the docker instance to the host. + local docker_prefix='sudo docker run -v /tmp:/tmp/host_deb_out' + local cp_cmd="/bin/bash -c 'cp -v /tmp/deb_out/*.deb /tmp/host_deb_out'" + local cmd="$docker_prefix grpc/$label $cp_cmd" + local ssh_cmd="bash -l -c \"$cmd\"" + echo "will run:" + echo " $ssh_cmd" + echo "on $host" + gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" || return 1 + + # copy the debs from host machine to the local one. + local rmt_debs="$host:/tmp/*.deb" + local local_copy="$(pwd)" + gcloud compute copy-files $rmt_debs $local_copy $project_opt $zone_opt || return 1 +} + _grpc_launch_servers_args() { [[ -n $1 ]] && { # host host=$1 @@ -984,6 +1041,35 @@ grpc_interop_gen_python_cmd() { echo $the_cmd } +# constructs the full dockerized python service_account auth interop test cmd. +# +# call-seq: +# flags= .... # generic flags to include the command +# cmd=$($grpc_gen_test_cmd $flags) +grpc_cloud_prod_auth_service_account_creds_gen_python_cmd() { + local cmd_prefix="sudo docker run grpc/python bin/bash -l -c"; + local gfe_flags=$(_grpc_prod_gfe_flags) + local added_gfe_flags=$(_grpc_default_creds_test_flags) + local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" + env_prefix+=" GOOGLE_APPLICATION_CREDENTIALS=/service_account/stubbyCloudTestingTest-7dd63462c60c.json" + local the_cmd="$cmd_prefix '$env_prefix python -B -m interop.client --use_tls $gfe_flags $added_gfe_flags $@'" + echo $the_cmd +} + +# constructs the full dockerized python gce auth interop test cmd. +# +# call-seq: +# flags= .... # generic flags to include the command +# cmd=$($grpc_gen_test_cmd $flags) +grpc_cloud_prod_auth_compute_engine_creds_gen_python_cmd() { + local cmd_prefix="sudo docker run grpc/python bin/bash -l -c"; + local gfe_flags=$(_grpc_prod_gfe_flags) + local added_gfe_flags=$(_grpc_gce_test_flags) + local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" + local the_cmd="$cmd_prefix '$env_prefix python -B -m interop.client --use_tls $gfe_flags $added_gfe_flags $@'" + echo $the_cmd +} + # constructs the full dockerized java interop test cmd. # # call-seq: @@ -1310,5 +1396,3 @@ _grpc_default_creds_test_flags() { _grpc_gce_test_flags() { echo " --default_service_account=155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel@developer.gserviceaccount.com --oauth_scope=https://www.googleapis.com/auth/xapi.zoo" } - -# TODO(grpc-team): add grpc_interop_gen_xxx_cmd for python diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh index 7f0b5bab1a9..1c6122e9ae1 100755 --- a/tools/gce_setup/interop_test_runner.sh +++ b/tools/gce_setup/interop_test_runner.sh @@ -36,7 +36,7 @@ echo $result_file_name main() { source grpc_docker.sh test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response) - clients=(cxx java go ruby node python csharp_mono) + clients=(cxx java go ruby node python csharp_mono php) servers=(cxx java go ruby node python csharp_mono) for test_case in "${test_cases[@]}" do diff --git a/tools/gce_setup/shared_startup_funcs.sh b/tools/gce_setup/shared_startup_funcs.sh index e6eecc56db6..c4a076757aa 100755 --- a/tools/gce_setup/shared_startup_funcs.sh +++ b/tools/gce_setup/shared_startup_funcs.sh @@ -434,6 +434,12 @@ grpc_dockerfile_install() { grpc_docker_sync_service_account $dockerfile_dir/service_account || return 1; } + # For deb builds, copy the distpackages folder into the docker directory so + # that it can be installed using ADD distpackages distpackages. + [[ $image_label == "grpc/build_deb" ]] && { + cp -vR ~/distpackages $dockerfile_dir + } + # TODO(temiola): maybe make cache/no-cache a func option? sudo docker build $cache_opt -t $image_label $dockerfile_dir || { echo "$FUNCNAME:: build of $image_label <- $dockerfile_dir" diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index b2e93626893..c279c3ecce4 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.7 +#!/usr/bin/env python # Copyright 2015, Google Inc. # All rights reserved. # diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 3e304ee88a6..520405b96af 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -315,15 +315,6 @@ "posix" ] }, - { - "flaky": false, - "language": "c", - "name": "gpr_useful_test", - "platforms": [ - "windows", - "posix" - ] - }, { "flaky": false, "language": "c", diff --git a/vsprojects/vs2010/Grpc.mak b/vsprojects/vs2010/Grpc.mak index 203c7872878..727aa377816 100644 --- a/vsprojects/vs2010/Grpc.mak +++ b/vsprojects/vs2010/Grpc.mak @@ -53,13 +53,13 @@ grpc_test_util: $(OUT_DIR): mkdir $(OUT_DIR) -buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_useful_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe +buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_tls_test.exe gpr_useful_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe echo All tests built. -test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test transport_security_test +test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_tls_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test transport_security_test echo All tests ran. -test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test +test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_tls_test gpr_useful_test echo All tests ran. alarm_heap_test.exe: grpc_test_util @@ -398,6 +398,14 @@ gpr_time_test: gpr_time_test.exe echo Running gpr_time_test $(OUT_DIR)\gpr_time_test.exe +gpr_tls_test.exe: grpc_test_util + echo Building gpr_tls_test + $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\tls_test.c + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_tls_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tls_test.obj +gpr_tls_test: gpr_tls_test.exe + echo Running gpr_tls_test + $(OUT_DIR)\gpr_tls_test.exe + gpr_useful_test.exe: grpc_test_util echo Building gpr_useful_test $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\useful_test.c diff --git a/vsprojects/vs2010/global.props b/vsprojects/vs2010/global.props index e9b9d6cb851..ae44e18d4ea 100644 --- a/vsprojects/vs2010/global.props +++ b/vsprojects/vs2010/global.props @@ -6,7 +6,7 @@ $(SolutionDir)\..\..;$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\third_party\zlib;$(SolutionDir)\..\third_party;$(SolutionDir)\..\..\third_party\openssl\inc32;$(SolutionDir)\..\..\third_party\protobuf\src - GRPC_OLD_CXX;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) EnableAllWarnings diff --git a/vsprojects/vs2010/gpr.vcxproj b/vsprojects/vs2010/gpr.vcxproj index f50f87134c4..62ab6f3bd09 100644 --- a/vsprojects/vs2010/gpr.vcxproj +++ b/vsprojects/vs2010/gpr.vcxproj @@ -97,6 +97,10 @@ + + + + @@ -166,6 +170,8 @@ + + diff --git a/vsprojects/vs2010/gpr.vcxproj.filters b/vsprojects/vs2010/gpr.vcxproj.filters index dffaf1e62df..13fdb3fef84 100644 --- a/vsprojects/vs2010/gpr.vcxproj.filters +++ b/vsprojects/vs2010/gpr.vcxproj.filters @@ -88,6 +88,9 @@ src\core\support + + src\core\support + src\core\support @@ -168,6 +171,18 @@ include\grpc\support + + include\grpc\support + + + include\grpc\support + + + include\grpc\support + + + include\grpc\support + include\grpc\support diff --git a/vsprojects/vs2010/grpc++.vcxproj b/vsprojects/vs2010/grpc++.vcxproj index 0ee433163c8..003355eabf8 100644 --- a/vsprojects/vs2010/grpc++.vcxproj +++ b/vsprojects/vs2010/grpc++.vcxproj @@ -93,6 +93,12 @@ + + + + + + @@ -104,6 +110,8 @@ + + diff --git a/vsprojects/vs2010/grpc++.vcxproj.filters b/vsprojects/vs2010/grpc++.vcxproj.filters index ed93daee044..6466a0fa26e 100644 --- a/vsprojects/vs2010/grpc++.vcxproj.filters +++ b/vsprojects/vs2010/grpc++.vcxproj.filters @@ -132,6 +132,24 @@ include\grpc++\impl + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + include\grpc++ @@ -161,6 +179,12 @@ + + src\cpp\client + + + src\cpp\server + src\cpp\client diff --git a/vsprojects/vs2013/Grpc.mak b/vsprojects/vs2013/Grpc.mak index f211d3f6c0e..69e09b3bcdb 100644 --- a/vsprojects/vs2013/Grpc.mak +++ b/vsprojects/vs2013/Grpc.mak @@ -53,13 +53,6 @@ grpc_test_util: $(OUT_DIR): mkdir $(OUT_DIR) -buildtests: buildtests_c buildtests_cxx - -buildtests_c: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stub_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe echo_client.exe echo_server.exe echo_test.exe fd_posix_test.exe fling_client.exe fling_server.exe fling_stream_test.exe fling_test.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_useful_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe - echo All tests built. - -buildtests_cxx: - echo All tests built. alarm_heap_test.exe: grpc_test_util $(OUT_DIR) echo Building alarm_heap_test @@ -389,7 +382,19 @@ gpr_time_test: gpr_time_test.exe echo Running gpr_time_test $(OUT_DIR)\gpr_time_test.exe +<<<<<<< HEAD gpr_useful_test.exe: grpc_test_util $(OUT_DIR) +======= +gpr_tls_test.exe: grpc_test_util + echo Building gpr_tls_test + $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\tls_test.c + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_tls_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tls_test.obj +gpr_tls_test: gpr_tls_test.exe + echo Running gpr_tls_test + $(OUT_DIR)\gpr_tls_test.exe + +gpr_useful_test.exe: grpc_test_util +>>>>>>> fba547644c7e55ae222cb130cb289e19db43b449 echo Building gpr_useful_test $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\useful_test.c $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_useful_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\useful_test.obj diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj index 4b44cc645fd..1876c0ff0a5 100644 --- a/vsprojects/vs2013/gpr.vcxproj +++ b/vsprojects/vs2013/gpr.vcxproj @@ -99,6 +99,10 @@ + + + + @@ -168,6 +172,8 @@ + + diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters index dffaf1e62df..13fdb3fef84 100644 --- a/vsprojects/vs2013/gpr.vcxproj.filters +++ b/vsprojects/vs2013/gpr.vcxproj.filters @@ -88,6 +88,9 @@ src\core\support + + src\core\support + src\core\support @@ -168,6 +171,18 @@ include\grpc\support + + include\grpc\support + + + include\grpc\support + + + include\grpc\support + + + include\grpc\support + include\grpc\support diff --git a/vsprojects/vs2013/grpc++.vcxproj b/vsprojects/vs2013/grpc++.vcxproj index d545a949cb3..dff588166b1 100644 --- a/vsprojects/vs2013/grpc++.vcxproj +++ b/vsprojects/vs2013/grpc++.vcxproj @@ -95,6 +95,12 @@ + + + + + + @@ -106,6 +112,8 @@ + + diff --git a/vsprojects/vs2013/grpc++.vcxproj.filters b/vsprojects/vs2013/grpc++.vcxproj.filters index ed93daee044..6466a0fa26e 100644 --- a/vsprojects/vs2013/grpc++.vcxproj.filters +++ b/vsprojects/vs2013/grpc++.vcxproj.filters @@ -132,6 +132,24 @@ include\grpc++\impl + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + + + include\grpc++\impl + include\grpc++ @@ -161,6 +179,12 @@ + + src\cpp\client + + + src\cpp\server + src\cpp\client