diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 41f81be1db6..e69dc0bd3ba 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Report a bug about: Create a report to help us improve labels: kind/bug, priority/P2 -assignees: markdroth +assignees: nicolasnoble --- diff --git a/.github/ISSUE_TEMPLATE/cleanup_request.md b/.github/ISSUE_TEMPLATE/cleanup_request.md index 7da478019fc..c9a6d3f911d 100644 --- a/.github/ISSUE_TEMPLATE/cleanup_request.md +++ b/.github/ISSUE_TEMPLATE/cleanup_request.md @@ -2,7 +2,7 @@ name: Request a cleanup about: Suggest a cleanup in our repository labels: kind/internal cleanup, priority/P2 -assignees: markdroth +assignees: nicolasnoble --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 00599d145d8..e3137998ae0 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Request a feature about: Suggest an idea for this project labels: kind/enhancement, priority/P2 -assignees: markdroth +assignees: nicolasnoble --- diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 5dc067381f9..cfde18bec27 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -2,7 +2,7 @@ name: Ask a question about: Ask a question labels: kind/question, priority/P3 -assignees: markdroth +assignees: nicolasnoble --- diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a85cfad9c7a..57af6c21597 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,4 +8,4 @@ If you know who should review your pull request, please remove the mentioning be --> -@markdroth +@nicolasnoble diff --git a/BUILD b/BUILD index a31ca64684d..a75ff60dc96 100644 --- a/BUILD +++ b/BUILD @@ -251,7 +251,6 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/security/auth_metadata_processor.h", "include/grpcpp/security/credentials.h", "include/grpcpp/security/server_credentials.h", - "include/grpcpp/security/server_credentials_impl.h", "include/grpcpp/security/tls_credentials_options.h", "include/grpcpp/server.h", "include/grpcpp/server_impl.h", @@ -408,7 +407,6 @@ grpc_cc_library( hdrs = [ "include/grpc++/support/error_details.h", "include/grpcpp/support/error_details.h", - "include/grpcpp/support/error_details_impl.h", ], language = "c++", standalone = True, diff --git a/BUILD.gn b/BUILD.gn index bb6cf098224..313e62f4ea9 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1177,7 +1177,6 @@ config("grpc_config") { "include/grpcpp/security/auth_metadata_processor.h", "include/grpcpp/security/credentials.h", "include/grpcpp/security/server_credentials.h", - "include/grpcpp/security/server_credentials_impl.h", "include/grpcpp/security/tls_credentials_options.h", "include/grpcpp/server.h", "include/grpcpp/server_builder.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d568cb0ebb..7408c1439ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2820,7 +2820,6 @@ foreach(_hdr include/grpcpp/security/auth_metadata_processor.h include/grpcpp/security/credentials.h include/grpcpp/security/server_credentials.h - include/grpcpp/security/server_credentials_impl.h include/grpcpp/security/tls_credentials_options.h include/grpcpp/server.h include/grpcpp/server_builder.h @@ -2990,7 +2989,6 @@ target_link_libraries(grpc++_error_details foreach(_hdr include/grpc++/support/error_details.h include/grpcpp/support/error_details.h - include/grpcpp/support/error_details_impl.h ) string(REPLACE "include/" "" _path ${_hdr}) get_filename_component(_path ${_path} PATH) @@ -3512,7 +3510,6 @@ foreach(_hdr include/grpcpp/security/auth_metadata_processor.h include/grpcpp/security/credentials.h include/grpcpp/security/server_credentials.h - include/grpcpp/security/server_credentials_impl.h include/grpcpp/security/tls_credentials_options.h include/grpcpp/server.h include/grpcpp/server_builder.h diff --git a/Makefile b/Makefile index 8dfb02355d1..cb15ee1cc57 100644 --- a/Makefile +++ b/Makefile @@ -4944,7 +4944,6 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/credentials.h \ include/grpcpp/security/server_credentials.h \ - include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/security/tls_credentials_options.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ @@ -5121,7 +5120,6 @@ LIBGRPC++_ERROR_DETAILS_SRC = \ PUBLIC_HEADERS_CXX += \ include/grpc++/support/error_details.h \ include/grpcpp/support/error_details.h \ - include/grpcpp/support/error_details_impl.h \ LIBGRPC++_ERROR_DETAILS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_ERROR_DETAILS_SRC)))) @@ -5634,7 +5632,6 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/credentials.h \ include/grpcpp/security/server_credentials.h \ - include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/security/tls_credentials_options.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl index e53777d0743..335c1f02e2a 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -283,11 +283,11 @@ def grpc_deps(): if "upb" not in native.existing_rules(): http_archive( name = "upb", - sha256 = "79f7de61203c4ee5e4fcb2f17c5f3338119d6eb94aca8bce05332d2c1cfee108", - strip_prefix = "upb-92e63da73328d01b417cf26c2de7b0a27a0f83af", + sha256 = "7992217989f3156f8109931c1fc6db3434b7414957cb82371552377beaeb9d6c", + strip_prefix = "upb-382d5afc60e05470c23e8de19b19fc5ad231e732", urls = [ - "https://storage.googleapis.com/grpc-bazel-mirror/github.com/protocolbuffers/upb/archive/92e63da73328d01b417cf26c2de7b0a27a0f83af.tar.gz", - "https://github.com/protocolbuffers/upb/archive/92e63da73328d01b417cf26c2de7b0a27a0f83af.tar.gz", + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/protocolbuffers/upb/archive/382d5afc60e05470c23e8de19b19fc5ad231e732.tar.gz", + "https://github.com/protocolbuffers/upb/archive/382d5afc60e05470c23e8de19b19fc5ad231e732.tar.gz", ], ) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 93d439dd25b..9bd597bad31 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -2152,7 +2152,6 @@ libs: - include/grpcpp/security/auth_metadata_processor.h - include/grpcpp/security/credentials.h - include/grpcpp/security/server_credentials.h - - include/grpcpp/security/server_credentials_impl.h - include/grpcpp/security/tls_credentials_options.h - include/grpcpp/server.h - include/grpcpp/server_builder.h @@ -2277,7 +2276,6 @@ libs: public_headers: - include/grpc++/support/error_details.h - include/grpcpp/support/error_details.h - - include/grpcpp/support/error_details_impl.h headers: [] src: - src/proto/grpc/status/status.proto @@ -2536,7 +2534,6 @@ libs: - include/grpcpp/security/auth_metadata_processor.h - include/grpcpp/security/credentials.h - include/grpcpp/security/server_credentials.h - - include/grpcpp/security/server_credentials_impl.h - include/grpcpp/security/tls_credentials_options.h - include/grpcpp/server.h - include/grpcpp/server_builder.h diff --git a/cmake/re2.cmake b/cmake/re2.cmake index 383d64faa72..3e83aae6910 100644 --- a/cmake/re2.cmake +++ b/cmake/re2.cmake @@ -21,6 +21,9 @@ if(gRPC_RE2_PROVIDER STREQUAL "module") set(RE2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/re2) endif() if(EXISTS "${RE2_ROOT_DIR}/CMakeLists.txt") + # Explicitly disable BUILD_TESTING to avoid re2's CMakeLists.txt triggering https://github.com/grpc/grpc/issues/23586 + option(BUILD_TESTING "re2.cmake explicitly disabled CTest's BUILD_TESTING option." OFF) + include_directories("${RE2_ROOT_DIR}") add_subdirectory(${RE2_ROOT_DIR} third_party/re2) diff --git a/doc/grpc_xds_features.md b/doc/grpc_xds_features.md index 3537db2b965..798a072e7ce 100644 --- a/doc/grpc_xds_features.md +++ b/doc/grpc_xds_features.md @@ -36,5 +36,6 @@ to authenticate with the xDS server. Features | gRFCs | [C++, Python,
Ruby, PHP, C#](https://github.com/grpc/grpc/releases) | [Java](https://github.com/grpc/grpc-java/releases) | [Go](https://github.com/grpc/grpc-go/releases) ---------|--------|--------------|------|------ -**xDS Infrastructure in gRPC client channel:**
LDS->RDS->CDS->EDS flow,
ADS stream, | [A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) | v1.30.0 | v1.30.0 | v1.30.0 | -**Load Balancing:**
Virtual host matching,
Only default path ("" or "/") matching,
Priority-based weighted round-robin locality picking,
Round-robin endpoint picking within locality,
Cluster route action,
Client-side Load reporting via [LRS](https://github.com/envoyproxy/data-plane-api/blob/master/envoy/service/load_stats/v2/lrs.proto)| [A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) | v1.30.0 | v1.30.0 | v1.30.0 | +**xDS Infrastructure in gRPC client channel:** | [A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) | v1.30.0 | v1.30.0 | v1.30.0 | +**Load Balancing:** | [A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) | v1.30.0 | v1.30.0 | v1.30.0 | +Request matching based on:Request routing to multiple clusters based on [weights](https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#route-weightedcluster) | [A28](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) | v1.31.0 | v1.31.0 | v1.31.0 | diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 43394c48cff..b6307dd5c6f 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -164,7 +164,6 @@ Pod::Spec.new do |s| 'include/grpcpp/security/auth_metadata_processor.h', 'include/grpcpp/security/credentials.h', 'include/grpcpp/security/server_credentials.h', - 'include/grpcpp/security/server_credentials_impl.h', 'include/grpcpp/security/tls_credentials_options.h', 'include/grpcpp/server.h', 'include/grpcpp/server_builder.h', diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h index a3d3bb27b5a..33f8a1a59d6 100644 --- a/include/grpc/impl/codegen/port_platform.h +++ b/include/grpc/impl/codegen/port_platform.h @@ -31,8 +31,13 @@ * Defines GPR_ABSEIL_SYNC to use synchronization features from Abseil */ #ifndef GPR_ABSEIL_SYNC +#if defined(__APPLE__) +// This is disabled on Apple platforms because macos/grpc_basictests_c_cpp +// fails with this. https://github.com/grpc/grpc/issues/23661 +#else #define GPR_ABSEIL_SYNC 1 #endif +#endif // GPR_ABSEIL_SYNC /* Get windows.h included everywhere (we need it) */ #if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h index 3294c4037b5..0c556f0a5f0 100644 --- a/include/grpcpp/impl/codegen/server_interface.h +++ b/include/grpcpp/impl/codegen/server_interface.h @@ -36,12 +36,12 @@ namespace grpc_impl { class Channel; class CompletionQueue; class ServerCompletionQueue; -class ServerCredentials; } // namespace grpc_impl namespace grpc { class AsyncGenericService; class GenericServerContext; +class ServerCredentials; class Service; extern CoreCodegenInterface* g_core_codegen_interface; @@ -173,7 +173,7 @@ class ServerInterface : public internal::CallHook { /// /// \warning It's an error to call this method on an already started server. virtual int AddListeningPort(const std::string& addr, - grpc_impl::ServerCredentials* creds) = 0; + ServerCredentials* creds) = 0; /// Start the server. /// diff --git a/include/grpcpp/security/server_credentials.h b/include/grpcpp/security/server_credentials.h index 1223b10978e..189f491a37d 100644 --- a/include/grpcpp/security/server_credentials.h +++ b/include/grpcpp/security/server_credentials.h @@ -1,6 +1,6 @@ /* * - * Copyright 2019 gRPC authors. + * Copyright 2015 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,15 @@ #ifndef GRPCPP_SECURITY_SERVER_CREDENTIALS_H #define GRPCPP_SECURITY_SERVER_CREDENTIALS_H -#include +#include +#include + +#include +#include +#include +#include + +struct grpc_server; namespace grpc_impl { @@ -27,8 +35,6 @@ class Server; } // namespace grpc_impl namespace grpc { -typedef ::grpc_impl::ServerCredentials ServerCredentials; - /// Options to create ServerCredentials with SSL struct SslServerCredentialsOptions { /// \warning Deprecated @@ -55,16 +61,45 @@ struct SslServerCredentialsOptions { grpc_ssl_client_certificate_request_type client_certificate_request; }; +/// Wrapper around \a grpc_server_credentials, a way to authenticate a server. +class ServerCredentials { + public: + virtual ~ServerCredentials(); + + /// This method is not thread-safe and has to be called before the server is + /// started. The last call to this function wins. + virtual void SetAuthMetadataProcessor( + const std::shared_ptr& processor) = 0; + + private: + friend class ::grpc_impl::Server; + + /// Tries to bind \a server to the given \a addr (eg, localhost:1234, + /// 192.168.1.1:31416, [::1]:27182, etc.) + /// + /// \return bound port number on success, 0 on failure. + // TODO(dgq): the "port" part seems to be a misnomer. + virtual int AddPortToServer(const std::string& addr, grpc_server* server) = 0; +}; + +/// Builds SSL ServerCredentials given SSL specific options std::shared_ptr SslServerCredentials( - const SslServerCredentialsOptions& options); + const grpc::SslServerCredentialsOptions& options); std::shared_ptr InsecureServerCredentials(); namespace experimental { -typedef ::grpc_impl::experimental::AltsServerCredentialsOptions - AltsServerCredentialsOptions; +/// Options to create ServerCredentials with ALTS +struct AltsServerCredentialsOptions { + /// Add fields if needed. +}; + +/// Builds ALTS ServerCredentials given ALTS specific options +std::shared_ptr AltsServerCredentials( + const AltsServerCredentialsOptions& options); +/// Builds Local ServerCredentials. std::shared_ptr AltsServerCredentials( const AltsServerCredentialsOptions& options); @@ -73,7 +108,7 @@ std::shared_ptr LocalServerCredentials( /// Builds TLS ServerCredentials given TLS options. std::shared_ptr TlsServerCredentials( - const ::grpc::experimental::TlsCredentialsOptions& options); + const experimental::TlsCredentialsOptions& options); } // namespace experimental } // namespace grpc diff --git a/include/grpcpp/security/server_credentials_impl.h b/include/grpcpp/security/server_credentials_impl.h deleted file mode 100644 index 734409ab8e5..00000000000 --- a/include/grpcpp/security/server_credentials_impl.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef GRPCPP_SECURITY_SERVER_CREDENTIALS_IMPL_H -#define GRPCPP_SECURITY_SERVER_CREDENTIALS_IMPL_H - -#include -#include - -#include -#include -#include -#include - -struct grpc_server; - -namespace grpc { - -struct SslServerCredentialsOptions; -} // namespace grpc -namespace grpc_impl { -class Server; - -/// Wrapper around \a grpc_server_credentials, a way to authenticate a server. -class ServerCredentials { - public: - virtual ~ServerCredentials(); - - /// This method is not thread-safe and has to be called before the server is - /// started. The last call to this function wins. - virtual void SetAuthMetadataProcessor( - const std::shared_ptr& processor) = 0; - - private: - friend class ::grpc_impl::Server; - - /// Tries to bind \a server to the given \a addr (eg, localhost:1234, - /// 192.168.1.1:31416, [::1]:27182, etc.) - /// - /// \return bound port number on success, 0 on failure. - // TODO(dgq): the "port" part seems to be a misnomer. - virtual int AddPortToServer(const std::string& addr, grpc_server* server) = 0; -}; - -/// Builds SSL ServerCredentials given SSL specific options -std::shared_ptr SslServerCredentials( - const grpc::SslServerCredentialsOptions& options); - -/// Builds insecure server credentials. -std::shared_ptr InsecureServerCredentials(); - -namespace experimental { - -/// Options to create ServerCredentials with ALTS -struct AltsServerCredentialsOptions { - /// Add fields if needed. -}; - -/// Builds ALTS ServerCredentials given ALTS specific options -std::shared_ptr AltsServerCredentials( - const AltsServerCredentialsOptions& options); - -/// Builds Local ServerCredentials. -std::shared_ptr LocalServerCredentials( - grpc_local_connect_type type); - -/// Builds TLS ServerCredentials given TLS options. -std::shared_ptr TlsServerCredentials( - const grpc::experimental::TlsCredentialsOptions& options); - -} // namespace experimental -} // namespace grpc_impl - -#endif // GRPCPP_SECURITY_SERVER_CREDENTIALS_IMPL_H diff --git a/include/grpcpp/server_builder.h b/include/grpcpp/server_builder.h index 46057f50c85..a32101732c7 100644 --- a/include/grpcpp/server_builder.h +++ b/include/grpcpp/server_builder.h @@ -43,13 +43,13 @@ namespace grpc_impl { class CompletionQueue; class Server; class ServerCompletionQueue; -class ServerCredentials; } // namespace grpc_impl namespace grpc { class AsyncGenericService; class ResourceQuota; +class ServerCredentials; class Service; namespace testing { class ServerBuilderPluginTest; @@ -134,7 +134,7 @@ class ServerBuilder { /// does not modify this pointer. ServerBuilder& AddListeningPort( const std::string& addr_uri, - std::shared_ptr creds, + std::shared_ptr creds, int* selected_port = nullptr); /// Add a completion queue for handling asynchronous services. @@ -316,7 +316,7 @@ class ServerBuilder { /// Experimental, to be deprecated struct Port { std::string addr; - std::shared_ptr creds; + std::shared_ptr creds; int* selected_port; }; @@ -384,7 +384,7 @@ class ServerBuilder { /// List of completion queues added via \a AddCompletionQueue method. std::vector cqs_; - std::shared_ptr creds_; + std::shared_ptr creds_; std::vector> plugins_; grpc_resource_quota* resource_quota_; grpc::AsyncGenericService* generic_service_{nullptr}; diff --git a/include/grpcpp/support/error_details.h b/include/grpcpp/support/error_details.h index 07bc750db5c..15b917f6c5c 100644 --- a/include/grpcpp/support/error_details.h +++ b/include/grpcpp/support/error_details.h @@ -19,7 +19,7 @@ #ifndef GRPCPP_SUPPORT_ERROR_DETAILS_H #define GRPCPP_SUPPORT_ERROR_DETAILS_H -#include +#include namespace google { namespace rpc { @@ -29,15 +29,19 @@ class Status; namespace grpc { -static inline Status ExtractErrorDetails(const Status& from, - ::google::rpc::Status* to) { - return ::grpc_impl::ExtractErrorDetails(from, to); -} - -static inline Status SetErrorDetails(const ::google::rpc::Status& from, - Status* to) { - return ::grpc_impl::SetErrorDetails(from, to); -} +/// Map a \a grpc::Status to a \a google::rpc::Status. +/// The given \a to object will be cleared. +/// On success, returns status with OK. +/// Returns status with \a INVALID_ARGUMENT, if failed to deserialize. +/// Returns status with \a FAILED_PRECONDITION, if \a to is nullptr. +grpc::Status ExtractErrorDetails(const grpc::Status& from, + ::google::rpc::Status* to); + +/// Map \a google::rpc::Status to a \a grpc::Status. +/// Returns OK on success. +/// Returns status with \a FAILED_PRECONDITION if \a to is nullptr. +grpc::Status SetErrorDetails(const ::google::rpc::Status& from, + grpc::Status* to); } // namespace grpc diff --git a/include/grpcpp/support/error_details_impl.h b/include/grpcpp/support/error_details_impl.h deleted file mode 100644 index ae5f04ced8f..00000000000 --- a/include/grpcpp/support/error_details_impl.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef GRPCPP_SUPPORT_ERROR_DETAILS_IMPL_H -#define GRPCPP_SUPPORT_ERROR_DETAILS_IMPL_H - -#include - -namespace google { -namespace rpc { -class Status; -} // namespace rpc -} // namespace google - -namespace grpc_impl { - -/// Map a \a grpc::Status to a \a google::rpc::Status. -/// The given \a to object will be cleared. -/// On success, returns status with OK. -/// Returns status with \a INVALID_ARGUMENT, if failed to deserialize. -/// Returns status with \a FAILED_PRECONDITION, if \a to is nullptr. -grpc::Status ExtractErrorDetails(const grpc::Status& from, - ::google::rpc::Status* to); - -/// Map \a google::rpc::Status to a \a grpc::Status. -/// Returns OK on success. -/// Returns status with \a FAILED_PRECONDITION if \a to is nullptr. -grpc::Status SetErrorDetails(const ::google::rpc::Status& from, - grpc::Status* to); - -} // namespace grpc_impl - -#endif // GRPCPP_SUPPORT_ERROR_DETAILS_IMPL_H diff --git a/setup.py b/setup.py index 2fb0296506e..90df0a1042e 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. """A setup module for the GRPC Python package.""" + +# setuptools need to be imported before distutils. Otherwise it might lead to +# undesirable behaviors or errors. +import setuptools + from distutils import cygwinccompiler from distutils import extension as _extension from distutils import util @@ -25,7 +30,6 @@ import shutil import sys import sysconfig -import setuptools from setuptools.command import egg_info import subprocess diff --git a/src/boringssl/gen_build_yaml.py b/src/boringssl/gen_build_yaml.py index b54f53df095..0b869fa64f3 100755 --- a/src/boringssl/gen_build_yaml.py +++ b/src/boringssl/gen_build_yaml.py @@ -13,24 +13,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function -import shutil -import sys +import json import os +import sys import yaml -sys.dont_write_bytecode = True - -boring_ssl_root = os.path.abspath( - os.path.join(os.path.dirname(sys.argv[0]), - '../../third_party/boringssl-with-bazel/src')) -sys.path.append(os.path.join(boring_ssl_root, 'util')) - +run_dir = os.path.dirname(sys.argv[0]) +sources_path = os.path.abspath( + os.path.join(run_dir, + '../../third_party/boringssl-with-bazel/sources.json')) try: - import generate_build_files -except ImportError: - print(yaml.dump({})) - sys.exit() + with open(sources_path, 'r') as s: + sources = json.load(s) +except IOError: + sources_path = os.path.abspath( + os.path.join(run_dir, + '../../../../third_party/openssl/boringssl/sources.json')) + with open(sources_path, 'r') as s: + sources = json.load(s) def map_dir(filename): @@ -38,18 +38,19 @@ def map_dir(filename): class Grpc(object): - """Implements a "platform" in the sense of boringssl's generate_build_files.py""" - yaml = None + """Adapter for boring-SSL json sources files. """ - def WriteFiles(self, files, asm_outputs): - test_binaries = ['ssl_test', 'crypto_test'] + def __init__(self, sources): + self.yaml = None + self.WriteFiles(sources) + def WriteFiles(self, files): + test_binaries = ['ssl_test', 'crypto_test'] self.yaml = { '#': 'generated with src/boringssl/gen_build_yaml.py', 'raw_boringssl_build_output_for_debugging': { 'files': files, - 'asm_outputs': asm_outputs, }, 'libs': [ { @@ -120,29 +121,5 @@ class Grpc(object): } -os.chdir(os.path.dirname(sys.argv[0])) -os.mkdir('src') -try: - for f in os.listdir(boring_ssl_root): - os.symlink(os.path.join(boring_ssl_root, f), os.path.join('src', f)) - - grpc_platform = Grpc() - # We use a hack to run boringssl's util/generate_build_files.py as part of this script. - # The call will populate "grpc_platform" with boringssl's source file metadata. - # As a side effect this script generates err_data.c and crypto_test_data.cc (requires golang) - # Both of these files are already available under third_party/boringssl-with-bazel - # so we don't need to generate them again, but there's no option to disable that behavior. - # - crypto_test_data.cc is required to run boringssl_crypto_test but we already - # use the copy under third_party/boringssl-with-bazel so we just delete it - # - err_data.c is already under third_party/boringssl-with-bazel so we just delete it - generate_build_files.main([grpc_platform]) - - print(yaml.dump(grpc_platform.yaml)) - -finally: - # we don't want err_data.c and crypto_test_data.cc (see comment above) - if os.path.exists('err_data.c'): - os.remove('err_data.c') - if os.path.exists('crypto_test_data.cc'): - os.remove('crypto_test_data.cc') - shutil.rmtree('src') +grpc_platform = Grpc(sources) +print(yaml.dump(grpc_platform.yaml)) diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h index 2ba2b87bb13..35c2a2af6b2 100644 --- a/src/core/ext/filters/client_channel/client_channel.h +++ b/src/core/ext/filters/client_channel/client_channel.h @@ -79,4 +79,4 @@ void grpc_client_channel_stop_connectivity_watch( grpc_core::RefCountedPtr grpc_client_channel_get_subchannel_call(grpc_call_element* elem); -#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H */ +#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc index 3f60f0ff373..620cc89e334 100644 --- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc +++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc @@ -325,10 +325,9 @@ void HttpConnectHandshaker::DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/, args_ = args; on_handshake_done_ = on_handshake_done; // Log connection via proxy. - char* proxy_name = grpc_endpoint_get_peer(args->endpoint); + std::string proxy_name(grpc_endpoint_get_peer(args->endpoint)); gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", server_name, - proxy_name); - gpr_free(proxy_name); + proxy_name.c_str()); // Construct HTTP CONNECT request. grpc_httpcli_request request; request.host = server_name; diff --git a/src/core/ext/filters/client_channel/server_address.cc b/src/core/ext/filters/client_channel/server_address.cc index 93d361a8154..16ec96b7b56 100644 --- a/src/core/ext/filters/client_channel/server_address.cc +++ b/src/core/ext/filters/client_channel/server_address.cc @@ -26,23 +26,56 @@ namespace grpc_core { // ServerAddress // -ServerAddress::ServerAddress(const grpc_resolved_address& address, - grpc_channel_args* args) - : address_(address), args_(args) {} +ServerAddress::ServerAddress( + const grpc_resolved_address& address, grpc_channel_args* args, + std::map> attributes) + : address_(address), args_(args), attributes_(std::move(attributes)) {} -ServerAddress::ServerAddress(const void* address, size_t address_len, - grpc_channel_args* args) - : args_(args) { +ServerAddress::ServerAddress( + const void* address, size_t address_len, grpc_channel_args* args, + std::map> attributes) + : args_(args), attributes_(std::move(attributes)) { memcpy(address_.addr, address, address_len); address_.len = static_cast(address_len); } +namespace { + +int CompareAttributes( + const std::map>& + attributes1, + const std::map>& + attributes2) { + auto it2 = attributes2.begin(); + for (auto it1 = attributes1.begin(); it1 != attributes1.end(); ++it1) { + // attributes2 has fewer elements than attributes1 + if (it2 == attributes2.end()) return -1; + // compare keys + int retval = strcmp(it1->first, it2->first); + if (retval != 0) return retval; + // compare values + retval = it1->second->Cmp(it2->second.get()); + if (retval != 0) return retval; + ++it2; + } + // attributes1 has fewer elements than attributes2 + if (it2 != attributes2.end()) return 1; + // equal + return 0; +} + +} // namespace + int ServerAddress::Cmp(const ServerAddress& other) const { if (address_.len > other.address_.len) return 1; if (address_.len < other.address_.len) return -1; int retval = memcmp(address_.addr, other.address_.addr, address_.len); if (retval != 0) return retval; - return grpc_channel_args_compare(args_, other.args_); + retval = grpc_channel_args_compare(args_, other.args_); + if (retval != 0) return retval; + return CompareAttributes(attributes_, other.attributes_); } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/server_address.h b/src/core/ext/filters/client_channel/server_address.h index f53dd3c7dd5..4a28ea75205 100644 --- a/src/core/ext/filters/client_channel/server_address.h +++ b/src/core/ext/filters/client_channel/server_address.h @@ -21,6 +21,8 @@ #include +#include + #include "absl/container/inlined_vector.h" #include "src/core/lib/channel/channel_args.h" @@ -37,26 +39,54 @@ namespace grpc_core { // args when a subchannel is created for this address. class ServerAddress { public: + // Base clas for resolver-supplied attributes. + // Unlike channel args, these attributes don't affect subchannel + // uniqueness or behavior. They are for use by LB policies only. + class AttributeInterface { + public: + virtual ~AttributeInterface(); + + // Creates a copy of the attribute. + virtual std::unique_ptr Copy() const = 0; + + // Compares this attribute with another. + virtual int Cmp(const AttributeInterface* other) const = 0; + }; + // Takes ownership of args. - ServerAddress(const grpc_resolved_address& address, grpc_channel_args* args); + ServerAddress(const grpc_resolved_address& address, grpc_channel_args* args, + std::map> + attributes = {}); ServerAddress(const void* address, size_t address_len, - grpc_channel_args* args); + grpc_channel_args* args, + std::map> + attributes = {}); ~ServerAddress() { grpc_channel_args_destroy(args_); } // Copyable. ServerAddress(const ServerAddress& other) - : address_(other.address_), args_(grpc_channel_args_copy(other.args_)) {} + : address_(other.address_), args_(grpc_channel_args_copy(other.args_)) { + for (const auto& p : other.attributes_) { + attributes_[p.first] = p.second->Copy(); + } + } ServerAddress& operator=(const ServerAddress& other) { address_ = other.address_; grpc_channel_args_destroy(args_); args_ = grpc_channel_args_copy(other.args_); + attributes_.clear(); + for (const auto& p : other.attributes_) { + attributes_[p.first] = p.second->Copy(); + } return *this; } // Movable. ServerAddress(ServerAddress&& other) - : address_(other.address_), args_(other.args_) { + : address_(other.address_), + args_(other.args_), + attributes_(std::move(other.attributes_)) { other.args_ = nullptr; } ServerAddress& operator=(ServerAddress&& other) { @@ -64,6 +94,7 @@ class ServerAddress { grpc_channel_args_destroy(args_); args_ = other.args_; other.args_ = nullptr; + attributes_ = std::move(other.attributes_); return *this; } @@ -74,9 +105,16 @@ class ServerAddress { const grpc_resolved_address& address() const { return address_; } const grpc_channel_args* args() const { return args_; } + const AttributeInterface* GetAttribute(const char* key) const { + auto it = attributes_.find(key); + if (it == attributes_.end()) return nullptr; + return it->second.get(); + } + private: grpc_resolved_address address_; grpc_channel_args* args_; + std::map> attributes_; }; // diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index b5593cb17db..1e930ca5fb5 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -129,6 +129,15 @@ void Chttp2Connector::StartHandshakeLocked() { endpoint_ = nullptr; // Endpoint handed off to handshake manager. } +namespace { +void NullThenSchedClosure(const DebugLocation& location, grpc_closure** closure, + grpc_error* error) { + grpc_closure* c = *closure; + *closure = nullptr; + ExecCtx::Run(location, c, error); +} +} // namespace + void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) { auto* args = static_cast(arg); Chttp2Connector* self = static_cast(args->user_data); @@ -154,53 +163,99 @@ void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) { error = GRPC_ERROR_REF(error); } self->result_->Reset(); + NullThenSchedClosure(DEBUG_LOCATION, &self->notify_, error); } else if (args->endpoint != nullptr) { - grpc_endpoint_delete_from_pollset_set(args->endpoint, - self->args_.interested_parties); self->result_->transport = grpc_create_chttp2_transport(args->args, args->endpoint, true); self->result_->socket_node = grpc_chttp2_transport_get_socket_node(self->result_->transport); + self->result_->channel_args = args->args; GPR_ASSERT(self->result_->transport != nullptr); - // TODO(roth): We ideally want to wait until we receive HTTP/2 - // settings from the server before we consider the connection - // established. If that doesn't happen before the connection - // timeout expires, then we should consider the connection attempt a - // failure and feed that information back into the backoff code. - // We could pass a notify_on_receive_settings callback to - // grpc_chttp2_transport_start_reading() to let us know when - // settings are received, but we would need to figure out how to use - // that information here. - // - // Unfortunately, we don't currently have a way to split apart the two - // effects of scheduling c->notify: we start sending RPCs immediately - // (which we want to do) and we consider the connection attempt successful - // (which we don't want to do until we get the notify_on_receive_settings - // callback from the transport). If we could split those things - // apart, then we could start sending RPCs but then wait for our - // timeout before deciding if the connection attempt is successful. - // If the attempt is not successful, then we would tear down the - // transport and feed the failure back into the backoff code. - // - // In addition, even if we did that, we would probably not want to do - // so until after transparent retries is implemented. Otherwise, any - // RPC that we attempt to send on the connection before the timeout - // would fail instead of being retried on a subsequent attempt. + self->endpoint_ = args->endpoint; + self->Ref().release(); // Ref held by OnReceiveSettings() + GRPC_CLOSURE_INIT(&self->on_receive_settings_, OnReceiveSettings, self, + grpc_schedule_on_exec_ctx); + self->Ref().release(); // Ref held by OnTimeout() grpc_chttp2_transport_start_reading(self->result_->transport, - args->read_buffer, nullptr); - self->result_->channel_args = args->args; + args->read_buffer, + &self->on_receive_settings_); + GRPC_CLOSURE_INIT(&self->on_timeout_, OnTimeout, self, + grpc_schedule_on_exec_ctx); + grpc_timer_init(&self->timer_, self->args_.deadline, &self->on_timeout_); } else { // If the handshaking succeeded but there is no endpoint, then the // handshaker may have handed off the connection to some external // code. Just verify that exit_early flag is set. GPR_DEBUG_ASSERT(args->exit_early); + NullThenSchedClosure(DEBUG_LOCATION, &self->notify_, error); } - grpc_closure* notify = self->notify_; - self->notify_ = nullptr; - ExecCtx::Run(DEBUG_LOCATION, notify, error); self->handshake_mgr_.reset(); } self->Unref(); } +void Chttp2Connector::OnReceiveSettings(void* arg, grpc_error* error) { + Chttp2Connector* self = static_cast(arg); + { + MutexLock lock(&self->mu_); + if (!self->notify_error_.has_value()) { + if (error != GRPC_ERROR_NONE) { + // Transport got an error while waiting on SETTINGS frame. + // TODO(yashykt): The following two lines should be moved to + // SubchannelConnector::Result::Reset() + grpc_transport_destroy(self->result_->transport); + grpc_channel_args_destroy(self->result_->channel_args); + self->result_->Reset(); + } + self->MaybeNotify(GRPC_ERROR_REF(error)); + grpc_timer_cancel(&self->timer_); + } else { + // OnTimeout() was already invoked. Call Notify() again so that notify_ + // can be invoked. + self->MaybeNotify(GRPC_ERROR_NONE); + } + } + self->Unref(); +} + +void Chttp2Connector::OnTimeout(void* arg, grpc_error* error) { + Chttp2Connector* self = static_cast(arg); + { + MutexLock lock(&self->mu_); + if (!self->notify_error_.has_value()) { + // The transport did not receive the settings frame in time. Destroy the + // transport. + // TODO(yashykt): The following two lines should be moved to + // SubchannelConnector::Result::Reset() + grpc_transport_destroy(self->result_->transport); + grpc_channel_args_destroy(self->result_->channel_args); + self->result_->Reset(); + self->MaybeNotify(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "connection attempt timed out before receiving SETTINGS frame")); + } else { + // OnReceiveSettings() was already invoked. Call Notify() again so that + // notify_ can be invoked. + self->MaybeNotify(GRPC_ERROR_NONE); + } + } + self->Unref(); +} + +void Chttp2Connector::MaybeNotify(grpc_error* error) { + if (notify_error_.has_value()) { + GRPC_ERROR_UNREF(error); + NullThenSchedClosure(DEBUG_LOCATION, ¬ify_, notify_error_.value()); + // Clear out the endpoint, since it is the responsibility of the transport + // to shut it down. + // Clear state for a new Connect(). + grpc_endpoint_delete_from_pollset_set(endpoint_, args_.interested_parties); + // We do not destroy the endpoint here, since it is the responsibility of + // the transport to shut it down. + endpoint_ = nullptr; + notify_error_.reset(); + } else { + notify_error_ = error; + } +} + } // namespace grpc_core diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.h b/src/core/ext/transport/chttp2/client/chttp2_connector.h index 1ecd172bba1..37143c8f187 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.h +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.h @@ -39,6 +39,19 @@ class Chttp2Connector : public SubchannelConnector { static void Connected(void* arg, grpc_error* error); void StartHandshakeLocked(); static void OnHandshakeDone(void* arg, grpc_error* error); + static void OnReceiveSettings(void* arg, grpc_error* error); + static void OnTimeout(void* arg, grpc_error* error); + + // We cannot invoke notify_ until both OnTimeout() and OnReceiveSettings() + // have been called since that is an indicator to the upper layer that we are + // done with the connection attempt. So, the notification process is broken + // into two steps. 1) Either OnTimeout() or OnReceiveSettings() gets invoked + // first. Whichever gets invoked, calls MaybeNotify() to set the result and + // triggers the other callback to be invoked. 2) When the other callback is + // invoked, we call MaybeNotify() again to actually invoke the notify_ + // callback. Note that this only happens if the handshake is done and the + // connector is waiting on the SETTINGS frame. + void MaybeNotify(grpc_error* error); Mutex mu_; Args args_; @@ -47,9 +60,13 @@ class Chttp2Connector : public SubchannelConnector { bool shutdown_ = false; bool connecting_ = false; // Holds the endpoint when first created before being handed off to - // the handshake manager. + // the handshake manager, and then again after handshake is done. grpc_endpoint* endpoint_ = nullptr; grpc_closure connected_; + grpc_closure on_receive_settings_; + grpc_timer timer_; + grpc_closure on_timeout_; + absl::optional notify_error_; RefCountedPtr handshake_mgr_; }; diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index 6bafa823e06..000c63c8786 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -53,19 +53,19 @@ namespace grpc_core { namespace { -class Chttp2ServerListener : public ServerListenerInterface { +class Chttp2ServerListener : public Server::ListenerInterface { public: - static grpc_error* Create(grpc_server* server, const char* addr, + static grpc_error* Create(Server* server, const char* addr, grpc_channel_args* args, int* port_num); - static grpc_error* CreateWithAcceptor(grpc_server* server, const char* name, + static grpc_error* CreateWithAcceptor(Server* server, const char* name, grpc_channel_args* args); // Do not instantiate directly. Use one of the factory methods above. - Chttp2ServerListener(grpc_server* server, grpc_channel_args* args); + Chttp2ServerListener(Server* server, grpc_channel_args* args); ~Chttp2ServerListener(); - void Start(grpc_server* server, + void Start(Server* server, const std::vector* pollsets) override; channelz::ListenSocketNode* channelz_listen_socket_node() const override { @@ -113,10 +113,10 @@ class Chttp2ServerListener : public ServerListenerInterface { static void TcpServerShutdownComplete(void* arg, grpc_error* error); - static void DestroyListener(grpc_server* /*server*/, void* arg, + static void DestroyListener(Server* /*server*/, void* arg, grpc_closure* destroy_done); - grpc_server* const server_; + Server* const server_; grpc_channel_args* const args_; grpc_tcp_server* tcp_server_; Mutex mu_; @@ -194,12 +194,10 @@ void Chttp2ServerListener::ConnectionState::OnHandshakeDone(void* arg, { MutexLock lock(&self->listener_->mu_); grpc_resource_user* resource_user = - grpc_server_get_default_resource_user(self->listener_->server_); + self->listener_->server_->default_resource_user(); if (error != GRPC_ERROR_NONE || self->listener_->shutdown_) { const char* error_str = grpc_error_string(error); gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str); - grpc_resource_user* resource_user = - grpc_server_get_default_resource_user(self->listener_->server_); if (resource_user != nullptr) { grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE); @@ -224,10 +222,9 @@ void Chttp2ServerListener::ConnectionState::OnHandshakeDone(void* arg, if (args->endpoint != nullptr) { grpc_transport* transport = grpc_create_chttp2_transport( args->args, args->endpoint, false, resource_user); - grpc_server_setup_transport( - self->listener_->server_, transport, self->accepting_pollset_, - args->args, grpc_chttp2_transport_get_socket_node(transport), - resource_user); + self->listener_->server_->SetupTransport( + transport, self->accepting_pollset_, args->args, + grpc_chttp2_transport_get_socket_node(transport), resource_user); // Use notify_on_receive_settings callback to enforce the // handshake deadline. // Note: The reinterpret_cast<>s here are safe, because @@ -270,7 +267,7 @@ void Chttp2ServerListener::ConnectionState::OnHandshakeDone(void* arg, // Chttp2ServerListener // -grpc_error* Chttp2ServerListener::Create(grpc_server* server, const char* addr, +grpc_error* Chttp2ServerListener::Create(Server* server, const char* addr, grpc_channel_args* args, int* port_num) { std::vector error_list; @@ -327,8 +324,7 @@ grpc_error* Chttp2ServerListener::Create(grpc_server* server, const char* addr, addr, absl::StrFormat("chttp2 listener %s", addr)); } /* Register with the server only upon success */ - grpc_server_add_listener(server, - OrphanablePtr(listener)); + server->AddListener(OrphanablePtr(listener)); return GRPC_ERROR_NONE; }(); if (resolved != nullptr) { @@ -352,7 +348,7 @@ grpc_error* Chttp2ServerListener::Create(grpc_server* server, const char* addr, return error; } -grpc_error* Chttp2ServerListener::CreateWithAcceptor(grpc_server* server, +grpc_error* Chttp2ServerListener::CreateWithAcceptor(Server* server, const char* name, grpc_channel_args* args) { Chttp2ServerListener* listener = new Chttp2ServerListener(server, args); @@ -366,12 +362,11 @@ grpc_error* Chttp2ServerListener::CreateWithAcceptor(grpc_server* server, TcpServerFdHandler** arg_val = grpc_channel_args_find_pointer(args, name); *arg_val = grpc_tcp_server_create_fd_handler(listener->tcp_server_); - grpc_server_add_listener(server, - OrphanablePtr(listener)); + server->AddListener(OrphanablePtr(listener)); return GRPC_ERROR_NONE; } -Chttp2ServerListener::Chttp2ServerListener(grpc_server* server, +Chttp2ServerListener::Chttp2ServerListener(Server* server, grpc_channel_args* args) : server_(server), args_(args) { GRPC_CLOSURE_INIT(&tcp_server_shutdown_complete_, TcpServerShutdownComplete, @@ -383,7 +378,7 @@ Chttp2ServerListener::~Chttp2ServerListener() { } /* Server callback: start listening on our ports */ -void Chttp2ServerListener::Start(grpc_server* /*server*/, +void Chttp2ServerListener::Start(Server* /*server*/, const std::vector* pollsets) { { MutexLock lock(&mu_); @@ -400,8 +395,7 @@ void Chttp2ServerListener::SetOnDestroyDone(grpc_closure* on_destroy_done) { RefCountedPtr Chttp2ServerListener::CreateHandshakeManager() { MutexLock lock(&mu_); if (shutdown_) return nullptr; - grpc_resource_user* resource_user = - grpc_server_get_default_resource_user(server_); + grpc_resource_user* resource_user = server_->default_resource_user(); if (resource_user != nullptr && !grpc_resource_user_safe_alloc(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE)) { @@ -475,7 +469,7 @@ void Chttp2ServerListener::Orphan() { // Chttp2ServerAddPort() // -grpc_error* Chttp2ServerAddPort(grpc_server* server, const char* addr, +grpc_error* Chttp2ServerAddPort(Server* server, const char* addr, grpc_channel_args* args, int* port_num) { if (strncmp(addr, "external:", 9) == 0) { return grpc_core::Chttp2ServerListener::CreateWithAcceptor(server, addr, diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h index 8f651bb5ce9..095cc5e4c04 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.h +++ b/src/core/ext/transport/chttp2/server/chttp2_server.h @@ -24,12 +24,13 @@ #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/surface/server.h" namespace grpc_core { /// Adds a port to \a server. Sets \a port_num to the port number. /// Takes ownership of \a args. -grpc_error* Chttp2ServerAddPort(grpc_server* server, const char* addr, +grpc_error* Chttp2ServerAddPort(Server* server, const char* addr, grpc_channel_args* args, int* port_num); } // namespace grpc_core diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc index 7220591a30f..eebae9efaa9 100644 --- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc +++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc @@ -33,8 +33,8 @@ int grpc_server_add_insecure_http2_port(grpc_server* server, const char* addr) { GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2, (server, addr)); grpc_error* err = grpc_core::Chttp2ServerAddPort( - server, addr, - grpc_channel_args_copy(grpc_server_get_channel_args(server)), &port_num); + server->core_server.get(), addr, + grpc_channel_args_copy(server->core_server->channel_args()), &port_num); if (err != GRPC_ERROR_NONE) { const char* msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc index f3ae7f4edb7..f27c197ea15 100644 --- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc +++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc @@ -41,21 +41,21 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server, GPR_ASSERT(reserved == nullptr); grpc_core::ExecCtx exec_ctx; + grpc_core::Server* core_server = server->core_server.get(); + const grpc_channel_args* server_args = core_server->channel_args(); std::string name = absl::StrCat("fd:", fd); - grpc_endpoint* server_endpoint = - grpc_tcp_create(grpc_fd_create(fd, name.c_str(), true), - grpc_server_get_channel_args(server), name.c_str()); + grpc_endpoint* server_endpoint = grpc_tcp_create( + grpc_fd_create(fd, name.c_str(), true), server_args, name.c_str()); - const grpc_channel_args* server_args = grpc_server_get_channel_args(server); grpc_transport* transport = grpc_create_chttp2_transport( server_args, server_endpoint, false /* is_client */); - for (grpc_pollset* pollset : grpc_server_get_pollsets(server)) { + for (grpc_pollset* pollset : core_server->pollsets()) { grpc_endpoint_add_to_pollset(server_endpoint, pollset); } - grpc_server_setup_transport(server, transport, nullptr, server_args, nullptr); + core_server->SetupTransport(transport, nullptr, server_args, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); } diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc index c3c4e39033b..a181db47f39 100644 --- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc +++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc @@ -68,10 +68,11 @@ int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr, args_to_add[0] = grpc_server_credentials_to_arg(creds); args_to_add[1] = grpc_security_connector_to_arg(sc.get()); args = - grpc_channel_args_copy_and_add(grpc_server_get_channel_args(server), + grpc_channel_args_copy_and_add(server->core_server->channel_args(), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Add server port. - err = grpc_core::Chttp2ServerAddPort(server, addr, args, &port_num); + err = grpc_core::Chttp2ServerAddPort(server->core_server.get(), addr, args, + &port_num); done: sc.reset(DEBUG_LOCATION, "server"); diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index ddaed426bf6..3ea224e0f9b 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -226,7 +226,6 @@ grpc_chttp2_transport::~grpc_chttp2_transport() { GRPC_ERROR_UNREF(closed_with_error); gpr_free(ping_acks); - gpr_free(peer_string); } static const grpc_transport_vtable* get_vtable(void); @@ -378,11 +377,9 @@ static bool read_channel_args(grpc_chttp2_transport* t, } } if (channelz_enabled) { - // TODO(ncteisen): add an API to endpoint to query for local addr, and pass - // it in here, so SocketNode knows its own address. t->channelz_socket = grpc_core::MakeRefCounted( - "", t->peer_string, + std::string(grpc_endpoint_get_local_address(t->ep)), t->peer_string, absl::StrFormat("%s %s", get_vtable()->name, t->peer_string)); } return enable_bdp; @@ -594,7 +591,7 @@ static void close_transport_locked(grpc_chttp2_transport* t, } if (t->notify_on_receive_settings != nullptr) { grpc_core::ExecCtx::Run(DEBUG_LOCATION, t->notify_on_receive_settings, - GRPC_ERROR_CANCELLED); + GRPC_ERROR_REF(error)); t->notify_on_receive_settings = nullptr; } GRPC_ERROR_UNREF(error); @@ -795,7 +792,7 @@ static void set_write_state(grpc_chttp2_transport* t, grpc_chttp2_write_state st, const char* reason) { GRPC_CHTTP2_IF_TRACING( gpr_log(GPR_INFO, "W:%p %s [%s] state %s -> %s [%s]", t, - t->is_client ? "CLIENT" : "SERVER", t->peer_string, + t->is_client ? "CLIENT" : "SERVER", t->peer_string.c_str(), write_state_name(t->write_state), write_state_name(st), reason)); t->write_state = st; // If the state is being reset back to idle, it means a write was just @@ -1084,7 +1081,7 @@ void grpc_chttp2_add_incoming_goaway(grpc_chttp2_transport* t, // We want to log this irrespective of whether http tracing is enabled if we // received a GOAWAY with a non NO_ERROR code. if (goaway_error != GRPC_HTTP2_NO_ERROR) { - gpr_log(GPR_INFO, "%s: Got goaway [%d] err=%s", t->peer_string, + gpr_log(GPR_INFO, "%s: Got goaway [%d] err=%s", t->peer_string.c_str(), goaway_error, grpc_error_string(t->goaway_error)); } // When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug @@ -1216,7 +1213,7 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t, "Error in HTTP transport completing operation"); closure->error_data.error = grpc_error_set_str( closure->error_data.error, GRPC_ERROR_STR_TARGET_ADDRESS, - grpc_slice_from_copied_string(t->peer_string)); + grpc_slice_from_copied_string(t->peer_string.c_str())); } closure->error_data.error = grpc_error_add_child(closure->error_data.error, error); @@ -1474,7 +1471,7 @@ static void perform_stream_op_locked(void* stream_op, } if (op_payload->send_initial_metadata.peer_string != nullptr) { gpr_atm_rel_store(op_payload->send_initial_metadata.peer_string, - (gpr_atm)t->peer_string); + (gpr_atm)t->peer_string.c_str()); } } @@ -1587,7 +1584,7 @@ static void perform_stream_op_locked(void* stream_op, op_payload->recv_initial_metadata.trailing_metadata_available; if (op_payload->recv_initial_metadata.peer_string != nullptr) { gpr_atm_rel_store(op_payload->recv_initial_metadata.peer_string, - (gpr_atm)t->peer_string); + (gpr_atm)t->peer_string.c_str()); } grpc_chttp2_maybe_complete_recv_initial_metadata(t, s); } @@ -1755,9 +1752,8 @@ static void retry_initiate_ping_locked(void* tp, grpc_error* error) { void grpc_chttp2_ack_ping(grpc_chttp2_transport* t, uint64_t id) { grpc_chttp2_ping_queue* pq = &t->ping_queue; if (pq->inflight_id != id) { - char* from = grpc_endpoint_get_peer(t->ep); - gpr_log(GPR_DEBUG, "Unknown ping response from %s: %" PRIx64, from, id); - gpr_free(from); + gpr_log(GPR_DEBUG, "Unknown ping response from %s: %" PRIx64, + t->peer_string.c_str(), id); return; } grpc_core::ExecCtx::RunList(DEBUG_LOCATION, @@ -1769,7 +1765,7 @@ void grpc_chttp2_ack_ping(grpc_chttp2_transport* t, uint64_t id) { static void send_goaway(grpc_chttp2_transport* t, grpc_error* error) { // We want to log this irrespective of whether http tracing is enabled - gpr_log(GPR_INFO, "%s: Sending goaway err=%s", t->peer_string, + gpr_log(GPR_INFO, "%s: Sending goaway err=%s", t->peer_string.c_str(), grpc_error_string(error)); t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED; grpc_http2_error_code http_error; @@ -2641,7 +2637,7 @@ static void start_bdp_ping(void* tp, grpc_error* error) { static void start_bdp_ping_locked(void* tp, grpc_error* error) { grpc_chttp2_transport* t = static_cast(tp); if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { - gpr_log(GPR_INFO, "%s: Start BDP ping err=%s", t->peer_string, + gpr_log(GPR_INFO, "%s: Start BDP ping err=%s", t->peer_string.c_str(), grpc_error_string(error)); } if (error != GRPC_ERROR_NONE || t->closed_with_error != GRPC_ERROR_NONE) { @@ -2665,7 +2661,7 @@ static void finish_bdp_ping(void* tp, grpc_error* error) { static void finish_bdp_ping_locked(void* tp, grpc_error* error) { grpc_chttp2_transport* t = static_cast(tp); if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { - gpr_log(GPR_INFO, "%s: Complete BDP ping err=%s", t->peer_string, + gpr_log(GPR_INFO, "%s: Complete BDP ping err=%s", t->peer_string.c_str(), grpc_error_string(error)); } if (error != GRPC_ERROR_NONE || t->closed_with_error != GRPC_ERROR_NONE) { @@ -2835,7 +2831,7 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) { } if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || GRPC_TRACE_FLAG_ENABLED(grpc_keepalive_trace)) { - gpr_log(GPR_INFO, "%s: Start keepalive ping", t->peer_string); + gpr_log(GPR_INFO, "%s: Start keepalive ping", t->peer_string.c_str()); } GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog"); GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked, @@ -2859,7 +2855,7 @@ static void finish_keepalive_ping_locked(void* arg, grpc_error* error) { if (error == GRPC_ERROR_NONE) { if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || GRPC_TRACE_FLAG_ENABLED(grpc_keepalive_trace)) { - gpr_log(GPR_INFO, "%s: Finish keepalive ping", t->peer_string); + gpr_log(GPR_INFO, "%s: Finish keepalive ping", t->peer_string.c_str()); } if (!t->keepalive_ping_started) { // start_keepalive_ping_locked has not run yet. Reschedule @@ -2897,7 +2893,7 @@ static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) { if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (error == GRPC_ERROR_NONE) { gpr_log(GPR_INFO, "%s: Keepalive watchdog fired. Closing transport.", - t->peer_string); + t->peer_string.c_str()); t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; close_transport_locked( t, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( @@ -3205,7 +3201,7 @@ static void benign_reclaimer_locked(void* arg, grpc_error* error) { // disconnect cleanly if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "HTTP2: %s - send goaway to free memory", - t->peer_string); + t->peer_string.c_str()); } send_goaway(t, grpc_error_set_int( @@ -3216,7 +3212,8 @@ static void benign_reclaimer_locked(void* arg, grpc_error* error) { gpr_log(GPR_INFO, "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR " streams", - t->peer_string, grpc_chttp2_stream_map_size(&t->stream_map)); + t->peer_string.c_str(), + grpc_chttp2_stream_map_size(&t->stream_map)); } t->benign_reclaimer_registered = false; if (error != GRPC_ERROR_CANCELLED) { @@ -3241,8 +3238,8 @@ static void destructive_reclaimer_locked(void* arg, grpc_error* error) { grpc_chttp2_stream* s = static_cast( grpc_chttp2_stream_map_rand(&t->stream_map)); if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { - gpr_log(GPR_INFO, "HTTP2: %s - abandon stream id %d", t->peer_string, - s->id); + gpr_log(GPR_INFO, "HTTP2: %s - abandon stream id %d", + t->peer_string.c_str(), s->id); } grpc_chttp2_cancel_stream( t, s, diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index f2b2bbd3920..e54744c1a75 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -175,7 +175,7 @@ TransportFlowControl::TransportFlowControl(const grpc_chttp2_transport* t, bool enable_bdp_probe) : t_(t), enable_bdp_probe_(enable_bdp_probe), - bdp_estimator_(t->peer_string), + bdp_estimator_(t->peer_string.c_str()), pid_controller_(grpc_core::PidController::Args() .set_gain_p(4) .set_gain_i(8) diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc index 647f52c10ef..7dbfc69ea0d 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.cc +++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc @@ -228,8 +228,8 @@ grpc_error* grpc_chttp2_settings_parser_parse(void* p, grpc_chttp2_transport* t, parser->incoming_settings[id] = parser->value; if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "CHTTP2:%s:%s: got setting %s = %d", - t->is_client ? "CLI" : "SVR", t->peer_string, sp->name, - parser->value); + t->is_client ? "CLI" : "SVR", t->peer_string.c_str(), + sp->name, parser->value); } } else if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 34589e0e340..28da24f647d 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -290,7 +290,7 @@ struct grpc_chttp2_transport { grpc_transport base; /* must be first */ grpc_core::RefCount refs; grpc_endpoint* ep; - char* peer_string; + std::string peer_string; grpc_resource_user* resource_user; diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 5948ac98f96..f8e21e8e159 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -58,7 +58,7 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace) || GRPC_TRACE_FLAG_ENABLED(grpc_keepalive_trace)) { gpr_log(GPR_INFO, "%s: Ping delayed [%s]: already pinging", - t->is_client ? "CLIENT" : "SERVER", t->peer_string); + t->is_client ? "CLIENT" : "SERVER", t->peer_string.c_str()); } return; } @@ -69,7 +69,7 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace) || GRPC_TRACE_FLAG_ENABLED(grpc_keepalive_trace)) { gpr_log(GPR_INFO, "%s: Ping delayed [%s]: too many recent pings: %d/%d", - t->is_client ? "CLIENT" : "SERVER", t->peer_string, + t->is_client ? "CLIENT" : "SERVER", t->peer_string.c_str(), t->ping_state.pings_before_data_required, t->ping_policy.max_pings_without_data); } @@ -95,7 +95,7 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { gpr_log(GPR_INFO, "%s: Ping delayed [%s]: not enough time elapsed since last ping. " " Last ping %f: Next ping %f: Now %f", - t->is_client ? "CLIENT" : "SERVER", t->peer_string, + t->is_client ? "CLIENT" : "SERVER", t->peer_string.c_str(), static_cast(t->ping_state.last_ping_sent_time), static_cast(next_allowed_ping), static_cast(now)); } @@ -125,7 +125,7 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace) || GRPC_TRACE_FLAG_ENABLED(grpc_keepalive_trace)) { gpr_log(GPR_INFO, "%s: Ping sent [%s]: %d/%d", - t->is_client ? "CLIENT" : "SERVER", t->peer_string, + t->is_client ? "CLIENT" : "SERVER", t->peer_string.c_str(), t->ping_state.pings_before_data_required, t->ping_policy.max_pings_without_data); } @@ -165,7 +165,8 @@ static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s, "helpful data: [fc:pending=%" PRIdPTR ":pending-compressed=%" PRIdPTR ":flowed=%" PRId64 ":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]", - t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length, + t->peer_string.c_str(), t, s->id, staller, + s->flow_controlled_buffer.length, s->stream_compression_method == GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS ? 0 diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index d40bffd6d09..4cf9e900a44 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -1276,7 +1276,7 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server, const char* args_to_remove[] = {GRPC_ARG_MAX_CONNECTION_IDLE_MS, GRPC_ARG_MAX_CONNECTION_AGE_MS}; const grpc_channel_args* server_args = grpc_channel_args_copy_and_remove( - grpc_server_get_channel_args(server), args_to_remove, + server->core_server->channel_args(), args_to_remove, GPR_ARRAY_SIZE(args_to_remove)); // Add a default authority channel argument for the client @@ -1293,8 +1293,8 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server, client_args); // TODO(ncteisen): design and support channelz GetSocket for inproc. - grpc_server_setup_transport(server, server_transport, nullptr, server_args, - nullptr); + server->core_server->SetupTransport(server_transport, nullptr, server_args, + nullptr); grpc_channel* channel = grpc_channel_create( "inproc", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport); diff --git a/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h b/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h index f415862e696..06270bd96bc 100644 --- a/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h +++ b/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h @@ -199,7 +199,7 @@ UPB_INLINE envoy_config_cluster_v3_Cluster_lb_config_oneofcases envoy_config_clu UPB_INLINE upb_strview envoy_config_cluster_v3_Cluster_name(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview); } UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_type(const envoy_config_cluster_v3_Cluster *msg) { return _upb_getoneofcase(msg, UPB_SIZE(168, 288)) == 2; } -UPB_INLINE int32_t envoy_config_cluster_v3_Cluster_type(const envoy_config_cluster_v3_Cluster *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(160, 280), UPB_SIZE(168, 288), 2, envoy_config_cluster_v3_Cluster_STATIC); } +UPB_INLINE int32_t envoy_config_cluster_v3_Cluster_type(const envoy_config_cluster_v3_Cluster *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(160, 280), UPB_SIZE(168, 288), 2, 0); } UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_eds_cluster_config(const envoy_config_cluster_v3_Cluster *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 64)); } UPB_INLINE const envoy_config_cluster_v3_Cluster_EdsClusterConfig* envoy_config_cluster_v3_Cluster_eds_cluster_config(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), const envoy_config_cluster_v3_Cluster_EdsClusterConfig*); } UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_connect_timeout(const envoy_config_cluster_v3_Cluster *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 72)); } diff --git a/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h b/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h index a3cab46af1a..6c4b7f81eb1 100644 --- a/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h +++ b/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h @@ -594,7 +594,7 @@ typedef enum { UPB_INLINE google_api_expr_v1alpha1_Constant_constant_kind_oneofcases google_api_expr_v1alpha1_Constant_constant_kind_case(const google_api_expr_v1alpha1_Constant* msg) { return (google_api_expr_v1alpha1_Constant_constant_kind_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(8, 16), int32_t); } UPB_INLINE bool google_api_expr_v1alpha1_Constant_has_null_value(const google_api_expr_v1alpha1_Constant *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 1; } -UPB_INLINE int32_t google_api_expr_v1alpha1_Constant_null_value(const google_api_expr_v1alpha1_Constant *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, google_protobuf_NULL_VALUE); } +UPB_INLINE int32_t google_api_expr_v1alpha1_Constant_null_value(const google_api_expr_v1alpha1_Constant *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, 0); } UPB_INLINE bool google_api_expr_v1alpha1_Constant_has_bool_value(const google_api_expr_v1alpha1_Constant *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 2; } UPB_INLINE bool google_api_expr_v1alpha1_Constant_bool_value(const google_api_expr_v1alpha1_Constant *msg) { return UPB_READ_ONEOF(msg, bool, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 2, false); } UPB_INLINE bool google_api_expr_v1alpha1_Constant_has_int64_value(const google_api_expr_v1alpha1_Constant *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 3; } diff --git a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c index 3c7363922e9..44cd3ae2cec 100644 --- a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c +++ b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c @@ -36,9 +36,9 @@ static const upb_msglayout *const google_protobuf_FileDescriptorProto_submsgs[6] }; static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 2, 0, 9, 1}, - {3, UPB_SIZE(36, 72), 0, 0, 9, 3}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, + {2, UPB_SIZE(12, 24), 2, 0, 12, 1}, + {3, UPB_SIZE(36, 72), 0, 0, 12, 3}, {4, UPB_SIZE(40, 80), 0, 0, 11, 3}, {5, UPB_SIZE(44, 88), 0, 1, 11, 3}, {6, UPB_SIZE(48, 96), 0, 4, 11, 3}, @@ -47,7 +47,7 @@ static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] {9, UPB_SIZE(32, 64), 5, 5, 11, 1}, {10, UPB_SIZE(56, 112), 0, 0, 5, 3}, {11, UPB_SIZE(60, 120), 0, 0, 5, 3}, - {12, UPB_SIZE(20, 40), 3, 0, 9, 1}, + {12, UPB_SIZE(20, 40), 3, 0, 12, 1}, }; const upb_msglayout google_protobuf_FileDescriptorProto_msginit = { @@ -67,7 +67,7 @@ static const upb_msglayout *const google_protobuf_DescriptorProto_submsgs[8] = { }; static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(16, 32), 0, 4, 11, 3}, {3, UPB_SIZE(20, 40), 0, 0, 11, 3}, {4, UPB_SIZE(24, 48), 0, 3, 11, 3}, @@ -76,7 +76,7 @@ static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { {7, UPB_SIZE(12, 24), 2, 5, 11, 1}, {8, UPB_SIZE(36, 72), 0, 6, 11, 3}, {9, UPB_SIZE(40, 80), 0, 2, 11, 3}, - {10, UPB_SIZE(44, 88), 0, 0, 9, 3}, + {10, UPB_SIZE(44, 88), 0, 0, 12, 3}, }; const upb_msglayout google_protobuf_DescriptorProto_msginit = { @@ -131,16 +131,16 @@ static const upb_msglayout *const google_protobuf_FieldDescriptorProto_submsgs[1 }; static const upb_msglayout_field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(36, 40), 6, 0, 9, 1}, - {2, UPB_SIZE(44, 56), 7, 0, 9, 1}, + {1, UPB_SIZE(36, 40), 6, 0, 12, 1}, + {2, UPB_SIZE(44, 56), 7, 0, 12, 1}, {3, UPB_SIZE(24, 24), 3, 0, 5, 1}, {4, UPB_SIZE(8, 8), 1, 0, 14, 1}, {5, UPB_SIZE(16, 16), 2, 0, 14, 1}, - {6, UPB_SIZE(52, 72), 8, 0, 9, 1}, - {7, UPB_SIZE(60, 88), 9, 0, 9, 1}, + {6, UPB_SIZE(52, 72), 8, 0, 12, 1}, + {7, UPB_SIZE(60, 88), 9, 0, 12, 1}, {8, UPB_SIZE(76, 120), 11, 0, 11, 1}, {9, UPB_SIZE(28, 28), 4, 0, 5, 1}, - {10, UPB_SIZE(68, 104), 10, 0, 9, 1}, + {10, UPB_SIZE(68, 104), 10, 0, 12, 1}, {17, UPB_SIZE(32, 32), 5, 0, 8, 1}, }; @@ -155,7 +155,7 @@ static const upb_msglayout *const google_protobuf_OneofDescriptorProto_submsgs[1 }; static const upb_msglayout_field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(12, 24), 2, 0, 11, 1}, }; @@ -172,11 +172,11 @@ static const upb_msglayout *const google_protobuf_EnumDescriptorProto_submsgs[3] }; static const upb_msglayout_field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(16, 32), 0, 2, 11, 3}, {3, UPB_SIZE(12, 24), 2, 1, 11, 1}, {4, UPB_SIZE(20, 40), 0, 0, 11, 3}, - {5, UPB_SIZE(24, 48), 0, 0, 9, 3}, + {5, UPB_SIZE(24, 48), 0, 0, 12, 3}, }; const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = { @@ -201,7 +201,7 @@ static const upb_msglayout *const google_protobuf_EnumValueDescriptorProto_subms }; static const upb_msglayout_field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 2, 0, 9, 1}, + {1, UPB_SIZE(8, 8), 2, 0, 12, 1}, {2, UPB_SIZE(4, 4), 1, 0, 5, 1}, {3, UPB_SIZE(16, 24), 3, 0, 11, 1}, }; @@ -218,7 +218,7 @@ static const upb_msglayout *const google_protobuf_ServiceDescriptorProto_submsgs }; static const upb_msglayout_field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(16, 32), 0, 0, 11, 3}, {3, UPB_SIZE(12, 24), 2, 1, 11, 1}, }; @@ -234,9 +234,9 @@ static const upb_msglayout *const google_protobuf_MethodDescriptorProto_submsgs[ }; static const upb_msglayout_field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 3, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 4, 0, 9, 1}, - {3, UPB_SIZE(20, 40), 5, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 3, 0, 12, 1}, + {2, UPB_SIZE(12, 24), 4, 0, 12, 1}, + {3, UPB_SIZE(20, 40), 5, 0, 12, 1}, {4, UPB_SIZE(28, 56), 6, 0, 11, 1}, {5, UPB_SIZE(1, 1), 1, 0, 8, 1}, {6, UPB_SIZE(2, 2), 2, 0, 8, 1}, @@ -253,11 +253,11 @@ static const upb_msglayout *const google_protobuf_FileOptions_submsgs[1] = { }; static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(28, 32), 11, 0, 9, 1}, - {8, UPB_SIZE(36, 48), 12, 0, 9, 1}, + {1, UPB_SIZE(28, 32), 11, 0, 12, 1}, + {8, UPB_SIZE(36, 48), 12, 0, 12, 1}, {9, UPB_SIZE(8, 8), 1, 0, 14, 1}, {10, UPB_SIZE(16, 16), 2, 0, 8, 1}, - {11, UPB_SIZE(44, 64), 13, 0, 9, 1}, + {11, UPB_SIZE(44, 64), 13, 0, 12, 1}, {16, UPB_SIZE(17, 17), 3, 0, 8, 1}, {17, UPB_SIZE(18, 18), 4, 0, 8, 1}, {18, UPB_SIZE(19, 19), 5, 0, 8, 1}, @@ -265,14 +265,14 @@ static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { {23, UPB_SIZE(21, 21), 7, 0, 8, 1}, {27, UPB_SIZE(22, 22), 8, 0, 8, 1}, {31, UPB_SIZE(23, 23), 9, 0, 8, 1}, - {36, UPB_SIZE(52, 80), 14, 0, 9, 1}, - {37, UPB_SIZE(60, 96), 15, 0, 9, 1}, - {39, UPB_SIZE(68, 112), 16, 0, 9, 1}, - {40, UPB_SIZE(76, 128), 17, 0, 9, 1}, - {41, UPB_SIZE(84, 144), 18, 0, 9, 1}, + {36, UPB_SIZE(52, 80), 14, 0, 12, 1}, + {37, UPB_SIZE(60, 96), 15, 0, 12, 1}, + {39, UPB_SIZE(68, 112), 16, 0, 12, 1}, + {40, UPB_SIZE(76, 128), 17, 0, 12, 1}, + {41, UPB_SIZE(84, 144), 18, 0, 12, 1}, {42, UPB_SIZE(24, 24), 10, 0, 8, 1}, - {44, UPB_SIZE(92, 160), 19, 0, 9, 1}, - {45, UPB_SIZE(100, 176), 20, 0, 9, 1}, + {44, UPB_SIZE(92, 160), 19, 0, 12, 1}, + {45, UPB_SIZE(100, 176), 20, 0, 12, 1}, {999, UPB_SIZE(108, 192), 0, 0, 11, 3}, }; @@ -402,12 +402,12 @@ static const upb_msglayout *const google_protobuf_UninterpretedOption_submsgs[1] static const upb_msglayout_field google_protobuf_UninterpretedOption__fields[7] = { {2, UPB_SIZE(56, 80), 0, 0, 11, 3}, - {3, UPB_SIZE(32, 32), 4, 0, 9, 1}, + {3, UPB_SIZE(32, 32), 4, 0, 12, 1}, {4, UPB_SIZE(8, 8), 1, 0, 4, 1}, {5, UPB_SIZE(16, 16), 2, 0, 3, 1}, {6, UPB_SIZE(24, 24), 3, 0, 1, 1}, {7, UPB_SIZE(40, 48), 5, 0, 12, 1}, - {8, UPB_SIZE(48, 64), 6, 0, 9, 1}, + {8, UPB_SIZE(48, 64), 6, 0, 12, 1}, }; const upb_msglayout google_protobuf_UninterpretedOption_msginit = { @@ -417,7 +417,7 @@ const upb_msglayout google_protobuf_UninterpretedOption_msginit = { }; static const upb_msglayout_field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 2, 0, 9, 2}, + {1, UPB_SIZE(4, 8), 2, 0, 12, 2}, {2, UPB_SIZE(1, 1), 1, 0, 8, 2}, }; @@ -444,9 +444,9 @@ const upb_msglayout google_protobuf_SourceCodeInfo_msginit = { static const upb_msglayout_field google_protobuf_SourceCodeInfo_Location__fields[5] = { {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_LABEL_PACKED}, {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_LABEL_PACKED}, - {3, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {4, UPB_SIZE(12, 24), 2, 0, 9, 1}, - {6, UPB_SIZE(28, 56), 0, 0, 9, 3}, + {3, UPB_SIZE(4, 8), 1, 0, 12, 1}, + {4, UPB_SIZE(12, 24), 2, 0, 12, 1}, + {6, UPB_SIZE(28, 56), 0, 0, 12, 3}, }; const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = { @@ -471,7 +471,7 @@ const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = { static const upb_msglayout_field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_LABEL_PACKED}, - {2, UPB_SIZE(12, 16), 3, 0, 9, 1}, + {2, UPB_SIZE(12, 16), 3, 0, 12, 1}, {3, UPB_SIZE(4, 4), 1, 0, 5, 1}, {4, UPB_SIZE(8, 8), 2, 0, 5, 1}, }; diff --git a/src/core/ext/upb-generated/google/protobuf/struct.upb.h b/src/core/ext/upb-generated/google/protobuf/struct.upb.h index 962431ecf48..b25201d3234 100644 --- a/src/core/ext/upb-generated/google/protobuf/struct.upb.h +++ b/src/core/ext/upb-generated/google/protobuf/struct.upb.h @@ -105,7 +105,7 @@ typedef enum { UPB_INLINE google_protobuf_Value_kind_oneofcases google_protobuf_Value_kind_case(const google_protobuf_Value* msg) { return (google_protobuf_Value_kind_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(8, 16), int32_t); } UPB_INLINE bool google_protobuf_Value_has_null_value(const google_protobuf_Value *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 1; } -UPB_INLINE int32_t google_protobuf_Value_null_value(const google_protobuf_Value *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, google_protobuf_NULL_VALUE); } +UPB_INLINE int32_t google_protobuf_Value_null_value(const google_protobuf_Value *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, 0); } UPB_INLINE bool google_protobuf_Value_has_number_value(const google_protobuf_Value *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 2; } UPB_INLINE double google_protobuf_Value_number_value(const google_protobuf_Value *msg) { return UPB_READ_ONEOF(msg, double, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 2, 0); } UPB_INLINE bool google_protobuf_Value_has_string_value(const google_protobuf_Value *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 3; } diff --git a/src/core/ext/upb-generated/validate/validate.upb.c b/src/core/ext/upb-generated/validate/validate.upb.c index 1d6ab9bca75..63c324368d7 100644 --- a/src/core/ext/upb-generated/validate/validate.upb.c +++ b/src/core/ext/upb-generated/validate/validate.upb.c @@ -274,17 +274,17 @@ const upb_msglayout validate_BoolRules_msginit = { }; static const upb_msglayout_field validate_StringRules__fields[25] = { - {1, UPB_SIZE(60, 64), 8, 0, 9, 1}, + {1, UPB_SIZE(60, 64), 8, 0, 12, 1}, {2, UPB_SIZE(8, 8), 1, 0, 4, 1}, {3, UPB_SIZE(16, 16), 2, 0, 4, 1}, {4, UPB_SIZE(24, 24), 3, 0, 4, 1}, {5, UPB_SIZE(32, 32), 4, 0, 4, 1}, - {6, UPB_SIZE(68, 80), 9, 0, 9, 1}, - {7, UPB_SIZE(76, 96), 10, 0, 9, 1}, - {8, UPB_SIZE(84, 112), 11, 0, 9, 1}, - {9, UPB_SIZE(92, 128), 12, 0, 9, 1}, - {10, UPB_SIZE(108, 160), 0, 0, 9, 3}, - {11, UPB_SIZE(112, 168), 0, 0, 9, 3}, + {6, UPB_SIZE(68, 80), 9, 0, 12, 1}, + {7, UPB_SIZE(76, 96), 10, 0, 12, 1}, + {8, UPB_SIZE(84, 112), 11, 0, 12, 1}, + {9, UPB_SIZE(92, 128), 12, 0, 12, 1}, + {10, UPB_SIZE(108, 160), 0, 0, 12, 3}, + {11, UPB_SIZE(112, 168), 0, 0, 12, 3}, {12, UPB_SIZE(120, 176), UPB_SIZE(-129, -185), 0, 8, 1}, {13, UPB_SIZE(120, 176), UPB_SIZE(-129, -185), 0, 8, 1}, {14, UPB_SIZE(120, 176), UPB_SIZE(-129, -185), 0, 8, 1}, @@ -296,7 +296,7 @@ static const upb_msglayout_field validate_StringRules__fields[25] = { {20, UPB_SIZE(48, 48), 6, 0, 4, 1}, {21, UPB_SIZE(120, 176), UPB_SIZE(-129, -185), 0, 8, 1}, {22, UPB_SIZE(120, 176), UPB_SIZE(-129, -185), 0, 8, 1}, - {23, UPB_SIZE(100, 144), 13, 0, 9, 1}, + {23, UPB_SIZE(100, 144), 13, 0, 12, 1}, {24, UPB_SIZE(120, 176), UPB_SIZE(-129, -185), 0, 14, 1}, {25, UPB_SIZE(56, 56), 7, 0, 8, 1}, }; @@ -311,7 +311,7 @@ static const upb_msglayout_field validate_BytesRules__fields[13] = { {1, UPB_SIZE(32, 32), 4, 0, 12, 1}, {2, UPB_SIZE(8, 8), 1, 0, 4, 1}, {3, UPB_SIZE(16, 16), 2, 0, 4, 1}, - {4, UPB_SIZE(40, 48), 5, 0, 9, 1}, + {4, UPB_SIZE(40, 48), 5, 0, 12, 1}, {5, UPB_SIZE(48, 64), 6, 0, 12, 1}, {6, UPB_SIZE(56, 80), 7, 0, 12, 1}, {7, UPB_SIZE(64, 96), 8, 0, 12, 1}, @@ -390,8 +390,8 @@ const upb_msglayout validate_MapRules_msginit = { static const upb_msglayout_field validate_AnyRules__fields[3] = { {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {2, UPB_SIZE(4, 8), 0, 0, 9, 3}, - {3, UPB_SIZE(8, 16), 0, 0, 9, 3}, + {2, UPB_SIZE(4, 8), 0, 0, 12, 3}, + {3, UPB_SIZE(8, 16), 0, 0, 12, 3}, }; const upb_msglayout validate_AnyRules_msginit = { diff --git a/src/core/ext/upb-generated/validate/validate.upb.h b/src/core/ext/upb-generated/validate/validate.upb.h index 7fde5b75a4b..c29b4ec589b 100644 --- a/src/core/ext/upb-generated/validate/validate.upb.h +++ b/src/core/ext/upb-generated/validate/validate.upb.h @@ -1363,7 +1363,7 @@ UPB_INLINE bool validate_StringRules_uuid(const validate_StringRules *msg) { ret UPB_INLINE bool validate_StringRules_has_not_contains(const validate_StringRules *msg) { return _upb_hasbit(msg, 13); } UPB_INLINE upb_strview validate_StringRules_not_contains(const validate_StringRules *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(100, 144), upb_strview); } UPB_INLINE bool validate_StringRules_has_well_known_regex(const validate_StringRules *msg) { return _upb_getoneofcase(msg, UPB_SIZE(128, 184)) == 24; } -UPB_INLINE int32_t validate_StringRules_well_known_regex(const validate_StringRules *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(120, 176), UPB_SIZE(128, 184), 24, validate_UNKNOWN); } +UPB_INLINE int32_t validate_StringRules_well_known_regex(const validate_StringRules *msg) { return UPB_READ_ONEOF(msg, int32_t, UPB_SIZE(120, 176), UPB_SIZE(128, 184), 24, 0); } UPB_INLINE bool validate_StringRules_has_strict(const validate_StringRules *msg) { return _upb_hasbit(msg, 7); } UPB_INLINE bool validate_StringRules_strict(const validate_StringRules *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 56), bool); } diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index a79a0147be3..64748fd854e 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -283,7 +283,7 @@ void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) { // ServerNode // -ServerNode::ServerNode(grpc_server* /*server*/, size_t channel_tracer_max_nodes) +ServerNode::ServerNode(size_t channel_tracer_max_nodes) : BaseNode(EntityType::kServer, ""), trace_(channel_tracer_max_nodes) {} ServerNode::~ServerNode() {} diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 63502030966..9a19beccbaf 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -238,7 +238,7 @@ class ChannelNode : public BaseNode { // Handles channelz bookkeeping for servers class ServerNode : public BaseNode { public: - ServerNode(grpc_server* server, size_t channel_tracer_max_nodes); + explicit ServerNode(size_t channel_tracer_max_nodes); ~ServerNode() override; diff --git a/src/core/lib/iomgr/endpoint.cc b/src/core/lib/iomgr/endpoint.cc index bb07fe79608..8954f9dc066 100644 --- a/src/core/lib/iomgr/endpoint.cc +++ b/src/core/lib/iomgr/endpoint.cc @@ -52,10 +52,14 @@ void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) { void grpc_endpoint_destroy(grpc_endpoint* ep) { ep->vtable->destroy(ep); } -char* grpc_endpoint_get_peer(grpc_endpoint* ep) { +absl::string_view grpc_endpoint_get_peer(grpc_endpoint* ep) { return ep->vtable->get_peer(ep); } +absl::string_view grpc_endpoint_get_local_address(grpc_endpoint* ep) { + return ep->vtable->get_local_address(ep); +} + int grpc_endpoint_get_fd(grpc_endpoint* ep) { return ep->vtable->get_fd(ep); } grpc_resource_user* grpc_endpoint_get_resource_user(grpc_endpoint* ep) { diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h index 932e7e15b9a..43c64f7ee2e 100644 --- a/src/core/lib/iomgr/endpoint.h +++ b/src/core/lib/iomgr/endpoint.h @@ -21,6 +21,8 @@ #include +#include "absl/strings/string_view.h" + #include #include #include @@ -46,7 +48,8 @@ struct grpc_endpoint_vtable { void (*shutdown)(grpc_endpoint* ep, grpc_error* why); void (*destroy)(grpc_endpoint* ep); grpc_resource_user* (*get_resource_user)(grpc_endpoint* ep); - char* (*get_peer)(grpc_endpoint* ep); + absl::string_view (*get_peer)(grpc_endpoint* ep); + absl::string_view (*get_local_address)(grpc_endpoint* ep); int (*get_fd)(grpc_endpoint* ep); bool (*can_track_err)(grpc_endpoint* ep); }; @@ -59,7 +62,9 @@ struct grpc_endpoint_vtable { void grpc_endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* slices, grpc_closure* cb, bool urgent); -char* grpc_endpoint_get_peer(grpc_endpoint* ep); +absl::string_view grpc_endpoint_get_peer(grpc_endpoint* ep); + +absl::string_view grpc_endpoint_get_local_address(grpc_endpoint* ep); /* Get the file descriptor used by \a ep. Return -1 if \a ep is not using an fd. */ diff --git a/src/core/lib/iomgr/endpoint_cfstream.cc b/src/core/lib/iomgr/endpoint_cfstream.cc index f9ee1c917bc..1751b4fcd43 100644 --- a/src/core/lib/iomgr/endpoint_cfstream.cc +++ b/src/core/lib/iomgr/endpoint_cfstream.cc @@ -34,6 +34,8 @@ #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/error_cfstream.h" +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" @@ -55,7 +57,8 @@ struct CFStreamEndpoint { grpc_closure read_action; grpc_closure write_action; - char* peer_string; + std::string peer_string; + std::string local_address; grpc_resource_user* resource_user; grpc_resource_user_slice_allocator slice_allocator; }; @@ -64,8 +67,7 @@ static void CFStreamFree(CFStreamEndpoint* ep) { CFRelease(ep->read_stream); CFRelease(ep->write_stream); CFSTREAM_HANDLE_UNREF(ep->stream_sync, "free"); - gpr_free(ep->peer_string); - gpr_free(ep); + delete ep; } #ifndef NDEBUG @@ -110,7 +112,7 @@ static grpc_error* CFStreamAnnotateError(grpc_error* src_error, grpc_error_set_int(src_error, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE), GRPC_ERROR_STR_TARGET_ADDRESS, - grpc_slice_from_copied_string(ep->peer_string)); + grpc_slice_from_copied_string(ep->peer_string.c_str())); } static void CallReadCb(CFStreamEndpoint* ep, grpc_error* error) { @@ -124,7 +126,8 @@ static void CallReadCb(CFStreamEndpoint* ep, grpc_error* error) { for (i = 0; i < ep->read_slices->count; i++) { char* dump = grpc_dump_slice(ep->read_slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", ep, ep->peer_string, dump); + gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", ep, ep->peer_string.c_str(), + dump); gpr_free(dump); } } @@ -230,7 +233,8 @@ static void WriteAction(void* arg, grpc_error* error) { if (grpc_tcp_trace.enabled()) { grpc_slice trace_slice = grpc_slice_sub(slice, 0, write_size); char* dump = grpc_dump_slice(trace_slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", ep, ep->peer_string, dump); + gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", ep, ep->peer_string.c_str(), + dump); gpr_free(dump); grpc_slice_unref_internal(trace_slice); } @@ -309,9 +313,14 @@ grpc_resource_user* CFStreamGetResourceUser(grpc_endpoint* ep) { return ep_impl->resource_user; } -char* CFStreamGetPeer(grpc_endpoint* ep) { +absl::string_view CFStreamGetPeer(grpc_endpoint* ep) { CFStreamEndpoint* ep_impl = reinterpret_cast(ep); - return gpr_strdup(ep_impl->peer_string); + return ep_impl->peer_string; +} + +absl::string_view CFStreamGetLocalAddress(grpc_endpoint* ep) { + CFStreamEndpoint* ep_impl = reinterpret_cast(ep); + return ep_impl->local_address; } int CFStreamGetFD(grpc_endpoint* ep) { return 0; } @@ -332,6 +341,7 @@ static const grpc_endpoint_vtable vtable = {CFStreamRead, CFStreamDestroy, CFStreamGetResourceUser, CFStreamGetPeer, + CFStreamGetLocalAddress, CFStreamGetFD, CFStreamCanTrackErr}; @@ -339,8 +349,7 @@ grpc_endpoint* grpc_cfstream_endpoint_create( CFReadStreamRef read_stream, CFWriteStreamRef write_stream, const char* peer_string, grpc_resource_quota* resource_quota, CFStreamHandle* stream_sync) { - CFStreamEndpoint* ep_impl = - static_cast(gpr_malloc(sizeof(CFStreamEndpoint))); + CFStreamEndpoint* ep_impl = new CFStreamEndpoint; if (grpc_tcp_trace.enabled()) { gpr_log(GPR_DEBUG, "CFStream endpoint:%p create readStream:%p writeStream: %p", @@ -355,7 +364,19 @@ grpc_endpoint* grpc_cfstream_endpoint_create( ep_impl->stream_sync = stream_sync; CFSTREAM_HANDLE_REF(ep_impl->stream_sync, "endpoint create"); - ep_impl->peer_string = gpr_strdup(peer_string); + ep_impl->peer_string = peer_string; + const int* native_handle = + reinterpret_cast(CFReadStreamCopyProperty( + ep_impl->read_stream, kCFStreamPropertySocketNativeHandle)); + grpc_resolved_address resolved_local_addr; + resolved_local_addr.len = sizeof(resolved_local_addr.addr); + if (getsockname(*native_handle, + reinterpret_cast(resolved_local_addr.addr), + &resolved_local_addr.len) < 0) { + ep_impl->local_address = ""; + } else { + ep_impl->local_address = grpc_sockaddr_to_uri(&resolved_local_addr); + } ep_impl->read_cb = nil; ep_impl->write_cb = nil; ep_impl->read_slices = nil; diff --git a/src/core/lib/iomgr/tcp_custom.cc b/src/core/lib/iomgr/tcp_custom.cc index 6cf36f7d669..06763f69257 100644 --- a/src/core/lib/iomgr/tcp_custom.cc +++ b/src/core/lib/iomgr/tcp_custom.cc @@ -32,6 +32,7 @@ #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/iomgr_custom.h" #include "src/core/lib/iomgr/resource_quota.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_custom.h" #include "src/core/lib/iomgr/tcp_server.h" @@ -57,24 +58,24 @@ struct custom_tcp_endpoint { gpr_refcount refcount; grpc_custom_socket* socket; - grpc_closure* read_cb; - grpc_closure* write_cb; + grpc_closure* read_cb = nullptr; + grpc_closure* write_cb = nullptr; - grpc_slice_buffer* read_slices; - grpc_slice_buffer* write_slices; + grpc_slice_buffer* read_slices = nullptr; + grpc_slice_buffer* write_slices = nullptr; grpc_resource_user* resource_user; grpc_resource_user_slice_allocator slice_allocator; bool shutting_down; - char* peer_string; + std::string peer_string; + std::string local_address; }; static void tcp_free(grpc_custom_socket* s) { custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)s->endpoint; grpc_resource_user_unref(tcp->resource_user); - gpr_free(tcp->peer_string); - gpr_free(tcp); + delete tcp; s->refs--; if (s->refs == 0) { grpc_custom_socket_vtable->destroy(s); @@ -132,7 +133,8 @@ static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) { for (i = 0; i < tcp->read_slices->count; i++) { char* dump = grpc_dump_slice(tcp->read_slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump); + gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, tcp->peer_string.c_str(), + dump); gpr_free(dump); } } @@ -233,8 +235,8 @@ static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices, for (j = 0; j < write_slices->count; j++) { char* data = grpc_dump_slice(write_slices->slices[j], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp->socket, tcp->peer_string, - data); + gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp->socket, + tcp->peer_string.c_str(), data); gpr_free(data); } } @@ -317,9 +319,14 @@ static void endpoint_destroy(grpc_endpoint* ep) { grpc_custom_socket_vtable->close(tcp->socket, custom_close_callback); } -static char* endpoint_get_peer(grpc_endpoint* ep) { +static absl::string_view endpoint_get_peer(grpc_endpoint* ep) { custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; - return gpr_strdup(tcp->peer_string); + return tcp->peer_string; +} + +static absl::string_view endpoint_get_local_address(grpc_endpoint* ep) { + custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; + return tcp->local_address; } static grpc_resource_user* endpoint_get_resource_user(grpc_endpoint* ep) { @@ -340,27 +347,36 @@ static grpc_endpoint_vtable vtable = {endpoint_read, endpoint_destroy, endpoint_get_resource_user, endpoint_get_peer, + endpoint_get_local_address, endpoint_get_fd, endpoint_can_track_err}; grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket, grpc_resource_quota* resource_quota, const char* peer_string) { - custom_tcp_endpoint* tcp = - (custom_tcp_endpoint*)gpr_malloc(sizeof(custom_tcp_endpoint)); + custom_tcp_endpoint* tcp = new custom_tcp_endpoint; grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ExecCtx exec_ctx; if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "Creating TCP endpoint %p", socket); } - memset(tcp, 0, sizeof(custom_tcp_endpoint)); socket->refs++; socket->endpoint = (grpc_endpoint*)tcp; tcp->socket = socket; tcp->base.vtable = &vtable; gpr_ref_init(&tcp->refcount, 1); - tcp->peer_string = gpr_strdup(peer_string); + tcp->peer_string = peer_string; + grpc_resolved_address resolved_local_addr; + resolved_local_addr.len = sizeof(resolved_local_addr.addr); + if (grpc_custom_socket_vtable->getsockname( + socket, reinterpret_cast(resolved_local_addr.addr), + reinterpret_cast(&resolved_local_addr.len)) != + GRPC_ERROR_NONE) { + tcp->local_address = ""; + } else { + tcp->local_address = grpc_sockaddr_to_uri(&resolved_local_addr); + } tcp->shutting_down = false; tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); grpc_resource_user_slice_allocator_init( diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index bd0562bfa74..3c5703460fc 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -54,6 +54,7 @@ #include "src/core/lib/iomgr/buffer_list.h" #include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/socket_utils_posix.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/slice_internal.h" @@ -351,6 +352,8 @@ using grpc_core::TcpZerocopySendRecord; namespace { struct grpc_tcp { + grpc_tcp(int max_sends, size_t send_bytes_threshold) + : tcp_zerocopy_send_ctx(max_sends, send_bytes_threshold) {} grpc_endpoint base; grpc_fd* em_fd; int fd; @@ -385,7 +388,8 @@ struct grpc_tcp { grpc_closure write_done_closure; grpc_closure error_closure; - char* peer_string; + std::string peer_string; + std::string local_address; grpc_resource_user* resource_user; grpc_resource_user_slice_allocator slice_allocator; @@ -605,7 +609,7 @@ static grpc_error* tcp_annotate_error(grpc_error* src_error, grpc_tcp* tcp) { * choose to retry. */ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE), GRPC_ERROR_STR_TARGET_ADDRESS, - grpc_slice_from_copied_string(tcp->peer_string)); + grpc_slice_from_copied_string(tcp->peer_string.c_str())); } static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error); @@ -623,7 +627,6 @@ static void tcp_free(grpc_tcp* tcp) { "tcp_unref_orphan"); grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer); grpc_resource_user_unref(tcp->resource_user); - gpr_free(tcp->peer_string); /* The lock is not really necessary here, since all refs have been released */ gpr_mu_lock(&tcp->tb_mu); grpc_core::TracedBuffer::Shutdown( @@ -632,8 +635,7 @@ static void tcp_free(grpc_tcp* tcp) { gpr_mu_unlock(&tcp->tb_mu); tcp->outgoing_buffer_arg = nullptr; gpr_mu_destroy(&tcp->tb_mu); - tcp->tcp_zerocopy_send_ctx.~TcpZerocopySendCtx(); - gpr_free(tcp); + delete tcp; } #ifndef NDEBUG @@ -680,7 +682,8 @@ static void call_read_cb(grpc_tcp* tcp, grpc_error* error) { gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg); size_t i; const char* str = grpc_error_string(error); - gpr_log(GPR_INFO, "READ %p (peer=%s) error=%s", tcp, tcp->peer_string, str); + gpr_log(GPR_INFO, "READ %p (peer=%s) error=%s", tcp, + tcp->peer_string.c_str(), str); if (gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) { for (i = 0; i < tcp->incoming_buffer->count; i++) { @@ -1563,7 +1566,7 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf, size_t i; for (i = 0; i < buf->count; i++) { - gpr_log(GPR_INFO, "WRITE %p (peer=%s)", tcp, tcp->peer_string); + gpr_log(GPR_INFO, "WRITE %p (peer=%s)", tcp, tcp->peer_string.c_str()); if (gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) { char* data = grpc_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -1637,9 +1640,14 @@ static void tcp_delete_from_pollset_set(grpc_endpoint* ep, grpc_pollset_set_del_fd(pollset_set, tcp->em_fd); } -static char* tcp_get_peer(grpc_endpoint* ep) { +static absl::string_view tcp_get_peer(grpc_endpoint* ep) { grpc_tcp* tcp = reinterpret_cast(ep); - return gpr_strdup(tcp->peer_string); + return tcp->peer_string; +} + +static absl::string_view tcp_get_local_address(grpc_endpoint* ep) { + grpc_tcp* tcp = reinterpret_cast(ep); + return tcp->local_address; } static int tcp_get_fd(grpc_endpoint* ep) { @@ -1677,6 +1685,7 @@ static const grpc_endpoint_vtable vtable = {tcp_read, tcp_destroy, tcp_get_resource_user, tcp_get_peer, + tcp_get_local_address, tcp_get_fd, tcp_can_track_err}; @@ -1745,10 +1754,21 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd, tcp_read_chunk_size = GPR_CLAMP(tcp_read_chunk_size, tcp_min_read_chunk_size, tcp_max_read_chunk_size); - grpc_tcp* tcp = static_cast(gpr_malloc(sizeof(grpc_tcp))); + grpc_tcp* tcp = new grpc_tcp(tcp_tx_zerocopy_max_simult_sends, + tcp_tx_zerocopy_send_bytes_thresh); tcp->base.vtable = &vtable; - tcp->peer_string = gpr_strdup(peer_string); + tcp->peer_string = peer_string; tcp->fd = grpc_fd_wrapped_fd(em_fd); + grpc_resolved_address resolved_local_addr; + memset(&resolved_local_addr, 0, sizeof(resolved_local_addr)); + resolved_local_addr.len = sizeof(resolved_local_addr.addr); + if (getsockname(tcp->fd, + reinterpret_cast(resolved_local_addr.addr), + &resolved_local_addr.len) < 0) { + tcp->local_address = ""; + } else { + tcp->local_address = grpc_sockaddr_to_uri(&resolved_local_addr); + } tcp->read_cb = nullptr; tcp->write_cb = nullptr; tcp->current_zerocopy_send = nullptr; @@ -1765,8 +1785,6 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd, tcp->socket_ts_enabled = false; tcp->ts_capable = true; tcp->outgoing_buffer_arg = nullptr; - new (&tcp->tcp_zerocopy_send_ctx) TcpZerocopySendCtx( - tcp_tx_zerocopy_max_simult_sends, tcp_tx_zerocopy_send_bytes_thresh); if (tcp_tx_zerocopy_enabled && !tcp->tcp_zerocopy_send_ctx.memory_limited()) { #ifdef GRPC_LINUX_ERRQUEUE const int enable = 1; diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index ab5a2a21e15..d28a54ccf43 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -125,17 +125,17 @@ typedef struct grpc_tcp { int shutting_down; grpc_error* shutdown_error; - char* peer_string; + std::string peer_string; + std::string local_address; } grpc_tcp; static void tcp_free(grpc_tcp* tcp) { grpc_winsocket_destroy(tcp->socket); gpr_mu_destroy(&tcp->mu); - gpr_free(tcp->peer_string); grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer); grpc_resource_user_unref(tcp->resource_user); if (tcp->shutting_down) GRPC_ERROR_UNREF(tcp->shutdown_error); - gpr_free(tcp); + delete tcp; } #ifndef NDEBUG @@ -213,8 +213,8 @@ static void on_read(void* tcpp, grpc_error* error) { for (i = 0; i < tcp->read_slices->count; i++) { char* dump = grpc_dump_slice(tcp->read_slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, tcp->peer_string, - dump); + gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, + tcp->peer_string.c_str(), dump); gpr_free(dump); } } @@ -361,7 +361,8 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices, for (i = 0; i < slices->count; i++) { char* data = grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data); + gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string.c_str(), + data); gpr_free(data); } } @@ -475,9 +476,14 @@ static void win_destroy(grpc_endpoint* ep) { TCP_UNREF(tcp, "destroy"); } -static char* win_get_peer(grpc_endpoint* ep) { +static absl::string_view win_get_peer(grpc_endpoint* ep) { grpc_tcp* tcp = (grpc_tcp*)ep; - return gpr_strdup(tcp->peer_string); + return tcp->peer_string; +} + +static absl::string_view win_get_local_address(grpc_endpoint* ep) { + grpc_tcp* tcp = (grpc_tcp*)ep; + return tcp->local_address; } static grpc_resource_user* win_get_resource_user(grpc_endpoint* ep) { @@ -498,6 +504,7 @@ static grpc_endpoint_vtable vtable = {win_read, win_destroy, win_get_resource_user, win_get_peer, + win_get_local_address, win_get_fd, win_can_track_err}; @@ -514,7 +521,7 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket, } } } - grpc_tcp* tcp = (grpc_tcp*)gpr_malloc(sizeof(grpc_tcp)); + grpc_tcp* tcp = new grpc_tcp; memset(tcp, 0, sizeof(grpc_tcp)); tcp->base.vtable = &vtable; tcp->socket = socket; @@ -522,7 +529,16 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket, gpr_ref_init(&tcp->refcount, 1); GRPC_CLOSURE_INIT(&tcp->on_read, on_read, tcp, grpc_schedule_on_exec_ctx); GRPC_CLOSURE_INIT(&tcp->on_write, on_write, tcp, grpc_schedule_on_exec_ctx); - tcp->peer_string = gpr_strdup(peer_string); + grpc_resolved_address resolved_local_addr; + resolved_local_addr.len = sizeof(resolved_local_addr.addr); + if (getsockname(tcp->socket->socket, + reinterpret_cast(resolved_local_addr.addr), + &resolved_local_addr.len) < 0) { + tcp->local_address = ""; + } else { + tcp->local_address = grpc_sockaddr_to_uri(&resolved_local_addr); + } + tcp->peer_string = peer_string; grpc_slice_buffer_init(&tcp->last_read_buffer); tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); grpc_resource_quota_unref_internal(resource_quota); diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc index eaa8c7da704..f42aaeae36b 100644 --- a/src/core/lib/security/transport/secure_endpoint.cc +++ b/src/core/lib/security/transport/secure_endpoint.cc @@ -401,11 +401,16 @@ static void endpoint_delete_from_pollset_set(grpc_endpoint* secure_ep, grpc_endpoint_delete_from_pollset_set(ep->wrapped_ep, pollset_set); } -static char* endpoint_get_peer(grpc_endpoint* secure_ep) { +static absl::string_view endpoint_get_peer(grpc_endpoint* secure_ep) { secure_endpoint* ep = reinterpret_cast(secure_ep); return grpc_endpoint_get_peer(ep->wrapped_ep); } +static absl::string_view endpoint_get_local_address(grpc_endpoint* secure_ep) { + secure_endpoint* ep = reinterpret_cast(secure_ep); + return grpc_endpoint_get_local_address(ep->wrapped_ep); +} + static int endpoint_get_fd(grpc_endpoint* secure_ep) { secure_endpoint* ep = reinterpret_cast(secure_ep); return grpc_endpoint_get_fd(ep->wrapped_ep); @@ -431,6 +436,7 @@ static const grpc_endpoint_vtable vtable = {endpoint_read, endpoint_destroy, endpoint_get_resource_user, endpoint_get_peer, + endpoint_get_local_address, endpoint_get_fd, endpoint_can_track_err}; diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 31f1559d72d..becb23518e2 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -245,7 +245,7 @@ struct grpc_call { struct { int* cancelled; // backpointer to owning server if this is a server side call. - grpc_server* server; + grpc_core::Server* core_server; } server; } final_op; gpr_atm status_error = 0; @@ -374,7 +374,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, } else { GRPC_STATS_INC_SERVER_CALLS_CREATED(); call->final_op.server.cancelled = nullptr; - call->final_op.server.server = args->server; + call->final_op.server.core_server = args->server; GPR_ASSERT(args->add_initial_metadata_count == 0); call->send_extra_metadata_count = 0; } @@ -476,11 +476,11 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, if (channelz_channel != nullptr) { channelz_channel->RecordCallStarted(); } - } else { - grpc_core::channelz::ServerNode* channelz_server = - grpc_server_get_channelz_node(call->final_op.server.server); - if (channelz_server != nullptr) { - channelz_server->RecordCallStarted(); + } else if (call->final_op.server.core_server != nullptr) { + grpc_core::channelz::ServerNode* channelz_node = + call->final_op.server.core_server->channelz_node(); + if (channelz_node != nullptr) { + channelz_node->RecordCallStarted(); } } @@ -759,15 +759,15 @@ static void set_final_status(grpc_call* call, grpc_error* error) { } else { *call->final_op.server.cancelled = error != GRPC_ERROR_NONE || !call->sent_server_trailing_metadata; - grpc_core::channelz::ServerNode* channelz_server = - grpc_server_get_channelz_node(call->final_op.server.server); - if (channelz_server != nullptr) { + grpc_core::channelz::ServerNode* channelz_node = + call->final_op.server.core_server->channelz_node(); + if (channelz_node != nullptr) { if (*call->final_op.server.cancelled || reinterpret_cast( gpr_atm_acq_load(&call->status_error)) != GRPC_ERROR_NONE) { - channelz_server->RecordCallFailed(); + channelz_node->RecordCallFailed(); } else { - channelz_server->RecordCallSucceeded(); + channelz_node->RecordCallSucceeded(); } } GRPC_ERROR_UNREF(error); diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h index a33664af6a9..34d01db9029 100644 --- a/src/core/lib/surface/call.h +++ b/src/core/lib/surface/call.h @@ -25,6 +25,7 @@ #include "src/core/lib/channel/context.h" #include "src/core/lib/gprpp/arena.h" #include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/surface/server.h" #include #include @@ -34,7 +35,7 @@ typedef void (*grpc_ioreq_completion_func)(grpc_call* call, int success, typedef struct grpc_call_create_args { grpc_channel* channel; - grpc_server* server; + grpc_core::Server* server; grpc_call* parent; uint32_t propagation_mask; diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index d8bc4e4dd32..88a69495c01 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -102,7 +102,7 @@ static void register_builtin_channel_init() { GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter, (void*)&grpc_lame_filter); grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, - (void*)&grpc_server_top_filter); + (void*)&grpc_core::Server::kServerTopFilter); } typedef struct grpc_plugin { diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 9b7c2262137..c94551545d1 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -1,20 +1,18 @@ -/* - * - * Copyright 2015-2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ +// +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// #include @@ -28,15 +26,16 @@ #include #include #include +#include #include #include +#include "absl/types/optional.h" + #include #include #include -#include "absl/types/optional.h" - #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channelz.h" #include "src/core/lib/channel/connected_channel.h" @@ -59,28 +58,17 @@ namespace grpc_core { TraceFlag grpc_server_channel_trace(false, "server_channel"); -namespace { - -void server_on_recv_initial_metadata(void* ptr, grpc_error* error); -void server_recv_trailing_metadata_ready(void* user_data, grpc_error* error); - -struct Listener { - explicit Listener(OrphanablePtr l) - : listener(std::move(l)) {} - - OrphanablePtr listener; - grpc_closure destroy_done; -}; - -enum class RequestedCallType { BATCH_CALL, REGISTERED_CALL }; +// +// Server::RequestedCall +// -struct registered_method; +struct Server::RequestedCall { + enum class Type { BATCH_CALL, REGISTERED_CALL }; -struct requested_call { - requested_call(void* tag_arg, grpc_completion_queue* call_cq, - grpc_call** call_arg, grpc_metadata_array* initial_md, - grpc_call_details* details) - : type(RequestedCallType::BATCH_CALL), + RequestedCall(void* tag_arg, grpc_completion_queue* call_cq, + grpc_call** call_arg, grpc_metadata_array* initial_md, + grpc_call_details* details) + : type(Type::BATCH_CALL), tag(tag_arg), cq_bound_to_call(call_cq), call(call_arg), @@ -89,11 +77,11 @@ struct requested_call { data.batch.details = details; } - requested_call(void* tag_arg, grpc_completion_queue* call_cq, - grpc_call** call_arg, grpc_metadata_array* initial_md, - registered_method* rm, gpr_timespec* deadline, - grpc_byte_buffer** optional_payload) - : type(RequestedCallType::REGISTERED_CALL), + RequestedCall(void* tag_arg, grpc_completion_queue* call_cq, + grpc_call** call_arg, grpc_metadata_array* initial_md, + RegisteredMethod* rm, gpr_timespec* deadline, + grpc_byte_buffer** optional_payload) + : type(Type::REGISTERED_CALL), tag(tag_arg), cq_bound_to_call(call_cq), call(call_arg), @@ -104,7 +92,7 @@ struct requested_call { } MultiProducerSingleConsumerQueue::Node mpscq_node; - const RequestedCallType type; + const Type type; void* const tag; grpc_completion_queue* const cq_bound_to_call; grpc_call** const call; @@ -115,66 +103,40 @@ struct requested_call { grpc_call_details* details; } batch; struct { - registered_method* method; + RegisteredMethod* method; gpr_timespec* deadline; grpc_byte_buffer** optional_payload; } registered; } data; }; -struct channel_registered_method { - registered_method* server_registered_method = nullptr; - uint32_t flags; - bool has_host; - ExternallyManagedSlice method; - ExternallyManagedSlice host; -}; - -struct channel_data { - channel_data() = default; - ~channel_data(); - - grpc_server* server = nullptr; - grpc_channel* channel; - size_t cq_idx; - absl::optional::iterator> list_position; - - // registered_methods is a hash-table of the methods and hosts of the - // registered methods. - // TODO(vjpai): Convert this to an STL map type as opposed to a direct bucket - // implementation. (Consider performance impact, hash function to use, etc.) - std::unique_ptr> registered_methods; - uint32_t registered_method_max_probes; - - grpc_closure finish_destroy_channel_closure; - intptr_t channelz_socket_uuid; -}; +// +// Server::RegisteredMethod +// -struct shutdown_tag { - shutdown_tag(void* tag_arg, grpc_completion_queue* cq_arg) - : tag(tag_arg), cq(cq_arg) {} +struct Server::RegisteredMethod { + RegisteredMethod( + const char* method_arg, const char* host_arg, + grpc_server_register_method_payload_handling payload_handling_arg, + uint32_t flags_arg) + : method(method_arg == nullptr ? "" : method_arg), + host(host_arg == nullptr ? "" : host_arg), + payload_handling(payload_handling_arg), + flags(flags_arg) {} - void* const tag; - grpc_completion_queue* const cq; - grpc_cq_completion completion; -}; + ~RegisteredMethod() = default; -enum class CallState { - /* waiting for metadata */ - NOT_STARTED, - /* initial metadata read, not flow controlled in yet */ - PENDING, - /* flow controlled in, on completion queue */ - ACTIVATED, - /* cancelled before being queued */ - ZOMBIED + const std::string method; + const std::string host; + const grpc_server_register_method_payload_handling payload_handling; + const uint32_t flags; + // One request matcher per method. + std::unique_ptr matcher; }; -struct call_data; - -grpc_call_error ValidateServerRequest( - grpc_completion_queue* cq_for_notification, void* tag, - grpc_byte_buffer** optional_payload, registered_method* rm); +// +// Server::RequestMatcherInterface +// // RPCs that come in from the transport must be matched against RPC requests // from the application. An incoming request from the application can be matched @@ -185,7 +147,7 @@ grpc_call_error ValidateServerRequest( // on the request's notification CQ. // // RequestMatcherInterface is the base class to provide this functionality. -class RequestMatcherInterface { +class Server::RequestMatcherInterface { public: virtual ~RequestMatcherInterface() {} @@ -208,7 +170,7 @@ class RequestMatcherInterface { // CQ. If there are pending RPCs waiting to be matched, publish one (match it // and notify the CQ). virtual void RequestCallWithPossiblePublish(size_t request_queue_index, - requested_call* call) = 0; + RequestedCall* call) = 0; // This function is invoked on an incoming RPC, represented by the calld // object. The RequestMatcher will try to match it against an @@ -217,339 +179,21 @@ class RequestMatcherInterface { // is done starting at the start_request_queue_index parameter in a cyclic // order rather than always starting at 0. virtual void MatchOrQueue(size_t start_request_queue_index, - call_data* calld) = 0; + CallData* calld) = 0; // Returns the server associated with this request matcher - virtual grpc_server* server() const = 0; -}; - -struct call_data { - call_data(grpc_call_element* elem, const grpc_call_element_args& args) - : call(grpc_call_from_top_element(elem)), - call_combiner(args.call_combiner) { - GRPC_CLOSURE_INIT(&on_recv_initial_metadata, - server_on_recv_initial_metadata, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready, - server_recv_trailing_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - } - ~call_data() { - GPR_ASSERT(state.Load(grpc_core::MemoryOrder::RELAXED) != - CallState::PENDING); - GRPC_ERROR_UNREF(recv_initial_metadata_error); - if (host_set) { - grpc_slice_unref_internal(host); - } - if (path_set) { - grpc_slice_unref_internal(path); - } - grpc_metadata_array_destroy(&initial_metadata); - grpc_byte_buffer_destroy(payload); - } - - grpc_call* call; - - Atomic state{CallState::NOT_STARTED}; - - bool path_set = false; - bool host_set = false; - grpc_slice path; - grpc_slice host; - grpc_millis deadline = GRPC_MILLIS_INF_FUTURE; - - grpc_completion_queue* cq_new = nullptr; - - grpc_metadata_batch* recv_initial_metadata = nullptr; - uint32_t recv_initial_metadata_flags = 0; - grpc_metadata_array initial_metadata = - grpc_metadata_array(); // Zero-initialize the C struct. - - RequestMatcherInterface* matcher = nullptr; - grpc_byte_buffer* payload = nullptr; - - grpc_closure got_initial_metadata; - grpc_closure on_recv_initial_metadata; - grpc_closure kill_zombie_closure; - grpc_closure* on_done_recv_initial_metadata; - grpc_closure recv_trailing_metadata_ready; - grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE; - grpc_closure* original_recv_trailing_metadata_ready; - grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE; - bool seen_recv_trailing_metadata_ready = false; - - grpc_closure publish; - - CallCombiner* call_combiner; -}; - -struct registered_method { - registered_method( - const char* method_arg, const char* host_arg, - grpc_server_register_method_payload_handling payload_handling_arg, - uint32_t flags_arg) - : method(method_arg == nullptr ? "" : method_arg), - host(host_arg == nullptr ? "" : host_arg), - payload_handling(payload_handling_arg), - flags(flags_arg) {} - - ~registered_method() = default; - - const std::string method; - const std::string host; - const grpc_server_register_method_payload_handling payload_handling; - const uint32_t flags; - /* one request matcher per method */ - std::unique_ptr matcher; -}; - -} // namespace -} // namespace grpc_core - -struct grpc_server { - explicit grpc_server(const grpc_channel_args* args) - : channel_args(grpc_channel_args_copy(args)) { - if (grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_CHANNELZ, - GRPC_ENABLE_CHANNELZ_DEFAULT)) { - size_t channel_tracer_max_memory = grpc_channel_args_find_integer( - args, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, - {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}); - channelz_server = - grpc_core::MakeRefCounted( - this, channel_tracer_max_memory); - channelz_server->AddTraceEvent( - grpc_core::channelz::ChannelTrace::Severity::Info, - grpc_slice_from_static_string("Server created")); - } - - if (args != nullptr) { - grpc_resource_quota* resource_quota = - grpc_resource_quota_from_channel_args(args, false /* create */); - if (resource_quota != nullptr) { - default_resource_user = - grpc_resource_user_create(resource_quota, "default"); - } - } - } - - ~grpc_server() { - grpc_channel_args_destroy(channel_args); - for (size_t i = 0; i < cqs.size(); i++) { - GRPC_CQ_INTERNAL_UNREF(cqs[i], "server"); - } - } - - grpc_channel_args* const channel_args; - - grpc_resource_user* default_resource_user = nullptr; - - std::vector cqs; - std::vector pollsets; - bool started = false; - - /* The two following mutexes control access to server-state - mu_global controls access to non-call-related state (e.g., channel state) - mu_call controls access to call-related state (e.g., the call lists) - - If they are ever required to be nested, you must lock mu_global - before mu_call. This is currently used in shutdown processing - (grpc_server_shutdown_and_notify and maybe_finish_shutdown) */ - grpc_core::Mutex mu_global; // mutex for server and channel state - grpc_core::Mutex mu_call; // mutex for call-specific state - - /* startup synchronization: flag is protected by mu_global, signals whether - we are doing the listener start routine or not */ - bool starting = false; - grpc_core::CondVar starting_cv; - - std::vector> registered_methods; - - // one request matcher for unregistered methods - std::unique_ptr - unregistered_request_matcher; - - std::atomic_bool shutdown_flag{false}; - bool shutdown_published = false; - std::vector shutdown_tags; - - std::list channels; - - std::list listeners; - size_t listeners_destroyed = 0; - grpc_core::RefCount internal_refcount; - - /** when did we print the last shutdown progress message */ - gpr_timespec last_shutdown_message_time; - - grpc_core::RefCountedPtr channelz_server; -}; - -// Non-API functions of the server that are only for gRPC core internal use. -// TODO(markdroth): Make these class member functions -void grpc_server_add_listener( - grpc_server* server, - grpc_core::OrphanablePtr listener) { - grpc_core::channelz::ListenSocketNode* listen_socket_node = - listener->channelz_listen_socket_node(); - if (listen_socket_node != nullptr && server->channelz_server != nullptr) { - server->channelz_server->AddChildListenSocket(listen_socket_node->Ref()); - } - server->listeners.emplace_back(std::move(listener)); -} - -const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server) { - return server->channel_args; -} - -grpc_resource_user* grpc_server_get_default_resource_user(grpc_server* server) { - return server->default_resource_user; -} - -bool grpc_server_has_open_connections(grpc_server* server) { - grpc_core::MutexLock lock(&server->mu_global); - return !server->channels.empty(); -} - -grpc_core::channelz::ServerNode* grpc_server_get_channelz_node( - grpc_server* server) { - if (server == nullptr) { - return nullptr; - } - return server->channelz_server.get(); -} - -namespace grpc_core { -namespace { - -void publish_call(grpc_server* server, call_data* calld, size_t cq_idx, - requested_call* rc); -void fail_call(grpc_server* server, size_t cq_idx, requested_call* rc, - grpc_error* error); -/* Before calling maybe_finish_shutdown, we must hold mu_global and not - hold mu_call */ -void maybe_finish_shutdown(grpc_server* server); - -void kill_zombie(void* elem, grpc_error* /*error*/) { - grpc_call_unref( - grpc_call_from_top_element(static_cast(elem))); -} - -// Validate a requested RPC for a server CQ and bind it to that CQ -grpc_call_error ValidateServerRequest( - grpc_completion_queue* cq_for_notification, void* tag, - grpc_byte_buffer** optional_payload, registered_method* rm) { - if ((rm == nullptr && optional_payload != nullptr) || - ((rm != nullptr) && ((optional_payload == nullptr) != - (rm->payload_handling == GRPC_SRM_PAYLOAD_NONE)))) { - return GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH; - } - if (grpc_cq_begin_op(cq_for_notification, tag) == false) { - return GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN; - } - return GRPC_CALL_OK; -} - -// Validate that a requested RPC has a valid server CQ and is valid, and bind it -grpc_call_error ValidateServerRequestAndCq( - size_t* cq_idx, grpc_server* server, - grpc_completion_queue* cq_for_notification, void* tag, - grpc_byte_buffer** optional_payload, registered_method* rm) { - size_t idx; - for (idx = 0; idx < server->cqs.size(); idx++) { - if (server->cqs[idx] == cq_for_notification) { - break; - } - } - if (idx == server->cqs.size()) { - return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; - } - grpc_call_error error = - ValidateServerRequest(cq_for_notification, tag, optional_payload, rm); - if (error != GRPC_CALL_OK) { - return error; - } - - *cq_idx = idx; - return GRPC_CALL_OK; -} -/* - * channel broadcaster - */ - -struct shutdown_cleanup_args { - grpc_closure closure; - grpc_slice slice; -}; - -void shutdown_cleanup(void* arg, grpc_error* /*error*/) { - shutdown_cleanup_args* a = static_cast(arg); - grpc_slice_unref_internal(a->slice); - delete a; -} - -void send_shutdown(grpc_channel* channel, bool send_goaway, - grpc_error* send_disconnect) { - shutdown_cleanup_args* sc = new shutdown_cleanup_args; - GRPC_CLOSURE_INIT(&sc->closure, shutdown_cleanup, sc, - grpc_schedule_on_exec_ctx); - grpc_transport_op* op = grpc_make_transport_op(&sc->closure); - grpc_channel_element* elem; - - op->goaway_error = - send_goaway ? grpc_error_set_int( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK) - : GRPC_ERROR_NONE; - op->set_accept_stream = true; - sc->slice = grpc_slice_from_copied_string("Server shutdown"); - op->disconnect_with_error = send_disconnect; - - elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - elem->filter->start_transport_op(elem, op); -} - -class ChannelBroadcaster { - public: - // This can have an empty constructor and destructor since we want to control - // when the actual setup and shutdown broadcast take place - - // This function copies over the channels from the locked server - void FillChannelsLocked(const grpc_server* s) { - GPR_DEBUG_ASSERT(channels_.empty()); - channels_.reserve(s->channels.size()); - for (const channel_data* chand : s->channels) { - channels_.push_back(chand->channel); - GRPC_CHANNEL_INTERNAL_REF(chand->channel, "broadcast"); - } - } - - // Broadcast a shutdown on each channel - void BroadcastShutdown(bool send_goaway, grpc_error* force_disconnect) { - for (grpc_channel* channel : channels_) { - send_shutdown(channel, send_goaway, GRPC_ERROR_REF(force_disconnect)); - GRPC_CHANNEL_INTERNAL_UNREF(channel, "broadcast"); - } - channels_.clear(); // just for safety against double broadcast - GRPC_ERROR_UNREF(force_disconnect); - } - - private: - std::vector channels_; + virtual Server* server() const = 0; }; -/* - * request_matcher - */ - // The RealRequestMatcher is an implementation of RequestMatcherInterface that // actually uses all the features of RequestMatcherInterface: expecting the // application to explicitly request RPCs and then matching those to incoming // RPCs, along with a slow path by which incoming RPCs are put on a locked // pending list if they aren't able to be matched to an application request. -class RealRequestMatcher : public RequestMatcherInterface { +class Server::RealRequestMatcher : public RequestMatcherInterface { public: - explicit RealRequestMatcher(grpc_server* server) - : server_(server), requests_per_cq_(server->cqs.size()) {} + explicit RealRequestMatcher(Server* server) + : server_(server), requests_per_cq_(server->cqs_.size()) {} ~RealRequestMatcher() override { for (LockedMultiProducerSingleConsumerQueue& queue : requests_per_cq_) { @@ -558,24 +202,20 @@ class RealRequestMatcher : public RequestMatcherInterface { } void ZombifyPending() override { - for (call_data* calld : pending_) { - calld->state.Store(CallState::ZOMBIED, grpc_core::MemoryOrder::RELAXED); - GRPC_CLOSURE_INIT( - &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0), - grpc_schedule_on_exec_ctx); - ExecCtx::Run(DEBUG_LOCATION, &calld->kill_zombie_closure, - GRPC_ERROR_NONE); + while (!pending_.empty()) { + CallData* calld = pending_.front(); + calld->SetState(CallData::CallState::ZOMBIED); + calld->KillZombie(); + pending_.pop(); } - pending_.clear(); } void KillRequests(grpc_error* error) override { for (size_t i = 0; i < requests_per_cq_.size(); i++) { - requested_call* rc; - while ((rc = reinterpret_cast( + RequestedCall* rc; + while ((rc = reinterpret_cast( requests_per_cq_[i].Pop())) != nullptr) { - fail_call(server_, i, rc, GRPC_ERROR_REF(error)); + server_->FailCall(i, rc, GRPC_ERROR_REF(error)); } } GRPC_ERROR_UNREF(error); @@ -586,106 +226,90 @@ class RealRequestMatcher : public RequestMatcherInterface { } void RequestCallWithPossiblePublish(size_t request_queue_index, - requested_call* call) override { + RequestedCall* call) override { if (requests_per_cq_[request_queue_index].Push(&call->mpscq_node)) { /* this was the first queued request: we need to lock and start matching calls */ struct PendingCall { - requested_call* rc = nullptr; - call_data* calld; + RequestedCall* rc = nullptr; + CallData* calld; }; auto pop_next_pending = [this, request_queue_index] { - PendingCall pending; + PendingCall pending_call; { - MutexLock lock(&server_->mu_call); + MutexLock lock(&server_->mu_call_); if (!pending_.empty()) { - pending.rc = reinterpret_cast( + pending_call.rc = reinterpret_cast( requests_per_cq_[request_queue_index].Pop()); - if (pending.rc != nullptr) { - pending.calld = pending_.front(); - pending_.pop_front(); + if (pending_call.rc != nullptr) { + pending_call.calld = pending_.front(); + pending_.pop(); } } } - return pending; + return pending_call; }; while (true) { PendingCall next_pending = pop_next_pending(); if (next_pending.rc == nullptr) break; - CallState expect_pending = CallState::PENDING; - if (!next_pending.calld->state.CompareExchangeStrong( - &expect_pending, CallState::ACTIVATED, - grpc_core::MemoryOrder::ACQ_REL, - grpc_core::MemoryOrder::RELAXED)) { + if (!next_pending.calld->MaybeActivate()) { // Zombied Call - GRPC_CLOSURE_INIT( - &next_pending.calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element( - grpc_call_get_call_stack(next_pending.calld->call), 0), - grpc_schedule_on_exec_ctx); - ExecCtx::Run(DEBUG_LOCATION, &next_pending.calld->kill_zombie_closure, - GRPC_ERROR_NONE); + next_pending.calld->KillZombie(); } else { - publish_call(server_, next_pending.calld, request_queue_index, - next_pending.rc); + next_pending.calld->Publish(request_queue_index, next_pending.rc); } } } } void MatchOrQueue(size_t start_request_queue_index, - call_data* calld) override { + CallData* calld) override { for (size_t i = 0; i < requests_per_cq_.size(); i++) { size_t cq_idx = (start_request_queue_index + i) % requests_per_cq_.size(); - requested_call* rc = - reinterpret_cast(requests_per_cq_[cq_idx].TryPop()); - if (rc == nullptr) { - continue; - } else { + RequestedCall* rc = + reinterpret_cast(requests_per_cq_[cq_idx].TryPop()); + if (rc != nullptr) { GRPC_STATS_INC_SERVER_CQS_CHECKED(i); - calld->state.Store(CallState::ACTIVATED, - grpc_core::MemoryOrder::RELAXED); - publish_call(server_, calld, cq_idx, rc); - return; /* early out */ + calld->SetState(CallData::CallState::ACTIVATED); + calld->Publish(cq_idx, rc); + return; } } - - /* no cq to take the request found: queue it on the slow list */ + // No cq to take the request found; queue it on the slow list. GRPC_STATS_INC_SERVER_SLOWPATH_REQUESTS_QUEUED(); - // We need to ensure that all the queues are empty. We do this under - // the server mu_call lock to ensure that if something is added to + // the server mu_call_ lock to ensure that if something is added to // an empty request queue, it will block until the call is actually // added to the pending list. - requested_call* rc = nullptr; + RequestedCall* rc = nullptr; size_t cq_idx = 0; size_t loop_count; { - MutexLock lock(&server_->mu_call); + MutexLock lock(&server_->mu_call_); for (loop_count = 0; loop_count < requests_per_cq_.size(); loop_count++) { cq_idx = (start_request_queue_index + loop_count) % requests_per_cq_.size(); - rc = reinterpret_cast(requests_per_cq_[cq_idx].Pop()); + rc = reinterpret_cast(requests_per_cq_[cq_idx].Pop()); if (rc != nullptr) { break; } } if (rc == nullptr) { - calld->state.Store(CallState::PENDING, grpc_core::MemoryOrder::RELAXED); - pending_.push_back(calld); + calld->SetState(CallData::CallState::PENDING); + pending_.push(calld); return; } } GRPC_STATS_INC_SERVER_CQS_CHECKED(loop_count + requests_per_cq_.size()); - calld->state.Store(CallState::ACTIVATED, grpc_core::MemoryOrder::RELAXED); - publish_call(server_, calld, cq_idx, rc); + calld->SetState(CallData::CallState::ACTIVATED); + calld->Publish(cq_idx, rc); } - grpc_server* server() const override { return server_; } + Server* server() const override { return server_; } private: - grpc_server* const server_; - std::list pending_; + Server* const server_; + std::queue pending_; std::vector requests_per_cq_; }; @@ -694,17 +318,17 @@ class RealRequestMatcher : public RequestMatcherInterface { // will call out to an allocation function passed in at the construction of the // object. These request matchers are designed for the C++ callback API, so they // only support 1 completion queue (passed in at the constructor). -class AllocatingRequestMatcherBase : public RequestMatcherInterface { +class Server::AllocatingRequestMatcherBase : public RequestMatcherInterface { public: - AllocatingRequestMatcherBase(grpc_server* server, grpc_completion_queue* cq) + AllocatingRequestMatcherBase(Server* server, grpc_completion_queue* cq) : server_(server), cq_(cq) { size_t idx; - for (idx = 0; idx < server->cqs.size(); idx++) { - if (server->cqs[idx] == cq) { + for (idx = 0; idx < server->cqs_.size(); idx++) { + if (server->cqs_[idx] == cq) { break; } } - GPR_ASSERT(idx < server->cqs.size()); + GPR_ASSERT(idx < server->cqs_.size()); cq_idx_ = idx; } @@ -715,11 +339,11 @@ class AllocatingRequestMatcherBase : public RequestMatcherInterface { size_t request_queue_count() const override { return 0; } void RequestCallWithPossiblePublish(size_t /*request_queue_index*/, - requested_call* /*call*/) final { + RequestedCall* /*call*/) final { GPR_ASSERT(false); } - grpc_server* server() const override { return server_; } + Server* server() const override { return server_; } // Supply the completion queue related to this request matcher grpc_completion_queue* cq() const { return cq_; } @@ -728,433 +352,746 @@ class AllocatingRequestMatcherBase : public RequestMatcherInterface { size_t cq_idx() const { return cq_idx_; } private: - grpc_server* const server_; + Server* const server_; grpc_completion_queue* const cq_; size_t cq_idx_; }; // An allocating request matcher for non-registered methods (used for generic // API and unimplemented RPCs). -class AllocatingRequestMatcherBatch : public AllocatingRequestMatcherBase { +class Server::AllocatingRequestMatcherBatch + : public AllocatingRequestMatcherBase { public: - AllocatingRequestMatcherBatch( - grpc_server* server, grpc_completion_queue* cq, - std::function allocator) + AllocatingRequestMatcherBatch(Server* server, grpc_completion_queue* cq, + std::function allocator) : AllocatingRequestMatcherBase(server, cq), allocator_(std::move(allocator)) {} + void MatchOrQueue(size_t /*start_request_queue_index*/, - call_data* calld) override { - ServerBatchCallAllocation call_info = allocator_(); - GPR_ASSERT(ValidateServerRequest(cq(), static_cast(call_info.tag), - nullptr, nullptr) == GRPC_CALL_OK); - requested_call* rc = new requested_call( + CallData* calld) override { + BatchCallAllocation call_info = allocator_(); + GPR_ASSERT(server()->ValidateServerRequest( + cq(), static_cast(call_info.tag), nullptr, nullptr) == + GRPC_CALL_OK); + RequestedCall* rc = new RequestedCall( static_cast(call_info.tag), cq(), call_info.call, call_info.initial_metadata, call_info.details); - calld->state.Store(CallState::ACTIVATED, grpc_core::MemoryOrder::RELAXED); - publish_call(server(), calld, cq_idx(), rc); + calld->SetState(CallData::CallState::ACTIVATED); + calld->Publish(cq_idx(), rc); } private: - std::function allocator_; + std::function allocator_; }; // An allocating request matcher for registered methods. -class AllocatingRequestMatcherRegistered : public AllocatingRequestMatcherBase { +class Server::AllocatingRequestMatcherRegistered + : public AllocatingRequestMatcherBase { public: AllocatingRequestMatcherRegistered( - grpc_server* server, grpc_completion_queue* cq, registered_method* rm, - std::function allocator) + Server* server, grpc_completion_queue* cq, RegisteredMethod* rm, + std::function allocator) : AllocatingRequestMatcherBase(server, cq), registered_method_(rm), allocator_(std::move(allocator)) {} + void MatchOrQueue(size_t /*start_request_queue_index*/, - call_data* calld) override { - ServerRegisteredCallAllocation call_info = allocator_(); - GPR_ASSERT(ValidateServerRequest(cq(), static_cast(call_info.tag), - call_info.optional_payload, - registered_method_) == GRPC_CALL_OK); - requested_call* rc = new requested_call( + CallData* calld) override { + RegisteredCallAllocation call_info = allocator_(); + GPR_ASSERT( + server()->ValidateServerRequest(cq(), static_cast(call_info.tag), + call_info.optional_payload, + registered_method_) == GRPC_CALL_OK); + RequestedCall* rc = new RequestedCall( static_cast(call_info.tag), cq(), call_info.call, call_info.initial_metadata, registered_method_, call_info.deadline, call_info.optional_payload); - calld->state.Store(CallState::ACTIVATED, grpc_core::MemoryOrder::RELAXED); - publish_call(server(), calld, cq_idx(), rc); + calld->SetState(CallData::CallState::ACTIVATED); + calld->Publish(cq_idx(), rc); } private: - registered_method* const registered_method_; - std::function allocator_; + RegisteredMethod* const registered_method_; + std::function allocator_; }; -/* - * server proper - */ +// +// ChannelBroadcaster +// + +namespace { -void server_ref(grpc_server* server) { server->internal_refcount.Ref(); } +class ChannelBroadcaster { + public: + // This can have an empty constructor and destructor since we want to control + // when the actual setup and shutdown broadcast take place. -void server_unref(grpc_server* server) { - if (GPR_UNLIKELY(server->internal_refcount.Unref())) { - delete server; + // Copies over the channels from the locked server. + void FillChannelsLocked(std::vector channels) { + GPR_DEBUG_ASSERT(channels_.empty()); + channels_ = std::move(channels); } -} -void finish_destroy_channel(void* cd, grpc_error* /*error*/) { - channel_data* chand = static_cast(cd); - grpc_server* server = chand->server; - GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server"); - server_unref(server); -} + // Broadcasts a shutdown on each channel. + void BroadcastShutdown(bool send_goaway, grpc_error* force_disconnect) { + for (grpc_channel* channel : channels_) { + SendShutdown(channel, send_goaway, GRPC_ERROR_REF(force_disconnect)); + GRPC_CHANNEL_INTERNAL_UNREF(channel, "broadcast"); + } + channels_.clear(); // just for safety against double broadcast + GRPC_ERROR_UNREF(force_disconnect); + } -void destroy_channel(channel_data* chand) { - if (!chand->list_position.has_value()) return; - GPR_ASSERT(chand->server != nullptr); - chand->server->channels.erase(*chand->list_position); - chand->list_position.reset(); - server_ref(chand->server); - maybe_finish_shutdown(chand->server); - GRPC_CLOSURE_INIT(&chand->finish_destroy_channel_closure, - finish_destroy_channel, chand, grpc_schedule_on_exec_ctx); + private: + struct ShutdownCleanupArgs { + grpc_closure closure; + grpc_slice slice; + }; - if (GRPC_TRACE_FLAG_ENABLED(grpc_server_channel_trace)) { - gpr_log(GPR_INFO, "Disconnected client"); + static void ShutdownCleanup(void* arg, grpc_error* /*error*/) { + ShutdownCleanupArgs* a = static_cast(arg); + grpc_slice_unref_internal(a->slice); + delete a; } - grpc_transport_op* op = - grpc_make_transport_op(&chand->finish_destroy_channel_closure); - op->set_accept_stream = true; - grpc_channel_next_op(grpc_channel_stack_element( - grpc_channel_get_channel_stack(chand->channel), 0), - op); -} + static void SendShutdown(grpc_channel* channel, bool send_goaway, + grpc_error* send_disconnect) { + ShutdownCleanupArgs* sc = new ShutdownCleanupArgs; + GRPC_CLOSURE_INIT(&sc->closure, ShutdownCleanup, sc, + grpc_schedule_on_exec_ctx); + grpc_transport_op* op = grpc_make_transport_op(&sc->closure); + grpc_channel_element* elem; + op->goaway_error = + send_goaway + ? grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK) + : GRPC_ERROR_NONE; + op->set_accept_stream = true; + sc->slice = grpc_slice_from_copied_string("Server shutdown"); + op->disconnect_with_error = send_disconnect; + elem = + grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); + elem->filter->start_transport_op(elem, op); + } -void done_request_event(void* req, grpc_cq_completion* /*c*/) { - delete static_cast(req); -} + std::vector channels_; +}; -void publish_call(grpc_server* server, call_data* calld, size_t cq_idx, - requested_call* rc) { - grpc_call_set_completion_queue(calld->call, rc->cq_bound_to_call); - grpc_call* call = calld->call; - *rc->call = call; - calld->cq_new = server->cqs[cq_idx]; - GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata); - switch (rc->type) { - case RequestedCallType::BATCH_CALL: - GPR_ASSERT(calld->host_set); - GPR_ASSERT(calld->path_set); - rc->data.batch.details->host = grpc_slice_ref_internal(calld->host); - rc->data.batch.details->method = grpc_slice_ref_internal(calld->path); - rc->data.batch.details->deadline = - grpc_millis_to_timespec(calld->deadline, GPR_CLOCK_MONOTONIC); - rc->data.batch.details->flags = calld->recv_initial_metadata_flags; - break; - case RequestedCallType::REGISTERED_CALL: - *rc->data.registered.deadline = - grpc_millis_to_timespec(calld->deadline, GPR_CLOCK_MONOTONIC); - if (rc->data.registered.optional_payload) { - *rc->data.registered.optional_payload = calld->payload; - calld->payload = nullptr; - } - break; - default: - GPR_UNREACHABLE_CODE(return ); - } +} // namespace - grpc_cq_end_op(calld->cq_new, rc->tag, GRPC_ERROR_NONE, done_request_event, - rc, &rc->completion, true); -} +// +// Server +// -void publish_new_rpc(void* arg, grpc_error* error) { - grpc_call_element* call_elem = static_cast(arg); - call_data* calld = static_cast(call_elem->call_data); - channel_data* chand = static_cast(call_elem->channel_data); - RequestMatcherInterface* rm = calld->matcher; - grpc_server* server = rm->server(); +const grpc_channel_filter Server::kServerTopFilter = { + Server::CallData::StartTransportStreamOpBatch, + grpc_channel_next_op, + sizeof(Server::CallData), + Server::CallData::InitCallElement, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + Server::CallData::DestroyCallElement, + sizeof(Server::ChannelData), + Server::ChannelData::InitChannelElement, + Server::ChannelData::DestroyChannelElement, + grpc_channel_next_get_info, + "server", +}; - if (error != GRPC_ERROR_NONE || - server->shutdown_flag.load(std::memory_order_acquire)) { - calld->state.Store(CallState::ZOMBIED, grpc_core::MemoryOrder::RELAXED); - GRPC_CLOSURE_INIT( - &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0), - grpc_schedule_on_exec_ctx); - ExecCtx::Run(DEBUG_LOCATION, &calld->kill_zombie_closure, - GRPC_ERROR_REF(error)); - return; +namespace { + +grpc_resource_user* CreateDefaultResourceUser(const grpc_channel_args* args) { + if (args != nullptr) { + grpc_resource_quota* resource_quota = + grpc_resource_quota_from_channel_args(args, false /* create */); + if (resource_quota != nullptr) { + return grpc_resource_user_create(resource_quota, "default"); + } } + return nullptr; +} - rm->MatchOrQueue(chand->cq_idx, calld); +RefCountedPtr CreateChannelzNode( + Server* server, const grpc_channel_args* args) { + RefCountedPtr channelz_node; + if (grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_CHANNELZ, + GRPC_ENABLE_CHANNELZ_DEFAULT)) { + size_t channel_tracer_max_memory = grpc_channel_args_find_integer( + args, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, + {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}); + channelz_node = + MakeRefCounted(channel_tracer_max_memory); + channelz_node->AddTraceEvent( + channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Server created")); + } + return channelz_node; } -void finish_start_new_rpc( - grpc_server* server, grpc_call_element* elem, RequestMatcherInterface* rm, - grpc_server_register_method_payload_handling payload_handling) { - call_data* calld = static_cast(elem->call_data); +} // namespace + +Server::Server(const grpc_channel_args* args) + : channel_args_(grpc_channel_args_copy(args)), + default_resource_user_(CreateDefaultResourceUser(args)), + channelz_node_(CreateChannelzNode(this, args)) {} - if (server->shutdown_flag.load(std::memory_order_acquire)) { - calld->state.Store(CallState::ZOMBIED, grpc_core::MemoryOrder::RELAXED); - GRPC_CLOSURE_INIT(&calld->kill_zombie_closure, kill_zombie, elem, - grpc_schedule_on_exec_ctx); - ExecCtx::Run(DEBUG_LOCATION, &calld->kill_zombie_closure, GRPC_ERROR_NONE); - return; +Server::~Server() { + grpc_channel_args_destroy(channel_args_); + for (size_t i = 0; i < cqs_.size(); i++) { + GRPC_CQ_INTERNAL_UNREF(cqs_[i], "server"); } +} - calld->matcher = rm; +void Server::AddListener(OrphanablePtr listener) { + channelz::ListenSocketNode* listen_socket_node = + listener->channelz_listen_socket_node(); + if (listen_socket_node != nullptr && channelz_node_ != nullptr) { + channelz_node_->AddChildListenSocket(listen_socket_node->Ref()); + } + listeners_.emplace_back(std::move(listener)); +} - switch (payload_handling) { - case GRPC_SRM_PAYLOAD_NONE: - publish_new_rpc(elem, GRPC_ERROR_NONE); - break; - case GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER: { - grpc_op op; - op.op = GRPC_OP_RECV_MESSAGE; - op.flags = 0; - op.reserved = nullptr; - op.data.recv_message.recv_message = &calld->payload; - GRPC_CLOSURE_INIT(&calld->publish, publish_new_rpc, elem, - grpc_schedule_on_exec_ctx); - grpc_call_start_batch_and_execute(calld->call, &op, 1, &calld->publish); - break; +void Server::Start() { + started_ = true; + for (grpc_completion_queue* cq : cqs_) { + if (grpc_cq_can_listen(cq)) { + pollsets_.push_back(grpc_cq_pollset(cq)); + } + } + if (unregistered_request_matcher_ == nullptr) { + unregistered_request_matcher_ = absl::make_unique(this); + } + for (std::unique_ptr& rm : registered_methods_) { + if (rm->matcher == nullptr) { + rm->matcher = absl::make_unique(this); } } + { + MutexLock lock(&mu_global_); + starting_ = true; + } + for (auto& listener : listeners_) { + listener.listener->Start(this, &pollsets_); + } + MutexLock lock(&mu_global_); + starting_ = false; + starting_cv_.Signal(); } -void start_new_rpc(grpc_call_element* elem) { - channel_data* chand = static_cast(elem->channel_data); - call_data* calld = static_cast(elem->call_data); - grpc_server* server = chand->server; - uint32_t i; - uint32_t hash; - channel_registered_method* rm; - - if (chand->registered_methods && calld->path_set && calld->host_set) { - /* TODO(ctiller): unify these two searches */ - /* check for an exact match with host */ - hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_internal(calld->host), - grpc_slice_hash_internal(calld->path)); - for (i = 0; i <= chand->registered_method_max_probes; i++) { - rm = &(*chand->registered_methods)[(hash + i) % - chand->registered_methods->size()]; - if (rm->server_registered_method == nullptr) break; - if (!rm->has_host) continue; - if (rm->host != calld->host) continue; - if (rm->method != calld->path) continue; - if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) && - 0 == (calld->recv_initial_metadata_flags & - GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) { - continue; - } - finish_start_new_rpc(server, elem, - rm->server_registered_method->matcher.get(), - rm->server_registered_method->payload_handling); - return; - } - /* check for a wildcard method definition (no host set) */ - hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash_internal(calld->path)); - for (i = 0; i <= chand->registered_method_max_probes; i++) { - rm = &(*chand->registered_methods)[(hash + i) % - chand->registered_methods->size()]; - if (rm->server_registered_method == nullptr) break; - if (rm->has_host) continue; - if (rm->method != calld->path) continue; - if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) && - 0 == (calld->recv_initial_metadata_flags & - GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) { - continue; - } - finish_start_new_rpc(server, elem, - rm->server_registered_method->matcher.get(), - rm->server_registered_method->payload_handling); - return; - } +void Server::SetupTransport( + grpc_transport* transport, grpc_pollset* accepting_pollset, + const grpc_channel_args* args, + const RefCountedPtr& socket_node, + grpc_resource_user* resource_user) { + // Create channel. + grpc_channel* channel = grpc_channel_create( + nullptr, args, GRPC_SERVER_CHANNEL, transport, resource_user); + ChannelData* chand = static_cast( + grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0) + ->channel_data); + // Set up CQs. + size_t cq_idx; + for (cq_idx = 0; cq_idx < cqs_.size(); cq_idx++) { + if (grpc_cq_pollset(cqs_[cq_idx]) == accepting_pollset) break; } - finish_start_new_rpc(server, elem, server->unregistered_request_matcher.get(), - GRPC_SRM_PAYLOAD_NONE); + if (cq_idx == cqs_.size()) { + // Completion queue not found. Pick a random one to publish new calls to. + cq_idx = static_cast(rand()) % cqs_.size(); + } + // Set up channelz node. + intptr_t channelz_socket_uuid = 0; + if (socket_node != nullptr) { + channelz_socket_uuid = socket_node->uuid(); + channelz_node_->AddChildSocket(socket_node); + } + // Initialize chand. + chand->InitTransport(Ref(), channel, cq_idx, transport, channelz_socket_uuid); +} + +bool Server::HasOpenConnections() { + MutexLock lock(&mu_global_); + return !channels_.empty(); } -void done_shutdown_event(void* server, grpc_cq_completion* /*completion*/) { - server_unref(static_cast(server)); +void Server::SetRegisteredMethodAllocator( + grpc_completion_queue* cq, void* method_tag, + std::function allocator) { + RegisteredMethod* rm = static_cast(method_tag); + rm->matcher = absl::make_unique( + this, cq, rm, std::move(allocator)); } -int num_channels(grpc_server* server) { return server->channels.size(); } +void Server::SetBatchMethodAllocator( + grpc_completion_queue* cq, std::function allocator) { + GPR_DEBUG_ASSERT(unregistered_request_matcher_ == nullptr); + unregistered_request_matcher_ = + absl::make_unique(this, cq, + std::move(allocator)); +} -void kill_pending_work_locked(grpc_server* server, grpc_error* error) { - if (server->started) { - server->unregistered_request_matcher->KillRequests(GRPC_ERROR_REF(error)); - server->unregistered_request_matcher->ZombifyPending(); - for (std::unique_ptr& rm : server->registered_methods) { - rm->matcher->KillRequests(GRPC_ERROR_REF(error)); - rm->matcher->ZombifyPending(); +void Server::RegisterCompletionQueue(grpc_completion_queue* cq) { + for (grpc_completion_queue* queue : cqs_) { + if (queue == cq) return; + } + GRPC_CQ_INTERNAL_REF(cq, "server"); + cqs_.push_back(cq); +} + +namespace { + +bool streq(const std::string& a, const char* b) { + return (a.empty() && b == nullptr) || + ((b != nullptr) && !strcmp(a.c_str(), b)); +} + +} // namespace + +Server::RegisteredMethod* Server::RegisterMethod( + const char* method, const char* host, + grpc_server_register_method_payload_handling payload_handling, + uint32_t flags) { + if (!method) { + gpr_log(GPR_ERROR, + "grpc_server_register_method method string cannot be NULL"); + return nullptr; + } + for (std::unique_ptr& m : registered_methods_) { + if (streq(m->method, method) && streq(m->host, host)) { + gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, + host ? host : "*"); + return nullptr; } } - GRPC_ERROR_UNREF(error); + if ((flags & ~GRPC_INITIAL_METADATA_USED_MASK) != 0) { + gpr_log(GPR_ERROR, "grpc_server_register_method invalid flags 0x%08x", + flags); + return nullptr; + } + registered_methods_.emplace_back(absl::make_unique( + method, host, payload_handling, flags)); + return registered_methods_.back().get(); +} + +void Server::DoneRequestEvent(void* req, grpc_cq_completion* /*c*/) { + delete static_cast(req); } -void maybe_finish_shutdown(grpc_server* server) { - size_t i; - if (!server->shutdown_flag.load(std::memory_order_acquire) || - server->shutdown_published) { +void Server::FailCall(size_t cq_idx, RequestedCall* rc, grpc_error* error) { + *rc->call = nullptr; + rc->initial_metadata->count = 0; + GPR_ASSERT(error != GRPC_ERROR_NONE); + grpc_cq_end_op(cqs_[cq_idx], rc->tag, error, DoneRequestEvent, rc, + &rc->completion); +} + +// Before calling MaybeFinishShutdown(), we must hold mu_global_ and not +// hold mu_call_. +void Server::MaybeFinishShutdown() { + if (!shutdown_flag_.load(std::memory_order_acquire) || shutdown_published_) { return; } - { - MutexLock lock(&server->mu_call); - kill_pending_work_locked( - server, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); + MutexLock lock(&mu_call_); + KillPendingWorkLocked( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); } - - if (!server->channels.empty() || - server->listeners_destroyed < server->listeners.size()) { + if (!channels_.empty() || listeners_destroyed_ < listeners_.size()) { if (gpr_time_cmp(gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), - server->last_shutdown_message_time), + last_shutdown_message_time_), gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { - server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); + last_shutdown_message_time_ = gpr_now(GPR_CLOCK_REALTIME); gpr_log(GPR_DEBUG, - "Waiting for %d channels and %" PRIuPTR "/%" PRIuPTR + "Waiting for %" PRIuPTR " channels and %" PRIuPTR "/%" PRIuPTR " listeners to be destroyed before shutting down server", - num_channels(server), - server->listeners.size() - server->listeners_destroyed, - server->listeners.size()); + channels_.size(), listeners_.size() - listeners_destroyed_, + listeners_.size()); } return; } - server->shutdown_published = 1; - for (i = 0; i < server->shutdown_tags.size(); i++) { - server_ref(server); - grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag, - GRPC_ERROR_NONE, done_shutdown_event, server, - &server->shutdown_tags[i].completion); + shutdown_published_ = true; + for (auto& shutdown_tag : shutdown_tags_) { + Ref().release(); + grpc_cq_end_op(shutdown_tag.cq, shutdown_tag.tag, GRPC_ERROR_NONE, + DoneShutdownEvent, this, &shutdown_tag.completion); } } -void server_on_recv_initial_metadata(void* ptr, grpc_error* error) { - grpc_call_element* elem = static_cast(ptr); - call_data* calld = static_cast(elem->call_data); - grpc_millis op_deadline; +void Server::KillPendingWorkLocked(grpc_error* error) { + if (started_) { + unregistered_request_matcher_->KillRequests(GRPC_ERROR_REF(error)); + unregistered_request_matcher_->ZombifyPending(); + for (std::unique_ptr& rm : registered_methods_) { + rm->matcher->KillRequests(GRPC_ERROR_REF(error)); + rm->matcher->ZombifyPending(); + } + } + GRPC_ERROR_UNREF(error); +} - if (error == GRPC_ERROR_NONE) { - GPR_DEBUG_ASSERT(calld->recv_initial_metadata->idx.named.path != nullptr); - GPR_DEBUG_ASSERT(calld->recv_initial_metadata->idx.named.authority != - nullptr); - calld->path = grpc_slice_ref_internal( - GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md)); - calld->host = grpc_slice_ref_internal( - GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.authority->md)); - calld->path_set = true; - calld->host_set = true; - grpc_metadata_batch_remove(calld->recv_initial_metadata, GRPC_BATCH_PATH); - grpc_metadata_batch_remove(calld->recv_initial_metadata, - GRPC_BATCH_AUTHORITY); - } else { - GRPC_ERROR_REF(error); +std::vector Server::GetChannelsLocked() const { + std::vector channels; + channels.reserve(channels_.size()); + for (const ChannelData* chand : channels_) { + channels.push_back(chand->channel()); + GRPC_CHANNEL_INTERNAL_REF(chand->channel(), "broadcast"); } - op_deadline = calld->recv_initial_metadata->deadline; - if (op_deadline != GRPC_MILLIS_INF_FUTURE) { - calld->deadline = op_deadline; + return channels; +} + +void Server::ListenerDestroyDone(void* arg, grpc_error* /*error*/) { + Server* server = static_cast(arg); + MutexLock lock(&server->mu_global_); + server->listeners_destroyed_++; + server->MaybeFinishShutdown(); +} + +namespace { + +void DonePublishedShutdown(void* /*done_arg*/, grpc_cq_completion* storage) { + delete storage; +} + +} // namespace + +// - Kills all pending requests-for-incoming-RPC-calls (i.e., the requests made +// via grpc_server_request_call() and grpc_server_request_registered_call() +// will now be cancelled). See KillPendingWorkLocked(). +// +// - Shuts down the listeners (i.e., the server will no longer listen on the +// port for new incoming channels). +// +// - Iterates through all channels on the server and sends shutdown msg (see +// ChannelBroadcaster::BroadcastShutdown() for details) to the clients via +// the transport layer. The transport layer then guarantees the following: +// -- Sends shutdown to the client (e.g., HTTP2 transport sends GOAWAY). +// -- If the server has outstanding calls that are in the process, the +// connection is NOT closed until the server is done with all those calls. +// -- Once there are no more calls in progress, the channel is closed. +void Server::ShutdownAndNotify(grpc_completion_queue* cq, void* tag) { + ChannelBroadcaster broadcaster; + { + // Wait for startup to be finished. Locks mu_global. + MutexLock lock(&mu_global_); + starting_cv_.WaitUntil(&mu_global_, [this] { return !starting_; }); + // Stay locked, and gather up some stuff to do. + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); + if (shutdown_published_) { + grpc_cq_end_op(cq, tag, GRPC_ERROR_NONE, DonePublishedShutdown, nullptr, + new grpc_cq_completion); + return; + } + shutdown_tags_.emplace_back(tag, cq); + if (shutdown_flag_.load(std::memory_order_acquire)) { + return; + } + last_shutdown_message_time_ = gpr_now(GPR_CLOCK_REALTIME); + broadcaster.FillChannelsLocked(GetChannelsLocked()); + shutdown_flag_.store(true, std::memory_order_release); + // Collect all unregistered then registered calls. + { + MutexLock lock(&mu_call_); + KillPendingWorkLocked( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); + } + MaybeFinishShutdown(); } - if (calld->host_set && calld->path_set) { - /* do nothing */ - } else { - /* Pass the error reference to calld->recv_initial_metadata_error */ - grpc_error* src_error = error; - error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Missing :authority or :path", &src_error, 1); - GRPC_ERROR_UNREF(src_error); - calld->recv_initial_metadata_error = GRPC_ERROR_REF(error); + // Shutdown listeners. + for (auto& listener : listeners_) { + channelz::ListenSocketNode* channelz_listen_socket_node = + listener.listener->channelz_listen_socket_node(); + if (channelz_node_ != nullptr && channelz_listen_socket_node != nullptr) { + channelz_node_->RemoveChildListenSocket( + channelz_listen_socket_node->uuid()); + } + GRPC_CLOSURE_INIT(&listener.destroy_done, ListenerDestroyDone, this, + grpc_schedule_on_exec_ctx); + listener.listener->SetOnDestroyDone(&listener.destroy_done); + listener.listener.reset(); } - grpc_closure* closure = calld->on_done_recv_initial_metadata; - calld->on_done_recv_initial_metadata = nullptr; - if (calld->seen_recv_trailing_metadata_ready) { - GRPC_CALL_COMBINER_START(calld->call_combiner, - &calld->recv_trailing_metadata_ready, - calld->recv_trailing_metadata_error, - "continue server_recv_trailing_metadata_ready"); + broadcaster.BroadcastShutdown(/*send_goaway=*/true, GRPC_ERROR_NONE); +} + +void Server::CancelAllCalls() { + ChannelBroadcaster broadcaster; + { + MutexLock lock(&mu_global_); + broadcaster.FillChannelsLocked(GetChannelsLocked()); } - Closure::Run(DEBUG_LOCATION, closure, error); + broadcaster.BroadcastShutdown( + /*send_goaway=*/false, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Cancelling all calls")); } -void server_recv_trailing_metadata_ready(void* user_data, grpc_error* error) { - grpc_call_element* elem = static_cast(user_data); - call_data* calld = static_cast(elem->call_data); - if (calld->on_done_recv_initial_metadata != nullptr) { - calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error); - calld->seen_recv_trailing_metadata_ready = true; - GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, - server_recv_trailing_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CALL_COMBINER_STOP(calld->call_combiner, - "deferring server_recv_trailing_metadata_ready " - "until after server_on_recv_initial_metadata"); - return; +void Server::Orphan() { + { + MutexLock lock(&mu_global_); + GPR_ASSERT(shutdown_flag_.load(std::memory_order_acquire) || + listeners_.empty()); + GPR_ASSERT(listeners_destroyed_ == listeners_.size()); } - error = - grpc_error_add_child(GRPC_ERROR_REF(error), - GRPC_ERROR_REF(calld->recv_initial_metadata_error)); - Closure::Run(DEBUG_LOCATION, calld->original_recv_trailing_metadata_ready, - error); + if (default_resource_user_ != nullptr) { + grpc_resource_quota_unref(grpc_resource_user_quota(default_resource_user_)); + grpc_resource_user_shutdown(default_resource_user_); + grpc_resource_user_unref(default_resource_user_); + } + Unref(); +} + +grpc_call_error Server::ValidateServerRequest( + grpc_completion_queue* cq_for_notification, void* tag, + grpc_byte_buffer** optional_payload, RegisteredMethod* rm) { + if ((rm == nullptr && optional_payload != nullptr) || + ((rm != nullptr) && ((optional_payload == nullptr) != + (rm->payload_handling == GRPC_SRM_PAYLOAD_NONE)))) { + return GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH; + } + if (grpc_cq_begin_op(cq_for_notification, tag) == false) { + return GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN; + } + return GRPC_CALL_OK; } -void server_mutate_op(grpc_call_element* elem, - grpc_transport_stream_op_batch* op) { - call_data* calld = static_cast(elem->call_data); - - if (op->recv_initial_metadata) { - GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags == nullptr); - calld->recv_initial_metadata = - op->payload->recv_initial_metadata.recv_initial_metadata; - calld->on_done_recv_initial_metadata = - op->payload->recv_initial_metadata.recv_initial_metadata_ready; - op->payload->recv_initial_metadata.recv_initial_metadata_ready = - &calld->on_recv_initial_metadata; - op->payload->recv_initial_metadata.recv_flags = - &calld->recv_initial_metadata_flags; - } - if (op->recv_trailing_metadata) { - calld->original_recv_trailing_metadata_ready = - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &calld->recv_trailing_metadata_ready; +grpc_call_error Server::ValidateServerRequestAndCq( + size_t* cq_idx, grpc_completion_queue* cq_for_notification, void* tag, + grpc_byte_buffer** optional_payload, RegisteredMethod* rm) { + size_t idx; + for (idx = 0; idx < cqs_.size(); idx++) { + if (cqs_[idx] == cq_for_notification) { + break; + } + } + if (idx == cqs_.size()) { + return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; } + grpc_call_error error = + ValidateServerRequest(cq_for_notification, tag, optional_payload, rm); + if (error != GRPC_CALL_OK) { + return error; + } + *cq_idx = idx; + return GRPC_CALL_OK; } -void server_start_transport_stream_op_batch( - grpc_call_element* elem, grpc_transport_stream_op_batch* op) { - server_mutate_op(elem, op); - grpc_call_next_op(elem, op); +grpc_call_error Server::QueueRequestedCall(size_t cq_idx, RequestedCall* rc) { + if (shutdown_flag_.load(std::memory_order_acquire)) { + FailCall(cq_idx, rc, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); + return GRPC_CALL_OK; + } + RequestMatcherInterface* rm; + switch (rc->type) { + case RequestedCall::Type::BATCH_CALL: + rm = unregistered_request_matcher_.get(); + break; + case RequestedCall::Type::REGISTERED_CALL: + rm = rc->data.registered.method->matcher.get(); + break; + } + rm->RequestCallWithPossiblePublish(cq_idx, rc); + return GRPC_CALL_OK; } -void got_initial_metadata(void* ptr, grpc_error* error) { - grpc_call_element* elem = static_cast(ptr); - call_data* calld = static_cast(elem->call_data); - if (error == GRPC_ERROR_NONE) { - start_new_rpc(elem); - } else { - CallState expect_not_started = CallState::NOT_STARTED; - CallState expect_pending = CallState::PENDING; - if (calld->state.CompareExchangeStrong( - &expect_not_started, CallState::ZOMBIED, - grpc_core::MemoryOrder::ACQ_REL, grpc_core::MemoryOrder::RELAXED)) { - GRPC_CLOSURE_INIT(&calld->kill_zombie_closure, kill_zombie, elem, - grpc_schedule_on_exec_ctx); - ExecCtx::Run(DEBUG_LOCATION, &calld->kill_zombie_closure, - GRPC_ERROR_NONE); - } else if (calld->state.CompareExchangeStrong( - &expect_pending, CallState::ZOMBIED, - grpc_core::MemoryOrder::ACQ_REL, - grpc_core::MemoryOrder::RELAXED)) { - /* zombied call will be destroyed when it's removed from the pending - queue... later */ +grpc_call_error Server::RequestCall(grpc_call** call, + grpc_call_details* details, + grpc_metadata_array* request_metadata, + grpc_completion_queue* cq_bound_to_call, + grpc_completion_queue* cq_for_notification, + void* tag) { + size_t cq_idx; + grpc_call_error error = ValidateServerRequestAndCq( + &cq_idx, cq_for_notification, tag, nullptr, nullptr); + if (error != GRPC_CALL_OK) { + return error; + } + RequestedCall* rc = + new RequestedCall(tag, cq_bound_to_call, call, request_metadata, details); + return QueueRequestedCall(cq_idx, rc); +} + +grpc_call_error Server::RequestRegisteredCall( + RegisteredMethod* rm, grpc_call** call, gpr_timespec* deadline, + grpc_metadata_array* request_metadata, grpc_byte_buffer** optional_payload, + grpc_completion_queue* cq_bound_to_call, + grpc_completion_queue* cq_for_notification, void* tag_new) { + size_t cq_idx; + grpc_call_error error = ValidateServerRequestAndCq( + &cq_idx, cq_for_notification, tag_new, optional_payload, rm); + if (error != GRPC_CALL_OK) { + return error; + } + RequestedCall* rc = + new RequestedCall(tag_new, cq_bound_to_call, call, request_metadata, rm, + deadline, optional_payload); + return QueueRequestedCall(cq_idx, rc); +} + +// +// Server::ChannelData::ConnectivityWatcher +// + +class Server::ChannelData::ConnectivityWatcher + : public AsyncConnectivityStateWatcherInterface { + public: + explicit ConnectivityWatcher(ChannelData* chand) : chand_(chand) { + GRPC_CHANNEL_INTERNAL_REF(chand_->channel_, "connectivity"); + } + + ~ConnectivityWatcher() { + GRPC_CHANNEL_INTERNAL_UNREF(chand_->channel_, "connectivity"); + } + + private: + void OnConnectivityStateChange(grpc_connectivity_state new_state, + const absl::Status& /*status*/) override { + // Don't do anything until we are being shut down. + if (new_state != GRPC_CHANNEL_SHUTDOWN) return; + // Shut down channel. + MutexLock lock(&chand_->server_->mu_global_); + chand_->Destroy(); + } + + ChannelData* chand_; +}; + +// +// Server::ChannelData +// + +Server::ChannelData::~ChannelData() { + if (registered_methods_ != nullptr) { + for (const ChannelRegisteredMethod& crm : *registered_methods_) { + grpc_slice_unref_internal(crm.method); + GPR_DEBUG_ASSERT(crm.method.refcount == &kNoopRefcount || + crm.method.refcount == nullptr); + if (crm.has_host) { + grpc_slice_unref_internal(crm.host); + GPR_DEBUG_ASSERT(crm.host.refcount == &kNoopRefcount || + crm.host.refcount == nullptr); + } + } + registered_methods_.reset(); + } + if (server_ != nullptr) { + if (server_->channelz_node_ != nullptr && channelz_socket_uuid_ != 0) { + server_->channelz_node_->RemoveChildSocket(channelz_socket_uuid_); + } + { + MutexLock lock(&server_->mu_global_); + if (list_position_.has_value()) { + server_->channels_.erase(*list_position_); + list_position_.reset(); + } + server_->MaybeFinishShutdown(); + } + } +} + +void Server::ChannelData::InitTransport(RefCountedPtr server, + grpc_channel* channel, size_t cq_idx, + grpc_transport* transport, + intptr_t channelz_socket_uuid) { + server_ = std::move(server); + channel_ = channel; + cq_idx_ = cq_idx; + channelz_socket_uuid_ = channelz_socket_uuid; + // Build a lookup table phrased in terms of mdstr's in this channels context + // to quickly find registered methods. + size_t num_registered_methods = server_->registered_methods_.size(); + if (num_registered_methods > 0) { + uint32_t max_probes = 0; + size_t slots = 2 * num_registered_methods; + registered_methods_.reset(new std::vector(slots)); + for (std::unique_ptr& rm : server_->registered_methods_) { + ExternallyManagedSlice host; + ExternallyManagedSlice method(rm->method.c_str()); + const bool has_host = !rm->host.empty(); + if (has_host) { + host = ExternallyManagedSlice(rm->host.c_str()); + } + uint32_t hash = + GRPC_MDSTR_KV_HASH(has_host ? host.Hash() : 0, method.Hash()); + uint32_t probes = 0; + for (probes = 0; (*registered_methods_)[(hash + probes) % slots] + .server_registered_method != nullptr; + probes++) { + } + if (probes > max_probes) max_probes = probes; + ChannelRegisteredMethod* crm = + &(*registered_methods_)[(hash + probes) % slots]; + crm->server_registered_method = rm.get(); + crm->flags = rm->flags; + crm->has_host = has_host; + if (has_host) { + crm->host = host; + } + crm->method = method; + } + GPR_ASSERT(slots <= UINT32_MAX); + registered_method_max_probes_ = max_probes; + } + // Publish channel. + { + MutexLock lock(&server_->mu_global_); + server_->channels_.push_front(this); + list_position_ = server_->channels_.begin(); + } + // Start accept_stream transport op. + grpc_transport_op* op = grpc_make_transport_op(nullptr); + op->set_accept_stream = true; + op->set_accept_stream_fn = AcceptStream; + op->set_accept_stream_user_data = this; + op->start_connectivity_watch = MakeOrphanable(this); + if (server_->shutdown_flag_.load(std::memory_order_acquire)) { + op->disconnect_with_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"); + } + grpc_transport_perform_op(transport, op); +} + +Server::ChannelRegisteredMethod* Server::ChannelData::GetRegisteredMethod( + const grpc_slice& host, const grpc_slice& path, bool is_idempotent) { + if (registered_methods_ == nullptr) return nullptr; + /* TODO(ctiller): unify these two searches */ + /* check for an exact match with host */ + uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_internal(host), + grpc_slice_hash_internal(path)); + for (size_t i = 0; i <= registered_method_max_probes_; i++) { + ChannelRegisteredMethod* rm = + &(*registered_methods_)[(hash + i) % registered_methods_->size()]; + if (rm->server_registered_method == nullptr) break; + if (!rm->has_host) continue; + if (rm->host != host) continue; + if (rm->method != path) continue; + if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) && + !is_idempotent) { + continue; + } + return rm; + } + /* check for a wildcard method definition (no host set) */ + hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash_internal(path)); + for (size_t i = 0; i <= registered_method_max_probes_; i++) { + ChannelRegisteredMethod* rm = + &(*registered_methods_)[(hash + i) % registered_methods_->size()]; + if (rm->server_registered_method == nullptr) break; + if (rm->has_host) continue; + if (rm->method != path) continue; + if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) && + !is_idempotent) { + continue; } + return rm; } + return nullptr; } -void accept_stream(void* cd, grpc_transport* /*transport*/, - const void* transport_server_data) { - channel_data* chand = static_cast(cd); +void Server::ChannelData::AcceptStream(void* arg, grpc_transport* /*transport*/, + const void* transport_server_data) { + auto* chand = static_cast(arg); /* create a call */ grpc_call_create_args args; - args.channel = chand->channel; - args.server = chand->server; + args.channel = chand->channel_; + args.server = chand->server_.get(); args.parent = nullptr; args.propagation_mask = 0; args.cq = nullptr; @@ -1167,200 +1104,353 @@ void accept_stream(void* cd, grpc_transport* /*transport*/, grpc_error* error = grpc_call_create(&args, &call); grpc_call_element* elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); + auto* calld = static_cast(elem->call_data); if (error != GRPC_ERROR_NONE) { - got_initial_metadata(elem, error); GRPC_ERROR_UNREF(error); + calld->FailCallCreation(); return; } - call_data* calld = static_cast(elem->call_data); - grpc_op op; - op.op = GRPC_OP_RECV_INITIAL_METADATA; - op.flags = 0; - op.reserved = nullptr; - op.data.recv_initial_metadata.recv_initial_metadata = - &calld->initial_metadata; - GRPC_CLOSURE_INIT(&calld->got_initial_metadata, got_initial_metadata, elem, - grpc_schedule_on_exec_ctx); - grpc_call_start_batch_and_execute(call, &op, 1, &calld->got_initial_metadata); + calld->Start(elem); } -grpc_error* server_init_call_elem(grpc_call_element* elem, - const grpc_call_element_args* args) { - channel_data* chand = static_cast(elem->channel_data); - server_ref(chand->server); - new (elem->call_data) call_data(elem, *args); - return GRPC_ERROR_NONE; +void Server::ChannelData::FinishDestroy(void* cd, grpc_error* /*error*/) { + auto* chand = static_cast(cd); + Server* server = chand->server_.get(); + GRPC_CHANNEL_INTERNAL_UNREF(chand->channel_, "server"); + server->Unref(); } -void server_destroy_call_elem(grpc_call_element* elem, - const grpc_call_final_info* /*final_info*/, - grpc_closure* /*ignored*/) { - call_data* calld = static_cast(elem->call_data); - calld->~call_data(); - channel_data* chand = static_cast(elem->channel_data); - server_unref(chand->server); +void Server::ChannelData::Destroy() { + if (!list_position_.has_value()) return; + GPR_ASSERT(server_ != nullptr); + server_->channels_.erase(*list_position_); + list_position_.reset(); + server_->Ref().release(); + server_->MaybeFinishShutdown(); + GRPC_CLOSURE_INIT(&finish_destroy_channel_closure_, FinishDestroy, this, + grpc_schedule_on_exec_ctx); + if (GRPC_TRACE_FLAG_ENABLED(grpc_server_channel_trace)) { + gpr_log(GPR_INFO, "Disconnected client"); + } + grpc_transport_op* op = + grpc_make_transport_op(&finish_destroy_channel_closure_); + op->set_accept_stream = true; + grpc_channel_next_op( + grpc_channel_stack_element(grpc_channel_get_channel_stack(channel_), 0), + op); } -grpc_error* server_init_channel_elem(grpc_channel_element* elem, - grpc_channel_element_args* args) { +grpc_error* Server::ChannelData::InitChannelElement( + grpc_channel_element* elem, grpc_channel_element_args* args) { GPR_ASSERT(args->is_first); GPR_ASSERT(!args->is_last); - - new (static_cast(elem->channel_data)) channel_data; - return GRPC_ERROR_NONE; -} - -channel_data::~channel_data() { - if (registered_methods) { - for (const channel_registered_method& crm : *registered_methods) { - grpc_slice_unref_internal(crm.method); - GPR_DEBUG_ASSERT(crm.method.refcount == &kNoopRefcount || - crm.method.refcount == nullptr); - if (crm.has_host) { - grpc_slice_unref_internal(crm.host); - GPR_DEBUG_ASSERT(crm.host.refcount == &kNoopRefcount || - crm.host.refcount == nullptr); - } - } - } - if (server) { - if (server->channelz_server != nullptr && channelz_socket_uuid != 0) { - server->channelz_server->RemoveChildSocket(channelz_socket_uuid); - } - { - MutexLock lock(&server->mu_global); - if (list_position.has_value()) { - server->channels.erase(*list_position); - } - maybe_finish_shutdown(server); - } - server_unref(server); - } + new (elem->channel_data) ChannelData(); + return GRPC_ERROR_NONE; } -void server_destroy_channel_elem(grpc_channel_element* elem) { - channel_data* chand = static_cast(elem->channel_data); - chand->~channel_data(); +void Server::ChannelData::DestroyChannelElement(grpc_channel_element* elem) { + auto* chand = static_cast(elem->channel_data); + chand->~ChannelData(); } -void register_completion_queue(grpc_server* server, grpc_completion_queue* cq, - void* reserved) { - size_t i; - GPR_ASSERT(!reserved); - for (i = 0; i < server->cqs.size(); i++) { - if (server->cqs[i] == cq) return; +// +// Server::CallData +// + +Server::CallData::CallData(grpc_call_element* elem, + const grpc_call_element_args& args, + RefCountedPtr server) + : server_(std::move(server)), + call_(grpc_call_from_top_element(elem)), + call_combiner_(args.call_combiner) { + GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady, + elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_, RecvTrailingMetadataReady, + elem, grpc_schedule_on_exec_ctx); +} + +Server::CallData::~CallData() { + GPR_ASSERT(state_.Load(MemoryOrder::RELAXED) != CallState::PENDING); + GRPC_ERROR_UNREF(recv_initial_metadata_error_); + if (host_.has_value()) { + grpc_slice_unref_internal(*host_); + } + if (path_.has_value()) { + grpc_slice_unref_internal(*path_); } + grpc_metadata_array_destroy(&initial_metadata_); + grpc_byte_buffer_destroy(payload_); +} - GRPC_CQ_INTERNAL_REF(cq, "server"); - server->cqs.push_back(cq); +void Server::CallData::SetState(CallState state) { + state_.Store(state, MemoryOrder::RELAXED); } -bool streq(const std::string& a, const char* b) { - return (a.empty() && b == nullptr) || - ((b != nullptr) && !strcmp(a.c_str(), b)); +bool Server::CallData::MaybeActivate() { + CallState expected = CallState::PENDING; + return state_.CompareExchangeStrong(&expected, CallState::ACTIVATED, + MemoryOrder::ACQ_REL, + MemoryOrder::RELAXED); } -class ConnectivityWatcher : public AsyncConnectivityStateWatcherInterface { - public: - explicit ConnectivityWatcher(channel_data* chand) : chand_(chand) { - GRPC_CHANNEL_INTERNAL_REF(chand_->channel, "connectivity"); +void Server::CallData::FailCallCreation() { + CallState expected_not_started = CallState::NOT_STARTED; + CallState expected_pending = CallState::PENDING; + if (state_.CompareExchangeStrong(&expected_not_started, CallState::ZOMBIED, + MemoryOrder::ACQ_REL, + MemoryOrder::ACQUIRE)) { + KillZombie(); + } else if (state_.CompareExchangeStrong(&expected_pending, CallState::ZOMBIED, + MemoryOrder::ACQ_REL, + MemoryOrder::RELAXED)) { + // Zombied call will be destroyed when it's removed from the pending + // queue... later. } +} - ~ConnectivityWatcher() { - GRPC_CHANNEL_INTERNAL_UNREF(chand_->channel, "connectivity"); +void Server::CallData::Start(grpc_call_element* elem) { + grpc_op op; + op.op = GRPC_OP_RECV_INITIAL_METADATA; + op.flags = 0; + op.reserved = nullptr; + op.data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_; + GRPC_CLOSURE_INIT(&recv_initial_metadata_batch_complete_, + RecvInitialMetadataBatchComplete, elem, + grpc_schedule_on_exec_ctx); + grpc_call_start_batch_and_execute(call_, &op, 1, + &recv_initial_metadata_batch_complete_); +} + +void Server::CallData::Publish(size_t cq_idx, RequestedCall* rc) { + grpc_call_set_completion_queue(call_, rc->cq_bound_to_call); + *rc->call = call_; + cq_new_ = server_->cqs_[cq_idx]; + GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, initial_metadata_); + switch (rc->type) { + case RequestedCall::Type::BATCH_CALL: + GPR_ASSERT(host_.has_value()); + GPR_ASSERT(path_.has_value()); + rc->data.batch.details->host = grpc_slice_ref_internal(*host_); + rc->data.batch.details->method = grpc_slice_ref_internal(*path_); + rc->data.batch.details->deadline = + grpc_millis_to_timespec(deadline_, GPR_CLOCK_MONOTONIC); + rc->data.batch.details->flags = recv_initial_metadata_flags_; + break; + case RequestedCall::Type::REGISTERED_CALL: + *rc->data.registered.deadline = + grpc_millis_to_timespec(deadline_, GPR_CLOCK_MONOTONIC); + if (rc->data.registered.optional_payload != nullptr) { + *rc->data.registered.optional_payload = payload_; + payload_ = nullptr; + } + break; + default: + GPR_UNREACHABLE_CODE(return ); } + grpc_cq_end_op(cq_new_, rc->tag, GRPC_ERROR_NONE, Server::DoneRequestEvent, + rc, &rc->completion, true); +} - private: - void OnConnectivityStateChange(grpc_connectivity_state new_state, - const absl::Status& /* status */) override { - // Don't do anything until we are being shut down. - if (new_state != GRPC_CHANNEL_SHUTDOWN) return; - // Shut down channel. - grpc_server* server = chand_->server; - MutexLock lock(&server->mu_global); - destroy_channel(chand_); +void Server::CallData::PublishNewRpc(void* arg, grpc_error* error) { + grpc_call_element* call_elem = static_cast(arg); + auto* calld = static_cast(call_elem->call_data); + auto* chand = static_cast(call_elem->channel_data); + RequestMatcherInterface* rm = calld->matcher_; + Server* server = rm->server(); + if (error != GRPC_ERROR_NONE || + server->shutdown_flag_.load(std::memory_order_acquire)) { + calld->state_.Store(CallState::ZOMBIED, MemoryOrder::RELAXED); + calld->KillZombie(); + return; } + rm->MatchOrQueue(chand->cq_idx(), calld); +} - channel_data* chand_; -}; +namespace { -void done_published_shutdown(void* /*done_arg*/, grpc_cq_completion* storage) { - delete storage; +void KillZombieClosure(void* call, grpc_error* /*error*/) { + grpc_call_unref(static_cast(call)); } -void listener_destroy_done(void* s, grpc_error* /*error*/) { - grpc_server* server = static_cast(s); - MutexLock lock(&server->mu_global); - server->listeners_destroyed++; - maybe_finish_shutdown(server); +} // namespace + +void Server::CallData::KillZombie() { + GRPC_CLOSURE_INIT(&kill_zombie_closure_, KillZombieClosure, call_, + grpc_schedule_on_exec_ctx); + ExecCtx::Run(DEBUG_LOCATION, &kill_zombie_closure_, GRPC_ERROR_NONE); } -grpc_call_error queue_call_request(grpc_server* server, size_t cq_idx, - requested_call* rc) { - if (server->shutdown_flag.load(std::memory_order_acquire)) { - fail_call(server, cq_idx, rc, - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); - return GRPC_CALL_OK; +void Server::CallData::StartNewRpc(grpc_call_element* elem) { + auto* chand = static_cast(elem->channel_data); + if (server_->shutdown_flag_.load(std::memory_order_acquire)) { + state_.Store(CallState::ZOMBIED, MemoryOrder::RELAXED); + KillZombie(); + return; } - RequestMatcherInterface* rm; - switch (rc->type) { - case RequestedCallType::BATCH_CALL: - rm = server->unregistered_request_matcher.get(); + // Find request matcher. + matcher_ = server_->unregistered_request_matcher_.get(); + grpc_server_register_method_payload_handling payload_handling = + GRPC_SRM_PAYLOAD_NONE; + if (path_.has_value() && host_.has_value()) { + ChannelRegisteredMethod* rm = + chand->GetRegisteredMethod(*host_, *path_, + (recv_initial_metadata_flags_ & + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)); + if (rm != nullptr) { + matcher_ = rm->server_registered_method->matcher.get(); + payload_handling = rm->server_registered_method->payload_handling; + } + } + // Start recv_message op if needed. + switch (payload_handling) { + case GRPC_SRM_PAYLOAD_NONE: + PublishNewRpc(elem, GRPC_ERROR_NONE); break; - case RequestedCallType::REGISTERED_CALL: - rm = rc->data.registered.method->matcher.get(); + case GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER: { + grpc_op op; + op.op = GRPC_OP_RECV_MESSAGE; + op.flags = 0; + op.reserved = nullptr; + op.data.recv_message.recv_message = &payload_; + GRPC_CLOSURE_INIT(&publish_, PublishNewRpc, elem, + grpc_schedule_on_exec_ctx); + grpc_call_start_batch_and_execute(call_, &op, 1, &publish_); break; + } } - rm->RequestCallWithPossiblePublish(cq_idx, rc); - return GRPC_CALL_OK; } -void fail_call(grpc_server* server, size_t cq_idx, requested_call* rc, - grpc_error* error) { - *rc->call = nullptr; - rc->initial_metadata->count = 0; - GPR_ASSERT(error != GRPC_ERROR_NONE); +void Server::CallData::RecvInitialMetadataBatchComplete(void* arg, + grpc_error* error) { + grpc_call_element* elem = static_cast(arg); + auto* calld = static_cast(elem->call_data); + if (error != GRPC_ERROR_NONE) { + calld->FailCallCreation(); + return; + } + calld->StartNewRpc(elem); +} - grpc_cq_end_op(server->cqs[cq_idx], rc->tag, error, done_request_event, rc, - &rc->completion); +void Server::CallData::StartTransportStreamOpBatchImpl( + grpc_call_element* elem, grpc_transport_stream_op_batch* batch) { + if (batch->recv_initial_metadata) { + GPR_ASSERT(batch->payload->recv_initial_metadata.recv_flags == nullptr); + recv_initial_metadata_ = + batch->payload->recv_initial_metadata.recv_initial_metadata; + original_recv_initial_metadata_ready_ = + batch->payload->recv_initial_metadata.recv_initial_metadata_ready; + batch->payload->recv_initial_metadata.recv_initial_metadata_ready = + &recv_initial_metadata_ready_; + batch->payload->recv_initial_metadata.recv_flags = + &recv_initial_metadata_flags_; + } + if (batch->recv_trailing_metadata) { + original_recv_trailing_metadata_ready_ = + batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &recv_trailing_metadata_ready_; + } + grpc_call_next_op(elem, batch); } -} // namespace +void Server::CallData::RecvInitialMetadataReady(void* ptr, grpc_error* error) { + grpc_call_element* elem = static_cast(ptr); + CallData* calld = static_cast(elem->call_data); + grpc_millis op_deadline; + if (error == GRPC_ERROR_NONE) { + GPR_DEBUG_ASSERT(calld->recv_initial_metadata_->idx.named.path != nullptr); + GPR_DEBUG_ASSERT(calld->recv_initial_metadata_->idx.named.authority != + nullptr); + calld->path_.emplace(grpc_slice_ref_internal( + GRPC_MDVALUE(calld->recv_initial_metadata_->idx.named.path->md))); + calld->host_.emplace(grpc_slice_ref_internal( + GRPC_MDVALUE(calld->recv_initial_metadata_->idx.named.authority->md))); + grpc_metadata_batch_remove(calld->recv_initial_metadata_, GRPC_BATCH_PATH); + grpc_metadata_batch_remove(calld->recv_initial_metadata_, + GRPC_BATCH_AUTHORITY); + } else { + GRPC_ERROR_REF(error); + } + op_deadline = calld->recv_initial_metadata_->deadline; + if (op_deadline != GRPC_MILLIS_INF_FUTURE) { + calld->deadline_ = op_deadline; + } + if (calld->host_.has_value() && calld->path_.has_value()) { + /* do nothing */ + } else { + /* Pass the error reference to calld->recv_initial_metadata_error */ + grpc_error* src_error = error; + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Missing :authority or :path", &src_error, 1); + GRPC_ERROR_UNREF(src_error); + calld->recv_initial_metadata_error_ = GRPC_ERROR_REF(error); + } + grpc_closure* closure = calld->original_recv_initial_metadata_ready_; + calld->original_recv_initial_metadata_ready_ = nullptr; + if (calld->seen_recv_trailing_metadata_ready_) { + GRPC_CALL_COMBINER_START(calld->call_combiner_, + &calld->recv_trailing_metadata_ready_, + calld->recv_trailing_metadata_error_, + "continue server recv_trailing_metadata_ready"); + } + Closure::Run(DEBUG_LOCATION, closure, error); +} -void SetServerRegisteredMethodAllocator( - grpc_server* server, grpc_completion_queue* cq, void* method_tag, - std::function allocator) { - registered_method* rm = static_cast(method_tag); - rm->matcher = absl::make_unique( - server, cq, rm, std::move(allocator)); +void Server::CallData::RecvTrailingMetadataReady(void* user_data, + grpc_error* error) { + grpc_call_element* elem = static_cast(user_data); + CallData* calld = static_cast(elem->call_data); + if (calld->original_recv_initial_metadata_ready_ != nullptr) { + calld->recv_trailing_metadata_error_ = GRPC_ERROR_REF(error); + calld->seen_recv_trailing_metadata_ready_ = true; + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready_, + RecvTrailingMetadataReady, elem, + grpc_schedule_on_exec_ctx); + GRPC_CALL_COMBINER_STOP(calld->call_combiner_, + "deferring server recv_trailing_metadata_ready " + "until after recv_initial_metadata_ready"); + return; + } + error = + grpc_error_add_child(GRPC_ERROR_REF(error), + GRPC_ERROR_REF(calld->recv_initial_metadata_error_)); + Closure::Run(DEBUG_LOCATION, calld->original_recv_trailing_metadata_ready_, + error); } -void SetServerBatchMethodAllocator( - grpc_server* server, grpc_completion_queue* cq, - std::function allocator) { - GPR_DEBUG_ASSERT(server->unregistered_request_matcher == nullptr); - server->unregistered_request_matcher = - absl::make_unique(server, cq, - std::move(allocator)); +grpc_error* Server::CallData::InitCallElement( + grpc_call_element* elem, const grpc_call_element_args* args) { + auto* chand = static_cast(elem->channel_data); + new (elem->call_data) Server::CallData(elem, *args, chand->server()); + return GRPC_ERROR_NONE; +} + +void Server::CallData::DestroyCallElement( + grpc_call_element* elem, const grpc_call_final_info* /*final_info*/, + grpc_closure* /*ignored*/) { + auto* calld = static_cast(elem->call_data); + calld->~CallData(); +} + +void Server::CallData::StartTransportStreamOpBatch( + grpc_call_element* elem, grpc_transport_stream_op_batch* batch) { + auto* calld = static_cast(elem->call_data); + calld->StartTransportStreamOpBatchImpl(elem, batch); } } // namespace grpc_core -const grpc_channel_filter grpc_server_top_filter = { - grpc_core::server_start_transport_stream_op_batch, - grpc_channel_next_op, - sizeof(grpc_core::call_data), - grpc_core::server_init_call_elem, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - grpc_core::server_destroy_call_elem, - sizeof(grpc_core::channel_data), - grpc_core::server_init_channel_elem, - grpc_core::server_destroy_channel_elem, - grpc_channel_next_get_info, - "server", -}; +// +// C-core API +// -// The following are core surface API functions. +grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) { + grpc_core::ExecCtx exec_ctx; + GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); + grpc_server* c_server = new grpc_server; + c_server->core_server = grpc_core::MakeOrphanable(args); + return c_server; +} void grpc_server_register_completion_queue(grpc_server* server, grpc_completion_queue* cq, @@ -1368,7 +1458,7 @@ void grpc_server_register_completion_queue(grpc_server* server, GRPC_API_TRACE( "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3, (server, cq, reserved)); - + GPR_ASSERT(!reserved); auto cq_type = grpc_get_cq_completion_type(cq); if (cq_type != GRPC_CQ_NEXT && cq_type != GRPC_CQ_CALLBACK) { gpr_log(GPR_INFO, @@ -1378,15 +1468,7 @@ void grpc_server_register_completion_queue(grpc_server* server, /* Ideally we should log an error and abort but ruby-wrapped-language API calls grpc_completion_queue_pluck() on server completion queues */ } - - grpc_core::register_completion_queue(server, cq, reserved); -} - -grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) { - grpc_core::ExecCtx exec_ctx; - GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); - - return new grpc_server(args); + server->core_server->RegisterCompletionQueue(cq); } void* grpc_server_register_method( @@ -1397,285 +1479,42 @@ void* grpc_server_register_method( "grpc_server_register_method(server=%p, method=%s, host=%s, " "flags=0x%08x)", 4, (server, method, host, flags)); - if (!method) { - gpr_log(GPR_ERROR, - "grpc_server_register_method method string cannot be NULL"); - return nullptr; - } - for (std::unique_ptr& m : - server->registered_methods) { - if (grpc_core::streq(m->method, method) && - grpc_core::streq(m->host, host)) { - gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, - host ? host : "*"); - return nullptr; - } - } - if ((flags & ~GRPC_INITIAL_METADATA_USED_MASK) != 0) { - gpr_log(GPR_ERROR, "grpc_server_register_method invalid flags 0x%08x", - flags); - return nullptr; - } - server->registered_methods.emplace_back( - new grpc_core::registered_method(method, host, payload_handling, flags)); - return static_cast(server->registered_methods.back().get()); + return server->core_server->RegisterMethod(method, host, payload_handling, + flags); } void grpc_server_start(grpc_server* server) { - size_t i; grpc_core::ExecCtx exec_ctx; - GRPC_API_TRACE("grpc_server_start(server=%p)", 1, (server)); - - server->started = true; - for (i = 0; i < server->cqs.size(); i++) { - if (grpc_cq_can_listen(server->cqs[i])) { - server->pollsets.push_back(grpc_cq_pollset(server->cqs[i])); - } - } - if (server->unregistered_request_matcher == nullptr) { - server->unregistered_request_matcher = - absl::make_unique(server); - } - for (std::unique_ptr& rm : - server->registered_methods) { - if (rm->matcher == nullptr) { - rm->matcher = absl::make_unique(server); - } - } - - { - grpc_core::MutexLock lock(&server->mu_global); - server->starting = true; - } - - for (auto& listener : server->listeners) { - listener.listener->Start(server, &server->pollsets); - } - - grpc_core::MutexLock lock(&server->mu_global); - server->starting = false; - server->starting_cv.Signal(); + server->core_server->Start(); } -/* - - Kills all pending requests-for-incoming-RPC-calls (i.e the requests made via - grpc_server_request_call and grpc_server_request_registered call will now be - cancelled). See 'kill_pending_work_locked()' - - - Shuts down the listeners (i.e the server will no longer listen on the port - for new incoming channels). - - - Iterates through all channels on the server and sends shutdown msg (see - 'ChannelBroadcaster::BroadcastShutdown' for details) to the clients via the - transport layer. The transport layer then guarantees the following: - -- Sends shutdown to the client (for eg: HTTP2 transport sends GOAWAY) - -- If the server has outstanding calls that are in the process, the - connection is NOT closed until the server is done with all those calls - -- Once, there are no more calls in progress, the channel is closed - */ void grpc_server_shutdown_and_notify(grpc_server* server, grpc_completion_queue* cq, void* tag) { - grpc_core::ChannelBroadcaster broadcaster; grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ExecCtx exec_ctx; - GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3, (server, cq, tag)); - - { - /* wait for startup to be finished: locks mu_global */ - grpc_core::MutexLock lock(&server->mu_global); - server->starting_cv.WaitUntil(&server->mu_global, - [server] { return !server->starting; }); - - /* stay locked, and gather up some stuff to do */ - GPR_ASSERT(grpc_cq_begin_op(cq, tag)); - if (server->shutdown_published) { - grpc_cq_end_op(cq, tag, GRPC_ERROR_NONE, - grpc_core::done_published_shutdown, nullptr, - new grpc_cq_completion); - return; - } - server->shutdown_tags.emplace_back(tag, cq); - if (server->shutdown_flag.load(std::memory_order_acquire)) { - return; - } - - server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); - - broadcaster.FillChannelsLocked(server); - - server->shutdown_flag.store(true, std::memory_order_release); - - /* collect all unregistered then registered calls */ - { - grpc_core::MutexLock lock(&server->mu_call); - grpc_core::kill_pending_work_locked( - server, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); - } - - grpc_core::maybe_finish_shutdown(server); - } - - /* Shutdown listeners */ - for (auto& listener : server->listeners) { - grpc_core::channelz::ListenSocketNode* channelz_listen_socket_node = - listener.listener->channelz_listen_socket_node(); - if (server->channelz_server != nullptr && - channelz_listen_socket_node != nullptr) { - server->channelz_server->RemoveChildListenSocket( - channelz_listen_socket_node->uuid()); - } - GRPC_CLOSURE_INIT(&listener.destroy_done, grpc_core::listener_destroy_done, - server, grpc_schedule_on_exec_ctx); - listener.listener->SetOnDestroyDone(&listener.destroy_done); - listener.listener.reset(); - } - - broadcaster.BroadcastShutdown(/*send_goaway=*/true, GRPC_ERROR_NONE); + server->core_server->ShutdownAndNotify(cq, tag); } void grpc_server_cancel_all_calls(grpc_server* server) { - grpc_core::ChannelBroadcaster broadcaster; grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ExecCtx exec_ctx; - GRPC_API_TRACE("grpc_server_cancel_all_calls(server=%p)", 1, (server)); - - { - grpc_core::MutexLock lock(&server->mu_global); - broadcaster.FillChannelsLocked(server); - } - - broadcaster.BroadcastShutdown( - /*send_goaway=*/false, - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Cancelling all calls")); + server->core_server->CancelAllCalls(); } void grpc_server_destroy(grpc_server* server) { grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ExecCtx exec_ctx; - GRPC_API_TRACE("grpc_server_destroy(server=%p)", 1, (server)); - - { - grpc_core::MutexLock lock(&server->mu_global); - GPR_ASSERT(server->shutdown_flag.load(std::memory_order_acquire) || - server->listeners.empty()); - GPR_ASSERT(server->listeners_destroyed == server->listeners.size()); - } - - if (server->default_resource_user != nullptr) { - grpc_resource_quota_unref( - grpc_resource_user_quota(server->default_resource_user)); - grpc_resource_user_shutdown(server->default_resource_user); - grpc_resource_user_unref(server->default_resource_user); - } - grpc_core::server_unref(server); -} - -const std::vector& grpc_server_get_pollsets( - grpc_server* server) { - return server->pollsets; -} - -void grpc_server_setup_transport( - grpc_server* s, grpc_transport* transport, grpc_pollset* accepting_pollset, - const grpc_channel_args* args, - const grpc_core::RefCountedPtr& - socket_node, - grpc_resource_user* resource_user) { - size_t num_registered_methods; - grpc_core::channel_registered_method* crm; - grpc_channel* channel; - grpc_core::channel_data* chand; - uint32_t hash; - size_t slots; - uint32_t probes; - uint32_t max_probes = 0; - grpc_transport_op* op = nullptr; - - channel = grpc_channel_create(nullptr, args, GRPC_SERVER_CHANNEL, transport, - resource_user); - chand = static_cast( - grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0) - ->channel_data); - chand->server = s; - grpc_core::server_ref(s); - chand->channel = channel; - if (socket_node != nullptr) { - chand->channelz_socket_uuid = socket_node->uuid(); - s->channelz_server->AddChildSocket(socket_node); - } else { - chand->channelz_socket_uuid = 0; - } - - size_t cq_idx; - for (cq_idx = 0; cq_idx < s->cqs.size(); cq_idx++) { - if (grpc_cq_pollset(s->cqs[cq_idx]) == accepting_pollset) break; - } - if (cq_idx == s->cqs.size()) { - /* completion queue not found: pick a random one to publish new calls to */ - cq_idx = static_cast(rand()) % s->cqs.size(); - } - chand->cq_idx = cq_idx; - - num_registered_methods = s->registered_methods.size(); - /* build a lookup table phrased in terms of mdstr's in this channels context - to quickly find registered methods */ - if (num_registered_methods > 0) { - slots = 2 * num_registered_methods; - chand->registered_methods.reset( - new std::vector(slots)); - for (std::unique_ptr& rm : - s->registered_methods) { - grpc_core::ExternallyManagedSlice host; - grpc_core::ExternallyManagedSlice method(rm->method.c_str()); - const bool has_host = !rm->host.empty(); - if (has_host) { - host = grpc_core::ExternallyManagedSlice(rm->host.c_str()); - } - hash = GRPC_MDSTR_KV_HASH(has_host ? host.Hash() : 0, method.Hash()); - for (probes = 0; (*chand->registered_methods)[(hash + probes) % slots] - .server_registered_method != nullptr; - probes++) { - } - if (probes > max_probes) max_probes = probes; - crm = &(*chand->registered_methods)[(hash + probes) % slots]; - crm->server_registered_method = rm.get(); - crm->flags = rm->flags; - crm->has_host = has_host; - if (has_host) { - crm->host = host; - } - crm->method = method; - } - GPR_ASSERT(slots <= UINT32_MAX); - chand->registered_method_max_probes = max_probes; - } - - { - grpc_core::MutexLock lock(&s->mu_global); - s->channels.push_front(chand); - chand->list_position = s->channels.begin(); - } - - op = grpc_make_transport_op(nullptr); - op->set_accept_stream = true; - op->set_accept_stream_fn = grpc_core::accept_stream; - op->set_accept_stream_user_data = chand; - op->start_connectivity_watch.reset(new grpc_core::ConnectivityWatcher(chand)); - if (s->shutdown_flag.load(std::memory_order_acquire)) { - op->disconnect_with_error = - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"); - } - grpc_transport_perform_op(transport, op); + delete server; } grpc_call_error grpc_server_request_call( grpc_server* server, grpc_call** call, grpc_call_details* details, - grpc_metadata_array* initial_metadata, + grpc_metadata_array* request_metadata, grpc_completion_queue* cq_bound_to_call, grpc_completion_queue* cq_for_notification, void* tag) { grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; @@ -1686,49 +1525,31 @@ grpc_call_error grpc_server_request_call( "server=%p, call=%p, details=%p, initial_metadata=%p, " "cq_bound_to_call=%p, cq_for_notification=%p, tag=%p)", 7, - (server, call, details, initial_metadata, cq_bound_to_call, + (server, call, details, request_metadata, cq_bound_to_call, cq_for_notification, tag)); - - size_t cq_idx; - grpc_call_error error = grpc_core::ValidateServerRequestAndCq( - &cq_idx, server, cq_for_notification, tag, nullptr, nullptr); - if (error != GRPC_CALL_OK) { - return error; - } - - grpc_core::requested_call* rc = new grpc_core::requested_call( - tag, cq_bound_to_call, call, initial_metadata, details); - return queue_call_request(server, cq_idx, rc); + return server->core_server->RequestCall(call, details, request_metadata, + cq_bound_to_call, cq_for_notification, + tag); } grpc_call_error grpc_server_request_registered_call( grpc_server* server, void* rmp, grpc_call** call, gpr_timespec* deadline, - grpc_metadata_array* initial_metadata, grpc_byte_buffer** optional_payload, + grpc_metadata_array* request_metadata, grpc_byte_buffer** optional_payload, grpc_completion_queue* cq_bound_to_call, grpc_completion_queue* cq_for_notification, void* tag_new) { grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ExecCtx exec_ctx; GRPC_STATS_INC_SERVER_REQUESTED_CALLS(); - grpc_core::registered_method* rm = - static_cast(rmp); + auto* rm = static_cast(rmp); GRPC_API_TRACE( "grpc_server_request_registered_call(" - "server=%p, rmp=%p, call=%p, deadline=%p, initial_metadata=%p, " + "server=%p, rmp=%p, call=%p, deadline=%p, request_metadata=%p, " "optional_payload=%p, cq_bound_to_call=%p, cq_for_notification=%p, " "tag=%p)", 9, - (server, rmp, call, deadline, initial_metadata, optional_payload, + (server, rmp, call, deadline, request_metadata, optional_payload, cq_bound_to_call, cq_for_notification, tag_new)); - - size_t cq_idx; - grpc_call_error error = ValidateServerRequestAndCq( - &cq_idx, server, cq_for_notification, tag_new, optional_payload, rm); - if (error != GRPC_CALL_OK) { - return error; - } - - grpc_core::requested_call* rc = new grpc_core::requested_call( - tag_new, cq_bound_to_call, call, initial_metadata, rm, deadline, - optional_payload); - return queue_call_request(server, cq_idx, rc); + return server->core_server->RequestRegisteredCall( + rm, call, deadline, request_metadata, optional_payload, cq_bound_to_call, + cq_for_notification, tag_new); } diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index d63a640f84d..3a13b6f404e 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -1,121 +1,397 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ +// +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// #ifndef GRPC_CORE_LIB_SURFACE_SERVER_H #define GRPC_CORE_LIB_SURFACE_SERVER_H #include +#include +#include + +#include "absl/types/optional.h" + #include + +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channelz.h" #include "src/core/lib/debug/trace.h" +#include "src/core/lib/gprpp/atomic.h" +#include "src/core/lib/surface/completion_queue.h" #include "src/core/lib/transport/transport.h" -extern const grpc_channel_filter grpc_server_top_filter; - -/** Lightweight tracing of server channel state */ -extern grpc_core::TraceFlag grpc_server_channel_trace; - namespace grpc_core { -/// Interface for listeners. -/// Implementations must override the Orphan() method, which should stop -/// listening and initiate destruction of the listener. -class ServerListenerInterface : public Orphanable { +extern TraceFlag grpc_server_channel_trace; + +class Server : public InternallyRefCounted { public: - virtual ~ServerListenerInterface() = default; + // Filter vtable. + static const grpc_channel_filter kServerTopFilter; - /// Starts listening. This listener may refer to the pollset object beyond - /// this call, so it is a pointer rather than a reference. - virtual void Start(grpc_server* server, - const std::vector* pollsets) = 0; + // Opaque type used for registered methods. + struct RegisteredMethod; - /// Returns the channelz node for the listen socket, or null if not - /// supported. - virtual channelz::ListenSocketNode* channelz_listen_socket_node() const = 0; + // An object to represent the most relevant characteristics of a + // newly-allocated call object when using an AllocatingRequestMatcherBatch. + struct BatchCallAllocation { + grpc_experimental_completion_queue_functor* tag; + grpc_call** call; + grpc_metadata_array* initial_metadata; + grpc_call_details* details; + }; - /// Sets a closure to be invoked by the listener when its destruction - /// is complete. - virtual void SetOnDestroyDone(grpc_closure* on_destroy_done) = 0; -}; + // An object to represent the most relevant characteristics of a + // newly-allocated call object when using an + // AllocatingRequestMatcherRegistered. + struct RegisteredCallAllocation { + grpc_experimental_completion_queue_functor* tag; + grpc_call** call; + grpc_metadata_array* initial_metadata; + gpr_timespec* deadline; + grpc_byte_buffer** optional_payload; + }; -} // namespace grpc_core + /// Interface for listeners. + /// Implementations must override the Orphan() method, which should stop + /// listening and initiate destruction of the listener. + class ListenerInterface : public Orphanable { + public: + virtual ~ListenerInterface() = default; -/* Add a listener to the server: when the server starts, it will call Start(), - and when it shuts down, it will orphan the listener. */ -void grpc_server_add_listener( - grpc_server* server, - grpc_core::OrphanablePtr listener); + /// Starts listening. This listener may refer to the pollset object beyond + /// this call, so it is a pointer rather than a reference. + virtual void Start(Server* server, + const std::vector* pollsets) = 0; -/* Setup a transport - creates a channel stack, binds the transport to the - server */ -void grpc_server_setup_transport( - grpc_server* server, grpc_transport* transport, - grpc_pollset* accepting_pollset, const grpc_channel_args* args, - const grpc_core::RefCountedPtr& - socket_node, - grpc_resource_user* resource_user = nullptr); + /// Returns the channelz node for the listen socket, or null if not + /// supported. + virtual channelz::ListenSocketNode* channelz_listen_socket_node() const = 0; -grpc_core::channelz::ServerNode* grpc_server_get_channelz_node( - grpc_server* server); + /// Sets a closure to be invoked by the listener when its destruction + /// is complete. + virtual void SetOnDestroyDone(grpc_closure* on_destroy_done) = 0; + }; -const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server); + explicit Server(const grpc_channel_args* args); + ~Server(); -grpc_resource_user* grpc_server_get_default_resource_user(grpc_server* server); + void Orphan() override; -bool grpc_server_has_open_connections(grpc_server* server); + const grpc_channel_args* channel_args() const { return channel_args_; } + grpc_resource_user* default_resource_user() const { + return default_resource_user_; + } + channelz::ServerNode* channelz_node() const { return channelz_node_.get(); } -// Do not call this before grpc_server_start. Returns the pollsets. The vector -// itself is immutable, but the pollsets inside are mutable. The result is valid -// for the lifetime of the server. -const std::vector& grpc_server_get_pollsets(grpc_server* server); + // Do not call this before Start(). Returns the pollsets. The + // vector itself is immutable, but the pollsets inside are mutable. The + // result is valid for the lifetime of the server. + const std::vector& pollsets() const { return pollsets_; } -namespace grpc_core { + bool HasOpenConnections(); -// An object to represent the most relevant characteristics of a newly-allocated -// call object when using an AllocatingRequestMatcherBatch -struct ServerBatchCallAllocation { - grpc_experimental_completion_queue_functor* tag; - grpc_call** call; - grpc_metadata_array* initial_metadata; - grpc_call_details* details; -}; + // Adds a listener to the server. When the server starts, it will call + // the listener's Start() method, and when it shuts down, it will orphan + // the listener. + void AddListener(OrphanablePtr listener); -// An object to represent the most relevant characteristics of a newly-allocated -// call object when using an AllocatingRequestMatcherRegistered -struct ServerRegisteredCallAllocation { - grpc_experimental_completion_queue_functor* tag; - grpc_call** call; - grpc_metadata_array* initial_metadata; - gpr_timespec* deadline; - grpc_byte_buffer** optional_payload; -}; + // Starts listening for connections. + void Start(); + + // Sets up a transport. Creates a channel stack and binds the transport to + // the server. Called from the listener when a new connection is accepted. + void SetupTransport(grpc_transport* transport, + grpc_pollset* accepting_pollset, + const grpc_channel_args* args, + const RefCountedPtr& socket_node, + grpc_resource_user* resource_user = nullptr); + + void RegisterCompletionQueue(grpc_completion_queue* cq); + + // Functions to specify that a specific registered method or the unregistered + // collection should use a specific allocator for request matching. + void SetRegisteredMethodAllocator( + grpc_completion_queue* cq, void* method_tag, + std::function allocator); + void SetBatchMethodAllocator(grpc_completion_queue* cq, + std::function allocator); + + RegisteredMethod* RegisterMethod( + const char* method, const char* host, + grpc_server_register_method_payload_handling payload_handling, + uint32_t flags); + + grpc_call_error RequestCall(grpc_call** call, grpc_call_details* details, + grpc_metadata_array* request_metadata, + grpc_completion_queue* cq_bound_to_call, + grpc_completion_queue* cq_for_notification, + void* tag); + + grpc_call_error RequestRegisteredCall( + RegisteredMethod* rm, grpc_call** call, gpr_timespec* deadline, + grpc_metadata_array* request_metadata, + grpc_byte_buffer** optional_payload, + grpc_completion_queue* cq_bound_to_call, + grpc_completion_queue* cq_for_notification, void* tag_new); + + void ShutdownAndNotify(grpc_completion_queue* cq, void* tag); + + void CancelAllCalls(); + + private: + struct RequestedCall; + + struct ChannelRegisteredMethod { + RegisteredMethod* server_registered_method = nullptr; + uint32_t flags; + bool has_host; + ExternallyManagedSlice method; + ExternallyManagedSlice host; + }; + + class RequestMatcherInterface; + class RealRequestMatcher; + class AllocatingRequestMatcherBase; + class AllocatingRequestMatcherBatch; + class AllocatingRequestMatcherRegistered; + + class ChannelData { + public: + ChannelData() = default; + ~ChannelData(); + + void InitTransport(RefCountedPtr server, grpc_channel* channel, + size_t cq_idx, grpc_transport* transport, + intptr_t channelz_socket_uuid); + + RefCountedPtr server() const { return server_; } + grpc_channel* channel() const { return channel_; } + size_t cq_idx() const { return cq_idx_; } + + ChannelRegisteredMethod* GetRegisteredMethod(const grpc_slice& host, + const grpc_slice& path, + bool is_idempotent); + + // Filter vtable functions. + static grpc_error* InitChannelElement(grpc_channel_element* elem, + grpc_channel_element_args* args); + static void DestroyChannelElement(grpc_channel_element* elem); + + private: + class ConnectivityWatcher; + + static void AcceptStream(void* arg, grpc_transport* /*transport*/, + const void* transport_server_data); + + void Destroy(); + + static void FinishDestroy(void* arg, grpc_error* error); + + RefCountedPtr server_; + grpc_channel* channel_; + // The index into Server::cqs_ of the CQ used as a starting point for + // where to publish new incoming calls. + size_t cq_idx_; + absl::optional::iterator> list_position_; + // A hash-table of the methods and hosts of the registered methods. + // TODO(vjpai): Convert this to an STL map type as opposed to a direct + // bucket implementation. (Consider performance impact, hash function to + // use, etc.) + std::unique_ptr> registered_methods_; + uint32_t registered_method_max_probes_; + grpc_closure finish_destroy_channel_closure_; + intptr_t channelz_socket_uuid_; + }; + + class CallData { + public: + enum class CallState { + NOT_STARTED, // Waiting for metadata. + PENDING, // Initial metadata read, not flow controlled in yet. + ACTIVATED, // Flow controlled in, on completion queue. + ZOMBIED, // Cancelled before being queued. + }; + + CallData(grpc_call_element* elem, const grpc_call_element_args& args, + RefCountedPtr server); + ~CallData(); + + // Starts the recv_initial_metadata batch on the call. + // Invoked from ChannelData::AcceptStream(). + void Start(grpc_call_element* elem); + + void SetState(CallState state); + + // Attempts to move from PENDING to ACTIVATED state. Returns true + // on success. + bool MaybeActivate(); + + // Publishes an incoming call to the application after it has been + // matched. + void Publish(size_t cq_idx, RequestedCall* rc); + + void KillZombie(); -// Functions to specify that a specific registered method or the unregistered -// collection should use a specific allocator for request matching. -void SetServerRegisteredMethodAllocator( - grpc_server* server, grpc_completion_queue* cq, void* method_tag, - std::function allocator); -void SetServerBatchMethodAllocator( - grpc_server* server, grpc_completion_queue* cq, - std::function allocator); + void FailCallCreation(); + + // Filter vtable functions. + static grpc_error* InitCallElement(grpc_call_element* elem, + const grpc_call_element_args* args); + static void DestroyCallElement(grpc_call_element* elem, + const grpc_call_final_info* /*final_info*/, + grpc_closure* /*ignored*/); + static void StartTransportStreamOpBatch( + grpc_call_element* elem, grpc_transport_stream_op_batch* batch); + + private: + // Helper functions for handling calls at the top of the call stack. + static void RecvInitialMetadataBatchComplete(void* arg, grpc_error* error); + void StartNewRpc(grpc_call_element* elem); + static void PublishNewRpc(void* arg, grpc_error* error); + + // Functions used inside the call stack. + void StartTransportStreamOpBatchImpl(grpc_call_element* elem, + grpc_transport_stream_op_batch* batch); + static void RecvInitialMetadataReady(void* arg, grpc_error* error); + static void RecvTrailingMetadataReady(void* arg, grpc_error* error); + + RefCountedPtr server_; + + grpc_call* call_; + + Atomic state_{CallState::NOT_STARTED}; + + absl::optional path_; + absl::optional host_; + grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE; + + grpc_completion_queue* cq_new_ = nullptr; + + RequestMatcherInterface* matcher_ = nullptr; + grpc_byte_buffer* payload_ = nullptr; + + grpc_closure kill_zombie_closure_; + + grpc_metadata_array initial_metadata_ = + grpc_metadata_array(); // Zero-initialize the C struct. + grpc_closure recv_initial_metadata_batch_complete_; + + grpc_metadata_batch* recv_initial_metadata_ = nullptr; + uint32_t recv_initial_metadata_flags_ = 0; + grpc_closure recv_initial_metadata_ready_; + grpc_closure* original_recv_initial_metadata_ready_; + grpc_error* recv_initial_metadata_error_ = GRPC_ERROR_NONE; + + bool seen_recv_trailing_metadata_ready_ = false; + grpc_closure recv_trailing_metadata_ready_; + grpc_closure* original_recv_trailing_metadata_ready_; + grpc_error* recv_trailing_metadata_error_ = GRPC_ERROR_NONE; + + grpc_closure publish_; + + CallCombiner* call_combiner_; + }; + + struct Listener { + explicit Listener(OrphanablePtr l) + : listener(std::move(l)) {} + OrphanablePtr listener; + grpc_closure destroy_done; + }; + + struct ShutdownTag { + ShutdownTag(void* tag_arg, grpc_completion_queue* cq_arg) + : tag(tag_arg), cq(cq_arg) {} + void* const tag; + grpc_completion_queue* const cq; + grpc_cq_completion completion; + }; + + static void ListenerDestroyDone(void* arg, grpc_error* error); + + static void DoneShutdownEvent(void* server, + grpc_cq_completion* /*completion*/) { + static_cast(server)->Unref(); + } + + static void DoneRequestEvent(void* req, grpc_cq_completion* completion); + + void FailCall(size_t cq_idx, RequestedCall* rc, grpc_error* error); + grpc_call_error QueueRequestedCall(size_t cq_idx, RequestedCall* rc); + + void MaybeFinishShutdown(); + + void KillPendingWorkLocked(grpc_error* error); + + static grpc_call_error ValidateServerRequest( + grpc_completion_queue* cq_for_notification, void* tag, + grpc_byte_buffer** optional_payload, RegisteredMethod* rm); + grpc_call_error ValidateServerRequestAndCq( + size_t* cq_idx, grpc_completion_queue* cq_for_notification, void* tag, + grpc_byte_buffer** optional_payload, RegisteredMethod* rm); + + std::vector GetChannelsLocked() const; + + grpc_channel_args* const channel_args_; + grpc_resource_user* default_resource_user_ = nullptr; + RefCountedPtr channelz_node_; + + std::vector cqs_; + std::vector pollsets_; + bool started_ = false; + + // The two following mutexes control access to server-state. + // mu_global_ controls access to non-call-related state (e.g., channel state). + // mu_call_ controls access to call-related state (e.g., the call lists). + // + // If they are ever required to be nested, you must lock mu_global_ + // before mu_call_. This is currently used in shutdown processing + // (ShutdownAndNotify() and MaybeFinishShutdown()). + Mutex mu_global_; // mutex for server and channel state + Mutex mu_call_; // mutex for call-specific state + + // startup synchronization: flag is protected by mu_global_, signals whether + // we are doing the listener start routine or not. + bool starting_ = false; + CondVar starting_cv_; + + std::vector> registered_methods_; + + // Request matcher for unregistered methods. + std::unique_ptr unregistered_request_matcher_; + + std::atomic_bool shutdown_flag_{false}; + bool shutdown_published_ = false; + std::vector shutdown_tags_; + + std::list channels_; + + std::list listeners_; + size_t listeners_destroyed_ = 0; + + // The last time we printed a shutdown progress message. + gpr_timespec last_shutdown_message_time_; +}; } // namespace grpc_core +struct grpc_server { + grpc_core::OrphanablePtr core_server; +}; + #endif /* GRPC_CORE_LIB_SURFACE_SERVER_H */ diff --git a/src/cpp/server/external_connection_acceptor_impl.h b/src/cpp/server/external_connection_acceptor_impl.h index 3fb94c90848..9c65ac1660d 100644 --- a/src/cpp/server/external_connection_acceptor_impl.h +++ b/src/cpp/server/external_connection_acceptor_impl.h @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index 48fb3ad9f34..89b3c685b29 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -92,10 +92,6 @@ void AuthMetadataProcessorAyncWrapper::InvokeProcessor( status.error_message().c_str()); } -} // namespace grpc - -namespace grpc { - int SecureServerCredentials::AddPortToServer(const std::string& addr, grpc_server* server) { return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 489480bc503..c9aa49c44f6 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -547,7 +547,7 @@ class Server::CallbackRequest final // is nullptr since these services don't have pre-defined methods. CallbackRequest(Server* server, grpc::internal::RpcServiceMethod* method, grpc::CompletionQueue* cq, - grpc_core::ServerRegisteredCallAllocation* data) + grpc_core::Server::RegisteredCallAllocation* data) : server_(server), method_(method), has_request_payload_(method->method_type() == @@ -568,7 +568,7 @@ class Server::CallbackRequest final // For generic services, method is nullptr since these services don't have // pre-defined methods. CallbackRequest(Server* server, grpc::CompletionQueue* cq, - grpc_core::ServerBatchCallAllocation* data) + grpc_core::Server::BatchCallAllocation* data) : server_(server), method_(nullptr), has_request_payload_(false), @@ -1063,9 +1063,9 @@ bool Server::RegisterService(const std::string* host, grpc::Service* service) { has_callback_methods_ = true; grpc::internal::RpcServiceMethod* method_value = method.get(); grpc::CompletionQueue* cq = CallbackCQ(); - grpc_core::SetServerRegisteredMethodAllocator( - server_, cq->cq(), method_registration_tag, [this, cq, method_value] { - grpc_core::ServerRegisteredCallAllocation result; + server_->core_server->SetRegisteredMethodAllocator( + cq->cq(), method_registration_tag, [this, cq, method_value] { + grpc_core::Server::RegisteredCallAllocation result; new CallbackRequest(this, method_value, cq, &result); return result; @@ -1104,8 +1104,8 @@ void Server::RegisterCallbackGenericService( generic_handler_.reset(service->Handler()); grpc::CompletionQueue* cq = CallbackCQ(); - grpc_core::SetServerBatchMethodAllocator(server_, cq->cq(), [this, cq] { - grpc_core::ServerBatchCallAllocation result; + server_->core_server->SetBatchMethodAllocator(cq->cq(), [this, cq] { + grpc_core::Server::BatchCallAllocation result; new CallbackRequest(this, cq, &result); return result; }); diff --git a/src/cpp/server/server_credentials.cc b/src/cpp/server/server_credentials.cc index 8b85264f9d7..c3b3a8b3793 100644 --- a/src/cpp/server/server_credentials.cc +++ b/src/cpp/server/server_credentials.cc @@ -16,10 +16,10 @@ * */ -#include +#include -namespace grpc_impl { +namespace grpc { ServerCredentials::~ServerCredentials() {} -} // namespace grpc_impl +} // namespace grpc diff --git a/src/cpp/util/error_details.cc b/src/cpp/util/error_details.cc index a1aafcbdc6e..f35a6125552 100644 --- a/src/cpp/util/error_details.cc +++ b/src/cpp/util/error_details.cc @@ -20,7 +20,7 @@ #include "src/proto/grpc/status/status.pb.h" -namespace grpc_impl { +namespace grpc { grpc::Status ExtractErrorDetails(const grpc::Status& from, ::google::rpc::Status* to) { @@ -47,4 +47,4 @@ grpc::Status SetErrorDetails(const ::google::rpc::Status& from, return grpc::Status::OK; } -} // namespace grpc_impl +} // namespace grpc diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 6b44b22acf7..34b58593d37 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -43,6 +43,16 @@ describe GRPC::ActiveCall do @server = new_core_server_for_testing(nil) server_port = @server.add_http2_port(host, :this_port_is_insecure) @server.start + @received_rpcs_queue = Queue.new + @server_thread = Thread.new do + begin + received_rpc = @server.request_call + rescue GRPC::Core::CallError, StandardError => e + # enqueue the exception in this case as a way to indicate the error + received_rpc = e + end + @received_rpcs_queue.push(received_rpc) + end @ch = GRPC::Core::Channel.new("0.0.0.0:#{server_port}", nil, :this_channel_is_insecure) end @@ -50,6 +60,7 @@ describe GRPC::ActiveCall do after(:each) do @server.shutdown_and_notify(deadline) @server.close + @server_thread.join end describe 'restricted view methods' do @@ -105,7 +116,7 @@ describe GRPC::ActiveCall do client_call.remote_send(msg) # check that server rpc new was received - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop expect(recvd_rpc).to_not eq nil recvd_call = recvd_rpc.call @@ -130,7 +141,7 @@ describe GRPC::ActiveCall do client_call.remote_send(msg) # confirm that the message was marshalled - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop recvd_call = recvd_rpc.call server_ops = { CallOps::SEND_INITIAL_METADATA => nil @@ -160,7 +171,7 @@ describe GRPC::ActiveCall do call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil) if f == 1 # confirm that the message was marshalled - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop recvd_call = recvd_rpc.call server_ops = { CallOps::SEND_INITIAL_METADATA => nil @@ -321,7 +332,7 @@ describe GRPC::ActiveCall do call = make_test_call metadata = { k1: 'v1', k2: 'v2' } ActiveCall.client_invoke(call, metadata) - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop recvd_call = recvd_rpc.call expect(recvd_call).to_not be_nil expect(recvd_rpc.metadata).to_not be_nil @@ -339,7 +350,7 @@ describe GRPC::ActiveCall do call = make_test_call ActiveCall.client_invoke(call) - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop server_call = ActiveCall.new( recvd_rpc.call, @pass_through, @@ -405,7 +416,7 @@ describe GRPC::ActiveCall do client_call = make_test_call ActiveCall.client_invoke(client_call) - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop recvd_call = recvd_rpc.call server_call = ActiveCall.new( @@ -575,7 +586,7 @@ describe GRPC::ActiveCall do @client_call = make_test_call @client_call.run_batch(CallOps::SEND_INITIAL_METADATA => {}) - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop recvd_call = recvd_rpc.call @server_call = ActiveCall.new( recvd_call, @@ -654,7 +665,7 @@ describe GRPC::ActiveCall do end def expect_server_to_be_invoked(**kw) - recvd_rpc = @server.request_call + recvd_rpc = @received_rpcs_queue.pop expect(recvd_rpc).to_not eq nil recvd_call = recvd_rpc.call recvd_call.run_batch(CallOps::SEND_INITIAL_METADATA => kw) diff --git a/templates/tools/distrib/python/grpc_version.py.template b/templates/tools/distrib/python/grpc_version.py.template new file mode 100644 index 00000000000..a2f471aff74 --- /dev/null +++ b/templates/tools/distrib/python/grpc_version.py.template @@ -0,0 +1,19 @@ +%YAML 1.2 +--- | + # Copyright 2020 gRPC authors. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! + + VERSION = '${settings.python_version.pep440()}' diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template index dbb3ffc9bb2..89ddb2c24bb 100644 --- a/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template +++ b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template @@ -19,6 +19,7 @@ <%include file="../../apt_get_basic.include"/> <%include file="../../python_deps.include"/> <%include file="../../cxx_deps.include"/> + <%include file="../../cmake_jessie_backports.include"/> <%include file="../../run_tests_addons.include"/> # Define the default command. CMD ["bash"] diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template b/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template index f5c48593b9a..c3a9c7fb892 100644 --- a/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template +++ b/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template @@ -25,4 +25,5 @@ cp -r /var/local/jenkins/service_account $HOME || true cd /var/local/git/grpc-dart/interop - /usr/lib/dart/bin/pub get --verbose + # De-flake attempt: run the cmd one more time in case of transient failure + /usr/lib/dart/bin/pub get --verbose || /usr/lib/dart/bin/pub get --verbose diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc index ba402f2a3fe..1f366758fd4 100644 --- a/test/core/bad_client/bad_client.cc +++ b/test/core/bad_client/bad_client.cc @@ -65,8 +65,8 @@ static void set_done_write(void* arg, grpc_error* /*error*/) { static void server_setup_transport(void* ts, grpc_transport* transport) { thd_args* a = static_cast(ts); grpc_core::ExecCtx exec_ctx; - grpc_server_setup_transport(a->server, transport, nullptr, - grpc_server_get_channel_args(a->server), nullptr); + a->server->core_server->SetupTransport( + transport, nullptr, a->server->core_server->channel_args(), nullptr); } /* Sets the read_done event */ @@ -219,7 +219,7 @@ void grpc_run_bad_client_test( grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq)); /* Check a ground truth */ - GPR_ASSERT(grpc_server_has_open_connections(a.server)); + GPR_ASSERT(a.server->core_server->HasOpenConnections()); gpr_event_init(&a.done_thd); a.validator = server_validator; diff --git a/test/core/bad_client/tests/bad_streaming_id.cc b/test/core/bad_client/tests/bad_streaming_id.cc index b63fccd8d25..3efc3ebdb12 100644 --- a/test/core/bad_client/tests/bad_streaming_id.cc +++ b/test/core/bad_client/tests/bad_streaming_id.cc @@ -76,7 +76,7 @@ namespace { void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/badreq.cc b/test/core/bad_client/tests/badreq.cc index cd6ed70c8cc..ab322b292b0 100644 --- a/test/core/bad_client/tests/badreq.cc +++ b/test/core/bad_client/tests/badreq.cc @@ -31,7 +31,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/connection_prefix.cc b/test/core/bad_client/tests/connection_prefix.cc index b0b6ca67af4..45473722512 100644 --- a/test/core/bad_client/tests/connection_prefix.cc +++ b/test/core/bad_client/tests/connection_prefix.cc @@ -21,7 +21,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/headers.cc b/test/core/bad_client/tests/headers.cc index ed6b533e230..b0795dd015b 100644 --- a/test/core/bad_client/tests/headers.cc +++ b/test/core/bad_client/tests/headers.cc @@ -25,7 +25,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/initial_settings_frame.cc b/test/core/bad_client/tests/initial_settings_frame.cc index 204bf735bfe..0deda7025b1 100644 --- a/test/core/bad_client/tests/initial_settings_frame.cc +++ b/test/core/bad_client/tests/initial_settings_frame.cc @@ -24,7 +24,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/out_of_bounds.cc b/test/core/bad_client/tests/out_of_bounds.cc index 1e5c8738f13..0e38223f288 100644 --- a/test/core/bad_client/tests/out_of_bounds.cc +++ b/test/core/bad_client/tests/out_of_bounds.cc @@ -31,7 +31,7 @@ namespace { void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/server_registered_method.cc b/test/core/bad_client/tests/server_registered_method.cc index e700cb490c0..da0ac28d53b 100644 --- a/test/core/bad_client/tests/server_registered_method.cc +++ b/test/core/bad_client/tests/server_registered_method.cc @@ -68,7 +68,7 @@ static void verifier_succeeds(grpc_server* server, grpc_completion_queue* cq, static void verifier_fails(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/simple_request.cc b/test/core/bad_client/tests/simple_request.cc index eace174a107..d1df05dd349 100644 --- a/test/core/bad_client/tests/simple_request.cc +++ b/test/core/bad_client/tests/simple_request.cc @@ -115,7 +115,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, static void failure_verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/unknown_frame.cc b/test/core/bad_client/tests/unknown_frame.cc index 1b42a7cb73f..645c08f6588 100644 --- a/test/core/bad_client/tests/unknown_frame.cc +++ b/test/core/bad_client/tests/unknown_frame.cc @@ -26,7 +26,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_client/tests/window_overflow.cc b/test/core/bad_client/tests/window_overflow.cc index 32afd15992c..dbb98a2b0d8 100644 --- a/test/core/bad_client/tests/window_overflow.cc +++ b/test/core/bad_client/tests/window_overflow.cc @@ -44,7 +44,7 @@ static void verifier(grpc_server* server, grpc_completion_queue* cq, void* /*registered_method*/) { - while (grpc_server_has_open_connections(server)) { + while (server->core_server->HasOpenConnections()) { GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(20), nullptr) .type == GRPC_QUEUE_TIMEOUT); diff --git a/test/core/bad_connection/close_fd_test.cc b/test/core/bad_connection/close_fd_test.cc index 380cbcd8dfa..05498f33521 100644 --- a/test/core/bad_connection/close_fd_test.cc +++ b/test/core/bad_connection/close_fd_test.cc @@ -73,9 +73,8 @@ static test_ctx g_ctx; static void server_setup_transport(grpc_transport* transport) { grpc_core::ExecCtx exec_ctx; grpc_endpoint_add_to_pollset(g_ctx.ep->server, grpc_cq_pollset(g_ctx.cq)); - grpc_server_setup_transport(g_ctx.server, transport, nullptr, - grpc_server_get_channel_args(g_ctx.server), - nullptr); + g_ctx.server->core_server->SetupTransport( + transport, nullptr, g_ctx.server->core_server->channel_args(), nullptr); } static void client_setup_transport(grpc_transport* transport) { diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 338cd0f7ee6..1a281257aeb 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -519,7 +519,7 @@ TEST_F(ChannelzRegistryBasedTest, InternalChannelTest) { TEST(ChannelzServerTest, BasicServerAPIFunctionality) { grpc_core::ExecCtx exec_ctx; ServerFixture server(10); - ServerNode* channelz_server = grpc_server_get_channelz_node(server.server()); + ServerNode* channelz_server = server.server()->core_server->channelz_node(); channelz_server->RecordCallStarted(); channelz_server->RecordCallFailed(); channelz_server->RecordCallSucceeded(); diff --git a/test/core/end2end/bad_server_response_test.cc b/test/core/end2end/bad_server_response_test.cc index dd927a155d3..56419a24647 100644 --- a/test/core/end2end/bad_server_response_test.cc +++ b/test/core/end2end/bad_server_response_test.cc @@ -29,6 +29,7 @@ #include #include +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/host_port.h" #include "src/core/lib/gprpp/memory.h" @@ -47,15 +48,16 @@ "Content-Length: 0\n" \ "Date: Tue, 07 Jun 2016 17:43:20 GMT\n\n" -#define HTTP2_RESP(STATUS_CODE) \ - "\x00\x00\x00\x04\x00\x00\x00\x00\x00" \ - "\x00\x00>\x01\x04\x00\x00\x00\x01" \ - "\x10\x0e" \ - "content-length\x01" \ - "0" \ - "\x10\x0c" \ - "content-type\x10" \ - "application/grpc" \ +#define HTTP2_SETTINGS_FRAME "\x00\x00\x00\x04\x00\x00\x00\x00\x00" + +#define HTTP2_RESP(STATUS_CODE) \ + "\x00\x00>\x01\x04\x00\x00\x00\x01" \ + "\x10\x0e" \ + "content-length\x01" \ + "0" \ + "\x10\x0c" \ + "content-type\x10" \ + "application/grpc" \ "\x10\x07:status\x03" #STATUS_CODE #define UNPARSEABLE_RESP "Bad Request\n" @@ -63,8 +65,6 @@ #define HTTP2_DETAIL_MSG(STATUS_CODE) \ "Received http2 header with status: " #STATUS_CODE -#define HTTP1_DETAIL_MSG "Trying to connect an http1.x server" - /* TODO(zyc) Check the content of incoming data instead of using this length */ /* The 'bad' server will start sending responses after reading this amount of * data from the client. */ @@ -80,24 +80,32 @@ struct rpc_state { grpc_slice_buffer outgoing_buffer; grpc_endpoint* tcp; gpr_atm done_atm; - bool write_done; + bool http2_response; + bool send_settings; const char* response_payload; size_t response_payload_length; + bool connection_attempt_made; }; static int server_port; static struct rpc_state state; static grpc_closure on_read; +static grpc_closure on_writing_settings_frame; static grpc_closure on_write; static void* tag(intptr_t t) { return (void*)t; } static void done_write(void* /*arg*/, grpc_error* error) { GPR_ASSERT(error == GRPC_ERROR_NONE); - gpr_atm_rel_store(&state.done_atm, 1); } +static void done_writing_settings_frame(void* /* arg */, grpc_error* error) { + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_endpoint_read(state.tcp, &state.temp_incoming_buffer, &on_read, + /*urgent=*/false); +} + static void handle_write() { grpc_slice slice = grpc_slice_from_copied_buffer( state.response_payload, state.response_payload_length); @@ -108,7 +116,10 @@ static void handle_write() { } static void handle_read(void* /*arg*/, grpc_error* error) { - GPR_ASSERT(error == GRPC_ERROR_NONE); + if (error != GRPC_ERROR_NONE) { + gpr_log(GPR_ERROR, "handle_read error: %s", grpc_error_string(error)); + return; + } state.incoming_data_length += state.temp_incoming_buffer.length; size_t i; @@ -119,11 +130,14 @@ static void handle_read(void* /*arg*/, grpc_error* error) { gpr_free(dump); } - gpr_log(GPR_DEBUG, "got %" PRIuPTR " bytes, expected %" PRIuPTR " bytes", + gpr_log(GPR_DEBUG, + "got %" PRIuPTR " bytes, expected %" PRIuPTR + " bytes or a non-HTTP2 response to be sent", state.incoming_data_length, SERVER_INCOMING_DATA_LENGTH_LOWER_THRESHOLD); if (state.incoming_data_length >= - SERVER_INCOMING_DATA_LENGTH_LOWER_THRESHOLD) { + SERVER_INCOMING_DATA_LENGTH_LOWER_THRESHOLD || + !state.http2_response) { handle_write(); } else { grpc_endpoint_read(state.tcp, &state.temp_incoming_buffer, &on_read, @@ -137,14 +151,26 @@ static void on_connect(void* arg, grpc_endpoint* tcp, gpr_free(acceptor); test_tcp_server* server = static_cast(arg); GRPC_CLOSURE_INIT(&on_read, handle_read, nullptr, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&on_writing_settings_frame, done_writing_settings_frame, + nullptr, grpc_schedule_on_exec_ctx); GRPC_CLOSURE_INIT(&on_write, done_write, nullptr, grpc_schedule_on_exec_ctx); grpc_slice_buffer_init(&state.temp_incoming_buffer); grpc_slice_buffer_init(&state.outgoing_buffer); + state.connection_attempt_made = true; state.tcp = tcp; state.incoming_data_length = 0; grpc_endpoint_add_to_pollset(tcp, server->pollset[0]); - grpc_endpoint_read(tcp, &state.temp_incoming_buffer, &on_read, - /*urgent=*/false); + if (state.send_settings) { + // Send settings frame from server + grpc_slice slice = grpc_slice_from_static_buffer( + HTTP2_SETTINGS_FRAME, sizeof(HTTP2_SETTINGS_FRAME) - 1); + grpc_slice_buffer_add(&state.outgoing_buffer, slice); + grpc_endpoint_write(state.tcp, &state.outgoing_buffer, + &on_writing_settings_frame, nullptr); + } else { + grpc_endpoint_read(state.tcp, &state.temp_incoming_buffer, &on_read, + /*urgent=*/false); + } } static gpr_timespec n_sec_deadline(int seconds) { @@ -166,13 +192,20 @@ static void start_rpc(int target_port, grpc_status_code expected_status, state.cq = grpc_completion_queue_create_for_next(nullptr); cqv = cq_verifier_create(state.cq); state.target = grpc_core::JoinHostPort("127.0.0.1", target_port); + state.channel = grpc_insecure_channel_create(state.target.c_str(), nullptr, nullptr); grpc_slice host = grpc_slice_from_static_string("localhost"); + // The default connect deadline is 20 seconds, so reduce the RPC deadline to 1 + // second. This helps us verify - a) If the server responded with a non-HTTP2 + // response, the connect fails immediately resulting in + // GRPC_STATUS_UNAVAILABLE instead of GRPC_STATUS_DEADLINE_EXCEEDED. b) If the + // server does not send a HTTP2 SETTINGs frame, the RPC fails with a + // DEADLINE_EXCEEDED. state.call = grpc_channel_create_call( state.channel, nullptr, GRPC_PROPAGATE_DEFAULTS, state.cq, grpc_slice_from_static_string("/Service/Method"), &host, - gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); + n_sec_deadline(1), nullptr); grpc_metadata_array_init(&initial_metadata_recv); grpc_metadata_array_init(&trailing_metadata_recv); @@ -241,7 +274,7 @@ typedef struct { static void actually_poll_server(void* arg) { poll_args* pa = static_cast(arg); - gpr_timespec deadline = n_sec_deadline(10); + gpr_timespec deadline = n_sec_deadline(1); while (true) { bool done = gpr_atm_acq_load(&state.done_atm) != 0; gpr_timespec time_left = @@ -251,7 +284,7 @@ static void actually_poll_server(void* arg) { if (done || gpr_time_cmp(time_left, gpr_time_0(GPR_TIMESPAN)) < 0) { break; } - test_tcp_server_poll(pa->server, 1000); + test_tcp_server_poll(pa->server, 100); } gpr_event_set(pa->signal_when_done, (void*)1); gpr_free(pa); @@ -260,7 +293,7 @@ static void actually_poll_server(void* arg) { static grpc_core::Thread* poll_server_until_read_done( test_tcp_server* server, gpr_event* signal_when_done) { gpr_atm_rel_store(&state.done_atm, 0); - state.write_done = 0; + state.connection_attempt_made = false; poll_args* pa = static_cast(gpr_malloc(sizeof(*pa))); pa->server = server; pa->signal_when_done = signal_when_done; @@ -270,7 +303,8 @@ static grpc_core::Thread* poll_server_until_read_done( return th; } -static void run_test(const char* response_payload, +static void run_test(bool http2_response, bool send_settings, + const char* response_payload, size_t response_payload_length, grpc_status_code expected_status, const char* expected_detail) { @@ -283,6 +317,8 @@ static void run_test(const char* response_payload, server_port = grpc_pick_unused_port_or_die(); test_tcp_server_init(&test_server, on_connect, &test_server); test_tcp_server_start(&test_server, server_port); + state.http2_response = http2_response; + state.send_settings = send_settings; state.response_payload = response_payload; state.response_payload_length = response_payload_length; @@ -292,7 +328,8 @@ static void run_test(const char* response_payload, start_rpc(server_port, expected_status, expected_detail); gpr_event_wait(&ev, gpr_inf_future(GPR_CLOCK_REALTIME)); thdptr->Join(); - + /* Proof that the server accepted the TCP connection. */ + GPR_ASSERT(state.connection_attempt_made == true); /* clean up */ grpc_endpoint_shutdown(state.tcp, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test Shutdown")); @@ -309,43 +346,48 @@ int main(int argc, char** argv) { grpc_init(); /* status defined in hpack static table */ - run_test(HTTP2_RESP(204), sizeof(HTTP2_RESP(204)) - 1, GRPC_STATUS_UNKNOWN, - HTTP2_DETAIL_MSG(204)); - run_test(HTTP2_RESP(206), sizeof(HTTP2_RESP(206)) - 1, GRPC_STATUS_UNKNOWN, - HTTP2_DETAIL_MSG(206)); - run_test(HTTP2_RESP(304), sizeof(HTTP2_RESP(304)) - 1, GRPC_STATUS_UNKNOWN, - HTTP2_DETAIL_MSG(304)); - run_test(HTTP2_RESP(400), sizeof(HTTP2_RESP(400)) - 1, GRPC_STATUS_INTERNAL, - HTTP2_DETAIL_MSG(400)); - run_test(HTTP2_RESP(404), sizeof(HTTP2_RESP(404)) - 1, + run_test(true, true, HTTP2_RESP(204), sizeof(HTTP2_RESP(204)) - 1, + GRPC_STATUS_UNKNOWN, HTTP2_DETAIL_MSG(204)); + run_test(true, true, HTTP2_RESP(206), sizeof(HTTP2_RESP(206)) - 1, + GRPC_STATUS_UNKNOWN, HTTP2_DETAIL_MSG(206)); + run_test(true, true, HTTP2_RESP(304), sizeof(HTTP2_RESP(304)) - 1, + GRPC_STATUS_UNKNOWN, HTTP2_DETAIL_MSG(304)); + run_test(true, true, HTTP2_RESP(400), sizeof(HTTP2_RESP(400)) - 1, + GRPC_STATUS_INTERNAL, HTTP2_DETAIL_MSG(400)); + run_test(true, true, HTTP2_RESP(404), sizeof(HTTP2_RESP(404)) - 1, GRPC_STATUS_UNIMPLEMENTED, HTTP2_DETAIL_MSG(404)); - run_test(HTTP2_RESP(500), sizeof(HTTP2_RESP(500)) - 1, GRPC_STATUS_UNKNOWN, - HTTP2_DETAIL_MSG(500)); + run_test(true, true, HTTP2_RESP(500), sizeof(HTTP2_RESP(500)) - 1, + GRPC_STATUS_UNKNOWN, HTTP2_DETAIL_MSG(500)); /* status not defined in hpack static table */ - run_test(HTTP2_RESP(401), sizeof(HTTP2_RESP(401)) - 1, + run_test(true, true, HTTP2_RESP(401), sizeof(HTTP2_RESP(401)) - 1, GRPC_STATUS_UNAUTHENTICATED, HTTP2_DETAIL_MSG(401)); - run_test(HTTP2_RESP(403), sizeof(HTTP2_RESP(403)) - 1, + run_test(true, true, HTTP2_RESP(403), sizeof(HTTP2_RESP(403)) - 1, GRPC_STATUS_PERMISSION_DENIED, HTTP2_DETAIL_MSG(403)); - run_test(HTTP2_RESP(429), sizeof(HTTP2_RESP(429)) - 1, + run_test(true, true, HTTP2_RESP(429), sizeof(HTTP2_RESP(429)) - 1, GRPC_STATUS_UNAVAILABLE, HTTP2_DETAIL_MSG(429)); - run_test(HTTP2_RESP(499), sizeof(HTTP2_RESP(499)) - 1, GRPC_STATUS_UNKNOWN, - HTTP2_DETAIL_MSG(499)); - run_test(HTTP2_RESP(502), sizeof(HTTP2_RESP(502)) - 1, + run_test(true, true, HTTP2_RESP(499), sizeof(HTTP2_RESP(499)) - 1, + GRPC_STATUS_UNKNOWN, HTTP2_DETAIL_MSG(499)); + run_test(true, true, HTTP2_RESP(502), sizeof(HTTP2_RESP(502)) - 1, GRPC_STATUS_UNAVAILABLE, HTTP2_DETAIL_MSG(502)); - run_test(HTTP2_RESP(503), sizeof(HTTP2_RESP(503)) - 1, + run_test(true, true, HTTP2_RESP(503), sizeof(HTTP2_RESP(503)) - 1, GRPC_STATUS_UNAVAILABLE, HTTP2_DETAIL_MSG(503)); - run_test(HTTP2_RESP(504), sizeof(HTTP2_RESP(504)) - 1, + run_test(true, true, HTTP2_RESP(504), sizeof(HTTP2_RESP(504)) - 1, GRPC_STATUS_UNAVAILABLE, HTTP2_DETAIL_MSG(504)); - - /* unparseable response */ - run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, GRPC_STATUS_UNKNOWN, - nullptr); - - /* http1 response */ - run_test(HTTP1_RESP_400, sizeof(HTTP1_RESP_400) - 1, GRPC_STATUS_INTERNAL, - HTTP1_DETAIL_MSG); - + /* unparseable response. RPC should fail immediately due to a connect failure. + */ + run_test(false, false, UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, + GRPC_STATUS_UNAVAILABLE, nullptr); + + /* http1 response. RPC should fail immediately due to a connect failure. */ + run_test(false, false, HTTP1_RESP_400, sizeof(HTTP1_RESP_400) - 1, + GRPC_STATUS_UNAVAILABLE, nullptr); + + /* http2 response without sending a SETTINGs frame. RPC should fail with + * DEADLINE_EXCEEDED since the RPC deadline is lower than the connection + * attempt deadline. */ + run_test(true, false, HTTP2_RESP(404), sizeof(HTTP2_RESP(404)) - 1, + GRPC_STATUS_DEADLINE_EXCEEDED, nullptr); grpc_shutdown(); return 0; } diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.cc b/test/core/end2end/fixtures/h2_sockpair+trace.cc index a3afee46424..fbecb7ec4bc 100644 --- a/test/core/end2end/fixtures/h2_sockpair+trace.cc +++ b/test/core/end2end/fixtures/h2_sockpair+trace.cc @@ -52,8 +52,8 @@ static void server_setup_transport(void* ts, grpc_transport* transport) { grpc_core::ExecCtx exec_ctx; grpc_endpoint_pair* sfd = static_cast(f->fixture_data); grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq)); - grpc_server_setup_transport(f->server, transport, nullptr, - grpc_server_get_channel_args(f->server), nullptr); + f->server->core_server->SetupTransport( + transport, nullptr, f->server->core_server->channel_args(), nullptr); } typedef struct { diff --git a/test/core/end2end/fixtures/h2_sockpair.cc b/test/core/end2end/fixtures/h2_sockpair.cc index 637bb0c0dee..8ae50a7e053 100644 --- a/test/core/end2end/fixtures/h2_sockpair.cc +++ b/test/core/end2end/fixtures/h2_sockpair.cc @@ -46,8 +46,8 @@ static void server_setup_transport(void* ts, grpc_transport* transport) { grpc_core::ExecCtx exec_ctx; grpc_endpoint_pair* sfd = static_cast(f->fixture_data); grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq)); - grpc_server_setup_transport(f->server, transport, nullptr, - grpc_server_get_channel_args(f->server), nullptr); + f->server->core_server->SetupTransport( + transport, nullptr, f->server->core_server->channel_args(), nullptr); } typedef struct { diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.cc b/test/core/end2end/fixtures/h2_sockpair_1byte.cc index 1b9a3a4051b..1f13711a57c 100644 --- a/test/core/end2end/fixtures/h2_sockpair_1byte.cc +++ b/test/core/end2end/fixtures/h2_sockpair_1byte.cc @@ -46,8 +46,8 @@ static void server_setup_transport(void* ts, grpc_transport* transport) { grpc_core::ExecCtx exec_ctx; grpc_endpoint_pair* sfd = static_cast(f->fixture_data); grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq)); - grpc_server_setup_transport(f->server, transport, nullptr, - grpc_server_get_channel_args(f->server), nullptr); + f->server->core_server->SetupTransport( + transport, nullptr, f->server->core_server->channel_args(), nullptr); } typedef struct { diff --git a/test/core/end2end/fuzzers/server_fuzzer.cc b/test/core/end2end/fuzzers/server_fuzzer.cc index 1fabd8ca172..e811175c329 100644 --- a/test/core/end2end/fuzzers/server_fuzzer.cc +++ b/test/core/end2end/fuzzers/server_fuzzer.cc @@ -58,7 +58,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { grpc_server_start(server); grpc_transport* transport = grpc_create_chttp2_transport(nullptr, mock_endpoint, false); - grpc_server_setup_transport(server, transport, nullptr, nullptr, nullptr); + server->core_server->SetupTransport(transport, nullptr, nullptr, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); grpc_call* call1 = nullptr; diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index fe50d9a6a5c..1be992dc0e8 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -214,7 +214,7 @@ static void test_channelz(grpc_end2end_test_config config) { GPR_ASSERT(channelz_channel != nullptr); grpc_core::channelz::ServerNode* channelz_server = - grpc_server_get_channelz_node(f.server); + f.server->core_server->channelz_node(); GPR_ASSERT(channelz_server != nullptr); std::string json = channelz_channel->RenderJsonString(); @@ -275,7 +275,7 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { GPR_ASSERT(channelz_channel != nullptr); grpc_core::channelz::ServerNode* channelz_server = - grpc_server_get_channelz_node(f.server); + f.server->core_server->channelz_node(); GPR_ASSERT(channelz_server != nullptr); run_one_request(config, f, true); diff --git a/test/core/handshake/client_ssl.cc b/test/core/handshake/client_ssl.cc index e7faa69f964..8a72620bb42 100644 --- a/test/core/handshake/client_ssl.cc +++ b/test/core/handshake/client_ssl.cc @@ -198,6 +198,10 @@ static void server_thread(void* arg) { gpr_log(GPR_INFO, "Handshake successful."); } + // Send out the settings frame. + const char settings_frame[] = "\x00\x00\x00\x04\x00\x00\x00\x00\x00"; + SSL_write(ssl, settings_frame, sizeof(settings_frame) - 1); + // Wait until the client drops its connection. char buf; while (SSL_read(ssl, &buf, sizeof(buf)) > 0) diff --git a/test/core/tsi/alts/handshaker/alts_concurrent_connectivity_test.cc b/test/core/tsi/alts/handshaker/alts_concurrent_connectivity_test.cc index 4ec5a612d76..5e351398fed 100644 --- a/test/core/tsi/alts/handshaker/alts_concurrent_connectivity_test.cc +++ b/test/core/tsi/alts/handshaker/alts_concurrent_connectivity_test.cc @@ -334,9 +334,17 @@ class FakeTcpServer { CLOSE_SOCKET, }; - FakeTcpServer( + enum class AcceptMode { + kWaitForClientToSendFirstBytes, // useful for emulating ALTS based + // grpc servers + kEagerlySendSettings, // useful for emulating insecure grpc servers (e.g. + // ALTS handshake servers) + }; + + explicit FakeTcpServer( + AcceptMode accept_mode, const std::function& process_read_cb) - : process_read_cb_(process_read_cb) { + : accept_mode_(accept_mode), process_read_cb_(process_read_cb) { port_ = grpc_pick_unused_port_or_die(); accept_socket_ = socket(AF_INET6, SOCK_STREAM, 0); address_ = absl::StrCat("[::]:", port_); @@ -429,12 +437,51 @@ class FakeTcpServer { return CONTINUE_READING; } + class FakeTcpServerPeer { + public: + explicit FakeTcpServerPeer(int fd) : fd_(fd) {} + + ~FakeTcpServerPeer() { close(fd_); } + + void MaybeContinueSendingSettings() { + // https://tools.ietf.org/html/rfc7540#section-4.1 + const std::vector kEmptyHttp2SettingsFrame = { + 0x00, 0x00, 0x00, // length + 0x04, // settings type + 0x00, // flags + 0x00, 0x00, 0x00, 0x00 // stream identifier + }; + if (total_bytes_sent_ < kEmptyHttp2SettingsFrame.size()) { + int bytes_to_send = kEmptyHttp2SettingsFrame.size() - total_bytes_sent_; + int bytes_sent = + send(fd_, kEmptyHttp2SettingsFrame.data() + total_bytes_sent_, + bytes_to_send, 0); + if (bytes_sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + gpr_log(GPR_ERROR, + "Fake TCP server encountered unexpected error:%d |%s| " + "sending %d bytes on fd:%d", + errno, strerror(errno), bytes_to_send, fd_); + GPR_ASSERT(0); + } else if (bytes_sent > 0) { + total_bytes_sent_ += bytes_sent; + GPR_ASSERT(total_bytes_sent_ <= kEmptyHttp2SettingsFrame.size()); + } + } + } + + int fd() { return fd_; } + + private: + int fd_; + int total_bytes_sent_ = 0; + }; + // Run a loop that periodically, every 10 ms: // 1) Checks if there are any new TCP connections to accept. // 2) Checks if any data has arrived yet on established connections, // and reads from them if so, processing the sockets as configured. static void RunServerLoop(FakeTcpServer* self) { - std::set peers; + std::set> peers; while (!gpr_event_get(&self->stop_ev_)) { int p = accept(self->accept_socket_, nullptr, nullptr); if (p == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { @@ -449,17 +496,19 @@ class FakeTcpServer { errno); abort(); } - peers.insert(p); + peers.insert(absl::make_unique(p)); } auto it = peers.begin(); while (it != peers.end()) { - int p = *it; + FakeTcpServerPeer* peer = (*it).get(); + if (self->accept_mode_ == AcceptMode::kEagerlySendSettings) { + peer->MaybeContinueSendingSettings(); + } char buf[100]; - int bytes_received_size = recv(p, buf, 100, 0); + int bytes_received_size = recv(peer->fd(), buf, 100, 0); ProcessReadResult r = - self->process_read_cb_(bytes_received_size, errno, p); + self->process_read_cb_(bytes_received_size, errno, peer->fd()); if (r == CLOSE_SOCKET) { - close(p); it = peers.erase(it); } else { GPR_ASSERT(r == CONTINUE_READING); @@ -469,9 +518,6 @@ class FakeTcpServer { gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(10, GPR_TIMESPAN))); } - for (auto it = peers.begin(); it != peers.end(); it++) { - close(*it); - } close(self->accept_socket_); } @@ -481,6 +527,7 @@ class FakeTcpServer { gpr_event stop_ev_; std::string address_; std::unique_ptr run_server_loop_thd_; + const AcceptMode accept_mode_; std::function process_read_cb_; }; @@ -500,7 +547,10 @@ TEST(AltsConcurrentConnectivityTest, // RPCs at the fake handshake server would be inherently racey. FakeHandshakeServer fake_handshake_server( false /* check num concurrent rpcs */); - FakeTcpServer fake_tcp_server( + // The fake_backend_server emulates a secure (ALTS based) gRPC backend. So + // it waits for the client to send the first bytes. + FakeTcpServer fake_backend_server( + FakeTcpServer::AcceptMode::kWaitForClientToSendFirstBytes, FakeTcpServer::CloseSocketUponReceivingBytesFromPeer); { gpr_timespec test_deadline = grpc_timeout_seconds_to_deadline(20); @@ -510,7 +560,7 @@ TEST(AltsConcurrentConnectivityTest, for (size_t i = 0; i < num_concurrent_connects; i++) { connect_loop_runners.push_back( std::unique_ptr(new ConnectLoopRunner( - fake_tcp_server.address(), fake_handshake_server.address(), + fake_backend_server.address(), fake_handshake_server.address(), 10 /* per connect deadline seconds */, 3 /* loops */, GRPC_CHANNEL_TRANSIENT_FAILURE /* expected connectivity states */, 0 /* reconnect_backoff_ms unset */))); @@ -530,9 +580,16 @@ TEST(AltsConcurrentConnectivityTest, * fail fast when the ALTS handshake server fails incoming handshakes fast. */ TEST(AltsConcurrentConnectivityTest, TestHandshakeFailsFastWhenHandshakeServerClosesConnectionAfterAccepting) { + // The fake_handshake_server emulates a broken ALTS handshaker, which + // is an insecure server. So send settings to the client eagerly. FakeTcpServer fake_handshake_server( + FakeTcpServer::AcceptMode::kEagerlySendSettings, FakeTcpServer::CloseSocketUponReceivingBytesFromPeer); - FakeTcpServer fake_tcp_server(FakeTcpServer::CloseSocketUponCloseFromPeer); + // The fake_backend_server emulates a secure (ALTS based) server, so wait + // for the client to send the first bytes. + FakeTcpServer fake_backend_server( + FakeTcpServer::AcceptMode::kWaitForClientToSendFirstBytes, + FakeTcpServer::CloseSocketUponCloseFromPeer); { gpr_timespec test_deadline = grpc_timeout_seconds_to_deadline(20); std::vector> connect_loop_runners; @@ -541,7 +598,7 @@ TEST(AltsConcurrentConnectivityTest, for (size_t i = 0; i < num_concurrent_connects; i++) { connect_loop_runners.push_back( std::unique_ptr(new ConnectLoopRunner( - fake_tcp_server.address(), fake_handshake_server.address(), + fake_backend_server.address(), fake_handshake_server.address(), 10 /* per connect deadline seconds */, 2 /* loops */, GRPC_CHANNEL_TRANSIENT_FAILURE /* expected connectivity states */, 0 /* reconnect_backoff_ms unset */))); @@ -562,9 +619,16 @@ TEST(AltsConcurrentConnectivityTest, * the overall connection deadline kicks in. */ TEST(AltsConcurrentConnectivityTest, TestHandshakeFailsFastWhenHandshakeServerHangsAfterAccepting) { + // fake_handshake_server emulates an insecure server, so send settings first. + // It will be unresponsive for the rest of the connection, though. FakeTcpServer fake_handshake_server( + FakeTcpServer::AcceptMode::kEagerlySendSettings, + FakeTcpServer::CloseSocketUponCloseFromPeer); + // fake_backend_server emulates an ALTS based server, so wait for the client + // to send the first bytes. + FakeTcpServer fake_backend_server( + FakeTcpServer::AcceptMode::kWaitForClientToSendFirstBytes, FakeTcpServer::CloseSocketUponCloseFromPeer); - FakeTcpServer fake_tcp_server(FakeTcpServer::CloseSocketUponCloseFromPeer); { gpr_timespec test_deadline = grpc_timeout_seconds_to_deadline(20); std::vector> connect_loop_runners; @@ -573,7 +637,7 @@ TEST(AltsConcurrentConnectivityTest, for (size_t i = 0; i < num_concurrent_connects; i++) { connect_loop_runners.push_back( std::unique_ptr(new ConnectLoopRunner( - fake_tcp_server.address(), fake_handshake_server.address(), + fake_backend_server.address(), fake_handshake_server.address(), 10 /* per connect deadline seconds */, 2 /* loops */, GRPC_CHANNEL_TRANSIENT_FAILURE /* expected connectivity states */, 100 /* reconnect_backoff_ms */))); diff --git a/test/core/util/mock_endpoint.cc b/test/core/util/mock_endpoint.cc index b001fd764a7..7e495c311cc 100644 --- a/test/core/util/mock_endpoint.cc +++ b/test/core/util/mock_endpoint.cc @@ -98,8 +98,12 @@ static void me_destroy(grpc_endpoint* ep) { gpr_free(m); } -static char* me_get_peer(grpc_endpoint* /*ep*/) { - return gpr_strdup("fake:mock_endpoint"); +static absl::string_view me_get_peer(grpc_endpoint* /*ep*/) { + return "fake:mock_endpoint"; +} + +static absl::string_view me_get_local_address(grpc_endpoint* /*ep*/) { + return "fake:mock_endpoint"; } static grpc_resource_user* me_get_resource_user(grpc_endpoint* ep) { @@ -120,6 +124,7 @@ static const grpc_endpoint_vtable vtable = {me_read, me_destroy, me_get_resource_user, me_get_peer, + me_get_local_address, me_get_fd, me_can_track_err}; diff --git a/test/core/util/passthru_endpoint.cc b/test/core/util/passthru_endpoint.cc index 0b14c55c73e..59e8276fe1f 100644 --- a/test/core/util/passthru_endpoint.cc +++ b/test/core/util/passthru_endpoint.cc @@ -152,11 +152,18 @@ static void me_destroy(grpc_endpoint* ep) { } } -static char* me_get_peer(grpc_endpoint* ep) { +static absl::string_view me_get_peer(grpc_endpoint* ep) { passthru_endpoint* p = (reinterpret_cast(ep))->parent; return (reinterpret_cast(ep)) == &p->client - ? gpr_strdup("fake:mock_client_endpoint") - : gpr_strdup("fake:mock_server_endpoint"); + ? "fake:mock_client_endpoint" + : "fake:mock_server_endpoint"; +} + +static absl::string_view me_get_local_address(grpc_endpoint* ep) { + passthru_endpoint* p = (reinterpret_cast(ep))->parent; + return (reinterpret_cast(ep)) == &p->client + ? "fake:mock_client_endpoint" + : "fake:mock_server_endpoint"; } static int me_get_fd(grpc_endpoint* /*ep*/) { return -1; } @@ -178,6 +185,7 @@ static const grpc_endpoint_vtable vtable = { me_destroy, me_get_resource_user, me_get_peer, + me_get_local_address, me_get_fd, me_can_track_err, }; diff --git a/test/core/util/reconnect_server.cc b/test/core/util/reconnect_server.cc index 80e4ad8060f..626fe95ced3 100644 --- a/test/core/util/reconnect_server.cc +++ b/test/core/util/reconnect_server.cc @@ -21,10 +21,12 @@ #include #include #include +#include #include #include #include +#include "absl/strings/string_view.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/tcp_server.h" @@ -59,8 +61,8 @@ static void on_connect(void* arg, grpc_endpoint* tcp, grpc_pollset* /*accepting_pollset*/, grpc_tcp_server_acceptor* acceptor) { gpr_free(acceptor); - char* peer; - char* last_colon; + absl::string_view peer; + int last_colon; reconnect_server* server = static_cast(arg); gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); timestamp_list* new_tail; @@ -68,18 +70,16 @@ static void on_connect(void* arg, grpc_endpoint* tcp, grpc_endpoint_shutdown(tcp, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Connected")); grpc_endpoint_destroy(tcp); - if (peer) { - last_colon = strrchr(peer, ':'); - if (server->peer == nullptr) { - server->peer = peer; - } else { - if (last_colon == nullptr) { - gpr_log(GPR_ERROR, "peer does not contain a ':'"); - } else if (strncmp(server->peer, peer, - static_cast(last_colon - peer)) != 0) { - gpr_log(GPR_ERROR, "mismatched peer! %s vs %s", server->peer, peer); - } - gpr_free(peer); + last_colon = peer.rfind(':'); + if (server->peer == nullptr) { + server->peer = new std::string(peer); + } else { + if (last_colon == std::string::npos) { + gpr_log(GPR_ERROR, "peer does not contain a ':'"); + } else if (peer.compare(0, static_cast(last_colon), + *server->peer) != 0) { + gpr_log(GPR_ERROR, "mismatched peer! %s vs %s", server->peer->c_str(), + std::string(peer).c_str()); } } new_tail = static_cast(gpr_malloc(sizeof(timestamp_list))); @@ -119,7 +119,7 @@ void reconnect_server_clear_timestamps(reconnect_server* server) { server->head = new_head; } server->tail = nullptr; - gpr_free(server->peer); + delete server->peer; server->peer = nullptr; } diff --git a/test/core/util/reconnect_server.h b/test/core/util/reconnect_server.h index d15abe529df..f7264dd156f 100644 --- a/test/core/util/reconnect_server.h +++ b/test/core/util/reconnect_server.h @@ -32,7 +32,7 @@ typedef struct reconnect_server { test_tcp_server tcp_server; timestamp_list* head; timestamp_list* tail; - char* peer; + std::string* peer; int max_reconnect_backoff_ms; } reconnect_server; diff --git a/test/core/util/test_config.cc b/test/core/util/test_config.cc index b926b57280a..391467ba789 100644 --- a/test/core/util/test_config.cc +++ b/test/core/util/test_config.cc @@ -413,6 +413,15 @@ TestEnvironment::~TestEnvironment() { break; } } + if (BuiltUnderMsan()) { + // This is a workaround for MSAN. MSAN doesn't like having shutdown thread + // running. Although the code above waits until shutdown is done, chances + // are that thread itself is still alive. To workaround this problem, this + // is going to wait for 0.5 sec to give a chance to the shutdown thread to + // exit. https://github.com/grpc/grpc/issues/23695 + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_millis(500, GPR_TIMESPAN))); + } gpr_log(GPR_INFO, "TestEnvironment ends"); } diff --git a/test/core/util/trickle_endpoint.cc b/test/core/util/trickle_endpoint.cc index f313d05f593..603b51ab80c 100644 --- a/test/core/util/trickle_endpoint.cc +++ b/test/core/util/trickle_endpoint.cc @@ -122,11 +122,16 @@ static grpc_resource_user* te_get_resource_user(grpc_endpoint* ep) { return grpc_endpoint_get_resource_user(te->wrapped); } -static char* te_get_peer(grpc_endpoint* ep) { +static absl::string_view te_get_peer(grpc_endpoint* ep) { trickle_endpoint* te = reinterpret_cast(ep); return grpc_endpoint_get_peer(te->wrapped); } +static absl::string_view te_get_local_address(grpc_endpoint* ep) { + trickle_endpoint* te = reinterpret_cast(ep); + return grpc_endpoint_get_local_address(te->wrapped); +} + static int te_get_fd(grpc_endpoint* ep) { trickle_endpoint* te = reinterpret_cast(ep); return grpc_endpoint_get_fd(te->wrapped); @@ -151,6 +156,7 @@ static const grpc_endpoint_vtable vtable = {te_read, te_destroy, te_get_resource_user, te_get_peer, + te_get_local_address, te_get_fd, te_can_track_err}; diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc index 04421d2765e..062a47a8bef 100644 --- a/test/cpp/end2end/filter_end2end_test.cc +++ b/test/cpp/end2end/filter_end2end_test.cc @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -184,6 +185,7 @@ class FilterEnd2endTest : public ::testing::Test { // The string needs to be long enough to test heap-based slice. send_request.set_message("Hello world. Hello world. Hello world."); + std::thread request_call([this]() { server_ok(4); }); std::unique_ptr call = generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_); call->StartCall(tag(1)); @@ -200,7 +202,7 @@ class FilterEnd2endTest : public ::testing::Test { generic_service_.RequestCall(&srv_ctx, &stream, srv_cq_.get(), srv_cq_.get(), tag(4)); - verify_ok(srv_cq_.get(), 4, true); + request_call.join(); EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); ByteBuffer recv_buffer; @@ -278,6 +280,7 @@ TEST_F(FilterEnd2endTest, SimpleBidiStreaming) { cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP); send_request.set_message("Hello"); + std::thread request_call([this]() { server_ok(2); }); std::unique_ptr cli_stream = generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_); cli_stream->StartCall(tag(1)); @@ -286,7 +289,7 @@ TEST_F(FilterEnd2endTest, SimpleBidiStreaming) { generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(), srv_cq_.get(), tag(2)); - verify_ok(srv_cq_.get(), 2, true); + request_call.join(); EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc index 60ea51875b1..0d39691bb60 100644 --- a/test/cpp/end2end/generic_end2end_test.cc +++ b/test/cpp/end2end/generic_end2end_test.cc @@ -140,6 +140,7 @@ class GenericEnd2endTest : public ::testing::Test { delete method_name; // Make sure that this is not needed after invocation + std::thread request_call([this]() { server_ok(4); }); call->StartCall(tag(1)); client_ok(1); std::unique_ptr send_buffer = @@ -154,7 +155,7 @@ class GenericEnd2endTest : public ::testing::Test { generic_service_.RequestCall(&srv_ctx, &stream, srv_cq_.get(), srv_cq_.get(), tag(4)); - verify_ok(srv_cq_.get(), 4, true); + request_call.join(); EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); @@ -282,7 +283,7 @@ TEST_F(GenericEnd2endTest, SequentialUnaryRpcs) { std::unique_ptr cli_send_buffer = SerializeToByteBuffer(&send_request); - // Use the same cq as server so that events can be polled in time. + std::thread request_call([this]() { server_ok(4); }); std::unique_ptr call = generic_stub_->PrepareUnaryCall(&cli_ctx, kMethodName, *cli_send_buffer.get(), &cli_cq_); @@ -293,8 +294,7 @@ TEST_F(GenericEnd2endTest, SequentialUnaryRpcs) { generic_service_.RequestCall(&srv_ctx, &stream, srv_cq_.get(), srv_cq_.get(), tag(4)); - - server_ok(4); + request_call.join(); EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); @@ -337,6 +337,7 @@ TEST_F(GenericEnd2endTest, SimpleBidiStreaming) { cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP); send_request.set_message("Hello"); + std::thread request_call([this]() { server_ok(2); }); std::unique_ptr cli_stream = generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_); cli_stream->StartCall(tag(1)); @@ -344,8 +345,8 @@ TEST_F(GenericEnd2endTest, SimpleBidiStreaming) { generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(), srv_cq_.get(), tag(2)); + request_call.join(); - verify_ok(srv_cq_.get(), 2, true); EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); diff --git a/test/cpp/end2end/port_sharing_end2end_test.cc b/test/cpp/end2end/port_sharing_end2end_test.cc index 94b4540cf70..f342bd00a85 100644 --- a/test/cpp/end2end/port_sharing_end2end_test.cc +++ b/test/cpp/end2end/port_sharing_end2end_test.cc @@ -156,9 +156,8 @@ class TestTcpServer { private: void OnConnect(grpc_endpoint* tcp, grpc_pollset* /*accepting_pollset*/, grpc_tcp_server_acceptor* acceptor) { - char* peer = grpc_endpoint_get_peer(tcp); - gpr_log(GPR_INFO, "Got incoming connection! from %s", peer); - gpr_free(peer); + std::string peer(grpc_endpoint_get_peer(tcp)); + gpr_log(GPR_INFO, "Got incoming connection! from %s", peer.c_str()); EXPECT_FALSE(acceptor->external_connection); listener_fd_ = grpc_tcp_server_port_fd( acceptor->from_server, acceptor->port_index, acceptor->fd_index); diff --git a/test/cpp/end2end/server_interceptors_end2end_test.cc b/test/cpp/end2end/server_interceptors_end2end_test.cc index e8e0435a960..25e64f7580d 100644 --- a/test/cpp/end2end/server_interceptors_end2end_test.cc +++ b/test/cpp/end2end/server_interceptors_end2end_test.cc @@ -536,6 +536,8 @@ TEST_F(ServerInterceptorsAsyncEnd2endTest, GenericRPCTest) { send_request.set_message("Hello"); cli_ctx.AddMetadata("testkey", "testvalue"); + CompletionQueue* cq = srv_cq.get(); + std::thread request_call([cq]() { Verifier().Expect(4, true).Verify(cq); }); std::unique_ptr call = generic_stub.PrepareCall(&cli_ctx, kMethodName, &cli_cq); call->StartCall(tag(1)); @@ -551,7 +553,7 @@ TEST_F(ServerInterceptorsAsyncEnd2endTest, GenericRPCTest) { service.RequestCall(&srv_ctx, &stream, srv_cq.get(), srv_cq.get(), tag(4)); - Verifier().Expect(4, true).Verify(srv_cq.get()); + request_call.join(); EXPECT_EQ(kMethodName, srv_ctx.method()); EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue")); srv_ctx.AddTrailingMetadata("testkey", "testvalue"); diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc index cdb313b8e3a..6a783d30aca 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc @@ -53,6 +53,7 @@ class DummyEndpoint : public grpc_endpoint { destroy, get_resource_user, get_peer, + get_local_address, get_fd, can_track_err}; grpc_endpoint::vtable = &my_vtable; @@ -124,7 +125,10 @@ class DummyEndpoint : public grpc_endpoint { static grpc_resource_user* get_resource_user(grpc_endpoint* ep) { return static_cast(ep)->ru_; } - static char* get_peer(grpc_endpoint* /*ep*/) { return gpr_strdup("test"); } + static absl::string_view get_peer(grpc_endpoint* /*ep*/) { return "test"; } + static absl::string_view get_local_address(grpc_endpoint* /*ep*/) { + return "test"; + } static int get_fd(grpc_endpoint* /*ep*/) { return 0; } static bool can_track_err(grpc_endpoint* /*ep*/) { return false; } }; diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc index c53eb2b9413..8ab0450f4ee 100644 --- a/test/cpp/microbenchmarks/bm_cq.cc +++ b/test/cpp/microbenchmarks/bm_cq.cc @@ -69,6 +69,11 @@ BENCHMARK(BM_CreateDestroyCore); static void DoneWithCompletionOnStack(void* /*arg*/, grpc_cq_completion* /*completion*/) {} +static void DoneWithCompletionOnHeap(void* /*arg*/, + grpc_cq_completion* completion) { + delete completion; +} + class DummyTag final : public internal::CompletionQueueTag { public: bool FinalizeResult(void** /*tag*/, bool* /*status*/) override { @@ -205,8 +210,20 @@ static void BM_Callback_CQ_Pass1Core(benchmark::State& state) { gpr_cv_init(&shutdown_cv); bool got_shutdown = false; ShutdownCallback shutdown_cb(&got_shutdown); - grpc_completion_queue* cc = - grpc_completion_queue_create_for_callback(&shutdown_cb, nullptr); + // This test with stack-allocated completions only works for non-polling or + // EM-polling callback core CQs because otherwise the callback could execute + // on another thread after the stack objects here go out of scope. An + // alternative would be to synchronize between the benchmark loop and the + // callback, but then it would be measuring the overhead of synchronization + // rather than the overhead of the completion queue. + // For generality, test here with non-polling. + grpc_completion_queue_attributes attr; + attr.version = 2; + attr.cq_completion_type = GRPC_CQ_CALLBACK; + attr.cq_polling_type = GRPC_CQ_NON_POLLING; + attr.cq_shutdown_cb = &shutdown_cb; + grpc_completion_queue* cc = grpc_completion_queue_create( + grpc_completion_queue_factory_lookup(&attr), &attr, nullptr); for (auto _ : state) { grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ExecCtx exec_ctx; @@ -240,7 +257,53 @@ static void BM_Callback_CQ_Pass1Core(benchmark::State& state) { gpr_cv_destroy(&shutdown_cv); gpr_mu_destroy(&shutdown_mu); } +static void BM_Callback_CQ_Pass1CoreHeapCompletion(benchmark::State& state) { + TrackCounters track_counters; + int iteration = 0, current_iterations = 0; + TagCallback tag_cb(&iteration); + gpr_mu_init(&mu); + gpr_cv_init(&cv); + gpr_mu_init(&shutdown_mu); + gpr_cv_init(&shutdown_cv); + bool got_shutdown = false; + ShutdownCallback shutdown_cb(&got_shutdown); + grpc_completion_queue* cc = + grpc_completion_queue_create_for_callback(&shutdown_cb, nullptr); + for (auto _ : state) { + grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; + grpc_core::ExecCtx exec_ctx; + grpc_cq_completion* completion = new grpc_cq_completion; + GPR_ASSERT(grpc_cq_begin_op(cc, &tag_cb)); + grpc_cq_end_op(cc, &tag_cb, GRPC_ERROR_NONE, DoneWithCompletionOnHeap, + nullptr, completion); + } + shutdown_and_destroy(cc); + + gpr_mu_lock(&mu); + current_iterations = static_cast(state.iterations()); + while (current_iterations != iteration) { + // Wait for all the callbacks to complete. + gpr_cv_wait(&cv, &mu, gpr_inf_future(GPR_CLOCK_REALTIME)); + } + gpr_mu_unlock(&mu); + + gpr_mu_lock(&shutdown_mu); + while (!got_shutdown) { + // Wait for the shutdown callback to complete. + gpr_cv_wait(&shutdown_cv, &shutdown_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); + } + gpr_mu_unlock(&shutdown_mu); + + GPR_ASSERT(got_shutdown); + GPR_ASSERT(iteration == static_cast(state.iterations())); + track_counters.Finish(state); + gpr_cv_destroy(&cv); + gpr_mu_destroy(&mu); + gpr_cv_destroy(&shutdown_cv); + gpr_mu_destroy(&shutdown_mu); +} BENCHMARK(BM_Callback_CQ_Pass1Core); +BENCHMARK(BM_Callback_CQ_Pass1CoreHeapCompletion); } // namespace testing } // namespace grpc diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h index 0f75314ea0e..73b4e41900e 100644 --- a/test/cpp/microbenchmarks/fullstack_fixtures.h +++ b/test/cpp/microbenchmarks/fullstack_fixtures.h @@ -174,17 +174,17 @@ class EndpointPairFixture : public BaseFixture { * */ { const grpc_channel_args* server_args = - grpc_server_get_channel_args(server_->c_server()); + server_->c_server()->core_server->channel_args(); server_transport_ = grpc_create_chttp2_transport( server_args, endpoints.server, false /* is_client */); for (grpc_pollset* pollset : - grpc_server_get_pollsets(server_->c_server())) { + server_->c_server()->core_server->pollsets()) { grpc_endpoint_add_to_pollset(endpoints.server, pollset); } - grpc_server_setup_transport(server_->c_server(), server_transport_, - nullptr, server_args, nullptr); + server_->c_server()->core_server->SetupTransport( + server_transport_, nullptr, server_args, nullptr); grpc_chttp2_transport_start_reading(server_transport_, nullptr, nullptr); } diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc index 9488cc6799b..e262078e149 100644 --- a/test/cpp/performance/writes_per_rpc_test.cc +++ b/test/cpp/performance/writes_per_rpc_test.cc @@ -71,17 +71,17 @@ class EndpointPairFixture { /* add server endpoint to server_ */ { const grpc_channel_args* server_args = - grpc_server_get_channel_args(server_->c_server()); + server_->c_server()->core_server->channel_args(); grpc_transport* transport = grpc_create_chttp2_transport( server_args, endpoints.server, false /* is_client */); for (grpc_pollset* pollset : - grpc_server_get_pollsets(server_->c_server())) { + server_->c_server()->core_server->pollsets()) { grpc_endpoint_add_to_pollset(endpoints.server, pollset); } - grpc_server_setup_transport(server_->c_server(), transport, nullptr, - server_args, nullptr); + server_->c_server()->core_server->SetupTransport(transport, nullptr, + server_args, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); } diff --git a/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc b/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc index 6257e42ebf4..1e2caa2be6f 100644 --- a/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc +++ b/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc @@ -20,6 +20,7 @@ #include +#include "test/core/util/test_config.h" #include "test/cpp/qps/benchmark_config.h" #include "test/cpp/qps/driver.h" #include "test/cpp/qps/report.h" @@ -58,6 +59,7 @@ static void RunSynchronousUnaryPingPong() { } // namespace grpc int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); grpc::testing::InitTest(&argc, &argv, true); grpc::testing::RunSynchronousUnaryPingPong(); diff --git a/test/cpp/qps/qps_interarrival_test.cc b/test/cpp/qps/qps_interarrival_test.cc index 2cc22e9985f..1f29cd72968 100644 --- a/test/cpp/qps/qps_interarrival_test.cc +++ b/test/cpp/qps/qps_interarrival_test.cc @@ -22,6 +22,7 @@ // Use the C histogram rather than C++ to avoid depending on proto #include "test/core/util/histogram.h" +#include "test/core/util/test_config.h" #include "test/cpp/qps/interarrival.h" #include "test/cpp/util/test_config.h" @@ -52,6 +53,7 @@ static void RunTest(RandomDistInterface&& r, int threads, using grpc::testing::ExpDist; int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); grpc::testing::InitTest(&argc, &argv, true); RunTest(ExpDist(10.0), 5, std::string("Exponential(10)")); diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc index 68062e66f25..19ff02b71f3 100644 --- a/test/cpp/qps/qps_openloop_test.cc +++ b/test/cpp/qps/qps_openloop_test.cc @@ -62,6 +62,7 @@ static void RunQPS() { } // namespace grpc int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); grpc::testing::InitTest(&argc, &argv, true); grpc::testing::RunQPS(); diff --git a/test/cpp/util/byte_buffer_test.cc b/test/cpp/util/byte_buffer_test.cc index fdae56a90c2..c63f351a8f0 100644 --- a/test/cpp/util/byte_buffer_test.cc +++ b/test/cpp/util/byte_buffer_test.cc @@ -27,6 +27,8 @@ #include #include +#include "test/core/util/test_config.h" + namespace grpc { static internal::GrpcLibraryInitializer g_gli_initializer; @@ -125,6 +127,7 @@ TEST_F(ByteBufferTest, SerializationMakesCopy) { } // namespace grpc int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); int ret = RUN_ALL_TESTS(); return ret; diff --git a/test/cpp/util/error_details_test.cc b/test/cpp/util/error_details_test.cc index d88005267f8..438f75f4cd4 100644 --- a/test/cpp/util/error_details_test.cc +++ b/test/cpp/util/error_details_test.cc @@ -21,6 +21,7 @@ #include "src/proto/grpc/status/status.pb.h" #include "src/proto/grpc/testing/echo_messages.pb.h" +#include "test/core/util/test_config.h" namespace grpc { namespace { @@ -118,6 +119,7 @@ TEST(SetTest, ValidScopeErrorCode) { } // namespace grpc int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/test/cpp/util/string_ref_test.cc b/test/cpp/util/string_ref_test.cc index 031ec33241b..8e3259b764b 100644 --- a/test/cpp/util/string_ref_test.cc +++ b/test/cpp/util/string_ref_test.cc @@ -22,6 +22,8 @@ #include +#include "test/core/util/test_config.h" + namespace grpc { namespace { @@ -197,6 +199,7 @@ TEST_F(StringRefTest, ComparisonOperators) { } // namespace grpc int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc index a8851a583d2..bcbfa14f94f 100644 --- a/test/cpp/util/time_test.cc +++ b/test/cpp/util/time_test.cc @@ -20,6 +20,8 @@ #include #include +#include "test/core/util/test_config.h" + using std::chrono::duration_cast; using std::chrono::microseconds; using std::chrono::system_clock; @@ -64,6 +66,7 @@ TEST_F(TimeTest, InfFuture) { } // namespace grpc int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/third_party/upb/bazel/upb_proto_library.bzl b/third_party/upb/bazel/upb_proto_library.bzl index c48128e52ff..d324948b074 100644 --- a/third_party/upb/bazel/upb_proto_library.bzl +++ b/third_party/upb/bazel/upb_proto_library.bzl @@ -121,6 +121,9 @@ _WrappedGeneratedSrcsInfo = provider(fields = ["srcs"]) _WrappedDefsGeneratedSrcsInfo = provider(fields = ["srcs"]) def _compile_upb_protos(ctx, proto_info, proto_sources, ext): + if len(proto_sources) == 0: + return GeneratedSrcsInfo(srcs = [], hdrs = []) + srcs = [_generate_output_file(ctx, name, ext + ".c") for name in proto_sources] hdrs = [_generate_output_file(ctx, name, ext + ".h") for name in proto_sources] transitive_sets = proto_info.transitive_descriptor_sets.to_list() diff --git a/third_party/upb/generated_for_cmake/google/protobuf/descriptor.upb.c b/third_party/upb/generated_for_cmake/google/protobuf/descriptor.upb.c index 3c7363922e9..44cd3ae2cec 100644 --- a/third_party/upb/generated_for_cmake/google/protobuf/descriptor.upb.c +++ b/third_party/upb/generated_for_cmake/google/protobuf/descriptor.upb.c @@ -36,9 +36,9 @@ static const upb_msglayout *const google_protobuf_FileDescriptorProto_submsgs[6] }; static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 2, 0, 9, 1}, - {3, UPB_SIZE(36, 72), 0, 0, 9, 3}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, + {2, UPB_SIZE(12, 24), 2, 0, 12, 1}, + {3, UPB_SIZE(36, 72), 0, 0, 12, 3}, {4, UPB_SIZE(40, 80), 0, 0, 11, 3}, {5, UPB_SIZE(44, 88), 0, 1, 11, 3}, {6, UPB_SIZE(48, 96), 0, 4, 11, 3}, @@ -47,7 +47,7 @@ static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] {9, UPB_SIZE(32, 64), 5, 5, 11, 1}, {10, UPB_SIZE(56, 112), 0, 0, 5, 3}, {11, UPB_SIZE(60, 120), 0, 0, 5, 3}, - {12, UPB_SIZE(20, 40), 3, 0, 9, 1}, + {12, UPB_SIZE(20, 40), 3, 0, 12, 1}, }; const upb_msglayout google_protobuf_FileDescriptorProto_msginit = { @@ -67,7 +67,7 @@ static const upb_msglayout *const google_protobuf_DescriptorProto_submsgs[8] = { }; static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(16, 32), 0, 4, 11, 3}, {3, UPB_SIZE(20, 40), 0, 0, 11, 3}, {4, UPB_SIZE(24, 48), 0, 3, 11, 3}, @@ -76,7 +76,7 @@ static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { {7, UPB_SIZE(12, 24), 2, 5, 11, 1}, {8, UPB_SIZE(36, 72), 0, 6, 11, 3}, {9, UPB_SIZE(40, 80), 0, 2, 11, 3}, - {10, UPB_SIZE(44, 88), 0, 0, 9, 3}, + {10, UPB_SIZE(44, 88), 0, 0, 12, 3}, }; const upb_msglayout google_protobuf_DescriptorProto_msginit = { @@ -131,16 +131,16 @@ static const upb_msglayout *const google_protobuf_FieldDescriptorProto_submsgs[1 }; static const upb_msglayout_field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(36, 40), 6, 0, 9, 1}, - {2, UPB_SIZE(44, 56), 7, 0, 9, 1}, + {1, UPB_SIZE(36, 40), 6, 0, 12, 1}, + {2, UPB_SIZE(44, 56), 7, 0, 12, 1}, {3, UPB_SIZE(24, 24), 3, 0, 5, 1}, {4, UPB_SIZE(8, 8), 1, 0, 14, 1}, {5, UPB_SIZE(16, 16), 2, 0, 14, 1}, - {6, UPB_SIZE(52, 72), 8, 0, 9, 1}, - {7, UPB_SIZE(60, 88), 9, 0, 9, 1}, + {6, UPB_SIZE(52, 72), 8, 0, 12, 1}, + {7, UPB_SIZE(60, 88), 9, 0, 12, 1}, {8, UPB_SIZE(76, 120), 11, 0, 11, 1}, {9, UPB_SIZE(28, 28), 4, 0, 5, 1}, - {10, UPB_SIZE(68, 104), 10, 0, 9, 1}, + {10, UPB_SIZE(68, 104), 10, 0, 12, 1}, {17, UPB_SIZE(32, 32), 5, 0, 8, 1}, }; @@ -155,7 +155,7 @@ static const upb_msglayout *const google_protobuf_OneofDescriptorProto_submsgs[1 }; static const upb_msglayout_field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(12, 24), 2, 0, 11, 1}, }; @@ -172,11 +172,11 @@ static const upb_msglayout *const google_protobuf_EnumDescriptorProto_submsgs[3] }; static const upb_msglayout_field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(16, 32), 0, 2, 11, 3}, {3, UPB_SIZE(12, 24), 2, 1, 11, 1}, {4, UPB_SIZE(20, 40), 0, 0, 11, 3}, - {5, UPB_SIZE(24, 48), 0, 0, 9, 3}, + {5, UPB_SIZE(24, 48), 0, 0, 12, 3}, }; const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = { @@ -201,7 +201,7 @@ static const upb_msglayout *const google_protobuf_EnumValueDescriptorProto_subms }; static const upb_msglayout_field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 2, 0, 9, 1}, + {1, UPB_SIZE(8, 8), 2, 0, 12, 1}, {2, UPB_SIZE(4, 4), 1, 0, 5, 1}, {3, UPB_SIZE(16, 24), 3, 0, 11, 1}, }; @@ -218,7 +218,7 @@ static const upb_msglayout *const google_protobuf_ServiceDescriptorProto_submsgs }; static const upb_msglayout_field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 1, 0, 12, 1}, {2, UPB_SIZE(16, 32), 0, 0, 11, 3}, {3, UPB_SIZE(12, 24), 2, 1, 11, 1}, }; @@ -234,9 +234,9 @@ static const upb_msglayout *const google_protobuf_MethodDescriptorProto_submsgs[ }; static const upb_msglayout_field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 3, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 4, 0, 9, 1}, - {3, UPB_SIZE(20, 40), 5, 0, 9, 1}, + {1, UPB_SIZE(4, 8), 3, 0, 12, 1}, + {2, UPB_SIZE(12, 24), 4, 0, 12, 1}, + {3, UPB_SIZE(20, 40), 5, 0, 12, 1}, {4, UPB_SIZE(28, 56), 6, 0, 11, 1}, {5, UPB_SIZE(1, 1), 1, 0, 8, 1}, {6, UPB_SIZE(2, 2), 2, 0, 8, 1}, @@ -253,11 +253,11 @@ static const upb_msglayout *const google_protobuf_FileOptions_submsgs[1] = { }; static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(28, 32), 11, 0, 9, 1}, - {8, UPB_SIZE(36, 48), 12, 0, 9, 1}, + {1, UPB_SIZE(28, 32), 11, 0, 12, 1}, + {8, UPB_SIZE(36, 48), 12, 0, 12, 1}, {9, UPB_SIZE(8, 8), 1, 0, 14, 1}, {10, UPB_SIZE(16, 16), 2, 0, 8, 1}, - {11, UPB_SIZE(44, 64), 13, 0, 9, 1}, + {11, UPB_SIZE(44, 64), 13, 0, 12, 1}, {16, UPB_SIZE(17, 17), 3, 0, 8, 1}, {17, UPB_SIZE(18, 18), 4, 0, 8, 1}, {18, UPB_SIZE(19, 19), 5, 0, 8, 1}, @@ -265,14 +265,14 @@ static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { {23, UPB_SIZE(21, 21), 7, 0, 8, 1}, {27, UPB_SIZE(22, 22), 8, 0, 8, 1}, {31, UPB_SIZE(23, 23), 9, 0, 8, 1}, - {36, UPB_SIZE(52, 80), 14, 0, 9, 1}, - {37, UPB_SIZE(60, 96), 15, 0, 9, 1}, - {39, UPB_SIZE(68, 112), 16, 0, 9, 1}, - {40, UPB_SIZE(76, 128), 17, 0, 9, 1}, - {41, UPB_SIZE(84, 144), 18, 0, 9, 1}, + {36, UPB_SIZE(52, 80), 14, 0, 12, 1}, + {37, UPB_SIZE(60, 96), 15, 0, 12, 1}, + {39, UPB_SIZE(68, 112), 16, 0, 12, 1}, + {40, UPB_SIZE(76, 128), 17, 0, 12, 1}, + {41, UPB_SIZE(84, 144), 18, 0, 12, 1}, {42, UPB_SIZE(24, 24), 10, 0, 8, 1}, - {44, UPB_SIZE(92, 160), 19, 0, 9, 1}, - {45, UPB_SIZE(100, 176), 20, 0, 9, 1}, + {44, UPB_SIZE(92, 160), 19, 0, 12, 1}, + {45, UPB_SIZE(100, 176), 20, 0, 12, 1}, {999, UPB_SIZE(108, 192), 0, 0, 11, 3}, }; @@ -402,12 +402,12 @@ static const upb_msglayout *const google_protobuf_UninterpretedOption_submsgs[1] static const upb_msglayout_field google_protobuf_UninterpretedOption__fields[7] = { {2, UPB_SIZE(56, 80), 0, 0, 11, 3}, - {3, UPB_SIZE(32, 32), 4, 0, 9, 1}, + {3, UPB_SIZE(32, 32), 4, 0, 12, 1}, {4, UPB_SIZE(8, 8), 1, 0, 4, 1}, {5, UPB_SIZE(16, 16), 2, 0, 3, 1}, {6, UPB_SIZE(24, 24), 3, 0, 1, 1}, {7, UPB_SIZE(40, 48), 5, 0, 12, 1}, - {8, UPB_SIZE(48, 64), 6, 0, 9, 1}, + {8, UPB_SIZE(48, 64), 6, 0, 12, 1}, }; const upb_msglayout google_protobuf_UninterpretedOption_msginit = { @@ -417,7 +417,7 @@ const upb_msglayout google_protobuf_UninterpretedOption_msginit = { }; static const upb_msglayout_field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 2, 0, 9, 2}, + {1, UPB_SIZE(4, 8), 2, 0, 12, 2}, {2, UPB_SIZE(1, 1), 1, 0, 8, 2}, }; @@ -444,9 +444,9 @@ const upb_msglayout google_protobuf_SourceCodeInfo_msginit = { static const upb_msglayout_field google_protobuf_SourceCodeInfo_Location__fields[5] = { {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_LABEL_PACKED}, {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_LABEL_PACKED}, - {3, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {4, UPB_SIZE(12, 24), 2, 0, 9, 1}, - {6, UPB_SIZE(28, 56), 0, 0, 9, 3}, + {3, UPB_SIZE(4, 8), 1, 0, 12, 1}, + {4, UPB_SIZE(12, 24), 2, 0, 12, 1}, + {6, UPB_SIZE(28, 56), 0, 0, 12, 3}, }; const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = { @@ -471,7 +471,7 @@ const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = { static const upb_msglayout_field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_LABEL_PACKED}, - {2, UPB_SIZE(12, 16), 3, 0, 9, 1}, + {2, UPB_SIZE(12, 16), 3, 0, 12, 1}, {3, UPB_SIZE(4, 4), 1, 0, 5, 1}, {4, UPB_SIZE(8, 8), 2, 0, 5, 1}, }; diff --git a/third_party/upb/kokoro/ubuntu/build.sh b/third_party/upb/kokoro/ubuntu/build.sh index c0261a75886..2174e8aa57d 100644 --- a/third_party/upb/kokoro/ubuntu/build.sh +++ b/third_party/upb/kokoro/ubuntu/build.sh @@ -31,4 +31,9 @@ if [[ $(uname) = "Linux" ]]; then # For some reason kokoro doesn't have Clang available right now. #CC=clang CXX=clang++ bazel test -c dbg --copt=-fsanitize=undefined --copt=-fno-sanitize=function,vptr --linkopt=-fsanitize=undefined --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 -- :all -:test_lua + +fi + +if which valgrind; then + bazel test --run_under='valgrind --leak-check=full --error-exitcode=1' :all -- -:test_conformance_upb -:cmake_build fi diff --git a/third_party/upb/tests/bindings/lua/test_upb.lua b/third_party/upb/tests/bindings/lua/test_upb.lua index d1c32b16746..4586b34ba74 100644 --- a/third_party/upb/tests/bindings/lua/test_upb.lua +++ b/third_party/upb/tests/bindings/lua/test_upb.lua @@ -3,6 +3,7 @@ local upb = require "lupb" local lunit = require "lunit" local upb_test = require "tests.test_pb" local test_messages_proto3 = require "google.protobuf.test_messages_proto3_pb" +local test_messages_proto2 = require "google.protobuf.test_messages_proto2_pb" local descriptor = require "google.protobuf.descriptor_pb" if _VERSION >= 'Lua 5.2' then @@ -69,6 +70,22 @@ function test_msg_map() assert_equal(12, msg2.map_int32_int32[6]) end +function test_utf8() + local proto2_msg = test_messages_proto2.TestAllTypesProto2() + proto2_msg.optional_string = "\xff" + local serialized = upb.encode(proto2_msg) + + -- Decoding invalid UTF-8 succeeds in proto2. + upb.decode(test_messages_proto2.TestAllTypesProto2, serialized) + + -- Decoding invalid UTF-8 fails in proto2. + assert_error_match("Error decoding protobuf", function() + upb.decode(test_messages_proto3.TestAllTypesProto3, serialized) + end) + + -- TOOD(haberman): should proto3 accessors also check UTF-8 at set time? +end + function test_string_double_map() msg = upb_test.MapTest() msg.map_string_double["one"] = 1.0 diff --git a/third_party/upb/tests/test_cpp.cc b/third_party/upb/tests/test_cpp.cc index 4ca81e1c353..802b7008f9d 100644 --- a/third_party/upb/tests/test_cpp.cc +++ b/third_party/upb/tests/test_cpp.cc @@ -50,7 +50,7 @@ static const int kExpectedHandlerData = 1232323; class StringBufTesterBase { public: - static const int kFieldNumber = 3; + static constexpr int kFieldNumber = 3; StringBufTesterBase() : seen_(false), handler_data_val_(0) {} @@ -286,7 +286,7 @@ class StartMsgTesterBase { public: // We don't need the FieldDef it will create, but the test harness still // requires that we provide one. - static const int kFieldNumber = 3; + static constexpr int kFieldNumber = 3; StartMsgTesterBase() : seen_(false), handler_data_val_(0) {} @@ -437,7 +437,7 @@ class StartMsgTesterBoolMethodWithHandlerData : public StartMsgTesterBase { class Int32ValueTesterBase { public: - static const int kFieldNumber = 1; + static constexpr int kFieldNumber = 1; Int32ValueTesterBase() : seen_(false), val_(0), handler_data_val_(0) {} @@ -939,6 +939,17 @@ void TestArena() { upb_arena_malloc(arena.ptr(), 1000000); } ASSERT(n == 0); + + { + // Test fuse. + upb::Arena arena1; + upb::Arena arena2; + + arena1.Fuse(arena2); + + upb_arena_malloc(arena1.ptr(), 10000); + upb_arena_malloc(arena2.ptr(), 10000); + } } extern "C" { diff --git a/third_party/upb/tests/test_generated_code.c b/third_party/upb/tests/test_generated_code.c index 25fbf77ce8d..c6f024a61fd 100644 --- a/third_party/upb/tests/test_generated_code.c +++ b/third_party/upb/tests/test_generated_code.c @@ -70,7 +70,7 @@ static void test_scalars() { static void check_string_map_empty( protobuf_test_messages_proto3_TestAllTypesProto3 *msg) { - size_t iter; + size_t iter = UPB_MAP_BEGIN; ASSERT( protobuf_test_messages_proto3_TestAllTypesProto3_map_string_string_size( @@ -212,7 +212,7 @@ static void test_string_map() { static void check_int32_map_empty( protobuf_test_messages_proto3_TestAllTypesProto3 *msg) { - size_t iter; + size_t iter = UPB_MAP_BEGIN; ASSERT( protobuf_test_messages_proto3_TestAllTypesProto3_map_int32_int32_size( diff --git a/third_party/upb/upb/decode.c b/third_party/upb/upb/decode.c index d1eec474dfd..a9f1cf548a0 100644 --- a/third_party/upb/upb/decode.c +++ b/third_party/upb/upb/decode.c @@ -62,11 +62,13 @@ static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) | (1 << UPB_DTYPE_SFIXED64); /* Op: an action to be performed for a wire-type/field-type combination. */ -#define OP_SCALAR_LG2(n) (n) -#define OP_FIXPCK_LG2(n) (n + 4) -#define OP_VARPCK_LG2(n) (n + 8) +#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ #define OP_STRING 4 -#define OP_SUBMSG 5 +#define OP_BYTES 5 +#define OP_SUBMSG 6 +/* Ops above are scalar-only. Repeated fields can use any op. */ +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ static const int8_t varint_ops[19] = { -1, /* field not found */ @@ -104,7 +106,7 @@ static const int8_t delim_ops[37] = { OP_STRING, /* STRING */ -1, /* GROUP */ OP_SUBMSG, /* MESSAGE */ - OP_STRING, /* BYTES */ + OP_BYTES, /* BYTES */ -1, /* UINT32 */ -1, /* ENUM */ -1, /* SFIXED32 */ @@ -123,7 +125,7 @@ static const int8_t delim_ops[37] = { OP_STRING, /* REPEATED STRING */ OP_SUBMSG, /* REPEATED GROUP */ OP_SUBMSG, /* REPEATED MESSAGE */ - OP_STRING, /* REPEATED BYTES */ + OP_BYTES, /* REPEATED BYTES */ OP_VARPCK_LG2(2), /* REPEATED UINT32 */ OP_VARPCK_LG2(2), /* REPEATED ENUM */ OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ @@ -143,8 +145,6 @@ typedef struct { typedef union { bool bool_val; - int32_t int32_val; - int64_t int64_val; uint32_t uint32_val; uint64_t uint64_val; upb_strview str_val; @@ -155,6 +155,40 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, UPB_NORETURN static void decode_err(upb_decstate *d) { longjmp(d->err, 1); } +void decode_verifyutf8(upb_decstate *d, const char *buf, int len) { + static const uint8_t utf8_offset[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + int i, j; + uint8_t offset; + + i = 0; + while (i < len) { + offset = utf8_offset[(uint8_t)buf[i]]; + if (offset == 0 || i + offset > len) { + decode_err(d); + } + for (j = i + 1; j < i + offset; j++) { + if ((buf[j] & 0xc0) != 0x80) { + decode_err(d); + } + } + i += offset; + } + if (i != len) decode_err(d); +} + static bool decode_reserve(upb_decstate *d, upb_array *arr, size_t elem) { bool need_realloc = arr->size - arr->len < elem; if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, d->arena)) { @@ -209,14 +243,21 @@ static void decode_munge(int type, wireval *val) { break; case UPB_DESCRIPTOR_TYPE_SINT32: { uint32_t n = val->uint32_val; - val->int32_val = (n >> 1) ^ -(int32_t)(n & 1); + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); break; } case UPB_DESCRIPTOR_TYPE_SINT64: { uint64_t n = val->uint64_val; - val->int64_val = (n >> 1) ^ -(int64_t)(n & 1); + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); break; } + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_UINT32: + if (!_upb_isle()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; + } + break; } } @@ -300,7 +341,10 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, memcpy(mem, &val, 1 << op); return ptr; case OP_STRING: - /* Append string. */ + decode_verifyutf8(d, val.str_val.data, val.str_val.size); + /* Fallthrough. */ + case OP_BYTES: + /* Append bytes. */ mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(upb_strview), void); arr->len++; @@ -389,7 +433,7 @@ static void decode_tomap(upb_decstate *d, upb_msg *msg, if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) { /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val.val = (uint64_t)_upb_msg_new(entry->submsgs[0], d->arena); + ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], d->arena)); } decode_tosubmsg(d, &ent.k, layout, field, val.str_val); @@ -434,6 +478,9 @@ static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, break; } case OP_STRING: + decode_verifyutf8(d, val.str_val.data, val.str_val.size); + /* Fallthrough. */ + case OP_BYTES: memcpy(mem, &val, sizeof(upb_strview)); break; case OP_SCALAR_LG2(3): @@ -477,14 +524,16 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, break; case UPB_WIRE_TYPE_32BIT: if (d->limit - ptr < 4) decode_err(d); - memcpy(&val, ptr, 4); + memcpy(&val.uint32_val, ptr, 4); + val.uint32_val = _upb_be_swap32(val.uint32_val); ptr += 4; op = OP_SCALAR_LG2(2); if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown; break; case UPB_WIRE_TYPE_64BIT: if (d->limit - ptr < 8) decode_err(d); - memcpy(&val, ptr, 8); + memcpy(&val.uint64_val, ptr, 8); + val.uint64_val = _upb_be_swap64(val.uint64_val); ptr += 8; op = OP_SCALAR_LG2(3); if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown; @@ -504,7 +553,7 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, break; } case UPB_WIRE_TYPE_START_GROUP: - val.int32_val = field_number; + val.uint32_val = field_number; op = OP_SUBMSG; if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown; break; diff --git a/third_party/upb/upb/def.c b/third_party/upb/upb/def.c index 8f143354001..00a5877bde2 100644 --- a/third_party/upb/upb/def.c +++ b/third_party/upb/upb/def.c @@ -922,6 +922,22 @@ static uint32_t upb_msglayout_place(upb_msglayout *l, size_t size) { return ret; } +static int field_number_cmp(const void *p1, const void *p2) { + const upb_msglayout_field *f1 = p1; + const upb_msglayout_field *f2 = p2; + return f1->number - f2->number; +} + +static void assign_layout_indices(const upb_msgdef *m, upb_msglayout_field *fields) { + int i; + int n = upb_msgdef_numfields(m); + for (i = 0; i < n; i++) { + upb_fielddef *f = (upb_fielddef*)upb_msgdef_itof(m, fields[i].number); + UPB_ASSERT(f); + f->layout_index = i; + } +} + /* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. * It computes a dynamic layout for all of the fields in |m|. */ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { @@ -997,16 +1013,19 @@ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { field->descriptortype = upb_fielddef_descriptortype(f); field->label = upb_fielddef_label(f); + if (field->descriptortype == UPB_DTYPE_STRING && + f->file->syntax == UPB_SYNTAX_PROTO2) { + /* See TableDescriptorType() in upbc/generator.cc for details and + * rationale. */ + field->descriptortype = UPB_DTYPE_BYTES; + } + if (upb_fielddef_ismap(f)) { field->label = _UPB_LABEL_MAP; } else if (upb_fielddef_packed(f)) { field->label = _UPB_LABEL_PACKED; } - /* TODO: we probably should sort the fields by field number to match the - * output of upbc, and to improve search speed for the table parser. */ - f->layout_index = f->index_; - if (upb_fielddef_issubmsg(f)) { const upb_msgdef *subm = upb_fielddef_msgsubdef(f); field->submsg_index = submsg_count++; @@ -1079,6 +1098,10 @@ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { * alignment. TODO: track overall alignment for real? */ l->size = UPB_ALIGN_UP(l->size, 8); + /* Sort fields by number. */ + qsort(fields, upb_msgdef_numfields(m), sizeof(*fields), field_number_cmp); + assign_layout_indices(m, fields); + return true; } @@ -1532,13 +1555,21 @@ static bool create_fielddef( f->oneof = NULL; } - if (google_protobuf_FieldDescriptorProto_has_options(field_proto)) { - options = google_protobuf_FieldDescriptorProto_options(field_proto); - f->lazy_ = google_protobuf_FieldOptions_lazy(options); + options = google_protobuf_FieldDescriptorProto_has_options(field_proto) ? + google_protobuf_FieldDescriptorProto_options(field_proto) : NULL; + + if (options && google_protobuf_FieldOptions_has_packed(options)) { f->packed_ = google_protobuf_FieldOptions_packed(options); + } else { + /* Repeated fields default to packed for proto3 only. */ + f->packed_ = upb_fielddef_isprimitive(f) && + f->label_ == UPB_LABEL_REPEATED && f->file->syntax == UPB_SYNTAX_PROTO3; + } + + if (options) { + f->lazy_ = google_protobuf_FieldOptions_lazy(options); } else { f->lazy_ = false; - f->packed_ = false; } return true; diff --git a/third_party/upb/upb/encode.c b/third_party/upb/upb/encode.c index 87162325ad9..a6ce62bfa53 100644 --- a/third_party/upb/upb/encode.c +++ b/third_party/upb/upb/encode.c @@ -77,12 +77,12 @@ static bool upb_put_bytes(upb_encstate *e, const void *data, size_t len) { } static bool upb_put_fixed64(upb_encstate *e, uint64_t val) { - /* TODO(haberman): byte-swap for big endian. */ + val = _upb_be_swap64(val); return upb_put_bytes(e, &val, sizeof(uint64_t)); } static bool upb_put_fixed32(upb_encstate *e, uint32_t val) { - /* TODO(haberman): byte-swap for big endian. */ + val = _upb_be_swap32(val); return upb_put_bytes(e, &val, sizeof(uint32_t)); } diff --git a/third_party/upb/upb/handlers.h b/third_party/upb/upb/handlers.h index 9ed70e959c6..53904b6022f 100644 --- a/third_party/upb/upb/handlers.h +++ b/third_party/upb/upb/handlers.h @@ -106,7 +106,7 @@ typedef struct { #define UPB_HANDLERATTR_INIT {NULL, NULL, NULL, false} /* Bufhandle, data passed along with a buffer to indicate its provenance. */ -typedef struct { +struct upb_bufhandle { /* The beginning of the buffer. This may be different than the pointer * passed to a StringBuf handler because the handler may receive data * that is from the middle or end of a larger buffer. */ @@ -133,7 +133,9 @@ typedef struct { : NULL; } #endif -} upb_bufhandle; +}; + +typedef struct upb_bufhandle upb_bufhandle; #define UPB_BUFHANDLE_INIT {NULL, 0, NULL, NULL} diff --git a/third_party/upb/upb/json_decode.c b/third_party/upb/upb/json_decode.c index 9c70173165e..953d2387ed8 100644 --- a/third_party/upb/upb/json_decode.c +++ b/third_party/upb/upb/json_decode.c @@ -409,6 +409,7 @@ static upb_strview jsondec_string(jsondec *d) { upb_strview ret; ret.data = buf; ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ return ret; } case '\\': diff --git a/third_party/upb/upb/json_encode.c b/third_party/upb/upb/json_encode.c index 21f661f8f6e..6b6d99b30ff 100644 --- a/third_party/upb/upb/json_encode.c +++ b/third_party/upb/upb/json_encode.c @@ -38,6 +38,14 @@ UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) { longjmp(e->err, 1); } +UPB_NORETURN static void jsonenc_errf(jsonenc *e, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_status_vseterrf(e->status, fmt, argp); + va_end(argp); + longjmp(e->err, 1); +} + static upb_arena *jsonenc_arena(jsonenc *e) { /* Create lazily, since it's only needed for Any */ if (!e->arena) { @@ -279,7 +287,11 @@ static const upb_msgdef *jsonenc_getanymsg(jsonenc *e, upb_strview type_url) { const char *ptr = end; const upb_msgdef *ret; - if (!e->ext_pool || type_url.size == 0) goto badurl; + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } + + if (type_url.size == 0) goto badurl; while (true) { if (--ptr == type_url.data) { @@ -295,13 +307,14 @@ static const upb_msgdef *jsonenc_getanymsg(jsonenc *e, upb_strview type_url) { ret = upb_symtab_lookupmsg2(e->ext_pool, ptr, end - ptr); if (!ret) { - jsonenc_err(e, "Couldn't find Any type"); + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); } return ret; badurl: - jsonenc_err(e, "Bad type URL"); + jsonenc_errf( + e, "Bad type URL: " UPB_STRVIEW_FORMAT, UPB_STRVIEW_ARGS(type_url)); } static void jsonenc_any(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) { diff --git a/third_party/upb/upb/msg.h b/third_party/upb/upb/msg.h index b321748ec05..695c278b211 100644 --- a/third_party/upb/upb/msg.h +++ b/third_party/upb/upb/msg.h @@ -324,7 +324,7 @@ UPB_INLINE upb_value _upb_map_tovalue(const void *val, size_t size, if (size == UPB_MAPTYPE_STRING) { upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp)); *strp = *(upb_strview*)val; - memcpy(&ret, &strp, sizeof(strp)); + ret = upb_value_ptr(strp); } else { memcpy(&ret, val, size); } @@ -455,7 +455,7 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size) /* This is like _upb_map_tovalue() except the entry already exists so we can * reuse the allocated upb_strview for string fields. */ if (size == UPB_MAPTYPE_STRING) { - upb_strview *strp = (upb_strview*)ent->val.val; + upb_strview *strp = (upb_strview*)(uintptr_t)ent->val.val; memcpy(strp, val, sizeof(*strp)); } else { memcpy(&ent->val.val, val, size); diff --git a/third_party/upb/upb/port_def.inc b/third_party/upb/upb/port_def.inc index 9e9c506597f..2c144dc066a 100644 --- a/third_party/upb/upb/port_def.inc +++ b/third_party/upb/upb/port_def.inc @@ -141,7 +141,7 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg); #elif defined _MSC_VER #define UPB_ASSUME(expr) if (!(expr)) __assume(0) #else -#define UPB_ASSUME(expr) do {} if (false && (expr)) +#define UPB_ASSUME(expr) do {} while (false && (expr)) #endif #else #define UPB_ASSUME(expr) assert(expr) diff --git a/third_party/upb/upb/table.c b/third_party/upb/upb/table.c index e89f72c6988..34a20530d8b 100644 --- a/third_party/upb/upb/table.c +++ b/third_party/upb/upb/table.c @@ -559,17 +559,6 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { return success; } -bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) { - return upb_inttable_insert2(t, upb_inttable_count(t), val, a); -} - -upb_value upb_inttable_pop(upb_inttable *t) { - upb_value val; - bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val); - UPB_ASSERT(ok); - return val; -} - bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, upb_alloc *a) { return upb_inttable_insert2(t, (uintptr_t)key, val, a); diff --git a/third_party/upb/upb/table.int.h b/third_party/upb/upb/table.int.h index 75575eb7d52..600637eef2e 100644 --- a/third_party/upb/upb/table.int.h +++ b/third_party/upb/upb/table.int.h @@ -326,15 +326,6 @@ UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, * invalidate iterators. */ bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); -/* Handy routines for treating an inttable like a stack. May not be mixed with - * other insert/remove calls. */ -bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a); -upb_value upb_inttable_pop(upb_inttable *t); - -UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) { - return upb_inttable_push2(t, val, &upb_alloc_global); -} - /* Convenience routines for inttables with pointer keys. */ bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, upb_alloc *a); diff --git a/third_party/upb/upb/upb.c b/third_party/upb/upb/upb.c index c2d406950d3..3089c059e1e 100644 --- a/third_party/upb/upb/upb.c +++ b/third_party/upb/upb/upb.c @@ -106,15 +106,28 @@ struct upb_arena { static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); +static upb_arena *arena_findroot(upb_arena *a) { + /* Path splitting keeps time complexity down, see: + * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + while (a->parent != a) { + upb_arena *next = a->parent; + a->parent = next->parent; + a = next; + } + return a; +} + static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size) { mem_block *block = ptr; + upb_arena *root = arena_findroot(a); - block->next = a->freelist; + /* The block is for arena |a|, but should appear in the freelist of |root|. */ + block->next = root->freelist; block->size = (uint32_t)size; block->cleanups = 0; - a->freelist = block; + root->freelist = block; a->last_size = block->size; - if (!a->freelist_tail) a->freelist_tail = block; + if (!root->freelist_tail) root->freelist_tail = block; a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); a->head.end = UPB_PTR_AT(block, size, char); @@ -149,17 +162,6 @@ static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize, return upb_arena_realloc(a, ptr, oldsize, size); } -static upb_arena *arena_findroot(upb_arena *a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_arena *next = a->parent; - a->parent = next->parent; - a = next; - } - return a; -} - /* Public Arena API ***********************************************************/ upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) { diff --git a/third_party/upb/upb/upb.h b/third_party/upb/upb/upb.h index c3e1c5f3d59..e1d9d8cfd35 100644 --- a/third_party/upb/upb/upb.h +++ b/third_party/upb/upb/upb.h @@ -273,6 +273,32 @@ typedef enum { #define UPB_MAP_BEGIN ((size_t)-1) +UPB_INLINE bool _upb_isle(void) { + int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t _upb_be_swap32(uint32_t val) { + if (_upb_isle()) { + return val; + } else { + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000ULL) >> 8) | ((val & 0xff000000ULL) >> 24); + } +} + +UPB_INLINE uint64_t _upb_be_swap64(uint64_t val) { + if (_upb_isle()) { + return val; + } else { + return ((val & 0xff) << 56) | ((val & 0xff00) << 40) | + ((val & 0xff0000) << 24) | ((val & 0xff000000) << 8) | + ((val & 0xff00000000ULL) >> 8) | ((val & 0xff0000000000ULL) >> 24) | + ((val & 0xff000000000000ULL) >> 40) | + ((val & 0xff00000000000000ULL) >> 56); + } +} + #include "upb/port_undef.inc" #ifdef __cplusplus diff --git a/third_party/upb/upb/upb.hpp b/third_party/upb/upb/upb.hpp index 60ef29b2966..a3ec5faff8f 100644 --- a/third_party/upb/upb/upb.hpp +++ b/third_party/upb/upb/upb.hpp @@ -60,6 +60,8 @@ class Arena { }); } + void Fuse(Arena& other) { upb_arena_fuse(ptr(), other.ptr()); } + private: std::unique_ptr ptr_; }; diff --git a/third_party/upb/upbc/generator.cc b/third_party/upb/upbc/generator.cc index d5c27fb2afa..72df0244aa1 100644 --- a/third_party/upb/upbc/generator.cc +++ b/third_party/upb/upbc/generator.cc @@ -281,7 +281,9 @@ std::string FieldDefault(const protobuf::FieldDescriptor* field) { case protobuf::FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; case protobuf::FieldDescriptor::CPPTYPE_ENUM: - return EnumValueSymbol(field->default_value_enum()); + // Use a number instead of a symbolic name so that we don't require + // this enum's header to be included. + return absl::StrCat(field->default_value_enum()->number()); } ABSL_ASSERT(false); return "XXX"; @@ -685,6 +687,22 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { ToPreproc(file->name())); } +int TableDescriptorType(const protobuf::FieldDescriptor* field) { + if (field->file()->syntax() == protobuf::FileDescriptor::SYNTAX_PROTO2 && + field->type() == protobuf::FieldDescriptor::TYPE_STRING) { + // From the perspective of the binary encoder/decoder, proto2 string fields + // are identical to bytes fields. Only in proto3 do we check UTF-8 for + // string fields at parse time. + // + // If we ever use these tables for JSON encoding/decoding (for example by + // embedding field names on the side) we will have to revisit this, because + // string vs. bytes behavior is not affected by proto2 vs proto3. + return protobuf::FieldDescriptor::TYPE_BYTES; + } else { + return field->type(); + } +} + void WriteSource(const protobuf::FileDescriptor* file, Output& output) { EmitFileWarning(file, output); @@ -779,7 +797,7 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) { GetSizeInit(layout.GetFieldOffset(field)), presence, submsg_index, - field->type(), + TableDescriptorType(field), label); } output("};\n\n"); diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py index 2983441176d..21a90383589 100755 --- a/tools/distrib/check_include_guards.py +++ b/tools/distrib/check_include_guards.py @@ -43,13 +43,14 @@ class GuardValidator(object): def __init__(self): self.ifndef_re = re.compile(r'#ifndef ([A-Z][A-Z_1-9]*)') self.define_re = re.compile(r'#define ([A-Z][A-Z_1-9]*)') - self.endif_c_re = re.compile( + self.endif_c_core_re = re.compile( r'#endif /\* (?: *\\\n *)?([A-Z][A-Z_1-9]*) (?:\\\n *)?\*/$') - self.endif_cpp_re = re.compile(r'#endif // ([A-Z][A-Z_1-9]*)') + self.endif_re = re.compile(r'#endif // ([A-Z][A-Z_1-9]*)') self.failed = False def fail(self, fpath, regexp, fcontents, match_txt, correct, fix): - cpp_header = 'grpc++' in fpath or 'grpcpp' in fpath + c_core_header = 'include' in fpath and not ('grpc++' in fpath or + 'grpcpp' in fpath) self.failed = True invalid_guards_msg_template = ( '{0}: Missing preprocessor guards (RE {1}). ' @@ -58,7 +59,8 @@ class GuardValidator(object): '#define {2}\n' '...\n' '... epic code ...\n' - '...\n') + ('#endif // {2}' if cpp_header else '#endif /* {2} */') + '...\n') + ('#endif /* {2} */' + if c_core_header else '#endif // {2}') if not match_txt: print invalid_guards_msg_template.format(fpath, regexp.pattern, build_valid_guard(fpath)) @@ -79,7 +81,8 @@ class GuardValidator(object): return fcontents def check(self, fpath, fix): - cpp_header = 'grpc++' in fpath or 'grpcpp' in fpath + c_core_header = 'include' in fpath and not ('grpc++' in fpath or + 'grpcpp' in fpath) valid_guard = build_valid_guard(fpath) fcontents = load(fpath) @@ -120,22 +123,27 @@ class GuardValidator(object): if fix: save(fpath, fcontents) # Is there a properly commented #endif? - endif_re = self.endif_cpp_re if cpp_header else self.endif_c_re flines = fcontents.rstrip().splitlines() - match = endif_re.search('\n'.join(flines[-3:])) + match = self.endif_c_core_re.search('\n'.join(flines[-3:])) + if not match and not c_core_header: + match = self.endif_re.search('\n'.join(flines[-3:])) if not match: # No endif. Check if we have the last line as just '#endif' and if so # replace it with a properly commented one. if flines[-1] == '#endif': - flines[-1] = ('#endif' + - (' // {}\n'.format(valid_guard) if cpp_header - else ' /* {} */\n'.format(valid_guard))) + flines[-1] = ( + '#endif' + + (' /* {} */\n'.format(valid_guard) + if c_core_header else ' // {}\n'.format(valid_guard))) if fix: fcontents = '\n'.join(flines) save(fpath, fcontents) else: # something else is wrong, bail out - self.fail(fpath, endif_re, flines[-1], '', '', False) + self.fail( + fpath, + self.endif_c_core_re if c_core_header else self.endif_re, + flines[-1], '', '', False) elif match.group(1) != running_guard: # Is the #endif guard the same as the #ifndef and #define guards? fcontents = self.fail(fpath, endif_re, fcontents, match.group(1), @@ -155,18 +163,6 @@ argp.add_argument('-f', '--fix', default=False, action='store_true') argp.add_argument('--precommit', default=False, action='store_true') args = argp.parse_args() -KNOWN_BAD = set([ - 'src/core/ext/filters/client_channel/health/health.pb.h', - 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h', - 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h', - 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h', - 'src/core/tsi/alts/handshaker/altscontext.pb.h', - 'src/core/tsi/alts/handshaker/handshaker.pb.h', - 'src/core/tsi/alts/handshaker/transport_security_common.pb.h', - 'include/grpc++/ext/reflection.grpc.pb.h', - 'include/grpc++/ext/reflection.pb.h', -]) - grep_filter = r"grep -E '^(include|src/core)/.*\.h$'" if args.precommit: git_command = 'git diff --name-only HEAD' @@ -189,7 +185,6 @@ except subprocess.CalledProcessError: validator = GuardValidator() for filename in filename_list: - if filename in KNOWN_BAD: continue # Skip check for upb generated code. if filename.endswith('.upb.h') or filename.endswith('.upb.c'): continue diff --git a/tools/distrib/python/docgen.py b/tools/distrib/python/docgen.py index 9c9e5910db7..0fc49a1d21c 100755 --- a/tools/distrib/python/docgen.py +++ b/tools/distrib/python/docgen.py @@ -22,77 +22,54 @@ import shutil import subprocess import sys import tempfile +import grpc_version parser = argparse.ArgumentParser() -parser.add_argument('--config', - metavar='c', - type=str, - nargs=1, - help='GRPC/GPR libraries build configuration', - default='opt') -parser.add_argument('--submit', action='store_true') parser.add_argument('--repo-owner', type=str, help=('Owner of the GitHub repository to be pushed')) -parser.add_argument('--doc-branch', type=str) +parser.add_argument('--doc-branch', + type=str, + default='python-doc-%s' % grpc_version.VERSION) args = parser.parse_args() SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..')) -CONFIG = args.config SETUP_PATH = os.path.join(PROJECT_ROOT, 'setup.py') REQUIREMENTS_PATH = os.path.join(PROJECT_ROOT, 'requirements.bazel.txt') DOC_PATH = os.path.join(PROJECT_ROOT, 'doc/build') -INCLUDE_PATH = os.path.join(PROJECT_ROOT, 'include') -LIBRARY_PATH = os.path.join(PROJECT_ROOT, 'libs/{}'.format(CONFIG)) -VIRTUALENV_DIR = os.path.join(SCRIPT_DIR, 'distrib_virtualenv') -VIRTUALENV_PYTHON_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'python') -VIRTUALENV_PIP_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'pip') -environment = os.environ.copy() -environment.update({ - 'CONFIG': CONFIG, - 'CFLAGS': '-I{}'.format(INCLUDE_PATH), - 'LDFLAGS': '-L{}'.format(LIBRARY_PATH), - 'LD_LIBRARY_PATH': LIBRARY_PATH, - 'GRPC_PYTHON_BUILD_WITH_CYTHON': '1', - 'GRPC_PYTHON_ENABLE_DOCUMENTATION_BUILD': '1', -}) +if "VIRTUAL_ENV" in os.environ: + VIRTUALENV_DIR = os.environ['VIRTUAL_ENV'] + PYTHON_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'python') + subprocess_arguments_list = [] +else: + VIRTUALENV_DIR = os.path.join(SCRIPT_DIR, 'distrib_virtualenv') + PYTHON_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'python') + subprocess_arguments_list = [ + ['python3', '-m', 'virtualenv', VIRTUALENV_DIR], + ] -subprocess_arguments_list = [ - { - 'args': ['virtualenv', VIRTUALENV_DIR], - 'env': environment - }, - { - 'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip==19.3.1'], - 'env': environment - }, - { - 'args': [VIRTUALENV_PIP_PATH, 'install', '-r', REQUIREMENTS_PATH], - 'env': environment - }, - { - 'args': [VIRTUALENV_PIP_PATH, 'install', 'Sphinx~=1.8.1'], - 'env': environment - }, - { - 'args': [VIRTUALENV_PYTHON_PATH, SETUP_PATH, 'doc'], - 'env': environment - }, +subprocess_arguments_list += [ + [PYTHON_PATH, '-m', 'pip', 'install', '--upgrade', 'pip==19.3.1'], + [PYTHON_PATH, '-m', 'pip', 'install', '-r', REQUIREMENTS_PATH], + [PYTHON_PATH, '-m', 'pip', 'install', '--upgrade', 'Sphinx'], + [PYTHON_PATH, SETUP_PATH, 'doc'], ] for subprocess_arguments in subprocess_arguments_list: - print('Running command: {}'.format(subprocess_arguments['args'])) - subprocess.check_call(**subprocess_arguments) + print('Running command: {}'.format(subprocess_arguments)) + subprocess.check_call(args=subprocess_arguments) -if not args.submit: +if not args.repo_owner or not args.doc_branch: + tty_width = int(os.popen('stty size', 'r').read().split()[1]) + print('-' * tty_width) print('Please check generated Python doc inside doc/build') -elif args.submit: - assert args.repo_owner - assert args.doc_branch - github_repository_owner = args.repo_owner + print( + 'To push to a GitHub repo, please provide repo owner and doc branch name' + ) +else: # Create a temporary directory out of tree, checkout gh-pages from the # specified repository, edit it, and push it. It's up to the user to then go # onto GitHub and make a PR against grpc/grpc:gh-pages. @@ -114,13 +91,14 @@ elif args.submit: subprocess.check_call(['git', 'checkout', '-b', doc_branch], cwd=repo_dir) subprocess.check_call([ 'git', 'remote', 'add', 'ssh-origin', - 'git@github.com:%s/grpc.git' % (github_repository_owner) + 'git@github.com:%s/grpc.git' % (args.repo_owner) ], cwd=repo_dir) print('Updating documentation...') shutil.rmtree(python_doc_dir, ignore_errors=True) shutil.copytree(DOC_PATH, python_doc_dir) - print('Attempting to push documentation...') + print('Attempting to push documentation to %s/%s...' % + (args.repo_owner, doc_branch)) try: subprocess.check_call(['git', 'add', '--all'], cwd=repo_dir) subprocess.check_call( diff --git a/tools/distrib/python/grpc_version.py b/tools/distrib/python/grpc_version.py new file mode 100644 index 00000000000..3f85118019d --- /dev/null +++ b/tools/distrib/python/grpc_version.py @@ -0,0 +1,17 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! + +VERSION = '1.32.0.dev0' diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile index 477618e5767..40b56cc8198 100644 --- a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile @@ -70,6 +70,15 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t # C++ dependencies RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean +#================= +# Use cmake 3.6 from jessie-backports +# should only be used for images based on debian jessie. + +RUN echo "deb http://archive.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list +RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf +RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list +RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean + RUN mkdir /var/local/jenkins diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh index ec1da444097..54c0fa89c86 100755 --- a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh +++ b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh @@ -32,8 +32,9 @@ cd /var/local/git/grpc mkdir -p /usr/local/share/grpc cp etc/roots.pem /usr/local/share/grpc/roots.pem -# build C++ interop client & server +# build C++ interop client, interop server and http2 interop client +mkdir -p cmake/build +cd cmake/build +cmake -DgRPC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ../.. make interop_client interop_server -j4 - -# build C++ http2 client make http2_client -j4 diff --git a/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh index 589983ce58c..2b4c07ed128 100644 --- a/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh +++ b/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh @@ -23,4 +23,5 @@ git clone /var/local/jenkins/grpc-dart /var/local/git/grpc-dart cp -r /var/local/jenkins/service_account $HOME || true cd /var/local/git/grpc-dart/interop -/usr/lib/dart/bin/pub get --verbose +# De-flake attempt: run the cmd one more time in case of transient failure +/usr/lib/dart/bin/pub get --verbose || /usr/lib/dart/bin/pub get --verbose diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index a4080632735..4a5a95fdec6 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -1024,7 +1024,6 @@ include/grpcpp/security/auth_context.h \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/credentials.h \ include/grpcpp/security/server_credentials.h \ -include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/security/tls_credentials_options.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 8d34e9e02ae..2dcc90b6806 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1024,7 +1024,6 @@ include/grpcpp/security/auth_context.h \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/credentials.h \ include/grpcpp/security/server_credentials.h \ -include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/security/tls_credentials_options.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 891e58f0d68..655b8fa94e0 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -221,6 +221,7 @@ LANG_RELEASE_MATRIX = { ('v1.28.1', ReleaseInfo()), ('v1.29.0', ReleaseInfo()), ('v1.30.2', ReleaseInfo()), + ('v1.31.0', ReleaseInfo()), ]), 'python': OrderedDict([ diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 32e247553b0..0ee4d5d72fc 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -97,16 +97,16 @@ class CXXLanguage: self.safename = 'cxx' def client_cmd(self, args): - return ['bins/opt/interop_client'] + args + return ['cmake/build/interop_client'] + args def client_cmd_http2interop(self, args): - return ['bins/opt/http2_client'] + args + return ['cmake/build/http2_client'] + args def cloud_to_prod_env(self): return {} def server_cmd(self, args): - return ['bins/opt/interop_server'] + args + return ['cmake/build/interop_server'] + args def global_env(self): return {}