From 6fcb5b29e18268c8948d5bd99c14fca13f9d7b67 Mon Sep 17 00:00:00 2001 From: kkm Date: Thu, 11 Oct 2018 20:22:40 -0700 Subject: [PATCH 01/99] Redo C# examples to use new Grpc.Tools * No pre-compilation of proto files required; * Tested under Windows and Linux dotnet and mono; * But not tested on Mac/mono; * README updated. --- examples/csharp/.gitignore | 2 + examples/csharp/Helloworld/Greeter.sln | 2 +- .../csharp/Helloworld/Greeter/Greeter.csproj | 15 +- .../csharp/Helloworld/Greeter/Helloworld.cs | 312 ------ .../Helloworld/Greeter/HelloworldGrpc.cs | 149 --- .../GreeterClient/GreeterClient.csproj | 8 +- .../GreeterServer/GreeterServer.csproj | 8 +- examples/csharp/Helloworld/README.md | 32 +- .../csharp/Helloworld/generate_protos.bat | 28 - .../csharp/HelloworldLegacyCsproj/Greeter.sln | 2 +- .../Greeter/Greeter.csproj | 23 +- .../Greeter/Helloworld.cs | 312 ------ .../Greeter/HelloworldGrpc.cs | 149 --- .../Greeter/packages.config | 10 +- .../GreeterClient/GreeterClient.csproj | 8 +- .../GreeterClient/packages.config | 6 +- .../GreeterServer/GreeterServer.csproj | 8 +- .../GreeterServer/packages.config | 6 +- .../csharp/HelloworldLegacyCsproj/README.md | 27 +- .../generate_protos.bat | 26 - examples/csharp/RouteGuide/RouteGuide.sln | 2 +- .../RouteGuide/RouteGuide/RouteGuide.cs | 981 ------------------ .../RouteGuide/RouteGuide/RouteGuide.csproj | 18 +- .../RouteGuide/RouteGuide/RouteGuideGrpc.cs | 331 ------ .../RouteGuide/RouteGuide/RouteGuideUtil.cs | 2 + .../RouteGuideClient/RouteGuideClient.csproj | 8 +- .../RouteGuideServer/RouteGuideServer.csproj | 8 +- .../csharp/RouteGuide/generate_protos.bat | 28 - 28 files changed, 83 insertions(+), 2428 deletions(-) delete mode 100644 examples/csharp/Helloworld/Greeter/Helloworld.cs delete mode 100644 examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs delete mode 100644 examples/csharp/Helloworld/generate_protos.bat delete mode 100644 examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs delete mode 100644 examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs delete mode 100644 examples/csharp/HelloworldLegacyCsproj/generate_protos.bat delete mode 100644 examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs delete mode 100644 examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs delete mode 100644 examples/csharp/RouteGuide/generate_protos.bat diff --git a/examples/csharp/.gitignore b/examples/csharp/.gitignore index 585000ea2d5..11f758f5c81 100644 --- a/examples/csharp/.gitignore +++ b/examples/csharp/.gitignore @@ -1,5 +1,7 @@ +.vs/ bin/ obj/ packages/ *.suo +*.user *.userprefs diff --git a/examples/csharp/Helloworld/Greeter.sln b/examples/csharp/Helloworld/Greeter.sln index ca50470e664..a5ba98d0bed 100644 --- a/examples/csharp/Helloworld/Greeter.sln +++ b/examples/csharp/Helloworld/Greeter.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26228.4 diff --git a/examples/csharp/Helloworld/Greeter/Greeter.csproj b/examples/csharp/Helloworld/Greeter/Greeter.csproj index eba262565d7..3421926dca5 100644 --- a/examples/csharp/Helloworld/Greeter/Greeter.csproj +++ b/examples/csharp/Helloworld/Greeter/Greeter.csproj @@ -1,18 +1,15 @@ - + - Greeter - netcoreapp2.1 - portable - Greeter - Greeter + netstandard1.5 - - - + + + + diff --git a/examples/csharp/Helloworld/Greeter/Helloworld.cs b/examples/csharp/Helloworld/Greeter/Helloworld.cs deleted file mode 100644 index e008ec27e54..00000000000 --- a/examples/csharp/Helloworld/Greeter/Helloworld.cs +++ /dev/null @@ -1,312 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: helloworld.proto -// -#pragma warning disable 1591, 0612, 3021 -#region Designer generated code - -using pb = global::Google.Protobuf; -using pbc = global::Google.Protobuf.Collections; -using pbr = global::Google.Protobuf.Reflection; -using scg = global::System.Collections.Generic; -namespace Helloworld { - - /// Holder for reflection information generated from helloworld.proto - public static partial class HelloworldReflection { - - #region Descriptor - /// File descriptor for helloworld.proto - public static pbr::FileDescriptor Descriptor { - get { return descriptor; } - } - private static pbr::FileDescriptor descriptor; - - static HelloworldReflection() { - byte[] descriptorData = global::System.Convert.FromBase64String( - string.Concat( - "ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz", - "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo", - "CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl", - "cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4", - "YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZw", - "cm90bzM=")); - descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { }, - new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloRequest), global::Helloworld.HelloRequest.Parser, new[]{ "Name" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloReply), global::Helloworld.HelloReply.Parser, new[]{ "Message" }, null, null, null) - })); - } - #endregion - - } - #region Messages - /// - /// The request message containing the user's name. - /// - public sealed partial class HelloRequest : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloRequest()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloRequest() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloRequest(HelloRequest other) : this() { - name_ = other.name_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloRequest Clone() { - return new HelloRequest(this); - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 1; - private string name_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as HelloRequest); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(HelloRequest other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Name != other.Name) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Name.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Name); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(HelloRequest other) { - if (other == null) { - return; - } - if (other.Name.Length != 0) { - Name = other.Name; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Name = input.ReadString(); - break; - } - } - } - } - - } - - /// - /// The response message containing the greetings - /// - public sealed partial class HelloReply : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloReply()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[1]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloReply() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloReply(HelloReply other) : this() { - message_ = other.message_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloReply Clone() { - return new HelloReply(this); - } - - /// Field number for the "message" field. - public const int MessageFieldNumber = 1; - private string message_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Message { - get { return message_; } - set { - message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as HelloReply); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(HelloReply other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Message != other.Message) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Message.Length != 0) hash ^= Message.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Message.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Message); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Message.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(HelloReply other) { - if (other == null) { - return; - } - if (other.Message.Length != 0) { - Message = other.Message; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Message = input.ReadString(); - break; - } - } - } - } - - } - - #endregion - -} - -#endregion Designer generated code diff --git a/examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs b/examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs deleted file mode 100644 index d6b959adc64..00000000000 --- a/examples/csharp/Helloworld/Greeter/HelloworldGrpc.cs +++ /dev/null @@ -1,149 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: helloworld.proto -// -// Original file comments: -// 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. -// -#pragma warning disable 0414, 1591 -#region Designer generated code - -using grpc = global::Grpc.Core; - -namespace Helloworld { - /// - /// The greeting service definition. - /// - public static partial class Greeter - { - static readonly string __ServiceName = "helloworld.Greeter"; - - static readonly grpc::Marshaller __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom); - static readonly grpc::Marshaller __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom); - - static readonly grpc::Method __Method_SayHello = new grpc::Method( - grpc::MethodType.Unary, - __ServiceName, - "SayHello", - __Marshaller_helloworld_HelloRequest, - __Marshaller_helloworld_HelloReply); - - /// Service descriptor - public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor - { - get { return global::Helloworld.HelloworldReflection.Descriptor.Services[0]; } - } - - /// Base class for server-side implementations of Greeter - public abstract partial class GreeterBase - { - /// - /// Sends a greeting - /// - /// The request received from the client. - /// The context of the server-side call handler being invoked. - /// The response to send back to the client (wrapped by a task). - public virtual global::System.Threading.Tasks.Task SayHello(global::Helloworld.HelloRequest request, grpc::ServerCallContext context) - { - throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); - } - - } - - /// Client for Greeter - public partial class GreeterClient : grpc::ClientBase - { - /// Creates a new client for Greeter - /// The channel to use to make remote calls. - public GreeterClient(grpc::Channel channel) : base(channel) - { - } - /// Creates a new client for Greeter that uses a custom CallInvoker. - /// The callInvoker to use to make remote calls. - public GreeterClient(grpc::CallInvoker callInvoker) : base(callInvoker) - { - } - /// Protected parameterless constructor to allow creation of test doubles. - protected GreeterClient() : base() - { - } - /// Protected constructor to allow creation of configured clients. - /// The client configuration. - protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration) - { - } - - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The response received from the server. - public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The options for the call. - /// The response received from the server. - public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::CallOptions options) - { - return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request); - } - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The call object. - public virtual grpc::AsyncUnaryCall SayHelloAsync(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The options for the call. - /// The call object. - public virtual grpc::AsyncUnaryCall SayHelloAsync(global::Helloworld.HelloRequest request, grpc::CallOptions options) - { - return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request); - } - /// Creates a new instance of client from given ClientBaseConfiguration. - protected override GreeterClient NewInstance(ClientBaseConfiguration configuration) - { - return new GreeterClient(configuration); - } - } - - /// Creates service definition that can be registered with a server - /// An object implementing the server-side handling logic. - public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl) - { - return grpc::ServerServiceDefinition.CreateBuilder() - .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build(); - } - - } -} -#endregion diff --git a/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj b/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj index 24a89d58c55..ac10d854972 100644 --- a/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj +++ b/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj @@ -1,12 +1,8 @@ - + - GreeterClient - netcoreapp2.1 - portable - GreeterClient + netcoreapp2.1 Exe - GreeterClient diff --git a/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj b/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj index 9ea1fa3817c..ac10d854972 100644 --- a/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj +++ b/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj @@ -1,12 +1,8 @@ - + - GreeterServer - netcoreapp2.1 - portable - GreeterServer + netcoreapp2.1 Exe - GreeterServer diff --git a/examples/csharp/Helloworld/README.md b/examples/csharp/Helloworld/README.md index 48711324262..e4771ee91a1 100644 --- a/examples/csharp/Helloworld/README.md +++ b/examples/csharp/Helloworld/README.md @@ -3,41 +3,31 @@ gRPC in 3 minutes (C#) BACKGROUND ------------- -For this sample, we've already generated the server and client stubs from [helloworld.proto][]. - -Example projects in this directory depend on the [Grpc](https://www.nuget.org/packages/Grpc/) -and [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf/) NuGet packages -which have been already added to the project for you. +This is a version of the helloworld example using the dotnet SDK +tools to compile [helloworld.proto][] in a common library, build the server +and the client, and run them. PREREQUISITES ------------- - The [.NET Core SDK 2.1+](https://www.microsoft.com/net/core) -You can also build the example directly using Visual Studio 2017, but it's not a requirement. - -BUILD -------- - -From the `examples/csharp/Helloworld` directory: +You can also build the solution `Greeter.sln` using Visual Studio 2017, +but it's not a requirement. -- `dotnet build Greeter.sln` - -Try it! -------- +BUILD AND RUN +------------- -- Run the server +- Build and run the server ``` - > cd GreeterServer - > dotnet run -f netcoreapp2.1 + > dotnet run -p GreeterServer ``` -- Run the client +- Build and run the client ``` - > cd GreeterClient - > dotnet run -f netcoreapp2.1 + > dotnet run -p GreeterClient ``` Tutorial diff --git a/examples/csharp/Helloworld/generate_protos.bat b/examples/csharp/Helloworld/generate_protos.bat deleted file mode 100644 index ab0c0eb46a4..00000000000 --- a/examples/csharp/Helloworld/generate_protos.bat +++ /dev/null @@ -1,28 +0,0 @@ -@rem Copyright 2016 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@rem Generate the C# code for .proto files - -setlocal - -@rem enter this directory -cd /d %~dp0 - -@rem packages will be available in nuget cache directory once the project is built or after "dotnet restore" -set PROTOC=%UserProfile%\.nuget\packages\Google.Protobuf.Tools\3.6.1\tools\windows_x64\protoc.exe -set PLUGIN=%UserProfile%\.nuget\packages\Grpc.Tools\1.14.1\tools\windows_x64\grpc_csharp_plugin.exe - -%PROTOC% -I../../protos --csharp_out Greeter ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%PLUGIN% - -endlocal diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter.sln b/examples/csharp/HelloworldLegacyCsproj/Greeter.sln index 49e364d91c0..26cae7a727e 100644 --- a/examples/csharp/HelloworldLegacyCsproj/Greeter.sln +++ b/examples/csharp/HelloworldLegacyCsproj/Greeter.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj b/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj index 197a9fb6257..da15ba3954b 100644 --- a/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj +++ b/examples/csharp/HelloworldLegacyCsproj/Greeter/Greeter.csproj @@ -1,5 +1,6 @@ - + + Debug AnyCPU @@ -36,7 +37,7 @@ ..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll - ..\packages\Grpc.Core.1.14.1\lib\net45\Grpc.Core.dll + ..\packages\Grpc.Core.1.17.0\lib\net45\Grpc.Core.dll @@ -47,25 +48,23 @@ - - - + protos\helloworld.proto - - - generate_protos.bat - + - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + + + - \ No newline at end of file + + diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs b/examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs deleted file mode 100644 index e008ec27e54..00000000000 --- a/examples/csharp/HelloworldLegacyCsproj/Greeter/Helloworld.cs +++ /dev/null @@ -1,312 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: helloworld.proto -// -#pragma warning disable 1591, 0612, 3021 -#region Designer generated code - -using pb = global::Google.Protobuf; -using pbc = global::Google.Protobuf.Collections; -using pbr = global::Google.Protobuf.Reflection; -using scg = global::System.Collections.Generic; -namespace Helloworld { - - /// Holder for reflection information generated from helloworld.proto - public static partial class HelloworldReflection { - - #region Descriptor - /// File descriptor for helloworld.proto - public static pbr::FileDescriptor Descriptor { - get { return descriptor; } - } - private static pbr::FileDescriptor descriptor; - - static HelloworldReflection() { - byte[] descriptorData = global::System.Convert.FromBase64String( - string.Concat( - "ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz", - "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo", - "CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl", - "cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4", - "YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZw", - "cm90bzM=")); - descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { }, - new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloRequest), global::Helloworld.HelloRequest.Parser, new[]{ "Name" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloReply), global::Helloworld.HelloReply.Parser, new[]{ "Message" }, null, null, null) - })); - } - #endregion - - } - #region Messages - /// - /// The request message containing the user's name. - /// - public sealed partial class HelloRequest : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloRequest()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloRequest() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloRequest(HelloRequest other) : this() { - name_ = other.name_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloRequest Clone() { - return new HelloRequest(this); - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 1; - private string name_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as HelloRequest); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(HelloRequest other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Name != other.Name) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Name.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Name); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(HelloRequest other) { - if (other == null) { - return; - } - if (other.Name.Length != 0) { - Name = other.Name; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Name = input.ReadString(); - break; - } - } - } - } - - } - - /// - /// The response message containing the greetings - /// - public sealed partial class HelloReply : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloReply()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[1]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloReply() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloReply(HelloReply other) : this() { - message_ = other.message_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public HelloReply Clone() { - return new HelloReply(this); - } - - /// Field number for the "message" field. - public const int MessageFieldNumber = 1; - private string message_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Message { - get { return message_; } - set { - message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as HelloReply); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(HelloReply other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Message != other.Message) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Message.Length != 0) hash ^= Message.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Message.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Message); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Message.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(HelloReply other) { - if (other == null) { - return; - } - if (other.Message.Length != 0) { - Message = other.Message; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Message = input.ReadString(); - break; - } - } - } - } - - } - - #endregion - -} - -#endregion Designer generated code diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs b/examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs deleted file mode 100644 index d6b959adc64..00000000000 --- a/examples/csharp/HelloworldLegacyCsproj/Greeter/HelloworldGrpc.cs +++ /dev/null @@ -1,149 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: helloworld.proto -// -// Original file comments: -// 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. -// -#pragma warning disable 0414, 1591 -#region Designer generated code - -using grpc = global::Grpc.Core; - -namespace Helloworld { - /// - /// The greeting service definition. - /// - public static partial class Greeter - { - static readonly string __ServiceName = "helloworld.Greeter"; - - static readonly grpc::Marshaller __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom); - static readonly grpc::Marshaller __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom); - - static readonly grpc::Method __Method_SayHello = new grpc::Method( - grpc::MethodType.Unary, - __ServiceName, - "SayHello", - __Marshaller_helloworld_HelloRequest, - __Marshaller_helloworld_HelloReply); - - /// Service descriptor - public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor - { - get { return global::Helloworld.HelloworldReflection.Descriptor.Services[0]; } - } - - /// Base class for server-side implementations of Greeter - public abstract partial class GreeterBase - { - /// - /// Sends a greeting - /// - /// The request received from the client. - /// The context of the server-side call handler being invoked. - /// The response to send back to the client (wrapped by a task). - public virtual global::System.Threading.Tasks.Task SayHello(global::Helloworld.HelloRequest request, grpc::ServerCallContext context) - { - throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); - } - - } - - /// Client for Greeter - public partial class GreeterClient : grpc::ClientBase - { - /// Creates a new client for Greeter - /// The channel to use to make remote calls. - public GreeterClient(grpc::Channel channel) : base(channel) - { - } - /// Creates a new client for Greeter that uses a custom CallInvoker. - /// The callInvoker to use to make remote calls. - public GreeterClient(grpc::CallInvoker callInvoker) : base(callInvoker) - { - } - /// Protected parameterless constructor to allow creation of test doubles. - protected GreeterClient() : base() - { - } - /// Protected constructor to allow creation of configured clients. - /// The client configuration. - protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration) - { - } - - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The response received from the server. - public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The options for the call. - /// The response received from the server. - public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::CallOptions options) - { - return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request); - } - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The call object. - public virtual grpc::AsyncUnaryCall SayHelloAsync(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// Sends a greeting - /// - /// The request to send to the server. - /// The options for the call. - /// The call object. - public virtual grpc::AsyncUnaryCall SayHelloAsync(global::Helloworld.HelloRequest request, grpc::CallOptions options) - { - return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request); - } - /// Creates a new instance of client from given ClientBaseConfiguration. - protected override GreeterClient NewInstance(ClientBaseConfiguration configuration) - { - return new GreeterClient(configuration); - } - } - - /// Creates service definition that can be registered with a server - /// An object implementing the server-side handling logic. - public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl) - { - return grpc::ServerServiceDefinition.CreateBuilder() - .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build(); - } - - } -} -#endregion diff --git a/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config b/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config index 23857be22fa..154b5993213 100644 --- a/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config +++ b/examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config @@ -1,8 +1,8 @@ - + - - - + + + - \ No newline at end of file + diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj index 3bb7ff1ee13..31a3a90345b 100644 --- a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj +++ b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/GreeterClient.csproj @@ -1,4 +1,4 @@ - + Debug @@ -36,7 +36,7 @@ ..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll - ..\packages\Grpc.Core.1.14.1\lib\net45\Grpc.Core.dll + ..\packages\Grpc.Core.1.17.0\lib\net45\Grpc.Core.dll @@ -59,11 +59,11 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config index df4df8282c4..2fd8228689d 100644 --- a/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config +++ b/examples/csharp/HelloworldLegacyCsproj/GreeterClient/packages.config @@ -1,7 +1,7 @@ - + - - + + \ No newline at end of file diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj index 4396b04efeb..27ca9630401 100644 --- a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj +++ b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/GreeterServer.csproj @@ -1,4 +1,4 @@ - + Debug @@ -36,7 +36,7 @@ ..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll - ..\packages\Grpc.Core.1.14.1\lib\net45\Grpc.Core.dll + ..\packages\Grpc.Core.1.17.0\lib\net45\Grpc.Core.dll @@ -59,11 +59,11 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config index df4df8282c4..2fd8228689d 100644 --- a/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config +++ b/examples/csharp/HelloworldLegacyCsproj/GreeterServer/packages.config @@ -1,7 +1,7 @@ - + - - + + \ No newline at end of file diff --git a/examples/csharp/HelloworldLegacyCsproj/README.md b/examples/csharp/HelloworldLegacyCsproj/README.md index 6d42c5ef258..60b09e09257 100644 --- a/examples/csharp/HelloworldLegacyCsproj/README.md +++ b/examples/csharp/HelloworldLegacyCsproj/README.md @@ -3,21 +3,21 @@ gRPC in 3 minutes (C#) BACKGROUND ------------- -This is a different version of the helloworld example, using the old-style .csproj -files supported by VS2013 and VS2015 (and older versions of mono). -You can still use gRPC with the old-style .csproj files, but [using the new-style -.csproj projects](../helloworld/README.md) (supported by VS2017 and dotnet SDK) is recommended. - -For this sample, we've already generated the server and client stubs from [helloworld.proto][]. - -Example projects depend on the [Grpc](https://www.nuget.org/packages/Grpc/), [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) +This is a different version of the helloworld example, using the "classic" .csproj +files, the only format supported by VS2013 (and older versions of mono). +You can still use gRPC with the classic .csproj files, but [using the new-style +.csproj projects](../helloworld/README.md) (supported by VS2015 Update3 and above, +and dotnet SDK) is recommended. + +Example projects depend on the [Grpc](https://www.nuget.org/packages/Grpc/), +[Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) and [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf/) NuGet packages which have been already added to the project for you. PREREQUISITES ------------- -- Windows: .NET Framework 4.5+, Visual Studio 2013 or 2015 +- Windows: .NET Framework 4.5+, Visual Studio 2013 or higher - Linux: Mono 4+, MonoDevelop 5.9+ - Mac OS X: Xamarin Studio 5.9+ @@ -28,12 +28,15 @@ BUILD # Using Visual Studio -* Build the solution (this will automatically download NuGet dependencies) +* Select "Restore NuGet Packages" from the solution context menu. It is recommended + to close and re-open the solution after the packages have been restored from + Visual Studio. +* Build the solution. # Using Monodevelop or Xamarin Studio -The nuget add-in available for Xamarin Studio and Monodevelop IDEs is too old to -download all of the nuget dependencies of gRPC. +The NuGet add-in available for Xamarin Studio and Monodevelop IDEs is too old to +download all of the NuGet dependencies of gRPC. Using these IDEs, a workaround is as follows: * Obtain a nuget executable for your platform and update it with diff --git a/examples/csharp/HelloworldLegacyCsproj/generate_protos.bat b/examples/csharp/HelloworldLegacyCsproj/generate_protos.bat deleted file mode 100644 index d1e7160f91e..00000000000 --- a/examples/csharp/HelloworldLegacyCsproj/generate_protos.bat +++ /dev/null @@ -1,26 +0,0 @@ -@rem Copyright 2016 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@rem Generate the C# code for .proto files - -setlocal - -@rem enter this directory -cd /d %~dp0 - -set TOOLS_PATH=packages\Grpc.Tools.1.14.1\tools\windows_x86 - -%TOOLS_PATH%\protoc.exe -I../../protos --csharp_out Greeter ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe - -endlocal diff --git a/examples/csharp/RouteGuide/RouteGuide.sln b/examples/csharp/RouteGuide/RouteGuide.sln index 73e6e306b16..5e103294a56 100644 --- a/examples/csharp/RouteGuide/RouteGuide.sln +++ b/examples/csharp/RouteGuide/RouteGuide.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26228.4 diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs deleted file mode 100644 index 10c9aec5f80..00000000000 --- a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.cs +++ /dev/null @@ -1,981 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: route_guide.proto -// -#pragma warning disable 1591, 0612, 3021 -#region Designer generated code - -using pb = global::Google.Protobuf; -using pbc = global::Google.Protobuf.Collections; -using pbr = global::Google.Protobuf.Reflection; -using scg = global::System.Collections.Generic; -namespace Routeguide { - - /// Holder for reflection information generated from route_guide.proto - public static partial class RouteGuideReflection { - - #region Descriptor - /// File descriptor for route_guide.proto - public static pbr::FileDescriptor Descriptor { - get { return descriptor; } - } - private static pbr::FileDescriptor descriptor; - - static RouteGuideReflection() { - byte[] descriptorData = global::System.Convert.FromBase64String( - string.Concat( - "ChFyb3V0ZV9ndWlkZS5wcm90bxIKcm91dGVndWlkZSIsCgVQb2ludBIQCghs", - "YXRpdHVkZRgBIAEoBRIRCglsb25naXR1ZGUYAiABKAUiSQoJUmVjdGFuZ2xl", - "Eh0KAmxvGAEgASgLMhEucm91dGVndWlkZS5Qb2ludBIdCgJoaRgCIAEoCzIR", - "LnJvdXRlZ3VpZGUuUG9pbnQiPAoHRmVhdHVyZRIMCgRuYW1lGAEgASgJEiMK", - "CGxvY2F0aW9uGAIgASgLMhEucm91dGVndWlkZS5Qb2ludCJBCglSb3V0ZU5v", - "dGUSIwoIbG9jYXRpb24YASABKAsyES5yb3V0ZWd1aWRlLlBvaW50Eg8KB21l", - "c3NhZ2UYAiABKAkiYgoMUm91dGVTdW1tYXJ5EhMKC3BvaW50X2NvdW50GAEg", - "ASgFEhUKDWZlYXR1cmVfY291bnQYAiABKAUSEAoIZGlzdGFuY2UYAyABKAUS", - "FAoMZWxhcHNlZF90aW1lGAQgASgFMoUCCgpSb3V0ZUd1aWRlEjYKCkdldEZl", - "YXR1cmUSES5yb3V0ZWd1aWRlLlBvaW50GhMucm91dGVndWlkZS5GZWF0dXJl", - "IgASPgoMTGlzdEZlYXR1cmVzEhUucm91dGVndWlkZS5SZWN0YW5nbGUaEy5y", - "b3V0ZWd1aWRlLkZlYXR1cmUiADABEj4KC1JlY29yZFJvdXRlEhEucm91dGVn", - "dWlkZS5Qb2ludBoYLnJvdXRlZ3VpZGUuUm91dGVTdW1tYXJ5IgAoARI/CglS", - "b3V0ZUNoYXQSFS5yb3V0ZWd1aWRlLlJvdXRlTm90ZRoVLnJvdXRlZ3VpZGUu", - "Um91dGVOb3RlIgAoATABQjYKG2lvLmdycGMuZXhhbXBsZXMucm91dGVndWlk", - "ZUIPUm91dGVHdWlkZVByb3RvUAGiAgNSVEdiBnByb3RvMw==")); - descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { }, - new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Point), global::Routeguide.Point.Parser, new[]{ "Latitude", "Longitude" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Rectangle), global::Routeguide.Rectangle.Parser, new[]{ "Lo", "Hi" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Feature), global::Routeguide.Feature.Parser, new[]{ "Name", "Location" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.RouteNote), global::Routeguide.RouteNote.Parser, new[]{ "Location", "Message" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.RouteSummary), global::Routeguide.RouteSummary.Parser, new[]{ "PointCount", "FeatureCount", "Distance", "ElapsedTime" }, null, null, null) - })); - } - #endregion - - } - #region Messages - /// - /// Points are represented as latitude-longitude pairs in the E7 representation - /// (degrees multiplied by 10**7 and rounded to the nearest integer). - /// Latitudes should be in the range +/- 90 degrees and longitude should be in - /// the range +/- 180 degrees (inclusive). - /// - public sealed partial class Point : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Point()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[0]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Point() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Point(Point other) : this() { - latitude_ = other.latitude_; - longitude_ = other.longitude_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Point Clone() { - return new Point(this); - } - - /// Field number for the "latitude" field. - public const int LatitudeFieldNumber = 1; - private int latitude_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int Latitude { - get { return latitude_; } - set { - latitude_ = value; - } - } - - /// Field number for the "longitude" field. - public const int LongitudeFieldNumber = 2; - private int longitude_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int Longitude { - get { return longitude_; } - set { - longitude_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as Point); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Point other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Latitude != other.Latitude) return false; - if (Longitude != other.Longitude) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Latitude != 0) hash ^= Latitude.GetHashCode(); - if (Longitude != 0) hash ^= Longitude.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Latitude != 0) { - output.WriteRawTag(8); - output.WriteInt32(Latitude); - } - if (Longitude != 0) { - output.WriteRawTag(16); - output.WriteInt32(Longitude); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Latitude != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(Latitude); - } - if (Longitude != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(Longitude); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Point other) { - if (other == null) { - return; - } - if (other.Latitude != 0) { - Latitude = other.Latitude; - } - if (other.Longitude != 0) { - Longitude = other.Longitude; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - Latitude = input.ReadInt32(); - break; - } - case 16: { - Longitude = input.ReadInt32(); - break; - } - } - } - } - - } - - /// - /// A latitude-longitude rectangle, represented as two diagonally opposite - /// points "lo" and "hi". - /// - public sealed partial class Rectangle : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Rectangle()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[1]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Rectangle() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Rectangle(Rectangle other) : this() { - lo_ = other.lo_ != null ? other.lo_.Clone() : null; - hi_ = other.hi_ != null ? other.hi_.Clone() : null; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Rectangle Clone() { - return new Rectangle(this); - } - - /// Field number for the "lo" field. - public const int LoFieldNumber = 1; - private global::Routeguide.Point lo_; - /// - /// One corner of the rectangle. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Routeguide.Point Lo { - get { return lo_; } - set { - lo_ = value; - } - } - - /// Field number for the "hi" field. - public const int HiFieldNumber = 2; - private global::Routeguide.Point hi_; - /// - /// The other corner of the rectangle. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Routeguide.Point Hi { - get { return hi_; } - set { - hi_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as Rectangle); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Rectangle other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (!object.Equals(Lo, other.Lo)) return false; - if (!object.Equals(Hi, other.Hi)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (lo_ != null) hash ^= Lo.GetHashCode(); - if (hi_ != null) hash ^= Hi.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (lo_ != null) { - output.WriteRawTag(10); - output.WriteMessage(Lo); - } - if (hi_ != null) { - output.WriteRawTag(18); - output.WriteMessage(Hi); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (lo_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Lo); - } - if (hi_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Hi); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Rectangle other) { - if (other == null) { - return; - } - if (other.lo_ != null) { - if (lo_ == null) { - lo_ = new global::Routeguide.Point(); - } - Lo.MergeFrom(other.Lo); - } - if (other.hi_ != null) { - if (hi_ == null) { - hi_ = new global::Routeguide.Point(); - } - Hi.MergeFrom(other.Hi); - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - if (lo_ == null) { - lo_ = new global::Routeguide.Point(); - } - input.ReadMessage(lo_); - break; - } - case 18: { - if (hi_ == null) { - hi_ = new global::Routeguide.Point(); - } - input.ReadMessage(hi_); - break; - } - } - } - } - - } - - /// - /// A feature names something at a given point. - /// - /// If a feature could not be named, the name is empty. - /// - public sealed partial class Feature : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Feature()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[2]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Feature() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Feature(Feature other) : this() { - name_ = other.name_; - location_ = other.location_ != null ? other.location_.Clone() : null; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public Feature Clone() { - return new Feature(this); - } - - /// Field number for the "name" field. - public const int NameFieldNumber = 1; - private string name_ = ""; - /// - /// The name of the feature. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Name { - get { return name_; } - set { - name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "location" field. - public const int LocationFieldNumber = 2; - private global::Routeguide.Point location_; - /// - /// The point where the feature is detected. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Routeguide.Point Location { - get { return location_; } - set { - location_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as Feature); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(Feature other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (Name != other.Name) return false; - if (!object.Equals(Location, other.Location)) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (Name.Length != 0) hash ^= Name.GetHashCode(); - if (location_ != null) hash ^= Location.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (Name.Length != 0) { - output.WriteRawTag(10); - output.WriteString(Name); - } - if (location_ != null) { - output.WriteRawTag(18); - output.WriteMessage(Location); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (Name.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); - } - if (location_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(Feature other) { - if (other == null) { - return; - } - if (other.Name.Length != 0) { - Name = other.Name; - } - if (other.location_ != null) { - if (location_ == null) { - location_ = new global::Routeguide.Point(); - } - Location.MergeFrom(other.Location); - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - if (location_ == null) { - location_ = new global::Routeguide.Point(); - } - input.ReadMessage(location_); - break; - } - } - } - } - - } - - /// - /// A RouteNote is a message sent while at a given point. - /// - public sealed partial class RouteNote : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RouteNote()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[3]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public RouteNote() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public RouteNote(RouteNote other) : this() { - location_ = other.location_ != null ? other.location_.Clone() : null; - message_ = other.message_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public RouteNote Clone() { - return new RouteNote(this); - } - - /// Field number for the "location" field. - public const int LocationFieldNumber = 1; - private global::Routeguide.Point location_; - /// - /// The location from which the message is sent. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public global::Routeguide.Point Location { - get { return location_; } - set { - location_ = value; - } - } - - /// Field number for the "message" field. - public const int MessageFieldNumber = 2; - private string message_ = ""; - /// - /// The message to be sent. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Message { - get { return message_; } - set { - message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as RouteNote); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(RouteNote other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (!object.Equals(Location, other.Location)) return false; - if (Message != other.Message) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (location_ != null) hash ^= Location.GetHashCode(); - if (Message.Length != 0) hash ^= Message.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (location_ != null) { - output.WriteRawTag(10); - output.WriteMessage(Location); - } - if (Message.Length != 0) { - output.WriteRawTag(18); - output.WriteString(Message); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (location_ != null) { - size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location); - } - if (Message.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(RouteNote other) { - if (other == null) { - return; - } - if (other.location_ != null) { - if (location_ == null) { - location_ = new global::Routeguide.Point(); - } - Location.MergeFrom(other.Location); - } - if (other.Message.Length != 0) { - Message = other.Message; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 10: { - if (location_ == null) { - location_ = new global::Routeguide.Point(); - } - input.ReadMessage(location_); - break; - } - case 18: { - Message = input.ReadString(); - break; - } - } - } - } - - } - - /// - /// A RouteSummary is received in response to a RecordRoute rpc. - /// - /// It contains the number of individual points received, the number of - /// detected features, and the total distance covered as the cumulative sum of - /// the distance between each point. - /// - public sealed partial class RouteSummary : pb::IMessage { - private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RouteSummary()); - private pb::UnknownFieldSet _unknownFields; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pb::MessageParser Parser { get { return _parser; } } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public static pbr::MessageDescriptor Descriptor { - get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[4]; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - pbr::MessageDescriptor pb::IMessage.Descriptor { - get { return Descriptor; } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public RouteSummary() { - OnConstruction(); - } - - partial void OnConstruction(); - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public RouteSummary(RouteSummary other) : this() { - pointCount_ = other.pointCount_; - featureCount_ = other.featureCount_; - distance_ = other.distance_; - elapsedTime_ = other.elapsedTime_; - _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public RouteSummary Clone() { - return new RouteSummary(this); - } - - /// Field number for the "point_count" field. - public const int PointCountFieldNumber = 1; - private int pointCount_; - /// - /// The number of points received. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int PointCount { - get { return pointCount_; } - set { - pointCount_ = value; - } - } - - /// Field number for the "feature_count" field. - public const int FeatureCountFieldNumber = 2; - private int featureCount_; - /// - /// The number of known features passed while traversing the route. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int FeatureCount { - get { return featureCount_; } - set { - featureCount_ = value; - } - } - - /// Field number for the "distance" field. - public const int DistanceFieldNumber = 3; - private int distance_; - /// - /// The distance covered in metres. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int Distance { - get { return distance_; } - set { - distance_ = value; - } - } - - /// Field number for the "elapsed_time" field. - public const int ElapsedTimeFieldNumber = 4; - private int elapsedTime_; - /// - /// The duration of the traversal in seconds. - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int ElapsedTime { - get { return elapsedTime_; } - set { - elapsedTime_ = value; - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override bool Equals(object other) { - return Equals(other as RouteSummary); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public bool Equals(RouteSummary other) { - if (ReferenceEquals(other, null)) { - return false; - } - if (ReferenceEquals(other, this)) { - return true; - } - if (PointCount != other.PointCount) return false; - if (FeatureCount != other.FeatureCount) return false; - if (Distance != other.Distance) return false; - if (ElapsedTime != other.ElapsedTime) return false; - return Equals(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override int GetHashCode() { - int hash = 1; - if (PointCount != 0) hash ^= PointCount.GetHashCode(); - if (FeatureCount != 0) hash ^= FeatureCount.GetHashCode(); - if (Distance != 0) hash ^= Distance.GetHashCode(); - if (ElapsedTime != 0) hash ^= ElapsedTime.GetHashCode(); - if (_unknownFields != null) { - hash ^= _unknownFields.GetHashCode(); - } - return hash; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public override string ToString() { - return pb::JsonFormatter.ToDiagnosticString(this); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void WriteTo(pb::CodedOutputStream output) { - if (PointCount != 0) { - output.WriteRawTag(8); - output.WriteInt32(PointCount); - } - if (FeatureCount != 0) { - output.WriteRawTag(16); - output.WriteInt32(FeatureCount); - } - if (Distance != 0) { - output.WriteRawTag(24); - output.WriteInt32(Distance); - } - if (ElapsedTime != 0) { - output.WriteRawTag(32); - output.WriteInt32(ElapsedTime); - } - if (_unknownFields != null) { - _unknownFields.WriteTo(output); - } - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public int CalculateSize() { - int size = 0; - if (PointCount != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(PointCount); - } - if (FeatureCount != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(FeatureCount); - } - if (Distance != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(Distance); - } - if (ElapsedTime != 0) { - size += 1 + pb::CodedOutputStream.ComputeInt32Size(ElapsedTime); - } - if (_unknownFields != null) { - size += _unknownFields.CalculateSize(); - } - return size; - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(RouteSummary other) { - if (other == null) { - return; - } - if (other.PointCount != 0) { - PointCount = other.PointCount; - } - if (other.FeatureCount != 0) { - FeatureCount = other.FeatureCount; - } - if (other.Distance != 0) { - Distance = other.Distance; - } - if (other.ElapsedTime != 0) { - ElapsedTime = other.ElapsedTime; - } - _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public void MergeFrom(pb::CodedInputStream input) { - uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { - default: - _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); - break; - case 8: { - PointCount = input.ReadInt32(); - break; - } - case 16: { - FeatureCount = input.ReadInt32(); - break; - } - case 24: { - Distance = input.ReadInt32(); - break; - } - case 32: { - ElapsedTime = input.ReadInt32(); - break; - } - } - } - } - - } - - #endregion - -} - -#endregion Designer generated code diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj index 86346d1e149..2d4f48ec2e9 100644 --- a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj +++ b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj @@ -1,25 +1,19 @@ - + - RouteGuide - netcoreapp2.1 - portable - RouteGuide - RouteGuide + netstandard1.5 - - - + + - - PreserveNewest - + + diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs b/examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs deleted file mode 100644 index 445708e4469..00000000000 --- a/examples/csharp/RouteGuide/RouteGuide/RouteGuideGrpc.cs +++ /dev/null @@ -1,331 +0,0 @@ -// -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: route_guide.proto -// -// Original file comments: -// 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. -// -#pragma warning disable 0414, 1591 -#region Designer generated code - -using grpc = global::Grpc.Core; - -namespace Routeguide { - /// - /// Interface exported by the server. - /// - public static partial class RouteGuide - { - static readonly string __ServiceName = "routeguide.RouteGuide"; - - static readonly grpc::Marshaller __Marshaller_routeguide_Point = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Point.Parser.ParseFrom); - static readonly grpc::Marshaller __Marshaller_routeguide_Feature = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Feature.Parser.ParseFrom); - static readonly grpc::Marshaller __Marshaller_routeguide_Rectangle = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Rectangle.Parser.ParseFrom); - static readonly grpc::Marshaller __Marshaller_routeguide_RouteSummary = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.RouteSummary.Parser.ParseFrom); - static readonly grpc::Marshaller __Marshaller_routeguide_RouteNote = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.RouteNote.Parser.ParseFrom); - - static readonly grpc::Method __Method_GetFeature = new grpc::Method( - grpc::MethodType.Unary, - __ServiceName, - "GetFeature", - __Marshaller_routeguide_Point, - __Marshaller_routeguide_Feature); - - static readonly grpc::Method __Method_ListFeatures = new grpc::Method( - grpc::MethodType.ServerStreaming, - __ServiceName, - "ListFeatures", - __Marshaller_routeguide_Rectangle, - __Marshaller_routeguide_Feature); - - static readonly grpc::Method __Method_RecordRoute = new grpc::Method( - grpc::MethodType.ClientStreaming, - __ServiceName, - "RecordRoute", - __Marshaller_routeguide_Point, - __Marshaller_routeguide_RouteSummary); - - static readonly grpc::Method __Method_RouteChat = new grpc::Method( - grpc::MethodType.DuplexStreaming, - __ServiceName, - "RouteChat", - __Marshaller_routeguide_RouteNote, - __Marshaller_routeguide_RouteNote); - - /// Service descriptor - public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor - { - get { return global::Routeguide.RouteGuideReflection.Descriptor.Services[0]; } - } - - /// Base class for server-side implementations of RouteGuide - public abstract partial class RouteGuideBase - { - /// - /// A simple RPC. - /// - /// Obtains the feature at a given position. - /// - /// A feature with an empty name is returned if there's no feature at the given - /// position. - /// - /// The request received from the client. - /// The context of the server-side call handler being invoked. - /// The response to send back to the client (wrapped by a task). - public virtual global::System.Threading.Tasks.Task GetFeature(global::Routeguide.Point request, grpc::ServerCallContext context) - { - throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); - } - - /// - /// A server-to-client streaming RPC. - /// - /// Obtains the Features available within the given Rectangle. Results are - /// streamed rather than returned at once (e.g. in a response message with a - /// repeated field), as the rectangle may cover a large area and contain a - /// huge number of features. - /// - /// The request received from the client. - /// Used for sending responses back to the client. - /// The context of the server-side call handler being invoked. - /// A task indicating completion of the handler. - public virtual global::System.Threading.Tasks.Task ListFeatures(global::Routeguide.Rectangle request, grpc::IServerStreamWriter responseStream, grpc::ServerCallContext context) - { - throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); - } - - /// - /// A client-to-server streaming RPC. - /// - /// Accepts a stream of Points on a route being traversed, returning a - /// RouteSummary when traversal is completed. - /// - /// Used for reading requests from the client. - /// The context of the server-side call handler being invoked. - /// The response to send back to the client (wrapped by a task). - public virtual global::System.Threading.Tasks.Task RecordRoute(grpc::IAsyncStreamReader requestStream, grpc::ServerCallContext context) - { - throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); - } - - /// - /// A Bidirectional streaming RPC. - /// - /// Accepts a stream of RouteNotes sent while a route is being traversed, - /// while receiving other RouteNotes (e.g. from other users). - /// - /// Used for reading requests from the client. - /// Used for sending responses back to the client. - /// The context of the server-side call handler being invoked. - /// A task indicating completion of the handler. - public virtual global::System.Threading.Tasks.Task RouteChat(grpc::IAsyncStreamReader requestStream, grpc::IServerStreamWriter responseStream, grpc::ServerCallContext context) - { - throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); - } - - } - - /// Client for RouteGuide - public partial class RouteGuideClient : grpc::ClientBase - { - /// Creates a new client for RouteGuide - /// The channel to use to make remote calls. - public RouteGuideClient(grpc::Channel channel) : base(channel) - { - } - /// Creates a new client for RouteGuide that uses a custom CallInvoker. - /// The callInvoker to use to make remote calls. - public RouteGuideClient(grpc::CallInvoker callInvoker) : base(callInvoker) - { - } - /// Protected parameterless constructor to allow creation of test doubles. - protected RouteGuideClient() : base() - { - } - /// Protected constructor to allow creation of configured clients. - /// The client configuration. - protected RouteGuideClient(ClientBaseConfiguration configuration) : base(configuration) - { - } - - /// - /// A simple RPC. - /// - /// Obtains the feature at a given position. - /// - /// A feature with an empty name is returned if there's no feature at the given - /// position. - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The response received from the server. - public virtual global::Routeguide.Feature GetFeature(global::Routeguide.Point request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return GetFeature(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// A simple RPC. - /// - /// Obtains the feature at a given position. - /// - /// A feature with an empty name is returned if there's no feature at the given - /// position. - /// - /// The request to send to the server. - /// The options for the call. - /// The response received from the server. - public virtual global::Routeguide.Feature GetFeature(global::Routeguide.Point request, grpc::CallOptions options) - { - return CallInvoker.BlockingUnaryCall(__Method_GetFeature, null, options, request); - } - /// - /// A simple RPC. - /// - /// Obtains the feature at a given position. - /// - /// A feature with an empty name is returned if there's no feature at the given - /// position. - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The call object. - public virtual grpc::AsyncUnaryCall GetFeatureAsync(global::Routeguide.Point request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return GetFeatureAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// A simple RPC. - /// - /// Obtains the feature at a given position. - /// - /// A feature with an empty name is returned if there's no feature at the given - /// position. - /// - /// The request to send to the server. - /// The options for the call. - /// The call object. - public virtual grpc::AsyncUnaryCall GetFeatureAsync(global::Routeguide.Point request, grpc::CallOptions options) - { - return CallInvoker.AsyncUnaryCall(__Method_GetFeature, null, options, request); - } - /// - /// A server-to-client streaming RPC. - /// - /// Obtains the Features available within the given Rectangle. Results are - /// streamed rather than returned at once (e.g. in a response message with a - /// repeated field), as the rectangle may cover a large area and contain a - /// huge number of features. - /// - /// The request to send to the server. - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The call object. - public virtual grpc::AsyncServerStreamingCall ListFeatures(global::Routeguide.Rectangle request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return ListFeatures(request, new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// A server-to-client streaming RPC. - /// - /// Obtains the Features available within the given Rectangle. Results are - /// streamed rather than returned at once (e.g. in a response message with a - /// repeated field), as the rectangle may cover a large area and contain a - /// huge number of features. - /// - /// The request to send to the server. - /// The options for the call. - /// The call object. - public virtual grpc::AsyncServerStreamingCall ListFeatures(global::Routeguide.Rectangle request, grpc::CallOptions options) - { - return CallInvoker.AsyncServerStreamingCall(__Method_ListFeatures, null, options, request); - } - /// - /// A client-to-server streaming RPC. - /// - /// Accepts a stream of Points on a route being traversed, returning a - /// RouteSummary when traversal is completed. - /// - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The call object. - public virtual grpc::AsyncClientStreamingCall RecordRoute(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return RecordRoute(new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// A client-to-server streaming RPC. - /// - /// Accepts a stream of Points on a route being traversed, returning a - /// RouteSummary when traversal is completed. - /// - /// The options for the call. - /// The call object. - public virtual grpc::AsyncClientStreamingCall RecordRoute(grpc::CallOptions options) - { - return CallInvoker.AsyncClientStreamingCall(__Method_RecordRoute, null, options); - } - /// - /// A Bidirectional streaming RPC. - /// - /// Accepts a stream of RouteNotes sent while a route is being traversed, - /// while receiving other RouteNotes (e.g. from other users). - /// - /// The initial metadata to send with the call. This parameter is optional. - /// An optional deadline for the call. The call will be cancelled if deadline is hit. - /// An optional token for canceling the call. - /// The call object. - public virtual grpc::AsyncDuplexStreamingCall RouteChat(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) - { - return RouteChat(new grpc::CallOptions(headers, deadline, cancellationToken)); - } - /// - /// A Bidirectional streaming RPC. - /// - /// Accepts a stream of RouteNotes sent while a route is being traversed, - /// while receiving other RouteNotes (e.g. from other users). - /// - /// The options for the call. - /// The call object. - public virtual grpc::AsyncDuplexStreamingCall RouteChat(grpc::CallOptions options) - { - return CallInvoker.AsyncDuplexStreamingCall(__Method_RouteChat, null, options); - } - /// Creates a new instance of client from given ClientBaseConfiguration. - protected override RouteGuideClient NewInstance(ClientBaseConfiguration configuration) - { - return new RouteGuideClient(configuration); - } - } - - /// Creates service definition that can be registered with a server - /// An object implementing the server-side handling logic. - public static grpc::ServerServiceDefinition BindService(RouteGuideBase serviceImpl) - { - return grpc::ServerServiceDefinition.CreateBuilder() - .AddMethod(__Method_GetFeature, serviceImpl.GetFeature) - .AddMethod(__Method_ListFeatures, serviceImpl.ListFeatures) - .AddMethod(__Method_RecordRoute, serviceImpl.RecordRoute) - .AddMethod(__Method_RouteChat, serviceImpl.RouteChat).Build(); - } - - } -} -#endregion diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs index f9af1908880..96bd8ca09b9 100644 --- a/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs +++ b/examples/csharp/RouteGuide/RouteGuide/RouteGuideUtil.cs @@ -108,6 +108,7 @@ namespace Routeguide return features; } +#pragma warning disable 0649 // Suppresses "Field 'x' is never assigned to". private class JsonFeature { public string name; @@ -119,5 +120,6 @@ namespace Routeguide public int longitude; public int latitude; } +#pragma warning restore 0649 } } diff --git a/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj b/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj index c6dadf082b8..b773dd0923c 100644 --- a/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj +++ b/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj @@ -1,12 +1,8 @@ - + - RouteGuideClient - netcoreapp2.1 - portable - RouteGuideClient + netcoreapp2.1 Exe - RouteGuideClient diff --git a/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj b/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj index 005c87ca0c2..b773dd0923c 100644 --- a/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj +++ b/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj @@ -1,12 +1,8 @@ - + - RouteGuideServer - netcoreapp2.1 - portable - RouteGuideServer + netcoreapp2.1 Exe - RouteGuideServer diff --git a/examples/csharp/RouteGuide/generate_protos.bat b/examples/csharp/RouteGuide/generate_protos.bat deleted file mode 100644 index f3a4382cf19..00000000000 --- a/examples/csharp/RouteGuide/generate_protos.bat +++ /dev/null @@ -1,28 +0,0 @@ -@rem Copyright 2016 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@rem Generate the C# code for .proto files - -setlocal - -@rem enter this directory -cd /d %~dp0 - -@rem packages will be available in nuget cache directory once the project is built or after "dotnet restore" -set PROTOC=%UserProfile%\.nuget\packages\Google.Protobuf.Tools\3.6.1\tools\windows_x64\protoc.exe -set PLUGIN=%UserProfile%\.nuget\packages\Grpc.Tools\1.14.1\tools\windows_x64\grpc_csharp_plugin.exe - -%PROTOC% -I../../protos --csharp_out RouteGuide ../../protos/route_guide.proto --grpc_out RouteGuide --plugin=protoc-gen-grpc=%PLUGIN% - -endlocal From 56f67728a82950ddeca8ad02e7432ef6d185ba2e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 15:30:46 -0800 Subject: [PATCH 02/99] Bump version to v1.17.0-pre1 --- BUILD | 2 +- build.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD b/BUILD index 3627096f2d2..192606d8b61 100644 --- a/BUILD +++ b/BUILD @@ -68,7 +68,7 @@ g_stands_for = "gizmo" core_version = "7.0.0-dev" -version = "1.17.0-dev" +version = "1.17.0-pre1" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", diff --git a/build.yaml b/build.yaml index 09acdbe6f17..32aeea9d64b 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 7.0.0-dev g_stands_for: gizmo - version: 1.17.0-dev + version: 1.17.0-pre1 filegroups: - name: alts_proto headers: From da14743f1a19d8d36b5891a71dc46cb55eaa496d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 15:32:20 -0800 Subject: [PATCH 03/99] Generate projects --- CMakeLists.txt | 2 +- Makefile | 4 ++-- gRPC-C++.podspec | 4 ++-- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_unitypackage.bat | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/objective-c/tests/version.h | 2 +- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_testing/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 28 files changed, 31 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c2ba2048c0..92dec7da80e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.17.0-dev") +set(PACKAGE_VERSION "1.17.0-pre1") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 12603f1fc8b..64e770565a7 100644 --- a/Makefile +++ b/Makefile @@ -438,8 +438,8 @@ Q = @ endif CORE_VERSION = 7.0.0-dev -CPP_VERSION = 1.17.0-dev -CSHARP_VERSION = 1.17.0-dev +CPP_VERSION = 1.17.0-pre1 +CSHARP_VERSION = 1.17.0-pre1 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index fae5ce4a6ea..6e0267723b6 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,7 +23,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.17.0-dev' + # version = '1.17.0-pre1' version = '0.0.4' s.version = version s.summary = 'gRPC C++ library' @@ -31,7 +31,7 @@ Pod::Spec.new do |s| s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.17.0-dev' + grpc_version = '1.17.0-pre1' s.source = { :git => 'https://github.com/grpc/grpc.git', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index f0a715cb585..42ee1176cca 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.17.0-dev' + version = '1.17.0-pre1' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 693b873d14d..bed6f8480b1 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.17.0-dev' + version = '1.17.0-pre1' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index fd590023e1a..67a087d9b68 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.17.0-dev' + version = '1.17.0-pre1' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 5e513cb1276..c99386bb866 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.17.0-dev' + version = '1.17.0-pre1' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/package.xml b/package.xml index 3044cbf8625..471cee33f9d 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2018-01-19 - 1.17.0dev - 1.17.0dev + 1.17.0RC1 + 1.17.0RC1 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 8abd45efb77..77c2cdd7d53 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.17.0-dev"; } +grpc::string Version() { return "1.17.0-pre1"; } } // namespace grpc diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index ed0d8843650..80bc939280f 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.17.0-dev + 1.17.0-pre1 3.6.1 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 14714c8c4ae..25d114686fb 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -38,6 +38,6 @@ namespace Grpc.Core /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.17.0-dev"; + public const string CurrentVersion = "1.17.0-pre1"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 27688360e9a..23caffec0ce 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-dev +set VERSION=1.17.0-pre1 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat index dd74de0491a..1ceefef6d69 100644 --- a/src/csharp/build_unitypackage.bat +++ b/src/csharp/build_unitypackage.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-dev +set VERSION=1.17.0-pre1 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index a95a120d213..020737b62ce 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.17.0-dev' + v = '1.17.0-pre1' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index d5463c0b4cc..a5603b5c7d2 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre1" diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index ca27c03b3c7..fa72c1117e9 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre1" #define GRPC_C_VERSION_STRING @"7.0.0-dev" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 70f8bbbf40b..5bfb987aaa2 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.17.0dev" +#define PHP_GRPC_VERSION "1.17.0RC1" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index 42b3a1ad498..a1b8f105d54 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.17.0.dev0""" +__version__ = """1.17.0rc1""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 71113e68d99..be2aac35949 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.17.0.dev0' +VERSION = '1.17.0rc1' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index a30aac2e0b8..befd54a4f21 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.17.0.dev0' +VERSION = '1.17.0rc1' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index aafea9fe76b..c940f290c85 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.17.0.dev0' +VERSION = '1.17.0rc1' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index 876acd3142f..99b6bd90171 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.17.0.dev0' +VERSION = '1.17.0rc1' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index cc9b41587ca..5aa6f60dcca 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.17.0.dev0' +VERSION = '1.17.0rc1' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 243d5666451..099d33debb4 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.17.0.dev' + VERSION = '1.17.0.pre1' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 92e85eb882b..f6d24eaaa33 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.17.0.dev' + VERSION = '1.17.0.pre1' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 4b775e667ea..7f4448d0b4b 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.17.0.dev0' +VERSION = '1.17.0rc1' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 392113c2843..cb4ebb465bf 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-dev +PROJECT_NUMBER = 1.17.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index a96683883ca..f52eee8e005 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-dev +PROJECT_NUMBER = 1.17.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 96ed4b75789d422eb362cb7909428217bab63c7d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 17:01:28 -0800 Subject: [PATCH 04/99] dev->pre1 for core version --- BUILD | 2 +- build.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD b/BUILD index 192606d8b61..71df75dc8b2 100644 --- a/BUILD +++ b/BUILD @@ -66,7 +66,7 @@ config_setting( # This should be updated along with build.yaml g_stands_for = "gizmo" -core_version = "7.0.0-dev" +core_version = "7.0.0-pre1" version = "1.17.0-pre1" diff --git a/build.yaml b/build.yaml index 32aeea9d64b..044976f0ca9 100644 --- a/build.yaml +++ b/build.yaml @@ -12,7 +12,7 @@ settings: '#08': Use "-preN" suffixes to identify pre-release versions '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here - core_version: 7.0.0-dev + core_version: 7.0.0-pre1 g_stands_for: gizmo version: 1.17.0-pre1 filegroups: From 4f41886324fcf83616f4ed493b675a308b40a22e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 17:21:04 -0800 Subject: [PATCH 05/99] Generate projects --- Makefile | 2 +- src/core/lib/surface/version.cc | 2 +- src/objective-c/tests/version.h | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 64e770565a7..10dfd976236 100644 --- a/Makefile +++ b/Makefile @@ -437,7 +437,7 @@ E = @echo Q = @ endif -CORE_VERSION = 7.0.0-dev +CORE_VERSION = 7.0.0-pre1 CPP_VERSION = 1.17.0-pre1 CSHARP_VERSION = 1.17.0-pre1 diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 66890ce65ac..3ca1d830f7c 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include -const char* grpc_version_string(void) { return "7.0.0-dev"; } +const char* grpc_version_string(void) { return "7.0.0-pre1"; } const char* grpc_g_stands_for(void) { return "gizmo"; } diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index fa72c1117e9..41a8c10ec24 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -23,4 +23,4 @@ // `tools/buildgen/generate_projects.sh`. #define GRPC_OBJC_VERSION_STRING @"1.17.0-pre1" -#define GRPC_C_VERSION_STRING @"7.0.0-dev" +#define GRPC_C_VERSION_STRING @"7.0.0-pre1" diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index b78fb607ad3..5ef4357e92b 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-dev +PROJECT_NUMBER = 7.0.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 7d105b32ce0..83a25e2b594 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-dev +PROJECT_NUMBER = 7.0.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 9809e018881ef4dd1a1cd7fc025445f772724648 Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Tue, 20 Nov 2018 15:21:29 -0800 Subject: [PATCH 06/99] Wrap pthread_atwork call --- src/php/ext/grpc/php_grpc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index cbc7f63be07..492325b1e8b 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -200,7 +200,9 @@ void postfork_parent() { void register_fork_handlers() { if (getenv("GRPC_ENABLE_FORK_SUPPORT")) { +#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK pthread_atfork(&prefork, &postfork_parent, &postfork_child); +#endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK } } From 894b313c0bd6992d2f1f1ab01f72c152c542511a Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Tue, 20 Nov 2018 16:12:05 -0800 Subject: [PATCH 07/99] Bump to v1.17.0-pre2 --- BUILD | 10 +++++----- build.yaml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BUILD b/BUILD index 71df75dc8b2..270c56ff6ed 100644 --- a/BUILD +++ b/BUILD @@ -66,9 +66,9 @@ config_setting( # This should be updated along with build.yaml g_stands_for = "gizmo" -core_version = "7.0.0-pre1" +core_version = "7.0.0-pre2" -version = "1.17.0-pre1" +version = "1.17.0-pre2" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", @@ -1087,11 +1087,11 @@ grpc_cc_library( "grpc_base", "grpc_client_authority_filter", "grpc_deadline_filter", + "health_proto", "inlined_vector", "orphanable", "ref_counted", "ref_counted_ptr", - "health_proto", ], ) @@ -1589,8 +1589,8 @@ grpc_cc_library( "src/core/lib/security/security_connector/load_system_roots_linux.cc", "src/core/lib/security/security_connector/local/local_security_connector.cc", "src/core/lib/security/security_connector/security_connector.cc", - "src/core/lib/security/security_connector/ssl_utils.cc", "src/core/lib/security/security_connector/ssl/ssl_security_connector.cc", + "src/core/lib/security/security_connector/ssl_utils.cc", "src/core/lib/security/transport/client_auth_filter.cc", "src/core/lib/security/transport/secure_endpoint.cc", "src/core/lib/security/transport/security_handshaker.cc", @@ -1623,8 +1623,8 @@ grpc_cc_library( "src/core/lib/security/security_connector/load_system_roots_linux.h", "src/core/lib/security/security_connector/local/local_security_connector.h", "src/core/lib/security/security_connector/security_connector.h", - "src/core/lib/security/security_connector/ssl_utils.h", "src/core/lib/security/security_connector/ssl/ssl_security_connector.h", + "src/core/lib/security/security_connector/ssl_utils.h", "src/core/lib/security/transport/auth_filters.h", "src/core/lib/security/transport/secure_endpoint.h", "src/core/lib/security/transport/security_handshaker.h", diff --git a/build.yaml b/build.yaml index 044976f0ca9..0a74fd29ffd 100644 --- a/build.yaml +++ b/build.yaml @@ -12,9 +12,9 @@ settings: '#08': Use "-preN" suffixes to identify pre-release versions '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here - core_version: 7.0.0-pre1 + core_version: 7.0.0-pre2 g_stands_for: gizmo - version: 1.17.0-pre1 + version: 1.17.0-pre2 filegroups: - name: alts_proto headers: From 42e3ae730913cff77b8c9eec7fb0bccd7e0b7db9 Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Tue, 20 Nov 2018 23:36:04 -0800 Subject: [PATCH 08/99] Re-generate projects --- CMakeLists.txt | 2 +- Makefile | 6 +++--- gRPC-C++.podspec | 4 ++-- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.xml | 4 ++-- src/core/lib/surface/version.cc | 2 +- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_unitypackage.bat | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/objective-c/tests/version.h | 4 ++-- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_testing/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 31 files changed, 36 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92dec7da80e..17f5f4ca637 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.17.0-pre1") +set(PACKAGE_VERSION "1.17.0-pre2") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 10dfd976236..3ac25a788dd 100644 --- a/Makefile +++ b/Makefile @@ -437,9 +437,9 @@ E = @echo Q = @ endif -CORE_VERSION = 7.0.0-pre1 -CPP_VERSION = 1.17.0-pre1 -CSHARP_VERSION = 1.17.0-pre1 +CORE_VERSION = 7.0.0-pre2 +CPP_VERSION = 1.17.0-pre2 +CSHARP_VERSION = 1.17.0-pre2 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 6e0267723b6..5aea7c6f8cd 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,7 +23,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.17.0-pre1' + # version = '1.17.0-pre2' version = '0.0.4' s.version = version s.summary = 'gRPC C++ library' @@ -31,7 +31,7 @@ Pod::Spec.new do |s| s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.17.0-pre1' + grpc_version = '1.17.0-pre2' s.source = { :git => 'https://github.com/grpc/grpc.git', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 42ee1176cca..65e0528e572 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.17.0-pre1' + version = '1.17.0-pre2' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index bed6f8480b1..719da004785 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.17.0-pre1' + version = '1.17.0-pre2' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 67a087d9b68..56b95d1642a 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.17.0-pre1' + version = '1.17.0-pre2' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index c99386bb866..9b856456151 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.17.0-pre1' + version = '1.17.0-pre2' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/package.xml b/package.xml index 471cee33f9d..433fdad8409 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2018-01-19 - 1.17.0RC1 - 1.17.0RC1 + 1.17.0RC2 + 1.17.0RC2 beta diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 3ca1d830f7c..625c1bd59a2 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include -const char* grpc_version_string(void) { return "7.0.0-pre1"; } +const char* grpc_version_string(void) { return "7.0.0-pre2"; } const char* grpc_g_stands_for(void) { return "gizmo"; } diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 77c2cdd7d53..33643848fa0 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.17.0-pre1"; } +grpc::string Version() { return "1.17.0-pre2"; } } // namespace grpc diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 80bc939280f..ade0cfdeecc 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.17.0-pre1 + 1.17.0-pre2 3.6.1 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 25d114686fb..3a060caeb2f 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -38,6 +38,6 @@ namespace Grpc.Core /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.17.0-pre1"; + public const string CurrentVersion = "1.17.0-pre2"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 23caffec0ce..af3354fa664 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-pre1 +set VERSION=1.17.0-pre2 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat index 1ceefef6d69..71e3a7302a6 100644 --- a/src/csharp/build_unitypackage.bat +++ b/src/csharp/build_unitypackage.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-pre1 +set VERSION=1.17.0-pre2 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 020737b62ce..ae5a976ecc6 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.17.0-pre1' + v = '1.17.0-pre2' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index a5603b5c7d2..2e4f01f9a4e 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre1" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre2" diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index 41a8c10ec24..cfe1ff98e55 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre1" -#define GRPC_C_VERSION_STRING @"7.0.0-pre1" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre2" +#define GRPC_C_VERSION_STRING @"7.0.0-pre2" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 5bfb987aaa2..5b6d808c728 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.17.0RC1" +#define PHP_GRPC_VERSION "1.17.0RC2" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index a1b8f105d54..cf0f72fe63a 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.17.0rc1""" +__version__ = """1.17.0rc2""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index be2aac35949..dd0817c1444 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.17.0rc1' +VERSION = '1.17.0rc2' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index befd54a4f21..1c6f6aa7c23 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.17.0rc1' +VERSION = '1.17.0rc2' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index c940f290c85..cd97840cb4b 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.17.0rc1' +VERSION = '1.17.0rc2' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index 99b6bd90171..d019ce75ad3 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.17.0rc1' +VERSION = '1.17.0rc2' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 5aa6f60dcca..cc59a197375 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.17.0rc1' +VERSION = '1.17.0rc2' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 099d33debb4..d1fa0b60fa2 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.17.0.pre1' + VERSION = '1.17.0.pre2' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index f6d24eaaa33..f30e5074840 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.17.0.pre1' + VERSION = '1.17.0.pre2' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 7f4448d0b4b..9cad73cb39e 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.17.0rc1' +VERSION = '1.17.0rc2' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index cb4ebb465bf..eb41083bc56 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-pre1 +PROJECT_NUMBER = 1.17.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index f52eee8e005..b888c408307 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-pre1 +PROJECT_NUMBER = 1.17.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index 5ef4357e92b..29a4ba79b16 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-pre1 +PROJECT_NUMBER = 7.0.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 83a25e2b594..acaf04a7c6c 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-pre1 +PROJECT_NUMBER = 7.0.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 64c5f313ef9c38c1e7f13b3560c0d48f08eea3eb Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 21 Nov 2018 09:47:25 +0100 Subject: [PATCH 09/99] avoid c-ares dependency on libnsl --- cmake/cares.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/cares.cmake b/cmake/cares.cmake index 3d4a0cae765..4ea0d8725d0 100644 --- a/cmake/cares.cmake +++ b/cmake/cares.cmake @@ -18,6 +18,10 @@ if("${gRPC_CARES_PROVIDER}" STREQUAL "module") endif() set(CARES_SHARED OFF CACHE BOOL "disable shared library") set(CARES_STATIC ON CACHE BOOL "link cares statically") + if(gRPC_BACKWARDS_COMPATIBILITY_MODE) + # See https://github.com/grpc/grpc/issues/17255 + set(HAVE_LIBNSL OFF CACHE BOOL "avoid cares dependency on libnsl") + endif() add_subdirectory(third_party/cares/cares) if(TARGET c-ares) From 96a0db9575988cc669e9081d7a142abeac91a022 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 21 Nov 2018 13:46:02 -0800 Subject: [PATCH 10/99] Use 'preX' when pre-releasing gRPC-C++.podspec --- gRPC-C++.podspec | 2 +- templates/gRPC-C++.podspec.template | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 5aea7c6f8cd..8bacc33966b 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -24,7 +24,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized # version = '1.17.0-pre2' - version = '0.0.4' + version = '0.0.6-pre2' s.version = version s.summary = 'gRPC C++ library' s.homepage = 'https://grpc.io' diff --git a/templates/gRPC-C++.podspec.template b/templates/gRPC-C++.podspec.template index ab330415af2..94d5a4fb09e 100644 --- a/templates/gRPC-C++.podspec.template +++ b/templates/gRPC-C++.podspec.template @@ -127,12 +127,20 @@ def ruby_multiline_list(files, indent): return (',\n' + indent*' ').join('\'%s\'' % f for f in files) + + def modify_podspec_version_string(pod_version, grpc_version): + # Append -preX when it is a pre-release + if len(str(grpc_version).split('-')) > 1: + return pod_version + '-' + str(grpc_version).split('-')[-1] + else: + return pod_version + %> Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized # version = '${settings.version}' - version = '0.0.4' + version = '${modify_podspec_version_string('0.0.6', settings.version)}' s.version = version s.summary = 'gRPC C++ library' s.homepage = 'https://grpc.io' From 90cdbd69aacb54f50b980764e26373a89950a86e Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Tue, 27 Nov 2018 22:32:32 -0800 Subject: [PATCH 11/99] Fix PHP ZTS build breakage --- src/php/ext/grpc/php_grpc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index 492325b1e8b..f7d5a85876b 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -170,12 +170,12 @@ void prefork() { acquire_persistent_locks(); } -void postfork_child() { +void postfork_child(TSRMLS_D) { // loop through persistant list and destroy all underlying grpc_channel objs destroy_grpc_channels(); // clear completion queue - grpc_php_shutdown_completion_queue(); + grpc_php_shutdown_completion_queue(TSRMLS_C); // clean-up grpc_core grpc_shutdown(); @@ -187,7 +187,7 @@ void postfork_child() { // restart grpc_core grpc_init(); - grpc_php_init_completion_queue(); + grpc_php_init_completion_queue(TSRMLS_C); // re-create grpc_channel and point wrapped to it // unlock wrapped grpc channel mutex From 019feec3d9308717adcda8ee6b01b364ee2d29dd Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Wed, 28 Nov 2018 09:23:53 -0800 Subject: [PATCH 12/99] Bump to v1.17.0-pre3 --- BUILD | 4 ++-- build.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BUILD b/BUILD index 270c56ff6ed..989bc02a0b8 100644 --- a/BUILD +++ b/BUILD @@ -66,9 +66,9 @@ config_setting( # This should be updated along with build.yaml g_stands_for = "gizmo" -core_version = "7.0.0-pre2" +core_version = "7.0.0-pre3" -version = "1.17.0-pre2" +version = "1.17.0-pre3" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", diff --git a/build.yaml b/build.yaml index 0a74fd29ffd..b8b002ac149 100644 --- a/build.yaml +++ b/build.yaml @@ -12,9 +12,9 @@ settings: '#08': Use "-preN" suffixes to identify pre-release versions '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here - core_version: 7.0.0-pre2 + core_version: 7.0.0-pre3 g_stands_for: gizmo - version: 1.17.0-pre2 + version: 1.17.0-pre3 filegroups: - name: alts_proto headers: From 698cf221d85f5ad0743487d4577af15d646d7483 Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Wed, 28 Nov 2018 09:24:31 -0800 Subject: [PATCH 13/99] Regenerate projects --- CMakeLists.txt | 2 +- Makefile | 6 +++--- gRPC-C++.podspec | 6 +++--- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.xml | 4 ++-- src/core/lib/surface/version.cc | 2 +- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_unitypackage.bat | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/objective-c/tests/version.h | 4 ++-- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_testing/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 31 files changed, 37 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17f5f4ca637..87f0846fd1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.17.0-pre2") +set(PACKAGE_VERSION "1.17.0-pre3") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 3ac25a788dd..1e32de5e6b2 100644 --- a/Makefile +++ b/Makefile @@ -437,9 +437,9 @@ E = @echo Q = @ endif -CORE_VERSION = 7.0.0-pre2 -CPP_VERSION = 1.17.0-pre2 -CSHARP_VERSION = 1.17.0-pre2 +CORE_VERSION = 7.0.0-pre3 +CPP_VERSION = 1.17.0-pre3 +CSHARP_VERSION = 1.17.0-pre3 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 8bacc33966b..35c446ede37 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,15 +23,15 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.17.0-pre2' - version = '0.0.6-pre2' + # version = '1.17.0-pre3' + version = '0.0.6-pre3' s.version = version s.summary = 'gRPC C++ library' s.homepage = 'https://grpc.io' s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.17.0-pre2' + grpc_version = '1.17.0-pre3' s.source = { :git => 'https://github.com/grpc/grpc.git', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 65e0528e572..674ea75243e 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.17.0-pre2' + version = '1.17.0-pre3' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 719da004785..5f01dbaeef1 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.17.0-pre2' + version = '1.17.0-pre3' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 56b95d1642a..6289a14205b 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.17.0-pre2' + version = '1.17.0-pre3' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 9b856456151..42d6819e30c 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.17.0-pre2' + version = '1.17.0-pre3' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/package.xml b/package.xml index 433fdad8409..aad44ab1398 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2018-01-19 - 1.17.0RC2 - 1.17.0RC2 + 1.17.0RC3 + 1.17.0RC3 beta diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 625c1bd59a2..6fdd2a960a6 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include -const char* grpc_version_string(void) { return "7.0.0-pre2"; } +const char* grpc_version_string(void) { return "7.0.0-pre3"; } const char* grpc_g_stands_for(void) { return "gizmo"; } diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 33643848fa0..97d7670396a 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.17.0-pre2"; } +grpc::string Version() { return "1.17.0-pre3"; } } // namespace grpc diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index ade0cfdeecc..183651bfe00 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.17.0-pre2 + 1.17.0-pre3 3.6.1 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 3a060caeb2f..5c28018e433 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -38,6 +38,6 @@ namespace Grpc.Core /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.17.0-pre2"; + public const string CurrentVersion = "1.17.0-pre3"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index af3354fa664..4ade233f767 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-pre2 +set VERSION=1.17.0-pre3 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat index 71e3a7302a6..e4b91a626ff 100644 --- a/src/csharp/build_unitypackage.bat +++ b/src/csharp/build_unitypackage.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-pre2 +set VERSION=1.17.0-pre3 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index ae5a976ecc6..db1dc596696 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.17.0-pre2' + v = '1.17.0-pre3' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 2e4f01f9a4e..32e3be3a8a5 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre2" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre3" diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index cfe1ff98e55..278348c2093 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre2" -#define GRPC_C_VERSION_STRING @"7.0.0-pre2" +#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre3" +#define GRPC_C_VERSION_STRING @"7.0.0-pre3" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 5b6d808c728..e1d36bfc3fc 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.17.0RC2" +#define PHP_GRPC_VERSION "1.17.0RC3" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index cf0f72fe63a..a1e58cc3ed8 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.17.0rc2""" +__version__ = """1.17.0rc3""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index dd0817c1444..2182471388f 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.17.0rc2' +VERSION = '1.17.0rc3' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 1c6f6aa7c23..147e8840a61 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.17.0rc2' +VERSION = '1.17.0rc3' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index cd97840cb4b..ac41352b34b 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.17.0rc2' +VERSION = '1.17.0rc3' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index d019ce75ad3..0083836a337 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.17.0rc2' +VERSION = '1.17.0rc3' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index cc59a197375..e4e5d85764d 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.17.0rc2' +VERSION = '1.17.0rc3' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index d1fa0b60fa2..23906096225 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.17.0.pre2' + VERSION = '1.17.0.pre3' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index f30e5074840..af6255d822a 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.17.0.pre2' + VERSION = '1.17.0.pre3' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 9cad73cb39e..a65fcd36da5 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.17.0rc2' +VERSION = '1.17.0rc3' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index eb41083bc56..766c5aeb77d 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-pre2 +PROJECT_NUMBER = 1.17.0-pre3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index b888c408307..7968d182c8d 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-pre2 +PROJECT_NUMBER = 1.17.0-pre3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index 29a4ba79b16..85f6bfce56a 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-pre2 +PROJECT_NUMBER = 7.0.0-pre3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index acaf04a7c6c..1ebb0ee8c4d 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-pre2 +PROJECT_NUMBER = 7.0.0-pre3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 460bc6f7ce7b0e00e35a891fd3c12d4738d52142 Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Wed, 28 Nov 2018 14:57:33 -0800 Subject: [PATCH 14/99] PHP: fix ZTS build --- src/php/ext/grpc/php_grpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index f7d5a85876b..111c6f4867d 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -170,7 +170,9 @@ void prefork() { acquire_persistent_locks(); } -void postfork_child(TSRMLS_D) { +void postfork_child() { + TSRMLS_FETCH(); + // loop through persistant list and destroy all underlying grpc_channel objs destroy_grpc_channels(); From a82070dc94086f85dfda485ec0d5aa10c3081bb0 Mon Sep 17 00:00:00 2001 From: kkm Date: Wed, 28 Nov 2018 23:53:21 -0800 Subject: [PATCH 15/99] Add explicit ItemGroups to .csproj --- examples/csharp/Helloworld/Greeter/Greeter.csproj | 2 ++ examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/csharp/Helloworld/Greeter/Greeter.csproj b/examples/csharp/Helloworld/Greeter/Greeter.csproj index 3421926dca5..7989f795418 100644 --- a/examples/csharp/Helloworld/Greeter/Greeter.csproj +++ b/examples/csharp/Helloworld/Greeter/Greeter.csproj @@ -8,7 +8,9 @@ + + diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj index 2d4f48ec2e9..4c6949488c7 100644 --- a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj +++ b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj @@ -12,7 +12,10 @@ - + + + + From b26d24df859562387bc0ef5cd81ca18fea5b72e5 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 30 Nov 2018 08:50:20 -0800 Subject: [PATCH 16/99] Stop passing ExecCtx as avl user_data. --- .../client_channel/subchannel_index.cc | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc index 1c23a6c4be4..aa8441f17b0 100644 --- a/src/core/ext/filters/client_channel/subchannel_index.cc +++ b/src/core/ext/filters/client_channel/subchannel_index.cc @@ -91,7 +91,7 @@ void grpc_subchannel_key_destroy(grpc_subchannel_key* k) { gpr_free(k); } -static void sck_avl_destroy(void* p, void* user_data) { +static void sck_avl_destroy(void* p, void* unused) { grpc_subchannel_key_destroy(static_cast(p)); } @@ -104,7 +104,7 @@ static long sck_avl_compare(void* a, void* b, void* unused) { static_cast(b)); } -static void scv_avl_destroy(void* p, void* user_data) { +static void scv_avl_destroy(void* p, void* unused) { GRPC_SUBCHANNEL_WEAK_UNREF((grpc_subchannel*)p, "subchannel_index"); } @@ -137,7 +137,7 @@ void grpc_subchannel_index_shutdown(void) { void grpc_subchannel_index_unref(void) { if (gpr_unref(&g_refcount)) { gpr_mu_destroy(&g_mu); - grpc_avl_unref(g_subchannel_index, grpc_core::ExecCtx::Get()); + grpc_avl_unref(g_subchannel_index, nullptr); } } @@ -147,13 +147,12 @@ grpc_subchannel* grpc_subchannel_index_find(grpc_subchannel_key* key) { // Lock, and take a reference to the subchannel index. // We don't need to do the search under a lock as avl's are immutable. gpr_mu_lock(&g_mu); - grpc_avl index = grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get()); + grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr); gpr_mu_unlock(&g_mu); grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF( - (grpc_subchannel*)grpc_avl_get(index, key, grpc_core::ExecCtx::Get()), - "index_find"); - grpc_avl_unref(index, grpc_core::ExecCtx::Get()); + (grpc_subchannel*)grpc_avl_get(index, key, nullptr), "index_find"); + grpc_avl_unref(index, nullptr); return c; } @@ -169,13 +168,11 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key, // Compare and swap loop: // - take a reference to the current index gpr_mu_lock(&g_mu); - grpc_avl index = - grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get()); + grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr); gpr_mu_unlock(&g_mu); // - Check to see if a subchannel already exists - c = static_cast( - grpc_avl_get(index, key, grpc_core::ExecCtx::Get())); + c = static_cast(grpc_avl_get(index, key, nullptr)); if (c != nullptr) { c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register"); } @@ -184,11 +181,9 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key, need_to_unref_constructed = true; } else { // no -> update the avl and compare/swap - grpc_avl updated = - grpc_avl_add(grpc_avl_ref(index, grpc_core::ExecCtx::Get()), - subchannel_key_copy(key), - GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), - grpc_core::ExecCtx::Get()); + grpc_avl updated = grpc_avl_add( + grpc_avl_ref(index, nullptr), subchannel_key_copy(key), + GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), nullptr); // it may happen (but it's expected to be unlikely) // that some other thread has changed the index: @@ -200,9 +195,9 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key, } gpr_mu_unlock(&g_mu); - grpc_avl_unref(updated, grpc_core::ExecCtx::Get()); + grpc_avl_unref(updated, nullptr); } - grpc_avl_unref(index, grpc_core::ExecCtx::Get()); + grpc_avl_unref(index, nullptr); } if (need_to_unref_constructed) { @@ -219,24 +214,22 @@ void grpc_subchannel_index_unregister(grpc_subchannel_key* key, // Compare and swap loop: // - take a reference to the current index gpr_mu_lock(&g_mu); - grpc_avl index = - grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get()); + grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr); gpr_mu_unlock(&g_mu); // Check to see if this key still refers to the previously // registered subchannel - grpc_subchannel* c = static_cast( - grpc_avl_get(index, key, grpc_core::ExecCtx::Get())); + grpc_subchannel* c = + static_cast(grpc_avl_get(index, key, nullptr)); if (c != constructed) { - grpc_avl_unref(index, grpc_core::ExecCtx::Get()); + grpc_avl_unref(index, nullptr); break; } // compare and swap the update (some other thread may have // mutated the index behind us) grpc_avl updated = - grpc_avl_remove(grpc_avl_ref(index, grpc_core::ExecCtx::Get()), key, - grpc_core::ExecCtx::Get()); + grpc_avl_remove(grpc_avl_ref(index, nullptr), key, nullptr); gpr_mu_lock(&g_mu); if (index.root == g_subchannel_index.root) { @@ -245,8 +238,8 @@ void grpc_subchannel_index_unregister(grpc_subchannel_key* key, } gpr_mu_unlock(&g_mu); - grpc_avl_unref(updated, grpc_core::ExecCtx::Get()); - grpc_avl_unref(index, grpc_core::ExecCtx::Get()); + grpc_avl_unref(updated, nullptr); + grpc_avl_unref(index, nullptr); } } From 5861f082607344ed42215ac341e97e4b4bbf0abc Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 28 Nov 2018 15:39:05 +0100 Subject: [PATCH 17/99] basic tcp_trace support for windows --- src/core/lib/iomgr/tcp_windows.cc | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index 64c4a56ae95..d7351c3661f 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -42,6 +42,7 @@ #include "src/core/lib/iomgr/tcp_windows.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" #if defined(__MSYS__) && defined(GPR_ARCH_64) /* Nasty workaround for nasty bug when using the 64 bits msys compiler @@ -182,6 +183,10 @@ static void on_read(void* tcpp, grpc_error* error) { grpc_slice sub; grpc_winsocket_callback_info* info = &socket->read_info; + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "TCP:%p on_read", tcp); + } + GRPC_ERROR_REF(error); if (error == GRPC_ERROR_NONE) { @@ -194,7 +199,21 @@ static void on_read(void* tcpp, grpc_error* error) { if (info->bytes_transfered != 0 && !tcp->shutting_down) { sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); grpc_slice_buffer_add(tcp->read_slices, sub); + + if (grpc_tcp_trace.enabled()) { + size_t i; + 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_free(dump); + } + } } else { + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp); + } grpc_slice_unref_internal(tcp->read_slice); error = tcp->shutting_down ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( @@ -219,6 +238,10 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, DWORD flags = 0; WSABUF buffer; + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "TCP:%p win_read", tcp); + } + if (tcp->shutting_down) { GRPC_CLOSURE_SCHED( cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( @@ -275,6 +298,10 @@ static void on_write(void* tcpp, grpc_error* error) { grpc_winsocket_callback_info* info = &handle->write_info; grpc_closure* cb; + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "TCP:%p on_write", tcp); + } + GRPC_ERROR_REF(error); gpr_mu_lock(&tcp->mu); @@ -308,6 +335,16 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices, WSABUF* buffers = local_buffers; size_t len; + if (grpc_tcp_trace.enabled()) { + size_t i; + 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_free(data); + } + } + if (tcp->shutting_down) { GRPC_CLOSURE_SCHED( cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( From b0139e15425196be518b251dbdfa3b86648b4740 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 3 Dec 2018 16:58:05 +0100 Subject: [PATCH 18/99] better slice management for win_read --- src/core/lib/iomgr/tcp_windows.cc | 57 ++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index d7351c3661f..658da9c46bf 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -113,7 +113,10 @@ typedef struct grpc_tcp { grpc_closure* read_cb; grpc_closure* write_cb; - grpc_slice read_slice; + + /* garbage after the last read */ + grpc_slice_buffer last_read_buffer; + grpc_slice_buffer* write_slices; grpc_slice_buffer* read_slices; @@ -132,6 +135,7 @@ 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); @@ -180,7 +184,6 @@ static void on_read(void* tcpp, grpc_error* error) { grpc_tcp* tcp = (grpc_tcp*)tcpp; grpc_closure* cb = tcp->read_cb; grpc_winsocket* socket = tcp->socket; - grpc_slice sub; grpc_winsocket_callback_info* info = &socket->read_info; if (grpc_tcp_trace.enabled()) { @@ -194,11 +197,19 @@ static void on_read(void* tcpp, grpc_error* error) { char* utf8_message = gpr_format_message(info->wsa_error); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(utf8_message); gpr_free(utf8_message); - grpc_slice_unref_internal(tcp->read_slice); + grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); } else { if (info->bytes_transfered != 0 && !tcp->shutting_down) { - sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); - grpc_slice_buffer_add(tcp->read_slices, sub); + GPR_ASSERT((size_t)info->bytes_transfered <= tcp->read_slices->length); + if (static_cast(info->bytes_transfered) != + tcp->read_slices->length) { + grpc_slice_buffer_trim_end( + tcp->read_slices, + tcp->read_slices->length - + static_cast(info->bytes_transfered), + &tcp->last_read_buffer); + } + GPR_ASSERT((size_t)info->bytes_transfered == tcp->read_slices->length); if (grpc_tcp_trace.enabled()) { size_t i; @@ -214,7 +225,7 @@ static void on_read(void* tcpp, grpc_error* error) { if (grpc_tcp_trace.enabled()) { gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp); } - grpc_slice_unref_internal(tcp->read_slice); + grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); error = tcp->shutting_down ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "TCP stream shutting down", &tcp->shutdown_error, 1) @@ -228,6 +239,8 @@ static void on_read(void* tcpp, grpc_error* error) { GRPC_CLOSURE_SCHED(cb, error); } +#define DEFAULT_TARGET_READ_SIZE 8192 +#define MAX_WSABUF_COUNT 16 static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, grpc_closure* cb) { grpc_tcp* tcp = (grpc_tcp*)ep; @@ -236,7 +249,8 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, int status; DWORD bytes_read = 0; DWORD flags = 0; - WSABUF buffer; + WSABUF buffers[MAX_WSABUF_COUNT]; + size_t i; if (grpc_tcp_trace.enabled()) { gpr_log(GPR_INFO, "TCP:%p win_read", tcp); @@ -252,18 +266,27 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, tcp->read_cb = cb; tcp->read_slices = read_slices; grpc_slice_buffer_reset_and_unref_internal(read_slices); + grpc_slice_buffer_swap(read_slices, &tcp->last_read_buffer); - tcp->read_slice = GRPC_SLICE_MALLOC(8192); + if (tcp->read_slices->length < DEFAULT_TARGET_READ_SIZE / 2 && + tcp->read_slices->count < MAX_WSABUF_COUNT) { + // TODO(jtattermusch): slice should be allocated using resource quota + grpc_slice_buffer_add(tcp->read_slices, + GRPC_SLICE_MALLOC(DEFAULT_TARGET_READ_SIZE)); + } - buffer.len = (ULONG)GRPC_SLICE_LENGTH( - tcp->read_slice); // we know slice size fits in 32bit. - buffer.buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slice); + GPR_ASSERT(tcp->read_slices->count <= MAX_WSABUF_COUNT); + for (i = 0; i < tcp->read_slices->count; i++) { + buffers[i].len = (ULONG)GRPC_SLICE_LENGTH( + tcp->read_slices->slices[i]); // we know slice size fits in 32bit. + buffers[i].buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[i]); + } TCP_REF(tcp, "read"); /* First let's try a synchronous, non-blocking read. */ - status = - WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); + status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count, + &bytes_read, &flags, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); /* Did we get data immediately ? Yay. */ @@ -275,8 +298,8 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, /* Otherwise, let's retry, by queuing a read. */ memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); - status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, - &info->overlapped, NULL); + status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count, + &bytes_read, &flags, &info->overlapped, NULL); if (status != 0) { int wsa_error = WSAGetLastError(); @@ -330,7 +353,7 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices, unsigned i; DWORD bytes_sent; int status; - WSABUF local_buffers[16]; + WSABUF local_buffers[MAX_WSABUF_COUNT]; WSABUF* allocated = NULL; WSABUF* buffers = local_buffers; size_t len; @@ -449,6 +472,7 @@ static void win_shutdown(grpc_endpoint* ep, grpc_error* why) { static void win_destroy(grpc_endpoint* ep) { grpc_network_status_unregister_endpoint(ep); grpc_tcp* tcp = (grpc_tcp*)ep; + grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer); TCP_UNREF(tcp, "destroy"); } @@ -497,6 +521,7 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket, 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_slice_buffer_init(&tcp->last_read_buffer); tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); /* Tell network status tracking code about the new endpoint */ grpc_network_status_register_endpoint(&tcp->base); From 97ec5c1d681d74a53c55589db3b3c90aaf7b8fc9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 3 Dec 2018 11:53:33 -0800 Subject: [PATCH 19/99] Bump version to v1.17.0 --- BUILD | 4 ++-- CMakeLists.txt | 2 +- Makefile | 6 +++--- build.yaml | 4 ++-- .../helloworld/HelloWorld.xcodeproj/project.pbxproj | 8 ++++++++ gRPC-C++.podspec | 6 +++--- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.xml | 8 ++++---- src/core/lib/surface/version.cc | 2 +- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_unitypackage.bat | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/objective-c/tests/version.h | 4 ++-- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_testing/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 34 files changed, 51 insertions(+), 43 deletions(-) diff --git a/BUILD b/BUILD index 989bc02a0b8..eeb1a2fa620 100644 --- a/BUILD +++ b/BUILD @@ -66,9 +66,9 @@ config_setting( # This should be updated along with build.yaml g_stands_for = "gizmo" -core_version = "7.0.0-pre3" +core_version = "7.0.0" -version = "1.17.0-pre3" +version = "1.17.0" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 87f0846fd1e..58525d6c6f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.17.0-pre3") +set(PACKAGE_VERSION "1.17.0") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 1e32de5e6b2..02273df21d1 100644 --- a/Makefile +++ b/Makefile @@ -437,9 +437,9 @@ E = @echo Q = @ endif -CORE_VERSION = 7.0.0-pre3 -CPP_VERSION = 1.17.0-pre3 -CSHARP_VERSION = 1.17.0-pre3 +CORE_VERSION = 7.0.0 +CPP_VERSION = 1.17.0 +CSHARP_VERSION = 1.17.0 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index b8b002ac149..62e07f64e42 100644 --- a/build.yaml +++ b/build.yaml @@ -12,9 +12,9 @@ settings: '#08': Use "-preN" suffixes to identify pre-release versions '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here - core_version: 7.0.0-pre3 + core_version: 7.0.0 g_stands_for: gizmo - version: 1.17.0-pre3 + version: 1.17.0 filegroups: - name: alts_proto headers: diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj index df5c40cda20..e067e82b3de 100644 --- a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj +++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj @@ -132,6 +132,8 @@ TargetAttributes = { 5E36905F1B2A23800040F884 = { CreatedOnToolsVersion = 6.2; + DevelopmentTeam = EQHXZ8M8AV; + ProvisioningStyle = Manual; }; }; }; @@ -321,9 +323,12 @@ baseConfigurationReference = DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = EQHXZ8M8AV; INFOPLIST_FILE = HelloWorld/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development"; }; name = Debug; }; @@ -332,9 +337,12 @@ baseConfigurationReference = 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = HelloWorld/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Release; }; diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 35c446ede37..73c87942430 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,15 +23,15 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.17.0-pre3' - version = '0.0.6-pre3' + # version = '1.17.0' + version = '0.0.6' s.version = version s.summary = 'gRPC C++ library' s.homepage = 'https://grpc.io' s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.17.0-pre3' + grpc_version = '1.17.0' s.source = { :git => 'https://github.com/grpc/grpc.git', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 674ea75243e..ff4d79426fe 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.17.0-pre3' + version = '1.17.0' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 5f01dbaeef1..d7050906e43 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.17.0-pre3' + version = '1.17.0' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 6289a14205b..955f3682f67 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.17.0-pre3' + version = '1.17.0' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 42d6819e30c..fb46ab46704 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.17.0-pre3' + version = '1.17.0' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/package.xml b/package.xml index aad44ab1398..bd2fffcc555 100644 --- a/package.xml +++ b/package.xml @@ -13,12 +13,12 @@ 2018-01-19 - 1.17.0RC3 - 1.17.0RC3 + 1.17.0 + 1.17.0 - beta - beta + stable + stable Apache 2.0 diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 6fdd2a960a6..ed30130f33d 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include -const char* grpc_version_string(void) { return "7.0.0-pre3"; } +const char* grpc_version_string(void) { return "7.0.0"; } const char* grpc_g_stands_for(void) { return "gizmo"; } diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 97d7670396a..0a3fd804fe5 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.17.0-pre3"; } +grpc::string Version() { return "1.17.0"; } } // namespace grpc diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 183651bfe00..4741e08cf53 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.17.0-pre3 + 1.17.0 3.6.1 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 5c28018e433..aa881867ec5 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -38,6 +38,6 @@ namespace Grpc.Core /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.17.0-pre3"; + public const string CurrentVersion = "1.17.0"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 4ade233f767..1b860c95380 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-pre3 +set VERSION=1.17.0 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat index e4b91a626ff..b9f9cf4dbb8 100644 --- a/src/csharp/build_unitypackage.bat +++ b/src/csharp/build_unitypackage.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.17.0-pre3 +set VERSION=1.17.0 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index db1dc596696..c72751d1c6f 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.17.0-pre3' + v = '1.17.0' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 32e3be3a8a5..fa5b04612ce 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre3" +#define GRPC_OBJC_VERSION_STRING @"1.17.0" diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index 278348c2093..1cfbf6f705d 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.17.0-pre3" -#define GRPC_C_VERSION_STRING @"7.0.0-pre3" +#define GRPC_OBJC_VERSION_STRING @"1.17.0" +#define GRPC_C_VERSION_STRING @"7.0.0" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index e1d36bfc3fc..e529c749dbd 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.17.0RC3" +#define PHP_GRPC_VERSION "1.17.0" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index a1e58cc3ed8..0677d1b9cf5 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.17.0rc3""" +__version__ = """1.17.0""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 2182471388f..8cbd5b24f25 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.17.0rc3' +VERSION = '1.17.0' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 147e8840a61..222d77aab18 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.17.0rc3' +VERSION = '1.17.0' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index ac41352b34b..daa8a84edb3 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.17.0rc3' +VERSION = '1.17.0' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index 0083836a337..af9ab31aa13 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.17.0rc3' +VERSION = '1.17.0' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index e4e5d85764d..887f8c105bc 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.17.0rc3' +VERSION = '1.17.0' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 23906096225..6b09d61c0b4 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.17.0.pre3' + VERSION = '1.17.0' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index af6255d822a..9ae2162335d 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.17.0.pre3' + VERSION = '1.17.0' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index a65fcd36da5..4070200384b 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.17.0rc3' +VERSION = '1.17.0' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 766c5aeb77d..88bfada6917 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-pre3 +PROJECT_NUMBER = 1.17.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 7968d182c8d..31f90cf1b66 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.17.0-pre3 +PROJECT_NUMBER = 1.17.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index 85f6bfce56a..a72cf688a2d 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-pre3 +PROJECT_NUMBER = 7.0.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 1ebb0ee8c4d..b54b441e3d8 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 7.0.0-pre3 +PROJECT_NUMBER = 7.0.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 570599cfc60c26e347ca8c2d1a9ab46607051734 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 30 Nov 2018 01:59:15 -0800 Subject: [PATCH 20/99] Cancel still-active c-ares queries after 10 seconds to avoid chance of deadlock --- include/grpc/impl/codegen/grpc_types.h | 5 ++ .../resolver/dns/c_ares/dns_resolver_ares.cc | 10 +++- .../dns/c_ares/grpc_ares_ev_driver.cc | 36 +++++++++++ .../resolver/dns/c_ares/grpc_ares_ev_driver.h | 1 + .../resolver/dns/c_ares/grpc_ares_wrapper.cc | 12 ++-- .../resolver/dns/c_ares/grpc_ares_wrapper.h | 4 +- .../dns/c_ares/grpc_ares_wrapper_fallback.cc | 3 +- src/core/lib/iomgr/resolve_address.h | 2 +- .../dns_resolver_connectivity_test.cc | 2 +- .../resolvers/dns_resolver_cooldown_test.cc | 6 +- test/core/end2end/fuzzers/api_fuzzer.cc | 2 +- test/core/end2end/goaway_server_test.cc | 6 +- test/cpp/naming/cancel_ares_query_test.cc | 59 +++++++++++++++++-- 13 files changed, 126 insertions(+), 22 deletions(-) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 17a43fab0f1..58f02dc7221 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -350,6 +350,11 @@ typedef struct { /** If set, inhibits health checking (which may be enabled via the * service config.) */ #define GRPC_ARG_INHIBIT_HEALTH_CHECKING "grpc.inhibit_health_checking" +/** If set, determines the number of milliseconds that the c-ares based + * DNS resolver will wait on queries before cancelling them. The default value + * is 10000. Setting this to "0" will disable c-ares query timeouts + * entirely. */ +#define GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS "grpc.dns_ares_query_timeout" /** \} */ /** Result of a grpc call. If the caller satisfies the prerequisites of a diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index 90bc88961d9..4ebc2c8161c 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -122,6 +122,8 @@ class AresDnsResolver : public Resolver { char* service_config_json_ = nullptr; // has shutdown been initiated bool shutdown_initiated_ = false; + // timeout in milliseconds for active DNS queries + int query_timeout_ms_; }; AresDnsResolver::AresDnsResolver(const ResolverArgs& args) @@ -159,6 +161,11 @@ AresDnsResolver::AresDnsResolver(const ResolverArgs& args) grpc_combiner_scheduler(combiner())); GRPC_CLOSURE_INIT(&on_resolved_, OnResolvedLocked, this, grpc_combiner_scheduler(combiner())); + const grpc_arg* query_timeout_ms_arg = + grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS); + query_timeout_ms_ = grpc_channel_arg_get_integer( + query_timeout_ms_arg, + {GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, 0, INT_MAX}); } AresDnsResolver::~AresDnsResolver() { @@ -410,7 +417,8 @@ void AresDnsResolver::StartResolvingLocked() { pending_request_ = grpc_dns_lookup_ares_locked( dns_server_, name_to_resolve_, kDefaultPort, interested_parties_, &on_resolved_, &lb_addresses_, true /* check_grpclb */, - request_service_config_ ? &service_config_json_ : nullptr, combiner()); + request_service_config_ ? &service_config_json_ : nullptr, + query_timeout_ms_, combiner()); last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now(); } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc index fdbd07ebf51..f42b1e309df 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc @@ -33,6 +33,7 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/iomgr/timer.h" typedef struct fd_node { /** the owner of this fd node */ @@ -76,6 +77,12 @@ struct grpc_ares_ev_driver { grpc_ares_request* request; /** Owned by the ev_driver. Creates new GrpcPolledFd's */ grpc_core::UniquePtr polled_fd_factory; + /** query timeout in milliseconds */ + int query_timeout_ms; + /** alarm to cancel active queries */ + grpc_timer query_timeout; + /** cancels queries on a timeout */ + grpc_closure on_timeout_locked; }; static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver); @@ -116,8 +123,11 @@ static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) { } } +static void on_timeout_locked(void* arg, grpc_error* error); + grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, grpc_pollset_set* pollset_set, + int query_timeout_ms, grpc_combiner* combiner, grpc_ares_request* request) { *ev_driver = grpc_core::New(); @@ -146,6 +156,9 @@ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, grpc_core::NewGrpcPolledFdFactory((*ev_driver)->combiner); (*ev_driver) ->polled_fd_factory->ConfigureAresChannelLocked((*ev_driver)->channel); + GRPC_CLOSURE_INIT(&(*ev_driver)->on_timeout_locked, on_timeout_locked, + *ev_driver, grpc_combiner_scheduler(combiner)); + (*ev_driver)->query_timeout_ms = query_timeout_ms; return GRPC_ERROR_NONE; } @@ -155,6 +168,7 @@ void grpc_ares_ev_driver_on_queries_complete_locked( // is working, grpc_ares_notify_on_event_locked will shut down the // fds; if it's not working, there are no fds to shut down. ev_driver->shutting_down = true; + grpc_timer_cancel(&ev_driver->query_timeout); grpc_ares_ev_driver_unref(ev_driver); } @@ -185,6 +199,17 @@ static fd_node* pop_fd_node_locked(fd_node** head, ares_socket_t as) { return nullptr; } +static void on_timeout_locked(void* arg, grpc_error* error) { + grpc_ares_ev_driver* driver = static_cast(arg); + GRPC_CARES_TRACE_LOG( + "ev_driver=%p on_timeout_locked. driver->shutting_down=%d. err=%s", + driver, driver->shutting_down, grpc_error_string(error)); + if (!driver->shutting_down && error == GRPC_ERROR_NONE) { + grpc_ares_ev_driver_shutdown_locked(driver); + } + grpc_ares_ev_driver_unref(driver); +} + static void on_readable_locked(void* arg, grpc_error* error) { fd_node* fdn = static_cast(arg); grpc_ares_ev_driver* ev_driver = fdn->ev_driver; @@ -314,6 +339,17 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) { if (!ev_driver->working) { ev_driver->working = true; grpc_ares_notify_on_event_locked(ev_driver); + grpc_millis timeout = + ev_driver->query_timeout_ms == 0 + ? GRPC_MILLIS_INF_FUTURE + : ev_driver->query_timeout_ms + grpc_core::ExecCtx::Get()->Now(); + GRPC_CARES_TRACE_LOG( + "ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in %" PRId64 + " ms", + ev_driver, timeout); + grpc_ares_ev_driver_ref(ev_driver); + grpc_timer_init(&ev_driver->query_timeout, timeout, + &ev_driver->on_timeout_locked); } } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h index 671c537fe72..b8cefd9470e 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h @@ -43,6 +43,7 @@ ares_channel* grpc_ares_ev_driver_get_channel_locked( created successfully. */ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, grpc_pollset_set* pollset_set, + int query_timeout_ms, grpc_combiner* combiner, grpc_ares_request* request); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 582e2203fc7..55715869b63 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -359,7 +359,7 @@ done: void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( grpc_ares_request* r, const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, - bool check_grpclb, grpc_combiner* combiner) { + bool check_grpclb, int query_timeout_ms, grpc_combiner* combiner) { grpc_error* error = GRPC_ERROR_NONE; grpc_ares_hostbyname_request* hr = nullptr; ares_channel* channel = nullptr; @@ -388,7 +388,7 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( port = gpr_strdup(default_port); } error = grpc_ares_ev_driver_create_locked(&r->ev_driver, interested_parties, - combiner, r); + query_timeout_ms, combiner, r); if (error != GRPC_ERROR_NONE) goto error_cleanup; channel = grpc_ares_ev_driver_get_channel_locked(r->ev_driver); // If dns_server is specified, use it. @@ -522,7 +522,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner) { + int query_timeout_ms, grpc_combiner* combiner) { grpc_ares_request* r = static_cast(gpr_zalloc(sizeof(grpc_ares_request))); r->ev_driver = nullptr; @@ -546,7 +546,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( // Look up name using c-ares lib. grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( r, dns_server, name, default_port, interested_parties, check_grpclb, - combiner); + query_timeout_ms, combiner); return r; } @@ -554,6 +554,7 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) { @@ -648,7 +649,8 @@ static void grpc_resolve_address_invoke_dns_lookup_ares_locked( r->ares_request = grpc_dns_lookup_ares_locked( nullptr /* dns_server */, r->name, r->default_port, r->interested_parties, &r->on_dns_lookup_done_locked, &r->lb_addrs, false /* check_grpclb */, - nullptr /* service_config_json */, r->combiner); + nullptr /* service_config_json */, GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, + r->combiner); } static void grpc_resolve_address_ares_impl(const char* name, diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h index a1231cc4e0d..9acef1d0ca9 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -26,6 +26,8 @@ #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/resolve_address.h" +#define GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS 10000 + extern grpc_core::TraceFlag grpc_trace_cares_address_sorting; extern grpc_core::TraceFlag grpc_trace_cares_resolver; @@ -60,7 +62,7 @@ extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addresses, bool check_grpclb, - char** service_config_json, grpc_combiner* combiner); + char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); /* Cancel the pending grpc_ares_request \a request */ extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc index 9f293c1ac07..fc78b183044 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc @@ -30,7 +30,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner) { + int query_timeout_ms, grpc_combiner* combiner) { return NULL; } @@ -38,6 +38,7 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {} diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h index 6afe94a7a92..7016ffc31aa 100644 --- a/src/core/lib/iomgr/resolve_address.h +++ b/src/core/lib/iomgr/resolve_address.h @@ -65,7 +65,7 @@ void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable); /* Asynchronously resolve addr. Use default_port if a port isn't designated in addr, otherwise use the port in addr. */ -/* TODO(ctiller): add a timeout here */ +/* TODO(apolcyn): add a timeout here */ void grpc_resolve_address(const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc index eb5a9117484..cc041ac7f3d 100644 --- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc @@ -64,7 +64,7 @@ static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner) { + int query_timeout_ms, grpc_combiner* combiner) { gpr_mu_lock(&g_mu); GPR_ASSERT(0 == strcmp("test", addr)); grpc_error* error = GRPC_ERROR_NONE; diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc index 1a7db40f598..51fcc0dec67 100644 --- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc @@ -41,7 +41,7 @@ static grpc_ares_request* (*g_default_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner); + int query_timeout_ms, grpc_combiner* combiner); // Counter incremented by test_resolve_address_impl indicating the number of // times a system-level resolution has happened. @@ -91,10 +91,10 @@ static grpc_ares_request* test_dns_lookup_ares_locked( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner) { + int query_timeout_ms, grpc_combiner* combiner) { grpc_ares_request* result = g_default_dns_lookup_ares_locked( dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs, - check_grpclb, service_config_json, combiner); + check_grpclb, service_config_json, query_timeout_ms, combiner); ++g_resolution_count; static grpc_millis last_resolution_time = 0; if (last_resolution_time == 0) { diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index e97a544e12c..9b6eddee6e1 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -378,7 +378,7 @@ grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner) { + int query_timeout, grpc_combiner* combiner) { addr_req* r = static_cast(gpr_malloc(sizeof(*r))); r->addr = gpr_strdup(addr); r->on_done = on_done; diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc index 3f1c5596ad9..6369caf0d1b 100644 --- a/test/core/end2end/goaway_server_test.cc +++ b/test/core/end2end/goaway_server_test.cc @@ -48,7 +48,7 @@ static grpc_ares_request* (*iomgr_dns_lookup_ares_locked)( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** addresses, bool check_grpclb, - char** service_config_json, grpc_combiner* combiner); + char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); static void (*iomgr_cancel_ares_request_locked)(grpc_ares_request* request); @@ -104,11 +104,11 @@ static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - grpc_combiner* combiner) { + int query_timeout_ms, grpc_combiner* combiner) { if (0 != strcmp(addr, "test")) { return iomgr_dns_lookup_ares_locked( dns_server, addr, default_port, interested_parties, on_done, lb_addrs, - check_grpclb, service_config_json, combiner); + check_grpclb, service_config_json, query_timeout_ms, combiner); } grpc_error* error = GRPC_ERROR_NONE; diff --git a/test/cpp/naming/cancel_ares_query_test.cc b/test/cpp/naming/cancel_ares_query_test.cc index dec7c171dc0..4c7a7c37357 100644 --- a/test/cpp/naming/cancel_ares_query_test.cc +++ b/test/cpp/naming/cancel_ares_query_test.cc @@ -260,8 +260,15 @@ TEST(CancelDuringAresQuery, TestFdsAreDeletedFromPollsetSet) { grpc_pollset_set_destroy(fake_other_pollset_set); } -TEST(CancelDuringAresQuery, - TestHitDeadlineAndDestroyChannelDuringAresResolutionIsGraceful) { +// Settings for TestCancelDuringActiveQuery test +typedef enum { + NONE, + SHORT, + ZERO, +} cancellation_test_query_timeout_setting; + +void TestCancelDuringActiveQuery( + cancellation_test_query_timeout_setting query_timeout_setting) { // Start up fake non responsive DNS server int fake_dns_port = grpc_pick_unused_port_or_die(); FakeNonResponsiveDNSServer fake_dns_server(fake_dns_port); @@ -271,9 +278,33 @@ TEST(CancelDuringAresQuery, &client_target, "dns://[::1]:%d/dont-care-since-wont-be-resolved.test.com:1234", fake_dns_port)); + gpr_log(GPR_DEBUG, "TestCancelActiveDNSQuery. query timeout setting: %d", + query_timeout_setting); + grpc_channel_args* client_args = nullptr; + grpc_status_code expected_status_code = GRPC_STATUS_OK; + if (query_timeout_setting == NONE) { + expected_status_code = GRPC_STATUS_DEADLINE_EXCEEDED; + client_args = nullptr; + } else if (query_timeout_setting == SHORT) { + expected_status_code = GRPC_STATUS_UNAVAILABLE; + grpc_arg arg; + arg.type = GRPC_ARG_INTEGER; + arg.key = const_cast(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS); + arg.value.integer = + 1; // Set this shorter than the call deadline so that it goes off. + client_args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); + } else if (query_timeout_setting == ZERO) { + expected_status_code = GRPC_STATUS_DEADLINE_EXCEEDED; + grpc_arg arg; + arg.type = GRPC_ARG_INTEGER; + arg.key = const_cast(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS); + arg.value.integer = 0; // Set this to zero to disable query timeouts. + client_args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); + } else { + abort(); + } grpc_channel* client = - grpc_insecure_channel_create(client_target, - /* client_args */ nullptr, nullptr); + grpc_insecure_channel_create(client_target, client_args, nullptr); gpr_free(client_target); grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr); cq_verifier* cqv = cq_verifier_create(cq); @@ -325,8 +356,9 @@ TEST(CancelDuringAresQuery, EXPECT_EQ(GRPC_CALL_OK, error); CQ_EXPECT_COMPLETION(cqv, Tag(1), 1); cq_verify(cqv); - EXPECT_EQ(status, GRPC_STATUS_DEADLINE_EXCEEDED); + EXPECT_EQ(status, expected_status_code); // Teardown + grpc_channel_args_destroy(client_args); grpc_slice_unref(details); gpr_free((void*)error_string); grpc_metadata_array_destroy(&initial_metadata_recv); @@ -338,6 +370,23 @@ TEST(CancelDuringAresQuery, EndTest(client, cq); } +TEST(CancelDuringAresQuery, + TestHitDeadlineAndDestroyChannelDuringAresResolutionIsGraceful) { + TestCancelDuringActiveQuery(NONE /* don't set query timeouts */); +} + +TEST( + CancelDuringAresQuery, + TestHitDeadlineAndDestroyChannelDuringAresResolutionWithQueryTimeoutIsGraceful) { + TestCancelDuringActiveQuery(SHORT /* set short query timeout */); +} + +TEST( + CancelDuringAresQuery, + TestHitDeadlineAndDestroyChannelDuringAresResolutionWithZeroQueryTimeoutIsGraceful) { + TestCancelDuringActiveQuery(ZERO /* disable query timeouts */); +} + } // namespace int main(int argc, char** argv) { From d42c56788c31547f8ed99833e10f77d6af2c1732 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 4 Dec 2018 13:48:01 -0800 Subject: [PATCH 21/99] More debug timers to record root cause --- src/core/lib/gpr/sync_posix.cc | 92 ++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc index 69bd6094850..813a03c34bc 100644 --- a/src/core/lib/gpr/sync_posix.cc +++ b/src/core/lib/gpr/sync_posix.cc @@ -30,11 +30,16 @@ // For debug of the timer manager crash only. // TODO (mxyan): remove after bug is fixed. #ifdef GRPC_DEBUG_TIMER_MANAGER +#include void (*g_grpc_debug_timer_manager_stats)( int64_t timer_manager_init_count, int64_t timer_manager_shutdown_count, int64_t fork_count, int64_t timer_wait_err, int64_t timer_cv_value, int64_t timer_mu_value, int64_t abstime_sec_value, - int64_t abstime_nsec_value) = nullptr; + int64_t abstime_nsec_value, int64_t abs_deadline_sec_value, int64_t abs_deadline_nsec_value, int64_t now1_sec_value, + int64_t now1_nsec_value, int64_t now2_sec_value, + int64_t now2_nsec_value, int64_t add_result_sec_value, + int64_t add_result_nsec_value, int64_t sub_result_sec_value, + int64_t sub_result_nsec_value) = nullptr; int64_t g_timer_manager_init_count = 0; int64_t g_timer_manager_shutdown_count = 0; int64_t g_fork_count = 0; @@ -43,6 +48,16 @@ int64_t g_timer_cv_value = 0; int64_t g_timer_mu_value = 0; int64_t g_abstime_sec_value = -1; int64_t g_abstime_nsec_value = -1; +int64_t g_abs_deadline_sec_value = -1; +int64_t g_abs_deadline_nsec_value = -1; +int64_t g_now1_sec_value = -1; +int64_t g_now1_nsec_value = -1; +int64_t g_now2_sec_value = -1; +int64_t g_now2_nsec_value = -1; +int64_t g_add_result_sec_value = -1; +int64_t g_add_result_nsec_value = -1; +int64_t g_sub_result_sec_value = -1; +int64_t g_sub_result_nsec_value = -1; #endif // GRPC_DEBUG_TIMER_MANAGER #ifdef GPR_LOW_LEVEL_COUNTERS @@ -90,17 +105,70 @@ void gpr_cv_init(gpr_cv* cv) { void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } +// For debug of the timer manager crash only. +// TODO (mxyan): remove after bug is fixed. +#ifdef GRPC_DEBUG_TIMER_MANAGER +static gpr_timespec gpr_convert_clock_type_debug_timespec(gpr_timespec t, + gpr_clock_type clock_type, + gpr_timespec &now1, + gpr_timespec &now2, + gpr_timespec &add_result, + gpr_timespec &sub_result) { + if (t.clock_type == clock_type) { + return t; + } + + if (t.tv_sec == INT64_MAX || t.tv_sec == INT64_MIN) { + t.clock_type = clock_type; + return t; + } + + if (clock_type == GPR_TIMESPAN) { + return gpr_time_sub(t, gpr_now(t.clock_type)); + } + + if (t.clock_type == GPR_TIMESPAN) { + return gpr_time_add(gpr_now(clock_type), t); + } + + now1 = gpr_now(t.clock_type); + sub_result = gpr_time_sub(t, now1); + now2 = gpr_now(clock_type); + add_result = gpr_time_add(now2, sub_result); + return add_result; +} + +#define gpr_convert_clock_type_debug(t, clock_type, now1, now2, add_result, sub_result) gpr_convert_clock_type_debug_timespec((t), (clock_type), (now1), (now2), (add_result), (sub_result)) +#else +#define gpr_convert_clock_type_debug(t, clock_type, now1, now2, add_result, sub_result) gpr_convert_clock_type((t), (clock_type)) +#endif + int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { int err = 0; +#ifdef GRPC_DEBUG_TIMER_MANAGER + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. + gpr_timespec abs_deadline_copy; + abs_deadline_copy.tv_sec = abs_deadline.tv_sec; + abs_deadline_copy.tv_nsec = abs_deadline.tv_nsec; + gpr_timespec now1; + gpr_timespec now2; + gpr_timespec add_result; + gpr_timespec sub_result; + memset(&now1, 0, sizeof(now1)); + memset(&now2, 0, sizeof(now2)); + memset(&add_result, 0, sizeof(add_result)); + memset(&sub_result, 0, sizeof(sub_result)); +#endif if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) { err = pthread_cond_wait(cv, mu); } else { struct timespec abs_deadline_ts; #if GPR_LINUX - abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_MONOTONIC); + abs_deadline = gpr_convert_clock_type_debug(abs_deadline, GPR_CLOCK_MONOTONIC, now1, now2, add_result, sub_result); #else - abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME); + abs_deadline = gpr_convert_clock_type_debug(abs_deadline, GPR_CLOCK_REALTIME, now1, now2, add_result, sub_result); #endif // GPR_LINUX abs_deadline_ts.tv_sec = static_cast(abs_deadline.tv_sec); abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec; @@ -123,11 +191,25 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { g_timer_wait_err = err; g_timer_cv_value = (int64_t)cv; g_timer_mu_value = (int64_t)mu; + g_abs_deadline_sec_value = abs_deadline_copy.tv_sec; + g_abs_deadline_nsec_value = abs_deadline_copy.tv_nsec; + g_now1_sec_value = now1.tv_sec; + g_now1_nsec_value = now1.tv_nsec; + g_now2_sec_value = now2.tv_sec; + g_now2_nsec_value = now2.tv_nsec; + g_add_result_sec_value = add_result.tv_sec; + g_add_result_nsec_value = add_result.tv_nsec; + g_sub_result_sec_value = sub_result.tv_sec; + g_sub_result_nsec_value = sub_result.tv_nsec; g_grpc_debug_timer_manager_stats( g_timer_manager_init_count, g_timer_manager_shutdown_count, g_fork_count, g_timer_wait_err, g_timer_cv_value, g_timer_mu_value, - g_abstime_sec_value, g_abstime_nsec_value); - } + g_abstime_sec_value, g_abstime_nsec_value, g_abs_deadline_sec_value, + g_abs_deadline_nsec_value, g_now1_sec_value, g_now1_nsec_value, + g_now2_sec_value, g_now2_nsec_value, g_add_result_sec_value, + g_add_result_nsec_value, g_sub_result_sec_value, + g_sub_result_nsec_value); + } } #endif GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); From 5ebbba543c5be26412eb5ba9493ee242eee2e0ac Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 4 Dec 2018 14:20:56 -0800 Subject: [PATCH 22/99] clang-format --- src/core/lib/gpr/sync_posix.cc | 36 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc index 813a03c34bc..4ded03055c8 100644 --- a/src/core/lib/gpr/sync_posix.cc +++ b/src/core/lib/gpr/sync_posix.cc @@ -35,11 +35,11 @@ void (*g_grpc_debug_timer_manager_stats)( int64_t timer_manager_init_count, int64_t timer_manager_shutdown_count, int64_t fork_count, int64_t timer_wait_err, int64_t timer_cv_value, int64_t timer_mu_value, int64_t abstime_sec_value, - int64_t abstime_nsec_value, int64_t abs_deadline_sec_value, int64_t abs_deadline_nsec_value, int64_t now1_sec_value, - int64_t now1_nsec_value, int64_t now2_sec_value, - int64_t now2_nsec_value, int64_t add_result_sec_value, - int64_t add_result_nsec_value, int64_t sub_result_sec_value, - int64_t sub_result_nsec_value) = nullptr; + int64_t abstime_nsec_value, int64_t abs_deadline_sec_value, + int64_t abs_deadline_nsec_value, int64_t now1_sec_value, + int64_t now1_nsec_value, int64_t now2_sec_value, int64_t now2_nsec_value, + int64_t add_result_sec_value, int64_t add_result_nsec_value, + int64_t sub_result_sec_value, int64_t sub_result_nsec_value) = nullptr; int64_t g_timer_manager_init_count = 0; int64_t g_timer_manager_shutdown_count = 0; int64_t g_fork_count = 0; @@ -108,12 +108,9 @@ void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } // For debug of the timer manager crash only. // TODO (mxyan): remove after bug is fixed. #ifdef GRPC_DEBUG_TIMER_MANAGER -static gpr_timespec gpr_convert_clock_type_debug_timespec(gpr_timespec t, - gpr_clock_type clock_type, - gpr_timespec &now1, - gpr_timespec &now2, - gpr_timespec &add_result, - gpr_timespec &sub_result) { +static gpr_timespec gpr_convert_clock_type_debug_timespec( + gpr_timespec t, gpr_clock_type clock_type, gpr_timespec& now1, + gpr_timespec& now2, gpr_timespec& add_result, gpr_timespec& sub_result) { if (t.clock_type == clock_type) { return t; } @@ -138,9 +135,14 @@ static gpr_timespec gpr_convert_clock_type_debug_timespec(gpr_timespec t, return add_result; } -#define gpr_convert_clock_type_debug(t, clock_type, now1, now2, add_result, sub_result) gpr_convert_clock_type_debug_timespec((t), (clock_type), (now1), (now2), (add_result), (sub_result)) +#define gpr_convert_clock_type_debug(t, clock_type, now1, now2, add_result, \ + sub_result) \ + gpr_convert_clock_type_debug_timespec((t), (clock_type), (now1), (now2), \ + (add_result), (sub_result)) #else -#define gpr_convert_clock_type_debug(t, clock_type, now1, now2, add_result, sub_result) gpr_convert_clock_type((t), (clock_type)) +#define gpr_convert_clock_type_debug(t, clock_type, now1, now2, add_result, \ + sub_result) \ + gpr_convert_clock_type((t), (clock_type)) #endif int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { @@ -166,9 +168,11 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { } else { struct timespec abs_deadline_ts; #if GPR_LINUX - abs_deadline = gpr_convert_clock_type_debug(abs_deadline, GPR_CLOCK_MONOTONIC, now1, now2, add_result, sub_result); + abs_deadline = gpr_convert_clock_type_debug( + abs_deadline, GPR_CLOCK_MONOTONIC, now1, now2, add_result, sub_result); #else - abs_deadline = gpr_convert_clock_type_debug(abs_deadline, GPR_CLOCK_REALTIME, now1, now2, add_result, sub_result); + abs_deadline = gpr_convert_clock_type_debug( + abs_deadline, GPR_CLOCK_REALTIME, now1, now2, add_result, sub_result); #endif // GPR_LINUX abs_deadline_ts.tv_sec = static_cast(abs_deadline.tv_sec); abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec; @@ -209,7 +213,7 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { g_now2_sec_value, g_now2_nsec_value, g_add_result_sec_value, g_add_result_nsec_value, g_sub_result_sec_value, g_sub_result_nsec_value); - } + } } #endif GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); From 0cf8c59a58777d49067a534dcb94f3c28ee4da99 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 4 Dec 2018 09:39:29 -0800 Subject: [PATCH 23/99] Change xds plugin name to xds_experimental until it's ready for use. --- src/core/ext/filters/client_channel/lb_policy/xds/xds.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index 29cd9043755..81a51ac56a9 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -1811,7 +1811,7 @@ class XdsFactory : public LoadBalancingPolicyFactory { return OrphanablePtr(New(addresses, args)); } - const char* name() const override { return "xds"; } + const char* name() const override { return "xds_experimental"; } }; } // namespace From d685afc4626a793f1e7f1d2f3b2b05e9d404aa79 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 5 Dec 2018 16:56:48 +0100 Subject: [PATCH 24/99] fix macos PR jobs on high-sierra workers --- tools/internal_ci/helper_scripts/prepare_build_macos_rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc index 24a3545dedc..0ef9735c1cd 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -36,7 +36,7 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db3 if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then set +x brew update - brew install jq + brew install jq || brew upgrade jq ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref) export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$ghprbTargetBranch" From 750e80ea1c12315ce987ed7b5c38595f698cf355 Mon Sep 17 00:00:00 2001 From: Yihua Zhang Date: Wed, 5 Dec 2018 10:27:01 -0800 Subject: [PATCH 25/99] bring back original network test for metadata server detection --- .../google_default_credentials.cc | 134 +++++++++++++++--- test/core/security/credentials_test.cc | 76 +++++++++- 2 files changed, 188 insertions(+), 22 deletions(-) diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc index fcab2529592..7474380c051 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -49,9 +49,11 @@ /* -- Default credentials. -- */ -static int g_compute_engine_detection_done = 0; -static int g_need_compute_engine_creds = 0; +static int g_metadata_server_detection_done = 0; +static int g_metadata_server_available = 0; +static int g_is_on_gce = 0; static gpr_mu g_state_mu; +static gpr_mu* g_polling_mu; static gpr_once g_once = GPR_ONCE_INIT; static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker = grpc_alts_is_running_on_gcp; @@ -89,15 +91,20 @@ static grpc_security_status google_default_create_security_connector( bool use_alts = is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer; grpc_security_status status = GRPC_SECURITY_ERROR; + /* Return failure if ALTS is selected but not running on GCE. */ + if (use_alts && !g_is_on_gce) { + goto end; + } status = use_alts ? c->alts_creds->vtable->create_security_connector( c->alts_creds, call_creds, target, args, sc, new_args) : c->ssl_creds->vtable->create_security_connector( c->ssl_creds, call_creds, target, args, sc, new_args); - /* grpclb-specific channel args are removed from the channel args set - * to ensure backends and fallback adresses will have the same set of channel - * args. By doing that, it guarantees the connections to backends will not be - * torn down and re-connected when switching in and out of fallback mode. - */ +/* grpclb-specific channel args are removed from the channel args set + * to ensure backends and fallback adresses will have the same set of channel + * args. By doing that, it guarantees the connections to backends will not be + * torn down and re-connected when switching in and out of fallback mode. + */ +end: if (use_alts) { static const char* args_to_remove[] = { GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER, @@ -113,6 +120,93 @@ static grpc_channel_credentials_vtable google_default_credentials_vtable = { google_default_credentials_destruct, google_default_create_security_connector, nullptr}; +static void on_metadata_server_detection_http_response(void* user_data, + grpc_error* error) { + compute_engine_detector* detector = + static_cast(user_data); + if (error == GRPC_ERROR_NONE && detector->response.status == 200 && + detector->response.hdr_count > 0) { + /* Internet providers can return a generic response to all requests, so + it is necessary to check that metadata header is present also. */ + size_t i; + for (i = 0; i < detector->response.hdr_count; i++) { + grpc_http_header* header = &detector->response.hdrs[i]; + if (strcmp(header->key, "Metadata-Flavor") == 0 && + strcmp(header->value, "Google") == 0) { + detector->success = 1; + break; + } + } + } + gpr_mu_lock(g_polling_mu); + detector->is_done = 1; + GRPC_LOG_IF_ERROR( + "Pollset kick", + grpc_pollset_kick(grpc_polling_entity_pollset(&detector->pollent), + nullptr)); + gpr_mu_unlock(g_polling_mu); +} + +static void destroy_pollset(void* p, grpc_error* e) { + grpc_pollset_destroy(static_cast(p)); +} + +static int is_metadata_server_reachable() { + compute_engine_detector detector; + grpc_httpcli_request request; + grpc_httpcli_context context; + grpc_closure destroy_closure; + /* The http call is local. If it takes more than one sec, it is for sure not + on compute engine. */ + grpc_millis max_detection_delay = GPR_MS_PER_SEC; + grpc_pollset* pollset = + static_cast(gpr_zalloc(grpc_pollset_size())); + grpc_pollset_init(pollset, &g_polling_mu); + detector.pollent = grpc_polling_entity_create_from_pollset(pollset); + detector.is_done = 0; + detector.success = 0; + memset(&detector.response, 0, sizeof(detector.response)); + memset(&request, 0, sizeof(grpc_httpcli_request)); + request.host = (char*)GRPC_COMPUTE_ENGINE_DETECTION_HOST; + request.http.path = (char*)"/"; + grpc_httpcli_context_init(&context); + grpc_resource_quota* resource_quota = + grpc_resource_quota_create("google_default_credentials"); + grpc_httpcli_get( + &context, &detector.pollent, resource_quota, &request, + grpc_core::ExecCtx::Get()->Now() + max_detection_delay, + GRPC_CLOSURE_CREATE(on_metadata_server_detection_http_response, &detector, + grpc_schedule_on_exec_ctx), + &detector.response); + grpc_resource_quota_unref_internal(resource_quota); + grpc_core::ExecCtx::Get()->Flush(); + /* Block until we get the response. This is not ideal but this should only be + called once for the lifetime of the process by the default credentials. */ + gpr_mu_lock(g_polling_mu); + while (!detector.is_done) { + grpc_pollset_worker* worker = nullptr; + if (!GRPC_LOG_IF_ERROR( + "pollset_work", + grpc_pollset_work(grpc_polling_entity_pollset(&detector.pollent), + &worker, GRPC_MILLIS_INF_FUTURE))) { + detector.is_done = 1; + detector.success = 0; + } + } + gpr_mu_unlock(g_polling_mu); + grpc_httpcli_context_destroy(&context); + GRPC_CLOSURE_INIT(&destroy_closure, destroy_pollset, + grpc_polling_entity_pollset(&detector.pollent), + grpc_schedule_on_exec_ctx); + grpc_pollset_shutdown(grpc_polling_entity_pollset(&detector.pollent), + &destroy_closure); + g_polling_mu = nullptr; + grpc_core::ExecCtx::Get()->Flush(); + gpr_free(grpc_polling_entity_pollset(&detector.pollent)); + grpc_http_response_destroy(&detector.response); + return detector.success; +} + /* Takes ownership of creds_path if not NULL. */ static grpc_error* create_default_creds_from_path( char* creds_path, grpc_call_credentials** creds) { @@ -182,7 +276,6 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) { grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Failed to create Google credentials"); grpc_error* err; - int need_compute_engine_creds = 0; grpc_core::ExecCtx exec_ctx; GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ()); @@ -202,16 +295,25 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) { error = grpc_error_add_child(error, err); gpr_mu_lock(&g_state_mu); - /* At last try to see if we're on compute engine (do the detection only once - since it requires a network test). */ - if (!g_compute_engine_detection_done) { - g_need_compute_engine_creds = g_gce_tenancy_checker(); - g_compute_engine_detection_done = 1; + + /* Try a platform-provided hint for GCE. */ + if (!g_metadata_server_detection_done) { + g_is_on_gce = g_gce_tenancy_checker(); + g_metadata_server_detection_done = g_is_on_gce; + g_metadata_server_available = g_is_on_gce; + } + /* TODO: Add a platform-provided hint for GAE. */ + + /* Do a network test for metadata server. */ + if (!g_metadata_server_detection_done) { + bool detected = is_metadata_server_reachable(); + /* Do not cache detecion result if netowrk test returns false. */ + g_metadata_server_detection_done = detected; + g_metadata_server_available = detected; } - need_compute_engine_creds = g_need_compute_engine_creds; gpr_mu_unlock(&g_state_mu); - if (need_compute_engine_creds) { + if (g_metadata_server_available) { call_creds = grpc_google_compute_engine_credentials_create(nullptr); if (call_creds == nullptr) { error = grpc_error_add_child( @@ -259,7 +361,7 @@ void grpc_flush_cached_google_default_credentials(void) { grpc_core::ExecCtx exec_ctx; gpr_once_init(&g_once, init_default_credentials); gpr_mu_lock(&g_state_mu); - g_compute_engine_detection_done = 0; + g_metadata_server_detection_done = 0; gpr_mu_unlock(&g_state_mu); } diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc index b3e3c3c7415..a7a6050ec0a 100644 --- a/test/core/security/credentials_test.cc +++ b/test/core/security/credentials_test.cc @@ -919,6 +919,22 @@ static void test_google_default_creds_refresh_token(void) { gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ } +static int default_creds_metadata_server_detection_httpcli_get_success_override( + const grpc_httpcli_request* request, grpc_millis deadline, + grpc_closure* on_done, grpc_httpcli_response* response) { + *response = http_response(200, ""); + grpc_http_header* headers = + static_cast(gpr_malloc(sizeof(*headers) * 1)); + headers[0].key = gpr_strdup("Metadata-Flavor"); + headers[0].value = gpr_strdup("Google"); + response->hdr_count = 1; + response->hdrs = headers; + GPR_ASSERT(strcmp(request->http.path, "/") == 0); + GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0); + GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE); + return 1; +} + static char* null_well_known_creds_path_getter(void) { return nullptr; } static bool test_gce_tenancy_checker(void) { @@ -963,26 +979,73 @@ static void test_google_default_creds_gce(void) { grpc_override_well_known_credentials_path_getter(nullptr); } -static void test_no_google_default_creds(void) { +static void test_google_default_creds_non_gce(void) { + grpc_core::ExecCtx exec_ctx; + expected_md emd[] = { + {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}}; + request_metadata_state* state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); + grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, + nullptr, nullptr}; grpc_flush_cached_google_default_credentials(); gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ grpc_override_well_known_credentials_path_getter( null_well_known_creds_path_getter); - set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker); g_test_gce_tenancy_checker_called = false; g_test_is_on_gce = false; + /* Simulate a successful detection of metadata server. */ + grpc_httpcli_set_override( + default_creds_metadata_server_detection_httpcli_get_success_override, + httpcli_post_should_not_be_called); + grpc_composite_channel_credentials* creds = + reinterpret_cast( + grpc_google_default_credentials_create()); + /* Verify that the default creds actually embeds a GCE creds. */ + GPR_ASSERT(creds != nullptr); + GPR_ASSERT(creds->call_creds != nullptr); + grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, + httpcli_post_should_not_be_called); + run_request_metadata_test(creds->call_creds, auth_md_ctx, state); + grpc_core::ExecCtx::Get()->Flush(); + GPR_ASSERT(g_test_gce_tenancy_checker_called == true); + /* Cleanup. */ + grpc_channel_credentials_unref(&creds->base); + grpc_httpcli_set_override(nullptr, nullptr); + grpc_override_well_known_credentials_path_getter(nullptr); +} + +static int default_creds_gce_detection_httpcli_get_failure_override( + const grpc_httpcli_request* request, grpc_millis deadline, + grpc_closure* on_done, grpc_httpcli_response* response) { + /* No magic header. */ + GPR_ASSERT(strcmp(request->http.path, "/") == 0); + GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0); + *response = http_response(200, ""); + GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE); + return 1; +} +static void test_no_google_default_creds(void) { + grpc_flush_cached_google_default_credentials(); + gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ + grpc_override_well_known_credentials_path_getter( + null_well_known_creds_path_getter); + set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker); + g_test_gce_tenancy_checker_called = false; + g_test_is_on_gce = false; + grpc_httpcli_set_override( + default_creds_gce_detection_httpcli_get_failure_override, + httpcli_post_should_not_be_called); /* Simulate a successful detection of GCE. */ GPR_ASSERT(grpc_google_default_credentials_create() == nullptr); - - /* Try a second one. GCE detection should not occur anymore. */ + /* Try a second one. GCE detection should occur again. */ g_test_gce_tenancy_checker_called = false; GPR_ASSERT(grpc_google_default_credentials_create() == nullptr); - GPR_ASSERT(g_test_gce_tenancy_checker_called == false); - + GPR_ASSERT(g_test_gce_tenancy_checker_called == true); /* Cleanup. */ grpc_override_well_known_credentials_path_getter(nullptr); + grpc_httpcli_set_override(nullptr, nullptr); } typedef enum { @@ -1233,6 +1296,7 @@ int main(int argc, char** argv) { test_google_default_creds_auth_key(); test_google_default_creds_refresh_token(); test_google_default_creds_gce(); + test_google_default_creds_non_gce(); test_no_google_default_creds(); test_metadata_plugin_success(); test_metadata_plugin_failure(); From 9dce850250ff332fea7837a7d0a42638edd1aee8 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Wed, 5 Dec 2018 11:48:17 -0800 Subject: [PATCH 26/99] stop() server and enable skipped channelz test --- .../tests/channelz/_channelz_servicer_test.py | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py b/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py index 84f85946896..8ca51895224 100644 --- a/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py +++ b/src/python/grpcio_tests/tests/channelz/_channelz_servicer_test.py @@ -69,32 +69,28 @@ class _ChannelServerPair(object): def __init__(self): # Server will enable channelz service - # Bind as attribute, so its `del` can be called explicitly, during - # the destruction process. Otherwise, if the removal of server - # rely on gc cycle, the test will become non-deterministic. - self._server = grpc.server( + self.server = grpc.server( futures.ThreadPoolExecutor(max_workers=3), options=_DISABLE_REUSE_PORT + _ENABLE_CHANNELZ) - port = self._server.add_insecure_port('[::]:0') - self._server.add_generic_rpc_handlers((_GenericHandler(),)) - self._server.start() + port = self.server.add_insecure_port('[::]:0') + self.server.add_generic_rpc_handlers((_GenericHandler(),)) + self.server.start() # Channel will enable channelz service... self.channel = grpc.insecure_channel('localhost:%d' % port, _ENABLE_CHANNELZ) - def __del__(self): - self._server.__del__() - self.channel.close() - def _generate_channel_server_pairs(n): return [_ChannelServerPair() for i in range(n)] -def _clean_channel_server_pairs(pairs): +def _close_channel_server_pairs(pairs): for pair in pairs: - pair.__del__() + pair.server.stop(None) + # TODO(ericgribkoff) This del should not be required + del pair.server + pair.channel.close() class ChannelzServicerTest(unittest.TestCase): @@ -147,9 +143,9 @@ class ChannelzServicerTest(unittest.TestCase): self._channelz_stub = channelz_pb2_grpc.ChannelzStub(self._channel) def tearDown(self): - self._server.__del__() + self._server.stop(None) self._channel.close() - _clean_channel_server_pairs(self._pairs) + _close_channel_server_pairs(self._pairs) def test_get_top_channels_basic(self): self._pairs = _generate_channel_server_pairs(1) @@ -278,20 +274,12 @@ class ChannelzServicerTest(unittest.TestCase): self.assertEqual(gtc_resp.channel[i].data.calls_failed, gsc_resp.subchannel.data.calls_failed) - @unittest.skip('Servers in core are not guaranteed to be destroyed ' \ - 'immediately when the reference goes out of scope, so ' \ - 'servers from multiple test cases are not hermetic. ' \ - 'TODO(https://github.com/grpc/grpc/issues/17258)') def test_server_basic(self): self._pairs = _generate_channel_server_pairs(1) resp = self._channelz_stub.GetServers( channelz_pb2.GetServersRequest(start_server_id=0)) self.assertEqual(len(resp.server), 1) - @unittest.skip('Servers in core are not guaranteed to be destroyed ' \ - 'immediately when the reference goes out of scope, so ' \ - 'servers from multiple test cases are not hermetic. ' \ - 'TODO(https://github.com/grpc/grpc/issues/17258)') def test_get_one_server(self): self._pairs = _generate_channel_server_pairs(1) gss_resp = self._channelz_stub.GetServers( @@ -303,10 +291,6 @@ class ChannelzServicerTest(unittest.TestCase): self.assertEqual(gss_resp.server[0].ref.server_id, gs_resp.server.ref.server_id) - @unittest.skip('Servers in core are not guaranteed to be destroyed ' \ - 'immediately when the reference goes out of scope, so ' \ - 'servers from multiple test cases are not hermetic. ' \ - 'TODO(https://github.com/grpc/grpc/issues/17258)') def test_server_call(self): self._pairs = _generate_channel_server_pairs(1) k_success = 23 @@ -401,10 +385,6 @@ class ChannelzServicerTest(unittest.TestCase): self.assertEqual(gs_resp.socket.data.messages_received, test_constants.STREAM_LENGTH) - @unittest.skip('Servers in core are not guaranteed to be destroyed ' \ - 'immediately when the reference goes out of scope, so ' \ - 'servers from multiple test cases are not hermetic. ' \ - 'TODO(https://github.com/grpc/grpc/issues/17258)') def test_server_sockets(self): self._pairs = _generate_channel_server_pairs(1) self._send_successful_unary_unary(0) @@ -423,10 +403,6 @@ class ChannelzServicerTest(unittest.TestCase): # If the RPC call failed, it will raise a grpc.RpcError # So, if there is no exception raised, considered pass - @unittest.skip('Servers in core are not guaranteed to be destroyed ' \ - 'immediately when the reference goes out of scope, so ' \ - 'servers from multiple test cases are not hermetic. ' \ - 'TODO(https://github.com/grpc/grpc/issues/17258)') def test_server_listen_sockets(self): self._pairs = _generate_channel_server_pairs(1) From 8d438057e42864e0a53217cd7b8d1636d5842422 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 5 Dec 2018 11:41:09 -0800 Subject: [PATCH 27/99] Add License to Python tarball --- PYTHON-MANIFEST.in | 1 + setup.cfg | 3 +++ 2 files changed, 4 insertions(+) diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in index c0de5289ee2..544fefbc487 100644 --- a/PYTHON-MANIFEST.in +++ b/PYTHON-MANIFEST.in @@ -20,3 +20,4 @@ include src/python/grpcio/README.rst include requirements.txt include etc/roots.pem include Makefile +include LICENSE diff --git a/setup.cfg b/setup.cfg index 218792e674c..125ec93491d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,3 +15,6 @@ exclude=.*protoc_plugin/protoc_plugin_test\.proto$ # Style settings [yapf] based_on_style = google + +[metadata] +license_files = LICENSE From 5710a3a25d57f63c8cf4e50d258d0aaa1cc54aee Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Wed, 5 Dec 2018 13:51:46 -0800 Subject: [PATCH 28/99] Revert "Strip manylinux1 binary wheels" This reverts commit be4b2db4ad68190288b5d1e8a9b54f094ebde157. Appears to leave the incorrect hash in the wheel RECORD file, as in https://github.com/grpc/grpc/issues/17409 --- tools/run_tests/artifacts/build_package_python.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tools/run_tests/artifacts/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh index d93e8979fcc..29801a5b867 100755 --- a/tools/run_tests/artifacts/build_package_python.sh +++ b/tools/run_tests/artifacts/build_package_python.sh @@ -19,20 +19,10 @@ cd "$(dirname "$0")/../../.." mkdir -p artifacts/ +# All the python packages have been built in the artifact phase already +# and we only collect them here to deliver them to the distribtest phase. cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/python_*/* artifacts/ || true -strip_binary_wheel() { - TEMP_WHEEL_DIR=$(mktemp -d) - unzip "$1" -d "$TEMP_WHEEL_DIR" - find "$TEMP_WHEEL_DIR" -name "_protoc_compiler*.so" -exec strip --strip-debug {} ";" - find "$TEMP_WHEEL_DIR" -name "cygrpc*.so" -exec strip --strip-debug {} ";" - (cd "$TEMP_WHEEL_DIR" && zip -r - .) > "$1" -} - -for wheel in artifacts/*.whl; do - strip_binary_wheel "$wheel" -done - # TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz # source distribution package, and only one of them will end up # in the artifacts/ directory. They should be all equivalent though. From 5584d58e6ce3dbc2f110f1096dfd739b1cb2ce18 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 5 Dec 2018 14:51:07 -0800 Subject: [PATCH 29/99] Add LICENSE to grpcio-* packages * Using the proprocess command to copy the LICENSE --- src/python/grpcio_channelz/MANIFEST.in | 1 + .../grpcio_channelz/channelz_commands.py | 8 +++- src/python/grpcio_channelz/setup.py | 2 +- src/python/grpcio_health_checking/MANIFEST.in | 1 + .../grpcio_health_checking/health_commands.py | 8 +++- src/python/grpcio_health_checking/setup.py | 2 +- src/python/grpcio_reflection/MANIFEST.in | 1 + .../grpcio_reflection/reflection_commands.py | 8 +++- src/python/grpcio_reflection/setup.py | 2 +- src/python/grpcio_testing/MANIFEST.in | 1 + src/python/grpcio_testing/setup.py | 33 +++++++++++++++- src/python/grpcio_testing/testing_commands.py | 39 +++++++++++++++++++ .../artifacts/build_artifact_python.sh | 3 +- 13 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 src/python/grpcio_testing/testing_commands.py diff --git a/src/python/grpcio_channelz/MANIFEST.in b/src/python/grpcio_channelz/MANIFEST.in index 5597f375ba6..ee93e21a69b 100644 --- a/src/python/grpcio_channelz/MANIFEST.in +++ b/src/python/grpcio_channelz/MANIFEST.in @@ -1,3 +1,4 @@ include grpc_version.py recursive-include grpc_channelz *.py global-exclude *.pyc +include LICENSE diff --git a/src/python/grpcio_channelz/channelz_commands.py b/src/python/grpcio_channelz/channelz_commands.py index e9ad3550340..7f158c2a4bf 100644 --- a/src/python/grpcio_channelz/channelz_commands.py +++ b/src/python/grpcio_channelz/channelz_commands.py @@ -21,10 +21,12 @@ import setuptools ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) CHANNELZ_PROTO = os.path.join(ROOT_DIR, '../../proto/grpc/channelz/channelz.proto') +LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') -class CopyProtoModules(setuptools.Command): - """Command to copy proto modules from grpc/src/proto.""" +class Preprocess(setuptools.Command): + """Command to copy proto modules from grpc/src/proto and LICENSE from + the root directory""" description = '' user_options = [] @@ -40,6 +42,8 @@ class CopyProtoModules(setuptools.Command): shutil.copyfile(CHANNELZ_PROTO, os.path.join(ROOT_DIR, 'grpc_channelz/v1/channelz.proto')) + if os.path.isfile(LICENSE): + shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) class BuildPackageProtos(setuptools.Command): diff --git a/src/python/grpcio_channelz/setup.py b/src/python/grpcio_channelz/setup.py index a495052376d..f8c0e93913d 100644 --- a/src/python/grpcio_channelz/setup.py +++ b/src/python/grpcio_channelz/setup.py @@ -69,7 +69,7 @@ try: 'grpcio-tools=={version}'.format(version=grpc_version.VERSION),) COMMAND_CLASS = { # Run preprocess from the repository *before* doing any packaging! - 'preprocess': _channelz_commands.CopyProtoModules, + 'preprocess': _channelz_commands.Preprocess, 'build_package_protos': _channelz_commands.BuildPackageProtos, } except ImportError: diff --git a/src/python/grpcio_health_checking/MANIFEST.in b/src/python/grpcio_health_checking/MANIFEST.in index 996c74a9d49..3a22311b8e7 100644 --- a/src/python/grpcio_health_checking/MANIFEST.in +++ b/src/python/grpcio_health_checking/MANIFEST.in @@ -1,3 +1,4 @@ include grpc_version.py recursive-include grpc_health *.py global-exclude *.pyc +include LICENSE diff --git a/src/python/grpcio_health_checking/health_commands.py b/src/python/grpcio_health_checking/health_commands.py index 933f965aa2d..3820ef0bbad 100644 --- a/src/python/grpcio_health_checking/health_commands.py +++ b/src/python/grpcio_health_checking/health_commands.py @@ -20,10 +20,12 @@ import setuptools ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) HEALTH_PROTO = os.path.join(ROOT_DIR, '../../proto/grpc/health/v1/health.proto') +LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') -class CopyProtoModules(setuptools.Command): - """Command to copy proto modules from grpc/src/proto.""" +class Preprocess(setuptools.Command): + """Command to copy proto modules from grpc/src/proto and LICENSE from + the root directory""" description = '' user_options = [] @@ -39,6 +41,8 @@ class CopyProtoModules(setuptools.Command): shutil.copyfile(HEALTH_PROTO, os.path.join(ROOT_DIR, 'grpc_health/v1/health.proto')) + if os.path.isfile(LICENSE): + shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) class BuildPackageProtos(setuptools.Command): diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py index db2edae2cea..5a09a80f6ae 100644 --- a/src/python/grpcio_health_checking/setup.py +++ b/src/python/grpcio_health_checking/setup.py @@ -68,7 +68,7 @@ try: 'grpcio-tools=={version}'.format(version=grpc_version.VERSION),) COMMAND_CLASS = { # Run preprocess from the repository *before* doing any packaging! - 'preprocess': _health_commands.CopyProtoModules, + 'preprocess': _health_commands.Preprocess, 'build_package_protos': _health_commands.BuildPackageProtos, } except ImportError: diff --git a/src/python/grpcio_reflection/MANIFEST.in b/src/python/grpcio_reflection/MANIFEST.in index d6fb6ce73aa..10b01fa41de 100644 --- a/src/python/grpcio_reflection/MANIFEST.in +++ b/src/python/grpcio_reflection/MANIFEST.in @@ -1,3 +1,4 @@ include grpc_version.py recursive-include grpc_reflection *.py global-exclude *.pyc +include LICENSE diff --git a/src/python/grpcio_reflection/reflection_commands.py b/src/python/grpcio_reflection/reflection_commands.py index 6f91f6b8751..311ca4c4dba 100644 --- a/src/python/grpcio_reflection/reflection_commands.py +++ b/src/python/grpcio_reflection/reflection_commands.py @@ -21,10 +21,12 @@ import setuptools ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) REFLECTION_PROTO = os.path.join( ROOT_DIR, '../../proto/grpc/reflection/v1alpha/reflection.proto') +LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') -class CopyProtoModules(setuptools.Command): - """Command to copy proto modules from grpc/src/proto.""" +class Preprocess(setuptools.Command): + """Command to copy proto modules from grpc/src/proto and LICENSE from + the root directory""" description = '' user_options = [] @@ -41,6 +43,8 @@ class CopyProtoModules(setuptools.Command): REFLECTION_PROTO, os.path.join(ROOT_DIR, 'grpc_reflection/v1alpha/reflection.proto')) + if os.path.isfile(LICENSE): + shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) class BuildPackageProtos(setuptools.Command): diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py index b4087d87b49..f205069acd5 100644 --- a/src/python/grpcio_reflection/setup.py +++ b/src/python/grpcio_reflection/setup.py @@ -69,7 +69,7 @@ try: 'grpcio-tools=={version}'.format(version=grpc_version.VERSION),) COMMAND_CLASS = { # Run preprocess from the repository *before* doing any packaging! - 'preprocess': _reflection_commands.CopyProtoModules, + 'preprocess': _reflection_commands.Preprocess, 'build_package_protos': _reflection_commands.BuildPackageProtos, } except ImportError: diff --git a/src/python/grpcio_testing/MANIFEST.in b/src/python/grpcio_testing/MANIFEST.in index 39b35652173..559dfaf786f 100644 --- a/src/python/grpcio_testing/MANIFEST.in +++ b/src/python/grpcio_testing/MANIFEST.in @@ -1,3 +1,4 @@ include grpc_version.py recursive-include grpc_testing *.py global-exclude *.pyc +include LICENSE diff --git a/src/python/grpcio_testing/setup.py b/src/python/grpcio_testing/setup.py index 6ceb1fc5c9d..18db71e0f09 100644 --- a/src/python/grpcio_testing/setup.py +++ b/src/python/grpcio_testing/setup.py @@ -24,6 +24,23 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) # Break import style to ensure that we can find same-directory modules. import grpc_version + +class _NoOpCommand(setuptools.Command): + """No-op command.""" + + description = '' + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + pass + + PACKAGE_DIRECTORIES = { '': '.', } @@ -33,6 +50,19 @@ INSTALL_REQUIRES = ( 'grpcio>={version}'.format(version=grpc_version.VERSION), ) +try: + import testing_commands as _testing_commands + # we are in the build environment, otherwise the above import fails + COMMAND_CLASS = { + # Run preprocess from the repository *before* doing any packaging! + 'preprocess': _testing_commands.Preprocess, + } +except ImportError: + COMMAND_CLASS = { + # wire up commands to no-op not to break the external dependencies + 'preprocess': _NoOpCommand, + } + setuptools.setup( name='grpcio-testing', version=grpc_version.VERSION, @@ -43,4 +73,5 @@ setuptools.setup( url='https://grpc.io', package_dir=PACKAGE_DIRECTORIES, packages=setuptools.find_packages('.'), - install_requires=INSTALL_REQUIRES) + install_requires=INSTALL_REQUIRES, + cmdclass=COMMAND_CLASS) diff --git a/src/python/grpcio_testing/testing_commands.py b/src/python/grpcio_testing/testing_commands.py new file mode 100644 index 00000000000..fb40d37efb6 --- /dev/null +++ b/src/python/grpcio_testing/testing_commands.py @@ -0,0 +1,39 @@ +# Copyright 2018 gRPC Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Provides distutils command classes for the GRPC Python setup process.""" + +import os +import shutil + +import setuptools + +ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) +LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') + + +class Preprocess(setuptools.Command): + """Command to copy LICENSE from root directory.""" + + description = '' + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + if os.path.isfile(LICENSE): + shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh index bc6e5582046..605470325ab 100755 --- a/tools/run_tests/artifacts/build_artifact_python.sh +++ b/tools/run_tests/artifacts/build_artifact_python.sh @@ -105,7 +105,8 @@ then "${PIP}" install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/" # Build grpcio_testing source distribution - ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py sdist + ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py preprocess \ + sdist cp -r src/python/grpcio_testing/dist/* "$ARTIFACT_DIR" # Build grpcio_channelz source distribution From eb0b39df3d9304bf1b15a4c294abaad36a173ddc Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Wed, 5 Dec 2018 16:04:26 -0800 Subject: [PATCH 30/99] Do OnDone as the actual last thing so that the reactor can be reused. --- include/grpcpp/impl/codegen/client_callback.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index 4d9579fd6ab..ede8ac54ca0 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -255,10 +255,12 @@ class ClientCallbackReaderWriterImpl void MaybeFinish() { if (--callbacks_outstanding_ == 0) { - reactor_->OnDone(finish_status_); + Status s = std::move(finish_status_); + auto* reactor = reactor_; auto* call = call_.call(); this->~ClientCallbackReaderWriterImpl(); g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); } } @@ -450,10 +452,12 @@ class ClientCallbackReaderImpl void MaybeFinish() { if (--callbacks_outstanding_ == 0) { - reactor_->OnDone(finish_status_); + Status s = std::move(finish_status_); + auto* reactor = reactor_; auto* call = call_.call(); this->~ClientCallbackReaderImpl(); g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); } } @@ -576,10 +580,12 @@ class ClientCallbackWriterImpl void MaybeFinish() { if (--callbacks_outstanding_ == 0) { - reactor_->OnDone(finish_status_); + Status s = std::move(finish_status_); + auto* reactor = reactor_; auto* call = call_.call(); this->~ClientCallbackWriterImpl(); g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); } } From 734be6c7890670ea3c651aecbba74420a6601db3 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 5 Dec 2018 18:28:43 -0800 Subject: [PATCH 31/99] Update doc to clarify serial queue requirement --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index e0ef8b1391f..e687a65da7d 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -253,7 +253,7 @@ extern id const kGRPCTrailersKey; + (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; /** - * Set the dispatch queue to be used for callbacks. + * Set the dispatch queue to be used for callbacks. Current implementation requires \a queue to be a serial queue. * * This configuration is only effective before the call starts. */ From f95262b53fe19cecf760457763ac6938be459835 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Tue, 4 Dec 2018 23:09:03 -0500 Subject: [PATCH 32/99] Implement a lock-free fast path for queue_call_request() For tiny RPCs, every single requests in almost the first item in the list. Hence, it would try to lock the server to process pending requests. Instead of locking, simply set and check atomic values when there is a possiblity of having pending requests. This increases QPS by 10%, for the 62-channel/0B-RPC benchmark using the callback API. --- src/core/lib/surface/server.cc | 104 ++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 5dc81b29bb7..1f66be240e3 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -192,10 +192,13 @@ struct call_data { }; struct request_matcher { + request_matcher(grpc_server* server); + ~request_matcher(); + grpc_server* server; - call_data* pending_head; - call_data* pending_tail; - gpr_locked_mpscq* requests_per_cq; + std::atomic pending_head{nullptr}; + call_data* pending_tail = nullptr; + gpr_locked_mpscq* requests_per_cq = nullptr; }; struct registered_method { @@ -344,22 +347,30 @@ static void channel_broadcaster_shutdown(channel_broadcaster* cb, * request_matcher */ -static void request_matcher_init(request_matcher* rm, grpc_server* server) { - memset(rm, 0, sizeof(*rm)); - rm->server = server; - rm->requests_per_cq = static_cast( - gpr_malloc(sizeof(*rm->requests_per_cq) * server->cq_count)); +namespace { +request_matcher::request_matcher(grpc_server* server) : server(server) { + requests_per_cq = static_cast( + gpr_malloc(sizeof(*requests_per_cq) * server->cq_count)); for (size_t i = 0; i < server->cq_count; i++) { - gpr_locked_mpscq_init(&rm->requests_per_cq[i]); + gpr_locked_mpscq_init(&requests_per_cq[i]); } } -static void request_matcher_destroy(request_matcher* rm) { - for (size_t i = 0; i < rm->server->cq_count; i++) { - GPR_ASSERT(gpr_locked_mpscq_pop(&rm->requests_per_cq[i]) == nullptr); - gpr_locked_mpscq_destroy(&rm->requests_per_cq[i]); +request_matcher::~request_matcher() { + for (size_t i = 0; i < server->cq_count; i++) { + GPR_ASSERT(gpr_locked_mpscq_pop(&requests_per_cq[i]) == nullptr); + gpr_locked_mpscq_destroy(&requests_per_cq[i]); } - gpr_free(rm->requests_per_cq); + gpr_free(requests_per_cq); +} +} // namespace + +static void request_matcher_init(request_matcher* rm, grpc_server* server) { + new (rm) request_matcher(server); +} + +static void request_matcher_destroy(request_matcher* rm) { + rm->~request_matcher(); } static void kill_zombie(void* elem, grpc_error* error) { @@ -368,9 +379,10 @@ static void kill_zombie(void* elem, grpc_error* error) { } static void request_matcher_zombify_all_pending_calls(request_matcher* rm) { - while (rm->pending_head) { - call_data* calld = rm->pending_head; - rm->pending_head = calld->pending_next; + call_data* calld; + while ((calld = rm->pending_head.load(std::memory_order_relaxed)) != + nullptr) { + rm->pending_head.store(calld->pending_next, std::memory_order_relaxed); gpr_atm_no_barrier_store(&calld->state, ZOMBIED); GRPC_CLOSURE_INIT( &calld->kill_zombie_closure, kill_zombie, @@ -568,8 +580,9 @@ static void publish_new_rpc(void* arg, grpc_error* error) { } gpr_atm_no_barrier_store(&calld->state, PENDING); - if (rm->pending_head == nullptr) { - rm->pending_tail = rm->pending_head = calld; + if (rm->pending_head.load(std::memory_order_relaxed) == nullptr) { + rm->pending_head.store(calld, std::memory_order_relaxed); + rm->pending_tail = calld; } else { rm->pending_tail->pending_next = calld; rm->pending_tail = calld; @@ -1433,30 +1446,39 @@ static grpc_call_error queue_call_request(grpc_server* server, size_t cq_idx, rm = &rc->data.registered.method->matcher; break; } - if (gpr_locked_mpscq_push(&rm->requests_per_cq[cq_idx], &rc->request_link)) { - /* this was the first queued request: we need to lock and start - matching calls */ - gpr_mu_lock(&server->mu_call); - while ((calld = rm->pending_head) != nullptr) { - rc = reinterpret_cast( - gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx])); - if (rc == nullptr) break; - rm->pending_head = calld->pending_next; - gpr_mu_unlock(&server->mu_call); - if (!gpr_atm_full_cas(&calld->state, PENDING, ACTIVATED)) { - // Zombied Call - 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); - GRPC_CLOSURE_SCHED(&calld->kill_zombie_closure, GRPC_ERROR_NONE); - } else { - publish_call(server, calld, cq_idx, rc); - } - gpr_mu_lock(&server->mu_call); - } + + // Fast path: if there is no pending request to be processed, immediately + // return. + if (!gpr_locked_mpscq_push(&rm->requests_per_cq[cq_idx], &rc->request_link) || + // Note: We are reading the pending_head without holding the server's call + // mutex. Even if we read a non-null value here due to reordering, + // we will check it below again after grabbing the lock. + rm->pending_head.load(std::memory_order_relaxed) == nullptr) { + return GRPC_CALL_OK; + } + // Slow path: This was the first queued request and there are pendings: + // We need to lock and start matching calls. + gpr_mu_lock(&server->mu_call); + while ((calld = rm->pending_head.load(std::memory_order_relaxed)) != + nullptr) { + rc = reinterpret_cast( + gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx])); + if (rc == nullptr) break; + rm->pending_head.store(calld->pending_next, std::memory_order_relaxed); gpr_mu_unlock(&server->mu_call); + if (!gpr_atm_full_cas(&calld->state, PENDING, ACTIVATED)) { + // Zombied Call + 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); + GRPC_CLOSURE_SCHED(&calld->kill_zombie_closure, GRPC_ERROR_NONE); + } else { + publish_call(server, calld, cq_idx, rc); + } + gpr_mu_lock(&server->mu_call); } + gpr_mu_unlock(&server->mu_call); return GRPC_CALL_OK; } From f1f5d2fa8c8ceea386f0a69da2e3a4e78973db51 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 6 Dec 2018 08:34:08 -0800 Subject: [PATCH 33/99] Fix LB policy name case handling. --- .../filters/client_channel/client_channel.cc | 6 +- .../client_channel/resolver_result_parsing.cc | 65 +++++++------------ 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index be7962261bc..3347676a48f 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -489,9 +489,9 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) { // taking a lock on chand->info_mu, because this function is the // only thing that modifies its value, and it can only be invoked // once at any given time. - bool lb_policy_name_changed = chand->info_lb_policy_name == nullptr || - gpr_stricmp(chand->info_lb_policy_name.get(), - lb_policy_name.get()) != 0; + bool lb_policy_name_changed = + chand->info_lb_policy_name == nullptr || + strcmp(chand->info_lb_policy_name.get(), lb_policy_name.get()) != 0; if (chand->lb_policy != nullptr && !lb_policy_name_changed) { // Continue using the same LB policy. Update with new addresses. if (grpc_client_channel_trace.enabled()) { diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc index 82a26ace634..4f7fd6b4243 100644 --- a/src/core/ext/filters/client_channel/resolver_result_parsing.cc +++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc @@ -40,32 +40,11 @@ namespace grpc_core { namespace internal { -namespace { - -// Converts string format from JSON to proto. -grpc_core::UniquePtr ConvertCamelToSnake(const char* camel) { - const size_t size = strlen(camel); - char* snake = static_cast(gpr_malloc(size * 2)); - size_t j = 0; - for (size_t i = 0; i < size; ++i) { - if (isupper(camel[i])) { - snake[j++] = '_'; - snake[j++] = tolower(camel[i]); - } else { - snake[j++] = camel[i]; - } - } - snake[j] = '\0'; - return grpc_core::UniquePtr(snake); -} - -} // namespace - ProcessedResolverResult::ProcessedResolverResult( const grpc_channel_args* resolver_result, bool parse_retry) { ProcessServiceConfig(resolver_result, parse_retry); // If no LB config was found above, just find the LB policy name then. - if (lb_policy_config_ == nullptr) ProcessLbPolicyName(resolver_result); + if (lb_policy_name_ == nullptr) ProcessLbPolicyName(resolver_result); } void ProcessedResolverResult::ProcessServiceConfig( @@ -98,18 +77,25 @@ void ProcessedResolverResult::ProcessServiceConfig( void ProcessedResolverResult::ProcessLbPolicyName( const grpc_channel_args* resolver_result) { - const char* lb_policy_name = nullptr; // Prefer the LB policy name found in the service config. Note that this is // checking the deprecated loadBalancingPolicy field, rather than the new // loadBalancingConfig field. if (service_config_ != nullptr) { - lb_policy_name = service_config_->GetLoadBalancingPolicyName(); + lb_policy_name_.reset( + gpr_strdup(service_config_->GetLoadBalancingPolicyName())); + // Convert to lower-case. + if (lb_policy_name_ != nullptr) { + char* lb_policy_name = lb_policy_name_.get(); + for (size_t i = 0; i < strlen(lb_policy_name); ++i) { + lb_policy_name[i] = tolower(lb_policy_name[i]); + } + } } // Otherwise, find the LB policy name set by the client API. - if (lb_policy_name == nullptr) { + if (lb_policy_name_ == nullptr) { const grpc_arg* channel_arg = grpc_channel_args_find(resolver_result, GRPC_ARG_LB_POLICY_NAME); - lb_policy_name = grpc_channel_arg_get_string(channel_arg); + lb_policy_name_.reset(gpr_strdup(grpc_channel_arg_get_string(channel_arg))); } // Special case: If at least one balancer address is present, we use // the grpclb policy, regardless of what the resolver has returned. @@ -119,20 +105,21 @@ void ProcessedResolverResult::ProcessLbPolicyName( grpc_lb_addresses* addresses = static_cast(channel_arg->value.pointer.p); if (grpc_lb_addresses_contains_balancer_address(*addresses)) { - if (lb_policy_name != nullptr && - gpr_stricmp(lb_policy_name, "grpclb") != 0) { + if (lb_policy_name_ != nullptr && + strcmp(lb_policy_name_.get(), "grpclb") != 0) { gpr_log(GPR_INFO, "resolver requested LB policy %s but provided at least one " "balancer address -- forcing use of grpclb LB policy", - lb_policy_name); + lb_policy_name_.get()); } - lb_policy_name = "grpclb"; + lb_policy_name_.reset(gpr_strdup("grpclb")); } } // Use pick_first if nothing was specified and we didn't select grpclb // above. - if (lb_policy_name == nullptr) lb_policy_name = "pick_first"; - lb_policy_name_.reset(gpr_strdup(lb_policy_name)); + if (lb_policy_name_ == nullptr) { + lb_policy_name_.reset(gpr_strdup("pick_first")); + } } void ProcessedResolverResult::ParseServiceConfig( @@ -175,15 +162,13 @@ void ProcessedResolverResult::ParseLbConfigFromServiceConfig( if (policy_content != nullptr) return; // Violate "oneof" type. policy_content = field; } - grpc_core::UniquePtr lb_policy_name = - ConvertCamelToSnake(policy_content->key); - if (!grpc_core::LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( - lb_policy_name.get())) { - continue; + // If we support this policy, then select it. + if (grpc_core::LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( + policy_content->key)) { + lb_policy_name_.reset(gpr_strdup(policy_content->key)); + lb_policy_config_ = policy_content->child; + return; } - lb_policy_name_ = std::move(lb_policy_name); - lb_policy_config_ = policy_content->child; - return; } } From 13a4977c23f2339f82093840533eec7047866fc0 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 6 Dec 2018 09:02:03 -0800 Subject: [PATCH 34/99] Treat StartCall like a reserved callback since it is required --- include/grpcpp/impl/codegen/client_callback.h | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index ede8ac54ca0..66cf9b7754c 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -270,6 +270,7 @@ class ClientCallbackReaderWriterImpl // 2. Any read backlog // 3. Recv trailing metadata, on_completion callback // 4. Any write backlog + // 5. See if the call can finish (if other callbacks were triggered already) started_ = true; start_tag_.Set(call_.call(), @@ -320,6 +321,7 @@ class ClientCallbackReaderWriterImpl if (writes_done_ops_at_start_) { call_.PerformOps(&writes_done_ops_); } + MaybeFinish(); } void Read(Response* msg) override { @@ -412,8 +414,8 @@ class ClientCallbackReaderWriterImpl CallbackWithSuccessTag read_tag_; bool read_ops_at_start_{false}; - // Minimum of 2 outstanding callbacks to pre-register for start and finish - std::atomic_int callbacks_outstanding_{2}; + // Minimum of 3 callbacks to pre-register for StartCall, start, and finish + std::atomic_int callbacks_outstanding_{3}; bool started_{false}; }; @@ -466,6 +468,7 @@ class ClientCallbackReaderImpl // 1. Send initial metadata (unless corked) + recv initial metadata // 2. Any backlog // 3. Recv trailing metadata, on_completion callback + // 4. See if the call can finish (if other callbacks were triggered already) started_ = true; start_tag_.Set(call_.call(), @@ -497,6 +500,8 @@ class ClientCallbackReaderImpl finish_ops_.ClientRecvStatus(context_, &finish_status_); finish_ops_.set_core_cq_tag(&finish_tag_); call_.PerformOps(&finish_ops_); + + MaybeFinish(); } void Read(Response* msg) override { @@ -540,8 +545,8 @@ class ClientCallbackReaderImpl CallbackWithSuccessTag read_tag_; bool read_ops_at_start_{false}; - // Minimum of 2 outstanding callbacks to pre-register for start and finish - std::atomic_int callbacks_outstanding_{2}; + // Minimum of 3 callbacks to pre-register for StartCall, start, and finish + std::atomic_int callbacks_outstanding_{3}; bool started_{false}; }; @@ -594,6 +599,7 @@ class ClientCallbackWriterImpl // 1. Send initial metadata (unless corked) + recv initial metadata // 2. Recv trailing metadata, on_completion callback // 3. Any backlog + // 4. See if the call can finish (if other callbacks were triggered already) started_ = true; start_tag_.Set(call_.call(), @@ -633,6 +639,8 @@ class ClientCallbackWriterImpl if (writes_done_ops_at_start_) { call_.PerformOps(&writes_done_ops_); } + + MaybeFinish(); } void Write(const Request* msg, WriteOptions options) override { @@ -714,8 +722,8 @@ class ClientCallbackWriterImpl CallbackWithSuccessTag writes_done_tag_; bool writes_done_ops_at_start_{false}; - // Minimum of 2 outstanding callbacks to pre-register for start and finish - std::atomic_int callbacks_outstanding_{2}; + // Minimum of 3 callbacks to pre-register for StartCall, start, and finish + std::atomic_int callbacks_outstanding_{3}; bool started_{false}; }; From 22c74fcff56f7a89c0404c24ea0efe424559ebab Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 6 Dec 2018 09:07:47 -0800 Subject: [PATCH 35/99] Make TraceFlag trivially destructible --- src/core/lib/debug/trace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h index 5ed52454bd7..4623494520e 100644 --- a/src/core/lib/debug/trace.h +++ b/src/core/lib/debug/trace.h @@ -53,7 +53,8 @@ void grpc_tracer_enable_flag(grpc_core::TraceFlag* flag); class TraceFlag { public: TraceFlag(bool default_enabled, const char* name); - ~TraceFlag() {} + // This needs to be trivially destructible as it is used as global variable. + ~TraceFlag() = default; const char* name() const { return name_; } From 611bb6b4950a845874660a156480cbd472fff01c Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 6 Dec 2018 09:13:52 -0800 Subject: [PATCH 36/99] Test reactor reuse --- .../end2end/client_callback_end2end_test.cc | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/test/cpp/end2end/client_callback_end2end_test.cc b/test/cpp/end2end/client_callback_end2end_test.cc index 65434bac6b2..a999321992f 100644 --- a/test/cpp/end2end/client_callback_end2end_test.cc +++ b/test/cpp/end2end/client_callback_end2end_test.cc @@ -182,7 +182,7 @@ class ClientCallbackEnd2endTest } } - void SendGenericEchoAsBidi(int num_rpcs) { + void SendGenericEchoAsBidi(int num_rpcs, int reuses) { const grpc::string kMethodName("/grpc.testing.EchoTestService/Echo"); grpc::string test_string(""); for (int i = 0; i < num_rpcs; i++) { @@ -191,14 +191,26 @@ class ClientCallbackEnd2endTest ByteBuffer> { public: Client(ClientCallbackEnd2endTest* test, const grpc::string& method_name, - const grpc::string& test_str) { - test->generic_stub_->experimental().PrepareBidiStreamingCall( - &cli_ctx_, method_name, this); - request_.set_message(test_str); - send_buf_ = SerializeToByteBuffer(&request_); - StartWrite(send_buf_.get()); - StartRead(&recv_buf_); - StartCall(); + const grpc::string& test_str, int reuses) + : reuses_remaining_(reuses) { + activate_ = [this, test, method_name, test_str] { + if (reuses_remaining_ > 0) { + cli_ctx_.reset(new ClientContext); + reuses_remaining_--; + test->generic_stub_->experimental().PrepareBidiStreamingCall( + cli_ctx_.get(), method_name, this); + request_.set_message(test_str); + send_buf_ = SerializeToByteBuffer(&request_); + StartWrite(send_buf_.get()); + StartRead(&recv_buf_); + StartCall(); + } else { + std::unique_lock l(mu_); + done_ = true; + cv_.notify_one(); + } + }; + activate_(); } void OnWriteDone(bool ok) override { StartWritesDone(); } void OnReadDone(bool ok) override { @@ -208,9 +220,7 @@ class ClientCallbackEnd2endTest }; void OnDone(const Status& s) override { EXPECT_TRUE(s.ok()); - std::unique_lock l(mu_); - done_ = true; - cv_.notify_one(); + activate_(); } void Await() { std::unique_lock l(mu_); @@ -222,11 +232,13 @@ class ClientCallbackEnd2endTest EchoRequest request_; std::unique_ptr send_buf_; ByteBuffer recv_buf_; - ClientContext cli_ctx_; + std::unique_ptr cli_ctx_; + int reuses_remaining_; + std::function activate_; std::mutex mu_; std::condition_variable cv_; bool done_ = false; - } rpc{this, kMethodName, test_string}; + } rpc{this, kMethodName, test_string, reuses}; rpc.Await(); } @@ -293,7 +305,12 @@ TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcs) { TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidi) { ResetStub(); - SendGenericEchoAsBidi(10); + SendGenericEchoAsBidi(10, 1); +} + +TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcsAsBidiWithReactorReuse) { + ResetStub(); + SendGenericEchoAsBidi(10, 10); } #if GRPC_ALLOW_EXCEPTIONS From 5f806d77dc9ddf0b3bec066bf71ff6dc76a6e504 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 4 Dec 2018 09:01:35 -0800 Subject: [PATCH 37/99] Fix bug in subchannel backoff reset code. --- .../ext/filters/client_channel/subchannel.cc | 2 +- test/cpp/end2end/client_lb_end2end_test.cc | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 0817b1dd392..4d98b63b49a 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -887,12 +887,12 @@ static void on_subchannel_connected(void* arg, grpc_error* error) { void grpc_subchannel_reset_backoff(grpc_subchannel* subchannel) { gpr_mu_lock(&subchannel->mu); + subchannel->backoff->Reset(); if (subchannel->have_alarm) { subchannel->deferred_reset_backoff = true; grpc_timer_cancel(&subchannel->alarm); } else { subchannel->backoff_begun = false; - subchannel->backoff->Reset(); maybe_start_connecting_locked(subchannel); } gpr_mu_unlock(&subchannel->mu); diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index b667460cf08..1a7b36cdc05 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -507,6 +507,46 @@ TEST_F(ClientLbEnd2endTest, PickFirstResetConnectionBackoff) { EXPECT_LT(waited_ms, kInitialBackOffMs); } +TEST_F(ClientLbEnd2endTest, + PickFirstResetConnectionBackoffNextAttemptStartsImmediately) { + ChannelArguments args; + constexpr int kInitialBackOffMs = 1000; + args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs); + const std::vector ports = {grpc_pick_unused_port_or_die()}; + auto channel = BuildChannel("pick_first", args); + auto stub = BuildStub(channel); + SetNextResolution(ports); + // Wait for connect, which should fail ~immediately, because the server + // is not up. + gpr_log(GPR_INFO, "=== INITIAL CONNECTION ATTEMPT"); + EXPECT_FALSE( + channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); + // Reset connection backoff. + gpr_log(GPR_INFO, "=== RESETTING BACKOFF"); + experimental::ChannelResetConnectionBackoff(channel.get()); + // Trigger a second connection attempt. This should also fail + // ~immediately, but the retry should be scheduled for + // kInitialBackOffMs instead of applying the multiplier. + gpr_log(GPR_INFO, "=== TRIGGERING SECOND CONNECTION ATTEMPT"); + EXPECT_FALSE( + channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); + // Bring up a server on the chosen port. + gpr_log(GPR_INFO, "=== STARTING BACKEND"); + StartServers(1, ports); + // Wait for connect. Should happen within kInitialBackOffMs. + gpr_log(GPR_INFO, "=== TRIGGERING THIRD CONNECTION ATTEMPT"); + const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC); + EXPECT_TRUE(channel->WaitForConnected( + grpc_timeout_milliseconds_to_deadline(kInitialBackOffMs))); + const gpr_timespec t1 = gpr_now(GPR_CLOCK_MONOTONIC); + const grpc_millis waited_ms = gpr_time_to_millis(gpr_time_sub(t1, t0)); + gpr_log(GPR_DEBUG, "Waited %" PRId64 " milliseconds", waited_ms); + // Give an extra 100ms for timing slack. + // (This is still far less than the 1.6x increase we would see if the + // backoff state was not reset properly.) + EXPECT_LT(waited_ms, kInitialBackOffMs + 100); +} + TEST_F(ClientLbEnd2endTest, PickFirstUpdates) { // Start servers and send one RPC per server. const int kNumServers = 3; From a267d4a48c59142f66a67459e63369be5a827886 Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 6 Dec 2018 09:37:58 -0800 Subject: [PATCH 38/99] Add a static_assert --- src/core/lib/debug/trace.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/lib/debug/trace.cc b/src/core/lib/debug/trace.cc index 01c1e867d9d..cafdb15c699 100644 --- a/src/core/lib/debug/trace.cc +++ b/src/core/lib/debug/trace.cc @@ -21,6 +21,7 @@ #include "src/core/lib/debug/trace.h" #include +#include #include #include @@ -79,6 +80,8 @@ void TraceFlagList::LogAllTracers() { // Flags register themselves on the list during construction TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) { + static_assert(std::is_trivially_destructible::value, + "TraceFlag needs to be trivially destructible."); set_enabled(default_enabled); TraceFlagList::Add(this); } From 6638279564f64e14e033865fc2191c60679b389d Mon Sep 17 00:00:00 2001 From: Yihua Zhang Date: Thu, 6 Dec 2018 10:01:48 -0800 Subject: [PATCH 39/99] revision 1 --- .../google_default_credentials.cc | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc index 7474380c051..cf6eb83758c 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -49,11 +49,16 @@ /* -- Default credentials. -- */ -static int g_metadata_server_detection_done = 0; +/* A sticky bit that will be set only if the result of metadata server detection + * is positive. We do not set the bit if the result is negative. Because it + * means the detection is done via network test that is unreliable and the + * unreliable result should not be referred by successive calls. */ static int g_metadata_server_available = 0; static int g_is_on_gce = 0; static gpr_mu g_state_mu; -static gpr_mu* g_polling_mu; +/* Protect a metadata_server_detector instance that can be modified by more than + * one gRPC threads */ +.static gpr_mu* g_polling_mu; static gpr_once g_once = GPR_ONCE_INIT; static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker = grpc_alts_is_running_on_gcp; @@ -65,7 +70,7 @@ typedef struct { int is_done; int success; grpc_http_response response; -} compute_engine_detector; +} metadata_server_detector; static void google_default_credentials_destruct( grpc_channel_credentials* creds) { @@ -93,7 +98,7 @@ static grpc_security_status google_default_create_security_connector( grpc_security_status status = GRPC_SECURITY_ERROR; /* Return failure if ALTS is selected but not running on GCE. */ if (use_alts && !g_is_on_gce) { - goto end; + gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE.") goto end; } status = use_alts ? c->alts_creds->vtable->create_security_connector( c->alts_creds, call_creds, target, args, sc, new_args) @@ -122,8 +127,8 @@ static grpc_channel_credentials_vtable google_default_credentials_vtable = { static void on_metadata_server_detection_http_response(void* user_data, grpc_error* error) { - compute_engine_detector* detector = - static_cast(user_data); + metadata_server_detector* detector = + static_cast(user_data); if (error == GRPC_ERROR_NONE && detector->response.status == 200 && detector->response.hdr_count > 0) { /* Internet providers can return a generic response to all requests, so @@ -152,7 +157,7 @@ static void destroy_pollset(void* p, grpc_error* e) { } static int is_metadata_server_reachable() { - compute_engine_detector detector; + metadata_server_detector detector; grpc_httpcli_request request; grpc_httpcli_context context; grpc_closure destroy_closure; @@ -297,19 +302,15 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) { gpr_mu_lock(&g_state_mu); /* Try a platform-provided hint for GCE. */ - if (!g_metadata_server_detection_done) { + if (!g_metadata_server_available) { g_is_on_gce = g_gce_tenancy_checker(); - g_metadata_server_detection_done = g_is_on_gce; g_metadata_server_available = g_is_on_gce; } /* TODO: Add a platform-provided hint for GAE. */ /* Do a network test for metadata server. */ - if (!g_metadata_server_detection_done) { - bool detected = is_metadata_server_reachable(); - /* Do not cache detecion result if netowrk test returns false. */ - g_metadata_server_detection_done = detected; - g_metadata_server_available = detected; + if (!g_metadata_server_available) { + g_metadata_server_available = is_metadata_server_reachable(); } gpr_mu_unlock(&g_state_mu); @@ -361,7 +362,7 @@ void grpc_flush_cached_google_default_credentials(void) { grpc_core::ExecCtx exec_ctx; gpr_once_init(&g_once, init_default_credentials); gpr_mu_lock(&g_state_mu); - g_metadata_server_detection_done = 0; + g_metadata_server_available = 0; gpr_mu_unlock(&g_state_mu); } From c449da58339d4618ca1af447607033fab81de101 Mon Sep 17 00:00:00 2001 From: Yihua Zhang Date: Thu, 6 Dec 2018 10:09:54 -0800 Subject: [PATCH 40/99] fix a compilation error --- .../credentials/google_default/google_default_credentials.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc index cf6eb83758c..0674540d01c 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -58,7 +58,7 @@ static int g_is_on_gce = 0; static gpr_mu g_state_mu; /* Protect a metadata_server_detector instance that can be modified by more than * one gRPC threads */ -.static gpr_mu* g_polling_mu; +static gpr_mu* g_polling_mu; static gpr_once g_once = GPR_ONCE_INIT; static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker = grpc_alts_is_running_on_gcp; @@ -98,7 +98,8 @@ static grpc_security_status google_default_create_security_connector( grpc_security_status status = GRPC_SECURITY_ERROR; /* Return failure if ALTS is selected but not running on GCE. */ if (use_alts && !g_is_on_gce) { - gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE.") goto end; + gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE."); + goto end; } status = use_alts ? c->alts_creds->vtable->create_security_connector( c->alts_creds, call_creds, target, args, sc, new_args) From bb5741f9c006957e72e6a91e3389c0c3bc34d6b8 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 6 Dec 2018 10:18:44 -0800 Subject: [PATCH 41/99] Change pick_first to immediately select the first subchannel in READY state. --- .../lb_policy/pick_first/pick_first.cc | 74 +++++++++---------- test/cpp/end2end/client_lb_end2end_test.cc | 48 +++++++++--- 2 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index d454401a669..d1a05f12554 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -380,6 +380,31 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args, selected_ = nullptr; return; } + // If one of the subchannels in the new list is already in state + // READY, then select it immediately. This can happen when the + // currently selected subchannel is also present in the update. It + // can also happen if one of the subchannels in the update is already + // in the subchannel index because it's in use by another channel. + for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) { + PickFirstSubchannelData* sd = subchannel_list->subchannel(i); + grpc_error* error = GRPC_ERROR_NONE; + grpc_connectivity_state state = sd->CheckConnectivityStateLocked(&error); + GRPC_ERROR_UNREF(error); + if (state == GRPC_CHANNEL_READY) { + subchannel_list_ = std::move(subchannel_list); + sd->ProcessUnselectedReadyLocked(); + sd->StartConnectivityWatchLocked(); + // If there was a previously pending update (which may or may + // not have contained the currently selected subchannel), drop + // it, so that it doesn't override what we've done here. + latest_pending_subchannel_list_.reset(); + // Make sure that subsequent calls to ExitIdleLocked() don't cause + // us to start watching a subchannel other than the one we've + // selected. + started_picking_ = true; + return; + } + } if (selected_ == nullptr) { // We don't yet have a selected subchannel, so replace the current // subchannel list immediately. @@ -387,46 +412,14 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args, // If we've started picking, start trying to connect to the first // subchannel in the new list. if (started_picking_) { - subchannel_list_->subchannel(0) - ->CheckConnectivityStateAndStartWatchingLocked(); + // Note: No need to use CheckConnectivityStateAndStartWatchingLocked() + // here, since we've already checked the initial connectivity + // state of all subchannels above. + subchannel_list_->subchannel(0)->StartConnectivityWatchLocked(); } } else { - // We do have a selected subchannel. - // Check if it's present in the new list. If so, we're done. - for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) { - PickFirstSubchannelData* sd = subchannel_list->subchannel(i); - if (sd->subchannel() == selected_->subchannel()) { - // The currently selected subchannel is in the update: we are done. - if (grpc_lb_pick_first_trace.enabled()) { - gpr_log(GPR_INFO, - "Pick First %p found already selected subchannel %p " - "at update index %" PRIuPTR " of %" PRIuPTR "; update done", - this, selected_->subchannel(), i, - subchannel_list->num_subchannels()); - } - // Make sure it's in state READY. It might not be if we grabbed - // the combiner while a connectivity state notification - // informing us otherwise is pending. - // Note that CheckConnectivityStateLocked() also takes a ref to - // the connected subchannel. - grpc_error* error = GRPC_ERROR_NONE; - if (sd->CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) { - selected_ = sd; - subchannel_list_ = std::move(subchannel_list); - sd->StartConnectivityWatchLocked(); - // If there was a previously pending update (which may or may - // not have contained the currently selected subchannel), drop - // it, so that it doesn't override what we've done here. - latest_pending_subchannel_list_.reset(); - return; - } - GRPC_ERROR_UNREF(error); - } - } - // Not keeping the previous selected subchannel, so set the latest - // pending subchannel list to the new subchannel list. We will wait - // for it to report READY before swapping it into the current - // subchannel list. + // We do have a selected subchannel, so keep using it until one of + // the subchannels in the new list reports READY. if (latest_pending_subchannel_list_ != nullptr) { if (grpc_lb_pick_first_trace.enabled()) { gpr_log(GPR_INFO, @@ -440,8 +433,11 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args, // If we've started picking, start trying to connect to the first // subchannel in the new list. if (started_picking_) { + // Note: No need to use CheckConnectivityStateAndStartWatchingLocked() + // here, since we've already checked the initial connectivity + // state of all subchannels above. latest_pending_subchannel_list_->subchannel(0) - ->CheckConnectivityStateAndStartWatchingLocked(); + ->StartConnectivityWatchLocked(); } } } diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index b667460cf08..759847be3e9 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -116,7 +116,10 @@ class MyTestServiceImpl : public TestServiceImpl { class ClientLbEnd2endTest : public ::testing::Test { protected: ClientLbEnd2endTest() - : server_host_("localhost"), kRequestMessage_("Live long and prosper.") { + : server_host_("localhost"), + kRequestMessage_("Live long and prosper."), + creds_(new SecureChannelCredentials( + grpc_fake_transport_security_credentials_create())) { // Make the backup poller poll very frequently in order to pick up // updates from all the subchannels's FDs. gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "1"); @@ -215,9 +218,7 @@ class ClientLbEnd2endTest : public ::testing::Test { } // else, default to pick first args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, response_generator_.get()); - std::shared_ptr creds(new SecureChannelCredentials( - grpc_fake_transport_security_credentials_create())); - return CreateCustomChannel("fake:///", std::move(creds), args); + return CreateCustomChannel("fake:///", creds_, args); } bool SendRpc( @@ -265,6 +266,7 @@ class ClientLbEnd2endTest : public ::testing::Test { MyTestServiceImpl service_; std::unique_ptr thread_; bool server_ready_ = false; + bool started_ = false; explicit ServerData(int port = 0) { port_ = port > 0 ? port : grpc_pick_unused_port_or_die(); @@ -272,6 +274,7 @@ class ClientLbEnd2endTest : public ::testing::Test { void Start(const grpc::string& server_host) { gpr_log(GPR_INFO, "starting server on port %d", port_); + started_ = true; std::mutex mu; std::unique_lock lock(mu); std::condition_variable cond; @@ -297,9 +300,11 @@ class ClientLbEnd2endTest : public ::testing::Test { cond->notify_one(); } - void Shutdown(bool join = true) { + void Shutdown() { + if (!started_) return; server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0)); - if (join) thread_->join(); + thread_->join(); + started_ = false; } void SetServingStatus(const grpc::string& service, bool serving) { @@ -378,6 +383,7 @@ class ClientLbEnd2endTest : public ::testing::Test { grpc_core::RefCountedPtr response_generator_; const grpc::string kRequestMessage_; + std::shared_ptr creds_; }; TEST_F(ClientLbEnd2endTest, PickFirst) { @@ -422,6 +428,30 @@ TEST_F(ClientLbEnd2endTest, PickFirstProcessPending) { CheckRpcSendOk(second_stub, DEBUG_LOCATION); } +TEST_F(ClientLbEnd2endTest, PickFirstSelectsReadyAtStartup) { + ChannelArguments args; + constexpr int kInitialBackOffMs = 5000; + args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs); + // Create 2 servers, but start only the second one. + std::vector ports = {grpc_pick_unused_port_or_die(), + grpc_pick_unused_port_or_die()}; + CreateServers(2, ports); + StartServer(1); + auto channel1 = BuildChannel("pick_first", args); + auto stub1 = BuildStub(channel1); + SetNextResolution(ports); + // Wait for second server to be ready. + WaitForServer(stub1, 1, DEBUG_LOCATION); + // Create a second channel with the same addresses. Its PF instance + // should immediately pick the second subchannel, since it's already + // in READY state. + auto channel2 = BuildChannel("pick_first", args); + SetNextResolution(ports); + // Check that the channel reports READY without waiting for the + // initial backoff. + EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1 /* timeout_seconds */)); +} + TEST_F(ClientLbEnd2endTest, PickFirstBackOffInitialReconnect) { ChannelArguments args; constexpr int kInitialBackOffMs = 100; @@ -899,7 +929,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdateInError) { servers_[0]->service_.ResetCounters(); // Shutdown one of the servers to be sent in the update. - servers_[1]->Shutdown(false); + servers_[1]->Shutdown(); ports.emplace_back(servers_[1]->port_); ports.emplace_back(servers_[2]->port_); SetNextResolution(ports); @@ -958,7 +988,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) { // Kill all servers gpr_log(GPR_INFO, "****** ABOUT TO KILL SERVERS *******"); for (size_t i = 0; i < servers_.size(); ++i) { - servers_[i]->Shutdown(true); + servers_[i]->Shutdown(); } gpr_log(GPR_INFO, "****** SERVERS KILLED *******"); gpr_log(GPR_INFO, "****** SENDING DOOMED REQUESTS *******"); @@ -1006,7 +1036,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) { } const auto pre_death = servers_[0]->service_.request_count(); // Kill the first server. - servers_[0]->Shutdown(true); + servers_[0]->Shutdown(); // Client request still succeed. May need retrying if RR had returned a pick // before noticing the change in the server's connectivity. while (!SendRpc(stub)) { From bc447b5f232198bc840fd1449acc076389f6b2ee Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Thu, 6 Dec 2018 11:16:15 -0800 Subject: [PATCH 42/99] Revert "Revert "Add Testonly to Targets"" --- test/cpp/microbenchmarks/BUILD | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD index 5ae9a9a7910..097e92f5836 100644 --- a/test/cpp/microbenchmarks/BUILD +++ b/test/cpp/microbenchmarks/BUILD @@ -29,6 +29,7 @@ grpc_cc_test( grpc_cc_library( name = "helpers", + testonly = 1, srcs = ["helpers.cc"], hdrs = [ "fullstack_context_mutators.h", @@ -55,6 +56,7 @@ grpc_cc_binary( grpc_cc_binary( name = "bm_arena", + testonly = 1, srcs = ["bm_arena.cc"], deps = [":helpers"], ) @@ -68,6 +70,7 @@ grpc_cc_binary( grpc_cc_binary( name = "bm_call_create", + testonly = 1, srcs = ["bm_call_create.cc"], deps = [":helpers"], ) @@ -95,6 +98,7 @@ grpc_cc_binary( grpc_cc_library( name = "fullstack_streaming_ping_pong_h", + testonly = 1, hdrs = [ "fullstack_streaming_ping_pong.h", ], @@ -112,6 +116,7 @@ grpc_cc_binary( grpc_cc_library( name = "fullstack_streaming_pump_h", + testonly = 1, hdrs = [ "fullstack_streaming_pump.h", ], @@ -129,12 +134,14 @@ grpc_cc_binary( grpc_cc_binary( name = "bm_fullstack_trickle", + testonly = 1, srcs = ["bm_fullstack_trickle.cc"], deps = [":helpers"], ) grpc_cc_library( name = "fullstack_unary_ping_pong_h", + testonly = 1, hdrs = [ "fullstack_unary_ping_pong.h", ], From 3dd24ea9789fcc455842b9582102f8c261e0bb1c Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 6 Dec 2018 12:27:41 -0800 Subject: [PATCH 43/99] code review changes --- .../ext/filters/client_channel/subchannel.cc | 8 ++++---- test/cpp/end2end/client_lb_end2end_test.cc | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 4d98b63b49a..af55f7710e2 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -153,7 +153,7 @@ struct grpc_subchannel { /** have we started the backoff loop */ bool backoff_begun; // reset_backoff() was called while alarm was pending - bool deferred_reset_backoff; + bool retry_immediately; /** our alarm */ grpc_timer alarm; @@ -709,8 +709,8 @@ static void on_alarm(void* arg, grpc_error* error) { if (c->disconnected) { error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected", &error, 1); - } else if (c->deferred_reset_backoff) { - c->deferred_reset_backoff = false; + } else if (c->retry_immediately) { + c->retry_immediately = false; error = GRPC_ERROR_NONE; } else { GRPC_ERROR_REF(error); @@ -889,7 +889,7 @@ void grpc_subchannel_reset_backoff(grpc_subchannel* subchannel) { gpr_mu_lock(&subchannel->mu); subchannel->backoff->Reset(); if (subchannel->have_alarm) { - subchannel->deferred_reset_backoff = true; + subchannel->retry_immediately = true; grpc_timer_cancel(&subchannel->alarm); } else { subchannel->backoff_begun = false; diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index 1a7b36cdc05..f60f110c5ff 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -527,24 +527,27 @@ TEST_F(ClientLbEnd2endTest, // Trigger a second connection attempt. This should also fail // ~immediately, but the retry should be scheduled for // kInitialBackOffMs instead of applying the multiplier. - gpr_log(GPR_INFO, "=== TRIGGERING SECOND CONNECTION ATTEMPT"); + gpr_log(GPR_INFO, "=== POLLING FOR SECOND CONNECTION ATTEMPT"); + const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC); EXPECT_FALSE( channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); // Bring up a server on the chosen port. gpr_log(GPR_INFO, "=== STARTING BACKEND"); StartServers(1, ports); // Wait for connect. Should happen within kInitialBackOffMs. - gpr_log(GPR_INFO, "=== TRIGGERING THIRD CONNECTION ATTEMPT"); - const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC); + // Give an extra 100ms to account for the time spent in the second and + // third connection attempts themselves (since what we really want to + // measure is the time between the two). As long as this is less than + // the 1.6x increase we would see if the backoff state was not reset + // properly, the test is still proving that the backoff was reset. + constexpr int kWaitMs = kInitialBackOffMs + 100; + gpr_log(GPR_INFO, "=== POLLING FOR THIRD CONNECTION ATTEMPT"); EXPECT_TRUE(channel->WaitForConnected( - grpc_timeout_milliseconds_to_deadline(kInitialBackOffMs))); + grpc_timeout_milliseconds_to_deadline(kWaitMs))); const gpr_timespec t1 = gpr_now(GPR_CLOCK_MONOTONIC); const grpc_millis waited_ms = gpr_time_to_millis(gpr_time_sub(t1, t0)); gpr_log(GPR_DEBUG, "Waited %" PRId64 " milliseconds", waited_ms); - // Give an extra 100ms for timing slack. - // (This is still far less than the 1.6x increase we would see if the - // backoff state was not reset properly.) - EXPECT_LT(waited_ms, kInitialBackOffMs + 100); + EXPECT_LT(waited_ms, kWaitMs); } TEST_F(ClientLbEnd2endTest, PickFirstUpdates) { From a324bcaad02117657f9027b14f9708f396ab9170 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Thu, 6 Dec 2018 13:53:16 -0800 Subject: [PATCH 44/99] Pre-fix python3 pylint failures --- src/python/grpcio/grpc/_channel.py | 1 + src/python/grpcio/grpc/_interceptor.py | 5 ++++- src/python/grpcio_tests/tests/qps/worker_server.py | 4 ++-- src/python/grpcio_tests/tests/unit/_exit_scenarios.py | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index ab154d85121..35fa82d56bd 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -175,6 +175,7 @@ def _event_handler(state, response_deserializer): return handle_event +#pylint: disable=too-many-statements def _consume_request_iterator(request_iterator, state, call, request_serializer, event_handler): if cygrpc.is_fork_support_enabled(): diff --git a/src/python/grpcio/grpc/_interceptor.py b/src/python/grpcio/grpc/_interceptor.py index 2a8ddd8ce42..fc0ad77eb9e 100644 --- a/src/python/grpcio/grpc/_interceptor.py +++ b/src/python/grpcio/grpc/_interceptor.py @@ -135,9 +135,12 @@ class _FailureOutcome(grpc.RpcError, grpc.Future, grpc.Call): def __iter__(self): return self - def next(self): + def __next__(self): raise self._exception + def next(self): + return self.__next__() + class _UnaryOutcome(grpc.Call, grpc.Future): diff --git a/src/python/grpcio_tests/tests/qps/worker_server.py b/src/python/grpcio_tests/tests/qps/worker_server.py index 740bdcf1eb3..337a94b546c 100644 --- a/src/python/grpcio_tests/tests/qps/worker_server.py +++ b/src/python/grpcio_tests/tests/qps/worker_server.py @@ -39,7 +39,7 @@ class WorkerServer(worker_service_pb2_grpc.WorkerServiceServicer): self._quit_event = threading.Event() def RunServer(self, request_iterator, context): - config = next(request_iterator).setup + config = next(request_iterator).setup #pylint: disable=stop-iteration-return server, port = self._create_server(config) cores = multiprocessing.cpu_count() server.start() @@ -102,7 +102,7 @@ class WorkerServer(worker_service_pb2_grpc.WorkerServiceServicer): return (server, port) def RunClient(self, request_iterator, context): - config = next(request_iterator).setup + config = next(request_iterator).setup #pylint: disable=stop-iteration-return client_runners = [] qps_data = histogram.Histogram(config.histogram_params.resolution, config.histogram_params.max_possible) diff --git a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py index f489db12cb3..d1263c2c56c 100644 --- a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py +++ b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py @@ -87,7 +87,7 @@ def hang_stream_stream(request_iterator, servicer_context): def hang_partial_stream_stream(request_iterator, servicer_context): for _ in range(test_constants.STREAM_LENGTH // 2): - yield next(request_iterator) + yield next(request_iterator) #pylint: disable=stop-iteration-return time.sleep(WAIT_TIME) From 97de30d7b3f3fdbddf140cc988ccfaf29bd8edab Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 6 Dec 2018 15:51:31 -0800 Subject: [PATCH 45/99] Allow the interceptor to know the method type --- .../grpcpp/impl/codegen/channel_interface.h | 1 - include/grpcpp/impl/codegen/client_context.h | 6 ++- .../grpcpp/impl/codegen/client_interceptor.h | 48 ++++++++++++++++--- include/grpcpp/impl/codegen/server_context.h | 4 +- .../grpcpp/impl/codegen/server_interceptor.h | 25 ++++++++-- .../grpcpp/impl/codegen/server_interface.h | 18 +++---- src/cpp/client/channel_cc.cc | 5 +- src/cpp/server/server_cc.cc | 17 ++++--- .../client_interceptors_end2end_test.cc | 1 + .../server_interceptors_end2end_test.cc | 27 ++++++++++- 10 files changed, 121 insertions(+), 31 deletions(-) diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h index 728a7b90496..5353f5feaa6 100644 --- a/include/grpcpp/impl/codegen/channel_interface.h +++ b/include/grpcpp/impl/codegen/channel_interface.h @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h index 142cfa35dd0..0a71f3d9b6a 100644 --- a/include/grpcpp/impl/codegen/client_context.h +++ b/include/grpcpp/impl/codegen/client_context.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -418,12 +419,13 @@ class ClientContext { void set_call(grpc_call* call, const std::shared_ptr& channel); experimental::ClientRpcInfo* set_client_rpc_info( - const char* method, grpc::ChannelInterface* channel, + const char* method, internal::RpcMethod::RpcType type, + grpc::ChannelInterface* channel, const std::vector< std::unique_ptr>& creators, size_t interceptor_pos) { - rpc_info_ = experimental::ClientRpcInfo(this, method, channel); + rpc_info_ = experimental::ClientRpcInfo(this, type, method, channel); rpc_info_.RegisterInterceptors(creators, interceptor_pos); return &rpc_info_; } diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h index f69c99ab229..2bae11a2516 100644 --- a/include/grpcpp/impl/codegen/client_interceptor.h +++ b/include/grpcpp/impl/codegen/client_interceptor.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace grpc { @@ -52,23 +53,56 @@ extern experimental::ClientInterceptorFactoryInterface* namespace experimental { class ClientRpcInfo { public: - ClientRpcInfo() {} + // TODO(yashykt): Stop default-constructing ClientRpcInfo and remove UNKNOWN + // from the list of possible Types. + enum class Type { + UNARY, + CLIENT_STREAMING, + SERVER_STREAMING, + BIDI_STREAMING, + UNKNOWN // UNKNOWN is not API and will be removed later + }; ~ClientRpcInfo(){}; ClientRpcInfo(const ClientRpcInfo&) = delete; ClientRpcInfo(ClientRpcInfo&&) = default; - ClientRpcInfo& operator=(ClientRpcInfo&&) = default; // Getter methods - const char* method() { return method_; } + const char* method() const { return method_; } ChannelInterface* channel() { return channel_; } grpc::ClientContext* client_context() { return ctx_; } + Type type() const { return type_; } private: - ClientRpcInfo(grpc::ClientContext* ctx, const char* method, - grpc::ChannelInterface* channel) - : ctx_(ctx), method_(method), channel_(channel) {} + static_assert(Type::UNARY == + static_cast(internal::RpcMethod::NORMAL_RPC), + "violated expectation about Type enum"); + static_assert(Type::CLIENT_STREAMING == + static_cast(internal::RpcMethod::CLIENT_STREAMING), + "violated expectation about Type enum"); + static_assert(Type::SERVER_STREAMING == + static_cast(internal::RpcMethod::SERVER_STREAMING), + "violated expectation about Type enum"); + static_assert(Type::BIDI_STREAMING == + static_cast(internal::RpcMethod::BIDI_STREAMING), + "violated expectation about Type enum"); + + // Default constructor should only be used by ClientContext + ClientRpcInfo() = default; + + // Constructor will only be called from ClientContext + ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type, + const char* method, grpc::ChannelInterface* channel) + : ctx_(ctx), + type_(static_cast(type)), + method_(method), + channel_(channel) {} + + // Move assignment should only be used by ClientContext + // TODO(yashykt): Delete move assignment + ClientRpcInfo& operator=(ClientRpcInfo&&) = default; + // Runs interceptor at pos \a pos. void RunInterceptor( experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) { @@ -97,6 +131,8 @@ class ClientRpcInfo { } grpc::ClientContext* ctx_ = nullptr; + // TODO(yashykt): make type_ const once move-assignment is deleted + Type type_{Type::UNKNOWN}; const char* method_ = nullptr; grpc::ChannelInterface* channel_ = nullptr; std::vector> interceptors_; diff --git a/include/grpcpp/impl/codegen/server_context.h b/include/grpcpp/impl/codegen/server_context.h index 4a5f9e2dd91..ccb5925e7d8 100644 --- a/include/grpcpp/impl/codegen/server_context.h +++ b/include/grpcpp/impl/codegen/server_context.h @@ -314,12 +314,12 @@ class ServerContext { uint32_t initial_metadata_flags() const { return 0; } experimental::ServerRpcInfo* set_server_rpc_info( - const char* method, + const char* method, internal::RpcMethod::RpcType type, const std::vector< std::unique_ptr>& creators) { if (creators.size() != 0) { - rpc_info_ = new experimental::ServerRpcInfo(this, method); + rpc_info_ = new experimental::ServerRpcInfo(this, method, type); rpc_info_->RegisterInterceptors(creators); } return rpc_info_; diff --git a/include/grpcpp/impl/codegen/server_interceptor.h b/include/grpcpp/impl/codegen/server_interceptor.h index 5fb5df28b70..cd7c0600b60 100644 --- a/include/grpcpp/impl/codegen/server_interceptor.h +++ b/include/grpcpp/impl/codegen/server_interceptor.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace grpc { @@ -44,6 +45,8 @@ class ServerInterceptorFactoryInterface { class ServerRpcInfo { public: + enum class Type { UNARY, CLIENT_STREAMING, SERVER_STREAMING, BIDI_STREAMING }; + ~ServerRpcInfo(){}; ServerRpcInfo(const ServerRpcInfo&) = delete; @@ -51,12 +54,27 @@ class ServerRpcInfo { ServerRpcInfo& operator=(ServerRpcInfo&&) = default; // Getter methods - const char* method() { return method_; } + const char* method() const { return method_; } + Type type() const { return type_; } grpc::ServerContext* server_context() { return ctx_; } private: - ServerRpcInfo(grpc::ServerContext* ctx, const char* method) - : ctx_(ctx), method_(method) { + static_assert(Type::UNARY == + static_cast(internal::RpcMethod::NORMAL_RPC), + "violated expectation about Type enum"); + static_assert(Type::CLIENT_STREAMING == + static_cast(internal::RpcMethod::CLIENT_STREAMING), + "violated expectation about Type enum"); + static_assert(Type::SERVER_STREAMING == + static_cast(internal::RpcMethod::SERVER_STREAMING), + "violated expectation about Type enum"); + static_assert(Type::BIDI_STREAMING == + static_cast(internal::RpcMethod::BIDI_STREAMING), + "violated expectation about Type enum"); + + ServerRpcInfo(grpc::ServerContext* ctx, const char* method, + internal::RpcMethod::RpcType type) + : ctx_(ctx), method_(method), type_(static_cast(type)) { ref_.store(1); } @@ -86,6 +104,7 @@ class ServerRpcInfo { grpc::ServerContext* ctx_ = nullptr; const char* method_ = nullptr; + const Type type_; std::atomic_int ref_; std::vector> interceptors_; diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h index 55c94f4d2fa..e0e26298270 100644 --- a/include/grpcpp/impl/codegen/server_interface.h +++ b/include/grpcpp/impl/codegen/server_interface.h @@ -174,13 +174,14 @@ class ServerInterface : public internal::CallHook { bool done_intercepting_; }; + /// RegisteredAsyncRequest is not part of the C++ API class RegisteredAsyncRequest : public BaseAsyncRequest { public: RegisteredAsyncRequest(ServerInterface* server, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, - const char* name); + const char* name, internal::RpcMethod::RpcType type); virtual bool FinalizeResult(void** tag, bool* status) override { /* If we are done intercepting, then there is nothing more for us to do */ @@ -189,7 +190,7 @@ class ServerInterface : public internal::CallHook { } call_wrapper_ = internal::Call( call_, server_, call_cq_, server_->max_receive_message_size(), - context_->set_server_rpc_info(name_, + context_->set_server_rpc_info(name_, type_, *server_->interceptor_creators())); return BaseAsyncRequest::FinalizeResult(tag, status); } @@ -198,6 +199,7 @@ class ServerInterface : public internal::CallHook { void IssueRequest(void* registered_method, grpc_byte_buffer** payload, ServerCompletionQueue* notification_cq); const char* name_; + const internal::RpcMethod::RpcType type_; }; class NoPayloadAsyncRequest final : public RegisteredAsyncRequest { @@ -207,9 +209,9 @@ class ServerInterface : public internal::CallHook { internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) - : RegisteredAsyncRequest(server, context, stream, call_cq, - notification_cq, tag, - registered_method->name()) { + : RegisteredAsyncRequest( + server, context, stream, call_cq, notification_cq, tag, + registered_method->name(), registered_method->method_type()) { IssueRequest(registered_method->server_tag(), nullptr, notification_cq); } @@ -225,9 +227,9 @@ class ServerInterface : public internal::CallHook { CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, Message* request) - : RegisteredAsyncRequest(server, context, stream, call_cq, - notification_cq, tag, - registered_method->name()), + : RegisteredAsyncRequest( + server, context, stream, call_cq, notification_cq, tag, + registered_method->name(), registered_method->method_type()), registered_method_(registered_method), server_(server), context_(context), diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index d1c55319f7c..a31d0b30b15 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -149,8 +149,9 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method, // ClientRpcInfo should be set before call because set_call also checks // whether the call has been cancelled, and if the call was cancelled, we // should notify the interceptors too/ - auto* info = context->set_client_rpc_info( - method.name(), this, interceptor_creators_, interceptor_pos); + auto* info = + context->set_client_rpc_info(method.name(), method.method_type(), this, + interceptor_creators_, interceptor_pos); context->set_call(c_call, shared_from_this()); return internal::Call(c_call, this, cq, info); diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 69af43a6562..1e3c57446f4 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -236,9 +236,10 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { : nullptr), request_(nullptr), method_(mrd->method_), - call_(mrd->call_, server, &cq_, server->max_receive_message_size(), - ctx_.set_server_rpc_info(method_->name(), - server->interceptor_creators_)), + call_( + mrd->call_, server, &cq_, server->max_receive_message_size(), + ctx_.set_server_rpc_info(method_->name(), method_->method_type(), + server->interceptor_creators_)), server_(server), global_callbacks_(nullptr), resources_(false) { @@ -427,7 +428,8 @@ class Server::CallbackRequest final : public internal::CompletionQueueTag { req_->call_, req_->server_, req_->cq_, req_->server_->max_receive_message_size(), req_->ctx_.set_server_rpc_info( - req_->method_->name(), req_->server_->interceptor_creators_)); + req_->method_->name(), req_->method_->method_type(), + req_->server_->interceptor_creators_)); req_->interceptor_methods_.SetCall(call_); req_->interceptor_methods_.SetReverse(); @@ -1041,10 +1043,12 @@ void ServerInterface::BaseAsyncRequest:: ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest( ServerInterface* server, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, const char* name) + ServerCompletionQueue* notification_cq, void* tag, const char* name, + internal::RpcMethod::RpcType type) : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag, true), - name_(name) {} + name_(name), + type_(type) {} void ServerInterface::RegisteredAsyncRequest::IssueRequest( void* registered_method, grpc_byte_buffer** payload, @@ -1091,6 +1095,7 @@ bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag, call_, server_, call_cq_, server_->max_receive_message_size(), context_->set_server_rpc_info( static_cast(context_)->method_.c_str(), + internal::RpcMethod::BIDI_STREAMING, *server_->interceptor_creators())); return BaseAsyncRequest::FinalizeResult(tag, status); } diff --git a/test/cpp/end2end/client_interceptors_end2end_test.cc b/test/cpp/end2end/client_interceptors_end2end_test.cc index 3a191d1e038..f55ece1c2bf 100644 --- a/test/cpp/end2end/client_interceptors_end2end_test.cc +++ b/test/cpp/end2end/client_interceptors_end2end_test.cc @@ -50,6 +50,7 @@ class HijackingInterceptor : public experimental::Interceptor { info_ = info; // Make sure it is the right method EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0); + EXPECT_EQ(info->type(), experimental::ClientRpcInfo::Type::UNARY); } virtual void Intercept(experimental::InterceptorBatchMethods* methods) { diff --git a/test/cpp/end2end/server_interceptors_end2end_test.cc b/test/cpp/end2end/server_interceptors_end2end_test.cc index c98b6143c66..1e0e3668707 100644 --- a/test/cpp/end2end/server_interceptors_end2end_test.cc +++ b/test/cpp/end2end/server_interceptors_end2end_test.cc @@ -44,7 +44,32 @@ namespace { class LoggingInterceptor : public experimental::Interceptor { public: - LoggingInterceptor(experimental::ServerRpcInfo* info) { info_ = info; } + LoggingInterceptor(experimental::ServerRpcInfo* info) { + info_ = info; + + // Check the method name and compare to the type + const char* method = info->method(); + experimental::ServerRpcInfo::Type type = info->type(); + + // Check that we use one of our standard methods with expected type. + // We accept BIDI_STREAMING for Echo in case it's an AsyncGenericService + // being tested (the GenericRpc test). + // The empty method is for the Unimplemented requests that arise + // when draining the CQ. + EXPECT_TRUE( + (strcmp(method, "/grpc.testing.EchoTestService/Echo") == 0 && + (type == experimental::ServerRpcInfo::Type::UNARY || + type == experimental::ServerRpcInfo::Type::BIDI_STREAMING)) || + (strcmp(method, "/grpc.testing.EchoTestService/RequestStream") == 0 && + type == experimental::ServerRpcInfo::Type::CLIENT_STREAMING) || + (strcmp(method, "/grpc.testing.EchoTestService/ResponseStream") == 0 && + type == experimental::ServerRpcInfo::Type::SERVER_STREAMING) || + (strcmp(method, "/grpc.testing.EchoTestService/BidiStream") == 0 && + type == experimental::ServerRpcInfo::Type::BIDI_STREAMING) || + strcmp(method, "/grpc.testing.EchoTestService/Unimplemented") == 0 || + (strcmp(method, "") == 0 && + type == experimental::ServerRpcInfo::Type::BIDI_STREAMING)); + } virtual void Intercept(experimental::InterceptorBatchMethods* methods) { if (methods->QueryInterceptionHookPoint( From f1f557bc43992ade0f09c9240c2d5c71c3478f0a Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 6 Dec 2018 16:16:58 -0800 Subject: [PATCH 46/99] Add a Shutdown call to HealthCheckServiceInterface --- .../grpcpp/health_check_service_interface.h | 4 + .../health/default_health_check_service.cc | 18 +++ .../health/default_health_check_service.h | 3 + .../end2end/health_service_end2end_test.cc | 107 ++++++++++++++++++ 4 files changed, 132 insertions(+) diff --git a/include/grpcpp/health_check_service_interface.h b/include/grpcpp/health_check_service_interface.h index b45a699bda9..dfd4c3983af 100644 --- a/include/grpcpp/health_check_service_interface.h +++ b/include/grpcpp/health_check_service_interface.h @@ -37,6 +37,10 @@ class HealthCheckServiceInterface { bool serving) = 0; /// Apply to all registered service names. virtual void SetServingStatus(bool serving) = 0; + + /// Set all registered service names to not serving and prevent future + /// state changes. + virtual void Shutdown() {} }; /// Enable/disable the default health checking service. This applies to all C++ diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc index c951c69d513..db6286d240e 100644 --- a/src/cpp/server/health/default_health_check_service.cc +++ b/src/cpp/server/health/default_health_check_service.cc @@ -42,18 +42,36 @@ DefaultHealthCheckService::DefaultHealthCheckService() { void DefaultHealthCheckService::SetServingStatus( const grpc::string& service_name, bool serving) { std::unique_lock lock(mu_); + if (shutdown_) { + return; + } services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING); } void DefaultHealthCheckService::SetServingStatus(bool serving) { const ServingStatus status = serving ? SERVING : NOT_SERVING; std::unique_lock lock(mu_); + if (shutdown_) { + return; + } for (auto& p : services_map_) { ServiceData& service_data = p.second; service_data.SetServingStatus(status); } } +void DefaultHealthCheckService::Shutdown() { + std::unique_lock lock(mu_); + if (shutdown_) { + return; + } + shutdown_ = true; + for (auto& p : services_map_) { + ServiceData& service_data = p.second; + service_data.SetServingStatus(NOT_SERVING); + } +} + DefaultHealthCheckService::ServingStatus DefaultHealthCheckService::GetServingStatus( const grpc::string& service_name) const { diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h index 450bd543f55..9551cd2e2cf 100644 --- a/src/cpp/server/health/default_health_check_service.h +++ b/src/cpp/server/health/default_health_check_service.h @@ -237,6 +237,8 @@ class DefaultHealthCheckService final : public HealthCheckServiceInterface { bool serving) override; void SetServingStatus(bool serving) override; + void Shutdown() override; + ServingStatus GetServingStatus(const grpc::string& service_name) const; HealthCheckServiceImpl* GetHealthCheckService( @@ -272,6 +274,7 @@ class DefaultHealthCheckService final : public HealthCheckServiceInterface { const std::shared_ptr& handler); mutable std::mutex mu_; + bool shutdown_ = false; // Guarded by mu_. std::map services_map_; // Guarded by mu_. std::unique_ptr impl_; }; diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc index 89c4bef09cf..a439d42b031 100644 --- a/test/cpp/end2end/health_service_end2end_test.cc +++ b/test/cpp/end2end/health_service_end2end_test.cc @@ -90,18 +90,36 @@ class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service { void SetStatus(const grpc::string& service_name, HealthCheckResponse::ServingStatus status) { std::lock_guard lock(mu_); + if (shutdown_) { + return; + } status_map_[service_name] = status; } void SetAll(HealthCheckResponse::ServingStatus status) { std::lock_guard lock(mu_); + if (shutdown_) { + return; + } for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) { iter->second = status; } } + void Shutdown() { + std::lock_guard lock(mu_); + if (shutdown_) { + return; + } + shutdown_ = true; + for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) { + iter->second = HealthCheckResponse::NOT_SERVING; + } + } + private: std::mutex mu_; + bool shutdown_ = false; std::map status_map_; }; @@ -125,6 +143,8 @@ class CustomHealthCheckService : public HealthCheckServiceInterface { : HealthCheckResponse::NOT_SERVING); } + void Shutdown() override { impl_->Shutdown(); } + private: HealthCheckServiceImpl* impl_; // not owned }; @@ -260,6 +280,71 @@ class HealthServiceEnd2endTest : public ::testing::Test { context.TryCancel(); } + // Verify that after HealthCheckServiceInterface::Shutdown is called + // 1. unary client will see NOT_SERVING. + // 2. unary client still sees NOT_SERVING after a SetServing(true) is called. + // 3. streaming (Watch) client will see an update. + // This has to be called last. + void VerifyHealthCheckServiceShutdown() { + const grpc::string kServiceName("service_name"); + HealthCheckServiceInterface* service = server_->GetHealthCheckService(); + EXPECT_TRUE(service != nullptr); + const grpc::string kHealthyService("healthy_service"); + const grpc::string kUnhealthyService("unhealthy_service"); + const grpc::string kNotRegisteredService("not_registered"); + service->SetServingStatus(kHealthyService, true); + service->SetServingStatus(kUnhealthyService, false); + + ResetStubs(); + + // Start Watch for service. + ClientContext context; + HealthCheckRequest request; + request.set_service(kServiceName); + std::unique_ptr<::grpc::ClientReaderInterface> reader = + hc_stub_->Watch(&context, request); + + // Initial response will be SERVICE_UNKNOWN. + HealthCheckResponse response; + EXPECT_TRUE(reader->Read(&response)); + EXPECT_EQ(response.SERVICE_UNKNOWN, response.status()); + + // Set service to SERVING and make sure we get an update. + service->SetServingStatus(kServiceName, true); + EXPECT_TRUE(reader->Read(&response)); + EXPECT_EQ(response.SERVING, response.status()); + + SendHealthCheckRpc("", Status::OK, HealthCheckResponse::SERVING); + SendHealthCheckRpc(kHealthyService, Status::OK, + HealthCheckResponse::SERVING); + SendHealthCheckRpc(kUnhealthyService, Status::OK, + HealthCheckResponse::NOT_SERVING); + SendHealthCheckRpc(kNotRegisteredService, + Status(StatusCode::NOT_FOUND, "")); + + // Shutdown health check service. + service->Shutdown(); + + // Watch client gets another update. + EXPECT_TRUE(reader->Read(&response)); + EXPECT_EQ(response.NOT_SERVING, response.status()); + // Finish Watch call. + context.TryCancel(); + + SendHealthCheckRpc("", Status::OK, HealthCheckResponse::NOT_SERVING); + SendHealthCheckRpc(kHealthyService, Status::OK, + HealthCheckResponse::NOT_SERVING); + SendHealthCheckRpc(kUnhealthyService, Status::OK, + HealthCheckResponse::NOT_SERVING); + SendHealthCheckRpc(kNotRegisteredService, + Status(StatusCode::NOT_FOUND, "")); + + // Setting status after Shutdown has no effect. + service->SetServingStatus(kHealthyService, true); + SendHealthCheckRpc(kHealthyService, Status::OK, + HealthCheckResponse::NOT_SERVING); + } + TestServiceImpl echo_test_service_; HealthCheckServiceImpl health_check_service_impl_; std::unique_ptr hc_stub_; @@ -295,6 +380,13 @@ TEST_F(HealthServiceEnd2endTest, DefaultHealthService) { Status(StatusCode::INVALID_ARGUMENT, "")); } +TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceShutdown) { + EnableDefaultHealthCheckService(true); + EXPECT_TRUE(DefaultHealthCheckServiceEnabled()); + SetUpServer(true, false, false, nullptr); + VerifyHealthCheckServiceShutdown(); +} + // Provide an empty service to disable the default service. TEST_F(HealthServiceEnd2endTest, ExplicitlyDisableViaOverride) { EnableDefaultHealthCheckService(true); @@ -326,6 +418,21 @@ TEST_F(HealthServiceEnd2endTest, ExplicitlyOverride) { VerifyHealthCheckServiceStreaming(); } +TEST_F(HealthServiceEnd2endTest, ExplicitlyHealthServiceShutdown) { + EnableDefaultHealthCheckService(true); + EXPECT_TRUE(DefaultHealthCheckServiceEnabled()); + std::unique_ptr override_service( + new CustomHealthCheckService(&health_check_service_impl_)); + HealthCheckServiceInterface* underlying_service = override_service.get(); + SetUpServer(false, false, true, std::move(override_service)); + HealthCheckServiceInterface* service = server_->GetHealthCheckService(); + EXPECT_TRUE(service == underlying_service); + + ResetStubs(); + + VerifyHealthCheckServiceShutdown(); +} + } // namespace } // namespace testing } // namespace grpc From d7c252c9473a2a97eb441369603d8cc9ad64403c Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 6 Dec 2018 16:53:24 -0800 Subject: [PATCH 47/99] Surface socket name --- src/core/ext/filters/client_channel/connector.h | 5 +++-- src/core/ext/filters/client_channel/subchannel.cc | 4 +++- .../transport/chttp2/client/chttp2_connector.cc | 4 ++-- .../ext/transport/chttp2/server/chttp2_server.cc | 2 +- .../transport/chttp2/transport/chttp2_transport.cc | 9 +++------ .../transport/chttp2/transport/chttp2_transport.h | 4 +++- src/core/lib/channel/channelz.cc | 10 ++++++---- src/core/lib/channel/channelz.h | 5 +++++ src/core/lib/surface/server.cc | 14 +++++++------- src/core/lib/surface/server.h | 4 ++-- 10 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h index ea34dcdab57..484cc1b3c39 100644 --- a/src/core/ext/filters/client_channel/connector.h +++ b/src/core/ext/filters/client_channel/connector.h @@ -22,6 +22,7 @@ #include #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/transport/transport.h" @@ -48,8 +49,8 @@ typedef struct { /** channel arguments (to be passed to the filters) */ grpc_channel_args* channel_args; - /** socket uuid of the connected transport. 0 if not available */ - intptr_t socket_uuid; + /** socket node of the connected transport */ + grpc_core::channelz::SocketNode* socket_node; } grpc_connect_out_args; struct grpc_connector_vtable { diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 0817b1dd392..e66b0711cf9 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -826,7 +826,9 @@ static bool publish_transport_locked(grpc_subchannel* c) { GRPC_ERROR_UNREF(error); return false; } - intptr_t socket_uuid = c->connecting_result.socket_uuid; + intptr_t socket_uuid = c->connecting_result.socket_node == nullptr + ? 0 + : c->connecting_result.socket_node->uuid(); memset(&c->connecting_result, 0, sizeof(c->connecting_result)); if (c->disconnected) { diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index 60a32022f57..62a07d2ba61 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -117,8 +117,8 @@ static void on_handshake_done(void* arg, grpc_error* error) { c->args.interested_parties); c->result->transport = grpc_create_chttp2_transport(args->args, args->endpoint, true); - c->result->socket_uuid = - grpc_chttp2_transport_get_socket_uuid(c->result->transport); + c->result->socket_node = + grpc_chttp2_transport_get_socket_node(c->result->transport); GPR_ASSERT(c->result->transport); // TODO(roth): We ideally want to wait until we receive HTTP/2 // settings from the server before we consider the connection diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index 33d2b22aa58..3d09187b9ba 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -149,7 +149,7 @@ static void on_handshake_done(void* arg, grpc_error* error) { grpc_server_setup_transport( connection_state->svr_state->server, transport, connection_state->accepting_pollset, args->args, - grpc_chttp2_transport_get_socket_uuid(transport), resource_user); + grpc_chttp2_transport_get_socket_node(transport), resource_user); // Use notify_on_receive_settings callback to enforce the // handshake deadline. connection_state->transport = diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 7377287e8cb..73e43131a0a 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -3145,14 +3145,11 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), static const grpc_transport_vtable* get_vtable(void) { return &vtable; } -intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport) { +grpc_core::channelz::SocketNode* grpc_chttp2_transport_get_socket_node( + grpc_transport* transport) { grpc_chttp2_transport* t = reinterpret_cast(transport); - if (t->channelz_socket != nullptr) { - return t->channelz_socket->uuid(); - } else { - return 0; - } + return t->channelz_socket.get(); } grpc_transport* grpc_create_chttp2_transport( diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h index b3fe1c082ec..b9929b1662e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h @@ -21,6 +21,7 @@ #include +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/transport/transport.h" @@ -35,7 +36,8 @@ grpc_transport* grpc_create_chttp2_transport( const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client, grpc_resource_user* resource_user = nullptr); -intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport); +grpc_core::channelz::SocketNode* grpc_chttp2_transport_get_socket_node( + grpc_transport* transport); /// Takes ownership of \a read_buffer, which (if non-NULL) contains /// leftover bytes previously read from the endpoint (e.g., by handshakers). diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 0802143fbeb..0cb28905181 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -207,18 +207,20 @@ char* ServerNode::RenderServerSockets(intptr_t start_socket_id) { grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; - ChildRefsList socket_refs; + ChildSocketsList socket_refs; grpc_server_populate_server_sockets(server_, &socket_refs, start_socket_id); if (!socket_refs.empty()) { // create list of socket refs grpc_json* array_parent = grpc_json_create_child( nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); for (size_t i = 0; i < socket_refs.size(); ++i) { - json_iterator = + grpc_json* socket_ref_json = grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); - grpc_json_add_number_string_child(json_iterator, nullptr, "socketId", - socket_refs[i]); + json_iterator = grpc_json_add_number_string_child( + socket_ref_json, nullptr, "socketId", socket_refs[i]->uuid()); + grpc_json_create_child(json_iterator, socket_ref_json, "name", + socket_refs[i]->remote(), GRPC_JSON_STRING, false); } } // For now we do not have any pagination rules. In the future we could diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 64ab5cb3a65..96a4333083a 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -59,6 +59,9 @@ namespace channelz { // add human readable names as in the channelz.proto typedef InlinedVector ChildRefsList; +class SocketNode; +typedef InlinedVector ChildSocketsList; + namespace testing { class CallCountingHelperPeer; class ChannelNodePeer; @@ -251,6 +254,8 @@ class SocketNode : public BaseNode { gpr_atm_no_barrier_fetch_add(&keepalives_sent_, static_cast(1)); } + const char* remote() { return remote_.get(); } + private: gpr_atm streams_started_ = 0; gpr_atm streams_succeeded_ = 0; diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 1f66be240e3..4c63b6bc394 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -109,7 +109,7 @@ struct channel_data { uint32_t registered_method_max_probes; grpc_closure finish_destroy_channel_closure; grpc_closure channel_connectivity_changed; - intptr_t socket_uuid; + grpc_core::channelz::SocketNode* socket_node; }; typedef struct shutdown_tag { @@ -1158,7 +1158,7 @@ void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets, void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, grpc_pollset* accepting_pollset, const grpc_channel_args* args, - intptr_t socket_uuid, + grpc_core::channelz::SocketNode* socket_node, grpc_resource_user* resource_user) { size_t num_registered_methods; size_t alloc; @@ -1180,7 +1180,7 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, chand->server = s; server_ref(s); chand->channel = channel; - chand->socket_uuid = socket_uuid; + chand->socket_node = socket_node; size_t cq_idx; for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) { @@ -1256,14 +1256,14 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, } void grpc_server_populate_server_sockets( - grpc_server* s, grpc_core::channelz::ChildRefsList* server_sockets, + grpc_server* s, grpc_core::channelz::ChildSocketsList* server_sockets, intptr_t start_idx) { gpr_mu_lock(&s->mu_global); channel_data* c = nullptr; for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { - intptr_t socket_uuid = c->socket_uuid; - if (socket_uuid >= start_idx) { - server_sockets->push_back(socket_uuid); + grpc_core::channelz::SocketNode* socket_node = c->socket_node; + if (socket_node && socket_node->uuid() >= start_idx) { + server_sockets->push_back(socket_node); } } gpr_mu_unlock(&s->mu_global); diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index 27038fdb7a6..8e8903d76b3 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -47,12 +47,12 @@ void grpc_server_add_listener(grpc_server* server, void* listener, void grpc_server_setup_transport(grpc_server* server, grpc_transport* transport, grpc_pollset* accepting_pollset, const grpc_channel_args* args, - intptr_t socket_uuid, + grpc_core::channelz::SocketNode* socket_node, grpc_resource_user* resource_user = nullptr); /* fills in the uuids of all sockets used for connections on this server */ void grpc_server_populate_server_sockets( - grpc_server* server, grpc_core::channelz::ChildRefsList* server_sockets, + grpc_server* server, grpc_core::channelz::ChildSocketsList* server_sockets, intptr_t start_idx); /* fills in the uuids of all listen sockets on this server */ From e7be6223d86172f2881935f83fb25b4bc7898942 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 6 Dec 2018 17:10:03 -0800 Subject: [PATCH 48/99] Delete unwanted constructor/assignment --- include/grpcpp/impl/codegen/server_interceptor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/grpcpp/impl/codegen/server_interceptor.h b/include/grpcpp/impl/codegen/server_interceptor.h index 5fb5df28b70..030c26a9b05 100644 --- a/include/grpcpp/impl/codegen/server_interceptor.h +++ b/include/grpcpp/impl/codegen/server_interceptor.h @@ -47,8 +47,8 @@ class ServerRpcInfo { ~ServerRpcInfo(){}; ServerRpcInfo(const ServerRpcInfo&) = delete; - ServerRpcInfo(ServerRpcInfo&&) = default; - ServerRpcInfo& operator=(ServerRpcInfo&&) = default; + ServerRpcInfo(ServerRpcInfo&&) = delete; + ServerRpcInfo& operator=(ServerRpcInfo&&) = delete; // Getter methods const char* method() { return method_; } From 47233225cafb2e9366e23fb4dd4bafee1005b0ef Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 6 Dec 2018 17:12:43 -0800 Subject: [PATCH 49/99] Split out the test service to separate library so that it can be reused --- CMakeLists.txt | 2 + Makefile | 5 + build.yaml | 4 + grpc.gyp | 2 + test/cpp/end2end/BUILD | 13 +++ .../end2end/health_service_end2end_test.cc | 75 +-------------- .../end2end/test_health_check_service_impl.cc | 96 +++++++++++++++++++ .../end2end/test_health_check_service_impl.h | 58 +++++++++++ .../generated/sources_and_headers.json | 6 ++ 9 files changed, 187 insertions(+), 74 deletions(-) create mode 100644 test/cpp/end2end/test_health_check_service_impl.cc create mode 100644 test/cpp/end2end/test_health_check_service_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1194d0072e3..6b02d778d1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4024,6 +4024,7 @@ add_library(grpc++_test_util ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h + test/cpp/end2end/test_health_check_service_impl.cc test/cpp/end2end/test_service_impl.cc test/cpp/util/byte_buffer_proto_helper.cc test/cpp/util/channel_trace_proto_helper.cc @@ -4224,6 +4225,7 @@ add_library(grpc++_test_util_unsecure ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h + test/cpp/end2end/test_health_check_service_impl.cc test/cpp/end2end/test_service_impl.cc test/cpp/util/byte_buffer_proto_helper.cc test/cpp/util/string_ref_helper.cc diff --git a/Makefile b/Makefile index 7dfce79c922..ed4e219f8b7 100644 --- a/Makefile +++ b/Makefile @@ -6439,6 +6439,7 @@ LIBGRPC++_TEST_UTIL_SRC = \ $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \ $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \ $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc \ + test/cpp/end2end/test_health_check_service_impl.cc \ test/cpp/end2end/test_service_impl.cc \ test/cpp/util/byte_buffer_proto_helper.cc \ test/cpp/util/channel_trace_proto_helper.cc \ @@ -6591,6 +6592,7 @@ ifneq ($(NO_DEPS),true) -include $(LIBGRPC++_TEST_UTIL_OBJS:.o=.dep) endif endif +$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_health_check_service_impl.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/channel_trace_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc @@ -6607,6 +6609,7 @@ LIBGRPC++_TEST_UTIL_UNSECURE_SRC = \ $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \ $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \ $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc \ + test/cpp/end2end/test_health_check_service_impl.cc \ test/cpp/end2end/test_service_impl.cc \ test/cpp/util/byte_buffer_proto_helper.cc \ test/cpp/util/string_ref_helper.cc \ @@ -6756,6 +6759,7 @@ ifneq ($(NO_DEPS),true) -include $(LIBGRPC++_TEST_UTIL_UNSECURE_OBJS:.o=.dep) endif endif +$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_health_check_service_impl.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/simple_messages.grpc.pb.cc @@ -25142,6 +25146,7 @@ test/core/tsi/alts/crypt/gsec_test_util.cc: $(OPENSSL_DEP) test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc: $(OPENSSL_DEP) test/core/util/reconnect_server.cc: $(OPENSSL_DEP) test/core/util/test_tcp_server.cc: $(OPENSSL_DEP) +test/cpp/end2end/test_health_check_service_impl.cc: $(OPENSSL_DEP) test/cpp/end2end/test_service_impl.cc: $(OPENSSL_DEP) test/cpp/interop/client.cc: $(OPENSSL_DEP) test/cpp/interop/client_helper.cc: $(OPENSSL_DEP) diff --git a/build.yaml b/build.yaml index 1e63933f555..af70be8459a 100644 --- a/build.yaml +++ b/build.yaml @@ -1755,6 +1755,7 @@ libs: build: private language: c++ headers: + - test/cpp/end2end/test_health_check_service_impl.h - test/cpp/end2end/test_service_impl.h - test/cpp/util/byte_buffer_proto_helper.h - test/cpp/util/channel_trace_proto_helper.h @@ -1769,6 +1770,7 @@ libs: - src/proto/grpc/testing/echo.proto - src/proto/grpc/testing/duplicate/echo_duplicate.proto - src/proto/grpc/testing/simple_messages.proto + - test/cpp/end2end/test_health_check_service_impl.cc - test/cpp/end2end/test_service_impl.cc - test/cpp/util/byte_buffer_proto_helper.cc - test/cpp/util/channel_trace_proto_helper.cc @@ -1789,6 +1791,7 @@ libs: build: private language: c++ headers: + - test/cpp/end2end/test_health_check_service_impl.h - test/cpp/end2end/test_service_impl.h - test/cpp/util/byte_buffer_proto_helper.h - test/cpp/util/string_ref_helper.h @@ -1799,6 +1802,7 @@ libs: - src/proto/grpc/testing/echo.proto - src/proto/grpc/testing/duplicate/echo_duplicate.proto - src/proto/grpc/testing/simple_messages.proto + - test/cpp/end2end/test_health_check_service_impl.cc - test/cpp/end2end/test_service_impl.cc - test/cpp/util/byte_buffer_proto_helper.cc - test/cpp/util/string_ref_helper.cc diff --git a/grpc.gyp b/grpc.gyp index 2b841354baf..564922ff727 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -1498,6 +1498,7 @@ 'src/proto/grpc/testing/echo.proto', 'src/proto/grpc/testing/duplicate/echo_duplicate.proto', 'src/proto/grpc/testing/simple_messages.proto', + 'test/cpp/end2end/test_health_check_service_impl.cc', 'test/cpp/end2end/test_service_impl.cc', 'test/cpp/util/byte_buffer_proto_helper.cc', 'test/cpp/util/channel_trace_proto_helper.cc', @@ -1522,6 +1523,7 @@ 'src/proto/grpc/testing/echo.proto', 'src/proto/grpc/testing/duplicate/echo_duplicate.proto', 'src/proto/grpc/testing/simple_messages.proto', + 'test/cpp/end2end/test_health_check_service_impl.cc', 'test/cpp/end2end/test_service_impl.cc', 'test/cpp/util/byte_buffer_proto_helper.cc', 'test/cpp/util/string_ref_helper.cc', diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD index 446804401a7..eb600ffb172 100644 --- a/test/cpp/end2end/BUILD +++ b/test/cpp/end2end/BUILD @@ -35,6 +35,18 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "test_health_check_service_impl", + testonly = True, + srcs = ["test_health_check_service_impl.cc"], + hdrs = ["test_health_check_service_impl.h"], + deps = [ + "//:grpc", + "//:grpc++", + "//src/proto/grpc/health/v1:health_proto", + ], +) + grpc_cc_library( name = "interceptors_util", testonly = True, @@ -283,6 +295,7 @@ grpc_cc_test( "gtest", ], deps = [ + ":test_health_check_service_impl", ":test_service_impl", "//:gpr", "//:grpc", diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc index a439d42b031..94c92327c87 100644 --- a/test/cpp/end2end/health_service_end2end_test.cc +++ b/test/cpp/end2end/health_service_end2end_test.cc @@ -37,6 +37,7 @@ #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" +#include "test/cpp/end2end/test_health_check_service_impl.h" #include "test/cpp/end2end/test_service_impl.h" #include @@ -49,80 +50,6 @@ namespace grpc { namespace testing { namespace { -// A sample sync implementation of the health checking service. This does the -// same thing as the default one. -class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service { - public: - Status Check(ServerContext* context, const HealthCheckRequest* request, - HealthCheckResponse* response) override { - std::lock_guard lock(mu_); - auto iter = status_map_.find(request->service()); - if (iter == status_map_.end()) { - return Status(StatusCode::NOT_FOUND, ""); - } - response->set_status(iter->second); - return Status::OK; - } - - Status Watch(ServerContext* context, const HealthCheckRequest* request, - ::grpc::ServerWriter* writer) override { - auto last_state = HealthCheckResponse::UNKNOWN; - while (!context->IsCancelled()) { - { - std::lock_guard lock(mu_); - HealthCheckResponse response; - auto iter = status_map_.find(request->service()); - if (iter == status_map_.end()) { - response.set_status(response.SERVICE_UNKNOWN); - } else { - response.set_status(iter->second); - } - if (response.status() != last_state) { - writer->Write(response, ::grpc::WriteOptions()); - } - } - gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis(1000, GPR_TIMESPAN))); - } - return Status::OK; - } - - void SetStatus(const grpc::string& service_name, - HealthCheckResponse::ServingStatus status) { - std::lock_guard lock(mu_); - if (shutdown_) { - return; - } - status_map_[service_name] = status; - } - - void SetAll(HealthCheckResponse::ServingStatus status) { - std::lock_guard lock(mu_); - if (shutdown_) { - return; - } - for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) { - iter->second = status; - } - } - - void Shutdown() { - std::lock_guard lock(mu_); - if (shutdown_) { - return; - } - shutdown_ = true; - for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) { - iter->second = HealthCheckResponse::NOT_SERVING; - } - } - - private: - std::mutex mu_; - bool shutdown_ = false; - std::map status_map_; -}; - // A custom implementation of the health checking service interface. This is // used to test that it prevents the server from creating a default service and // also serves as an example of how to override the default service. diff --git a/test/cpp/end2end/test_health_check_service_impl.cc b/test/cpp/end2end/test_health_check_service_impl.cc new file mode 100644 index 00000000000..fa70a44d24f --- /dev/null +++ b/test/cpp/end2end/test_health_check_service_impl.cc @@ -0,0 +1,96 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "test/cpp/end2end/test_health_check_service_impl.h" + +#include + +using grpc::health::v1::HealthCheckRequest; +using grpc::health::v1::HealthCheckResponse; + +namespace grpc { +namespace testing { + +Status HealthCheckServiceImpl::Check(ServerContext* context, + const HealthCheckRequest* request, + HealthCheckResponse* response) { + std::lock_guard lock(mu_); + auto iter = status_map_.find(request->service()); + if (iter == status_map_.end()) { + return Status(StatusCode::NOT_FOUND, ""); + } + response->set_status(iter->second); + return Status::OK; +} +Status HealthCheckServiceImpl::Watch( + ServerContext* context, const HealthCheckRequest* request, + ::grpc::ServerWriter* writer) { + auto last_state = HealthCheckResponse::UNKNOWN; + while (!context->IsCancelled()) { + { + std::lock_guard lock(mu_); + HealthCheckResponse response; + auto iter = status_map_.find(request->service()); + if (iter == status_map_.end()) { + response.set_status(response.SERVICE_UNKNOWN); + } else { + response.set_status(iter->second); + } + if (response.status() != last_state) { + writer->Write(response, ::grpc::WriteOptions()); + } + } + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis(1000, GPR_TIMESPAN))); + } + return Status::OK; +} + +void HealthCheckServiceImpl::SetStatus( + const grpc::string& service_name, + HealthCheckResponse::ServingStatus status) { + std::lock_guard lock(mu_); + if (shutdown_) { + return; + } + status_map_[service_name] = status; +} + +void HealthCheckServiceImpl::SetAll(HealthCheckResponse::ServingStatus status) { + std::lock_guard lock(mu_); + if (shutdown_) { + return; + } + for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) { + iter->second = status; + } +} + +void HealthCheckServiceImpl::Shutdown() { + std::lock_guard lock(mu_); + if (shutdown_) { + return; + } + shutdown_ = true; + for (auto iter = status_map_.begin(); iter != status_map_.end(); ++iter) { + iter->second = HealthCheckResponse::NOT_SERVING; + } +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/end2end/test_health_check_service_impl.h b/test/cpp/end2end/test_health_check_service_impl.h new file mode 100644 index 00000000000..5d36ce5320a --- /dev/null +++ b/test/cpp/end2end/test_health_check_service_impl.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef GRPC_TEST_CPP_END2END_TEST_HEALTH_CHECK_SERVICE_IMPL_H +#define GRPC_TEST_CPP_END2END_TEST_HEALTH_CHECK_SERVICE_IMPL_H + +#include +#include + +#include +#include + +#include "src/proto/grpc/health/v1/health.grpc.pb.h" + +namespace grpc { +namespace testing { + +// A sample sync implementation of the health checking service. This does the +// same thing as the default one. +class HealthCheckServiceImpl : public health::v1::Health::Service { + public: + Status Check(ServerContext* context, + const health::v1::HealthCheckRequest* request, + health::v1::HealthCheckResponse* response) override; + Status Watch(ServerContext* context, + const health::v1::HealthCheckRequest* request, + ServerWriter* writer) override; + void SetStatus(const grpc::string& service_name, + health::v1::HealthCheckResponse::ServingStatus status); + void SetAll(health::v1::HealthCheckResponse::ServingStatus status); + + void Shutdown(); + + private: + std::mutex mu_; + bool shutdown_ = false; + std::map + status_map_; +}; + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_END2END_TEST_HEALTH_CHECK_SERVICE_IMPL_H diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index a7231554e3d..0a7a4daf7de 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -7447,6 +7447,7 @@ "src/proto/grpc/testing/simple_messages.grpc.pb.h", "src/proto/grpc/testing/simple_messages.pb.h", "src/proto/grpc/testing/simple_messages_mock.grpc.pb.h", + "test/cpp/end2end/test_health_check_service_impl.h", "test/cpp/end2end/test_service_impl.h", "test/cpp/util/byte_buffer_proto_helper.h", "test/cpp/util/channel_trace_proto_helper.h", @@ -7459,6 +7460,8 @@ "language": "c++", "name": "grpc++_test_util", "src": [ + "test/cpp/end2end/test_health_check_service_impl.cc", + "test/cpp/end2end/test_health_check_service_impl.h", "test/cpp/end2end/test_service_impl.cc", "test/cpp/end2end/test_service_impl.h", "test/cpp/util/byte_buffer_proto_helper.cc", @@ -7503,6 +7506,7 @@ "src/proto/grpc/testing/simple_messages.grpc.pb.h", "src/proto/grpc/testing/simple_messages.pb.h", "src/proto/grpc/testing/simple_messages_mock.grpc.pb.h", + "test/cpp/end2end/test_health_check_service_impl.h", "test/cpp/end2end/test_service_impl.h", "test/cpp/util/byte_buffer_proto_helper.h", "test/cpp/util/string_ref_helper.h", @@ -7512,6 +7516,8 @@ "language": "c++", "name": "grpc++_test_util_unsecure", "src": [ + "test/cpp/end2end/test_health_check_service_impl.cc", + "test/cpp/end2end/test_health_check_service_impl.h", "test/cpp/end2end/test_service_impl.cc", "test/cpp/end2end/test_service_impl.h", "test/cpp/util/byte_buffer_proto_helper.cc", From a6a21d1c64b610805c42ca2218d6d95313cb5329 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Dec 2018 08:38:29 -0800 Subject: [PATCH 50/99] more code review changes --- test/cpp/end2end/client_lb_end2end_test.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index f60f110c5ff..40b657f1053 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -522,13 +522,15 @@ TEST_F(ClientLbEnd2endTest, EXPECT_FALSE( channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); // Reset connection backoff. + // Note that the time at which the third attempt will be started is + // actually computed at this point, so we record the start time here. gpr_log(GPR_INFO, "=== RESETTING BACKOFF"); + const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC); experimental::ChannelResetConnectionBackoff(channel.get()); // Trigger a second connection attempt. This should also fail // ~immediately, but the retry should be scheduled for // kInitialBackOffMs instead of applying the multiplier. gpr_log(GPR_INFO, "=== POLLING FOR SECOND CONNECTION ATTEMPT"); - const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC); EXPECT_FALSE( channel->WaitForConnected(grpc_timeout_milliseconds_to_deadline(10))); // Bring up a server on the chosen port. From 2246607dedfbad98c3aa4f39997907a203985863 Mon Sep 17 00:00:00 2001 From: yang-g Date: Fri, 7 Dec 2018 08:54:47 -0800 Subject: [PATCH 51/99] Review comments --- .../health/default_health_check_service.cc | 3 ++- .../end2end/health_service_end2end_test.cc | 19 +++++++++++-------- .../end2end/test_health_check_service_impl.cc | 3 ++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc index db6286d240e..44aebd2f9d9 100644 --- a/src/cpp/server/health/default_health_check_service.cc +++ b/src/cpp/server/health/default_health_check_service.cc @@ -43,7 +43,8 @@ void DefaultHealthCheckService::SetServingStatus( const grpc::string& service_name, bool serving) { std::unique_lock lock(mu_); if (shutdown_) { - return; + // Set to NOT_SERVING in case service_name is not in the map. + serving = false; } services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING); } diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc index 94c92327c87..b96ff53a3ea 100644 --- a/test/cpp/end2end/health_service_end2end_test.cc +++ b/test/cpp/end2end/health_service_end2end_test.cc @@ -211,14 +211,16 @@ class HealthServiceEnd2endTest : public ::testing::Test { // 1. unary client will see NOT_SERVING. // 2. unary client still sees NOT_SERVING after a SetServing(true) is called. // 3. streaming (Watch) client will see an update. + // 4. setting a new service to serving after shutdown will add the service + // name but return NOT_SERVING to client. // This has to be called last. void VerifyHealthCheckServiceShutdown() { - const grpc::string kServiceName("service_name"); HealthCheckServiceInterface* service = server_->GetHealthCheckService(); EXPECT_TRUE(service != nullptr); const grpc::string kHealthyService("healthy_service"); const grpc::string kUnhealthyService("unhealthy_service"); const grpc::string kNotRegisteredService("not_registered"); + const grpc::string kNewService("add_after_shutdown"); service->SetServingStatus(kHealthyService, true); service->SetServingStatus(kUnhealthyService, false); @@ -227,18 +229,12 @@ class HealthServiceEnd2endTest : public ::testing::Test { // Start Watch for service. ClientContext context; HealthCheckRequest request; - request.set_service(kServiceName); + request.set_service(kHealthyService); std::unique_ptr<::grpc::ClientReaderInterface> reader = hc_stub_->Watch(&context, request); - // Initial response will be SERVICE_UNKNOWN. HealthCheckResponse response; EXPECT_TRUE(reader->Read(&response)); - EXPECT_EQ(response.SERVICE_UNKNOWN, response.status()); - - // Set service to SERVING and make sure we get an update. - service->SetServingStatus(kServiceName, true); - EXPECT_TRUE(reader->Read(&response)); EXPECT_EQ(response.SERVING, response.status()); SendHealthCheckRpc("", Status::OK, HealthCheckResponse::SERVING); @@ -248,6 +244,7 @@ class HealthServiceEnd2endTest : public ::testing::Test { HealthCheckResponse::NOT_SERVING); SendHealthCheckRpc(kNotRegisteredService, Status(StatusCode::NOT_FOUND, "")); + SendHealthCheckRpc(kNewService, Status(StatusCode::NOT_FOUND, "")); // Shutdown health check service. service->Shutdown(); @@ -270,6 +267,12 @@ class HealthServiceEnd2endTest : public ::testing::Test { service->SetServingStatus(kHealthyService, true); SendHealthCheckRpc(kHealthyService, Status::OK, HealthCheckResponse::NOT_SERVING); + + // Adding serving status for a new service after shutdown will return + // NOT_SERVING. + service->SetServingStatus(kNewService, true); + SendHealthCheckRpc(kNewService, Status::OK, + HealthCheckResponse::NOT_SERVING); } TestServiceImpl echo_test_service_; diff --git a/test/cpp/end2end/test_health_check_service_impl.cc b/test/cpp/end2end/test_health_check_service_impl.cc index fa70a44d24f..0801e301996 100644 --- a/test/cpp/end2end/test_health_check_service_impl.cc +++ b/test/cpp/end2end/test_health_check_service_impl.cc @@ -37,6 +37,7 @@ Status HealthCheckServiceImpl::Check(ServerContext* context, response->set_status(iter->second); return Status::OK; } + Status HealthCheckServiceImpl::Watch( ServerContext* context, const HealthCheckRequest* request, ::grpc::ServerWriter* writer) { @@ -66,7 +67,7 @@ void HealthCheckServiceImpl::SetStatus( HealthCheckResponse::ServingStatus status) { std::lock_guard lock(mu_); if (shutdown_) { - return; + status = HealthCheckResponse::NOT_SERVING; } status_map_[service_name] = status; } From c5528b821b80f14f49d3a2857b12aecad0c6f009 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Dec 2018 09:24:51 -0800 Subject: [PATCH 52/99] Remove unnecessary initialization of fields in PickState. --- src/core/ext/filters/client_channel/client_channel.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 3347676a48f..ebc412b468d 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -570,12 +570,6 @@ static void start_transport_op_locked(void* arg, grpc_error* error_ignored) { } else { grpc_error* error = GRPC_ERROR_NONE; grpc_core::LoadBalancingPolicy::PickState pick_state; - pick_state.initial_metadata = nullptr; - pick_state.initial_metadata_flags = 0; - pick_state.on_complete = nullptr; - memset(&pick_state.subchannel_call_context, 0, - sizeof(pick_state.subchannel_call_context)); - pick_state.user_data = nullptr; // Pick must return synchronously, because pick_state.on_complete is null. GPR_ASSERT(chand->lb_policy->PickLocked(&pick_state, &error)); if (pick_state.connected_subchannel != nullptr) { From 87b1c3ce56363a557f2874ab94b8af516e8ae532 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 7 Dec 2018 10:11:30 -0800 Subject: [PATCH 53/99] reviewer feedback --- .../ext/filters/client_channel/connector.h | 4 ++-- .../ext/filters/client_channel/subchannel.cc | 4 +--- .../chttp2/client/chttp2_connector.cc | 3 ++- .../chttp2/transport/chttp2_transport.cc | 6 +++--- .../chttp2/transport/chttp2_transport.h | 4 ++-- src/core/lib/surface/server.cc | 20 ++++++++++--------- src/core/lib/surface/server.h | 10 +++++----- test/core/end2end/tests/channelz.cc | 2 +- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h index 484cc1b3c39..a5ef9bc2555 100644 --- a/src/core/ext/filters/client_channel/connector.h +++ b/src/core/ext/filters/client_channel/connector.h @@ -49,8 +49,8 @@ typedef struct { /** channel arguments (to be passed to the filters) */ grpc_channel_args* channel_args; - /** socket node of the connected transport */ - grpc_core::channelz::SocketNode* socket_node; + /** socket node of the connected transport. 0 if not availible */ + intptr_t socket_uuid; } grpc_connect_out_args; struct grpc_connector_vtable { diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index e66b0711cf9..0817b1dd392 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -826,9 +826,7 @@ static bool publish_transport_locked(grpc_subchannel* c) { GRPC_ERROR_UNREF(error); return false; } - intptr_t socket_uuid = c->connecting_result.socket_node == nullptr - ? 0 - : c->connecting_result.socket_node->uuid(); + intptr_t socket_uuid = c->connecting_result.socket_uuid; memset(&c->connecting_result, 0, sizeof(c->connecting_result)); if (c->disconnected) { diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index 62a07d2ba61..42a2e2e896c 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -117,8 +117,9 @@ static void on_handshake_done(void* arg, grpc_error* error) { c->args.interested_parties); c->result->transport = grpc_create_chttp2_transport(args->args, args->endpoint, true); - c->result->socket_node = + grpc_core::RefCountedPtr socket_node = grpc_chttp2_transport_get_socket_node(c->result->transport); + c->result->socket_uuid = socket_node == nullptr ? 0 : socket_node->uuid(); GPR_ASSERT(c->result->transport); // TODO(roth): We ideally want to wait until we receive HTTP/2 // settings from the server before we consider the connection diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 73e43131a0a..9b6574b612d 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -3145,11 +3145,11 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), static const grpc_transport_vtable* get_vtable(void) { return &vtable; } -grpc_core::channelz::SocketNode* grpc_chttp2_transport_get_socket_node( - grpc_transport* transport) { +grpc_core::RefCountedPtr +grpc_chttp2_transport_get_socket_node(grpc_transport* transport) { grpc_chttp2_transport* t = reinterpret_cast(transport); - return t->channelz_socket.get(); + return t->channelz_socket; } grpc_transport* grpc_create_chttp2_transport( diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h index b9929b1662e..c22cfb0ad7d 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h @@ -36,8 +36,8 @@ grpc_transport* grpc_create_chttp2_transport( const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client, grpc_resource_user* resource_user = nullptr); -grpc_core::channelz::SocketNode* grpc_chttp2_transport_get_socket_node( - grpc_transport* transport); +grpc_core::RefCountedPtr +grpc_chttp2_transport_get_socket_node(grpc_transport* transport); /// Takes ownership of \a read_buffer, which (if non-NULL) contains /// leftover bytes previously read from the endpoint (e.g., by handshakers). diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 4c63b6bc394..e257caa8f91 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -109,7 +109,7 @@ struct channel_data { uint32_t registered_method_max_probes; grpc_closure finish_destroy_channel_closure; grpc_closure channel_connectivity_changed; - grpc_core::channelz::SocketNode* socket_node; + grpc_core::RefCountedPtr socket_node; }; typedef struct shutdown_tag { @@ -462,6 +462,9 @@ static 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"); + if (chand->socket_node != nullptr) { + chand->socket_node->Unref(); + } server_unref(server); } @@ -1155,11 +1158,11 @@ void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets, *pollsets = server->pollsets; } -void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport, - grpc_pollset* accepting_pollset, - const grpc_channel_args* args, - grpc_core::channelz::SocketNode* socket_node, - grpc_resource_user* resource_user) { +void grpc_server_setup_transport( + grpc_server* s, grpc_transport* transport, grpc_pollset* accepting_pollset, + const grpc_channel_args* args, + grpc_core::RefCountedPtr socket_node, + grpc_resource_user* resource_user) { size_t num_registered_methods; size_t alloc; registered_method* rm; @@ -1261,9 +1264,8 @@ void grpc_server_populate_server_sockets( gpr_mu_lock(&s->mu_global); channel_data* c = nullptr; for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { - grpc_core::channelz::SocketNode* socket_node = c->socket_node; - if (socket_node && socket_node->uuid() >= start_idx) { - server_sockets->push_back(socket_node); + if (c->socket_node != nullptr && c->socket_node->uuid() >= start_idx) { + server_sockets->push_back(c->socket_node.get()); } } gpr_mu_unlock(&s->mu_global); diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index 8e8903d76b3..393bb242148 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -44,11 +44,11 @@ void grpc_server_add_listener(grpc_server* server, void* listener, /* 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, - grpc_core::channelz::SocketNode* socket_node, - grpc_resource_user* resource_user = nullptr); +void grpc_server_setup_transport( + grpc_server* server, grpc_transport* transport, + grpc_pollset* accepting_pollset, const grpc_channel_args* args, + grpc_core::RefCountedPtr socket_node, + grpc_resource_user* resource_user = nullptr); /* fills in the uuids of all sockets used for connections on this server */ void grpc_server_populate_server_sockets( diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 922783aa0d0..49a0bc80112 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -260,7 +260,7 @@ static void test_channelz(grpc_end2end_test_config config) { gpr_free(json); json = channelz_server->RenderServerSockets(0); - GPR_ASSERT(nullptr != strstr(json, "\"socketRef\":")); + GPR_ASSERT(nullptr != strstr(json, "\"end\":true")); gpr_free(json); end_test(&f); From e95d1185e9c594d9df172a9e5be37dc9720c0e10 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Tue, 4 Dec 2018 15:40:34 -0800 Subject: [PATCH 54/99] Add grpc-java 1.17.1 to interop matrix --- tools/interop_matrix/client_matrix.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index ff3344cd95d..931beddb9cf 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -207,6 +207,9 @@ LANG_RELEASE_MATRIX = { { 'v1.16.1': None }, + { + 'v1.17.1': None + }, ], 'python': [ { From 83c6640e926b3e623e4a290fd779bc7f70a90129 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 7 Dec 2018 11:03:28 -0800 Subject: [PATCH 55/99] Allow the health checking service --- test/cpp/end2end/server_interceptors_end2end_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/cpp/end2end/server_interceptors_end2end_test.cc b/test/cpp/end2end/server_interceptors_end2end_test.cc index 1e0e3668707..9460a7d6c64 100644 --- a/test/cpp/end2end/server_interceptors_end2end_test.cc +++ b/test/cpp/end2end/server_interceptors_end2end_test.cc @@ -52,11 +52,13 @@ class LoggingInterceptor : public experimental::Interceptor { experimental::ServerRpcInfo::Type type = info->type(); // Check that we use one of our standard methods with expected type. + // Also allow the health checking service. // We accept BIDI_STREAMING for Echo in case it's an AsyncGenericService // being tested (the GenericRpc test). // The empty method is for the Unimplemented requests that arise // when draining the CQ. EXPECT_TRUE( + strstr(method, "/grpc.health") == method || (strcmp(method, "/grpc.testing.EchoTestService/Echo") == 0 && (type == experimental::ServerRpcInfo::Type::UNARY || type == experimental::ServerRpcInfo::Type::BIDI_STREAMING)) || From 12192bed323cacc5e59a5fca89da2a1ec66816a5 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 7 Dec 2018 12:01:16 -0800 Subject: [PATCH 56/99] reviewer feedback --- src/core/ext/filters/client_channel/connector.h | 3 +-- src/core/lib/surface/server.cc | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h index a5ef9bc2555..ea34dcdab57 100644 --- a/src/core/ext/filters/client_channel/connector.h +++ b/src/core/ext/filters/client_channel/connector.h @@ -22,7 +22,6 @@ #include #include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/channel/channelz.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/transport/transport.h" @@ -49,7 +48,7 @@ typedef struct { /** channel arguments (to be passed to the filters) */ grpc_channel_args* channel_args; - /** socket node of the connected transport. 0 if not availible */ + /** socket uuid of the connected transport. 0 if not available */ intptr_t socket_uuid; } grpc_connect_out_args; diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index e257caa8f91..44e938ad775 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -462,9 +462,7 @@ static 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"); - if (chand->socket_node != nullptr) { - chand->socket_node->Unref(); - } + chand->socket_node.reset(); server_unref(server); } From b5f4b4f1303578415bb7d87c6c6c26918fcf3a59 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 7 Dec 2018 12:09:32 -0800 Subject: [PATCH 57/99] Move the unref --- src/core/lib/surface/server.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 44e938ad775..5f7f630d16d 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -462,7 +462,6 @@ static 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"); - chand->socket_node.reset(); server_unref(server); } @@ -951,6 +950,7 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem, static void destroy_channel_elem(grpc_channel_element* elem) { size_t i; channel_data* chand = static_cast(elem->channel_data); + chand->socket_node.reset(); if (chand->registered_methods) { for (i = 0; i < chand->registered_method_slots; i++) { grpc_slice_unref_internal(chand->registered_methods[i].method); From dedff37b4f569e888836b0cf92a9d6de2ddec326 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Dec 2018 12:41:51 -0800 Subject: [PATCH 58/99] Allow encoding arbitrary channel args on a per-address basis. --- BUILD | 3 +- CMakeLists.txt | 12 +- Makefile | 12 +- build.yaml | 3 +- config.m4 | 2 +- config.w32 | 2 +- gRPC-C++.podspec | 1 + gRPC-Core.podspec | 4 +- grpc.gemspec | 3 +- grpc.gyp | 8 +- package.xml | 3 +- .../filters/client_channel/client_channel.cc | 16 +- .../ext/filters/client_channel/lb_policy.h | 9 +- .../client_channel/lb_policy/grpclb/grpclb.cc | 242 +++++++---------- .../lb_policy/grpclb/grpclb_channel.h | 2 +- .../lb_policy/grpclb/grpclb_channel_secure.cc | 33 +-- .../lb_policy/grpclb/load_balancer_api.h | 2 +- .../lb_policy/pick_first/pick_first.cc | 19 +- .../lb_policy/round_robin/round_robin.cc | 40 +-- .../lb_policy/subchannel_list.h | 53 ++-- .../client_channel/lb_policy/xds/xds.cc | 247 +++++------------- .../lb_policy/xds/xds_channel.h | 2 +- .../lb_policy/xds/xds_channel_secure.cc | 33 +-- .../lb_policy/xds/xds_load_balancer_api.h | 2 +- .../client_channel/lb_policy_factory.cc | 163 ------------ .../client_channel/lb_policy_factory.h | 86 +----- .../resolver/dns/c_ares/dns_resolver_ares.cc | 12 +- .../dns/c_ares/grpc_ares_ev_driver.cc | 1 + .../resolver/dns/c_ares/grpc_ares_wrapper.cc | 149 +++++------ .../resolver/dns/c_ares/grpc_ares_wrapper.h | 13 +- .../dns/c_ares/grpc_ares_wrapper_fallback.cc | 9 +- .../dns/c_ares/grpc_ares_wrapper_posix.cc | 3 +- .../dns/c_ares/grpc_ares_wrapper_windows.cc | 26 +- .../resolver/dns/native/dns_resolver.cc | 14 +- .../resolver/fake/fake_resolver.cc | 3 +- .../resolver/fake/fake_resolver.h | 3 +- .../resolver/sockaddr/sockaddr_resolver.cc | 34 +-- .../client_channel/resolver_result_parsing.cc | 20 +- .../filters/client_channel/server_address.cc | 103 ++++++++ .../filters/client_channel/server_address.h | 108 ++++++++ .../ext/filters/client_channel/subchannel.cc | 6 +- .../ext/filters/client_channel/subchannel.h | 13 +- src/core/lib/iomgr/sockaddr_utils.cc | 1 + src/python/grpcio/grpc_core_dependencies.py | 2 +- .../dns_resolver_connectivity_test.cc | 12 +- .../resolvers/dns_resolver_cooldown_test.cc | 15 +- .../resolvers/fake_resolver_test.cc | 42 +-- test/core/end2end/fuzzers/api_fuzzer.cc | 28 +- test/core/end2end/goaway_server_test.cc | 29 +- test/core/end2end/no_server_test.cc | 1 + test/core/util/ubsan_suppressions.txt | 3 +- test/cpp/client/client_channel_stress_test.cc | 28 +- test/cpp/end2end/client_lb_end2end_test.cc | 18 +- test/cpp/end2end/grpclb_end2end_test.cc | 37 ++- test/cpp/naming/address_sorting_test.cc | 127 +++++---- test/cpp/naming/resolver_component_test.cc | 21 +- tools/doxygen/Doxyfile.core.internal | 3 +- .../generated/sources_and_headers.json | 4 +- 58 files changed, 846 insertions(+), 1044 deletions(-) delete mode 100644 src/core/ext/filters/client_channel/lb_policy_factory.cc create mode 100644 src/core/ext/filters/client_channel/server_address.cc create mode 100644 src/core/ext/filters/client_channel/server_address.h diff --git a/BUILD b/BUILD index 9e3e594038d..5550e583a87 100644 --- a/BUILD +++ b/BUILD @@ -1048,7 +1048,6 @@ grpc_cc_library( "src/core/ext/filters/client_channel/http_connect_handshaker.cc", "src/core/ext/filters/client_channel/http_proxy.cc", "src/core/ext/filters/client_channel/lb_policy.cc", - "src/core/ext/filters/client_channel/lb_policy_factory.cc", "src/core/ext/filters/client_channel/lb_policy_registry.cc", "src/core/ext/filters/client_channel/parse_address.cc", "src/core/ext/filters/client_channel/proxy_mapper.cc", @@ -1057,6 +1056,7 @@ grpc_cc_library( "src/core/ext/filters/client_channel/resolver_registry.cc", "src/core/ext/filters/client_channel/resolver_result_parsing.cc", "src/core/ext/filters/client_channel/retry_throttle.cc", + "src/core/ext/filters/client_channel/server_address.cc", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel_index.cc", ], @@ -1080,6 +1080,7 @@ grpc_cc_library( "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.h", + "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h", ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 1194d0072e3..084ddfde0e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1240,7 +1240,6 @@ add_library(grpc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1249,6 +1248,7 @@ add_library(grpc src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -1592,7 +1592,6 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1601,6 +1600,7 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -1963,7 +1963,6 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1972,6 +1971,7 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -2283,7 +2283,6 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -2292,6 +2291,7 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -2617,7 +2617,6 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -2626,6 +2625,7 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -3469,7 +3469,6 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -3478,6 +3477,7 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc diff --git a/Makefile b/Makefile index 7dfce79c922..cdddf49d1ee 100644 --- a/Makefile +++ b/Makefile @@ -3735,7 +3735,6 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -3744,6 +3743,7 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4081,7 +4081,6 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4090,6 +4089,7 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4445,7 +4445,6 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4454,6 +4453,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4751,7 +4751,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4760,6 +4759,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -5058,7 +5058,6 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -5067,6 +5066,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -5885,7 +5885,6 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -5894,6 +5893,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ diff --git a/build.yaml b/build.yaml index 1e63933f555..4dd08e0425f 100644 --- a/build.yaml +++ b/build.yaml @@ -589,6 +589,7 @@ filegroups: - src/core/ext/filters/client_channel/resolver_registry.h - src/core/ext/filters/client_channel/resolver_result_parsing.h - src/core/ext/filters/client_channel/retry_throttle.h + - src/core/ext/filters/client_channel/server_address.h - src/core/ext/filters/client_channel/subchannel.h - src/core/ext/filters/client_channel/subchannel_index.h src: @@ -603,7 +604,6 @@ filegroups: - src/core/ext/filters/client_channel/http_connect_handshaker.cc - src/core/ext/filters/client_channel/http_proxy.cc - src/core/ext/filters/client_channel/lb_policy.cc - - src/core/ext/filters/client_channel/lb_policy_factory.cc - src/core/ext/filters/client_channel/lb_policy_registry.cc - src/core/ext/filters/client_channel/parse_address.cc - src/core/ext/filters/client_channel/proxy_mapper.cc @@ -612,6 +612,7 @@ filegroups: - src/core/ext/filters/client_channel/resolver_registry.cc - src/core/ext/filters/client_channel/resolver_result_parsing.cc - src/core/ext/filters/client_channel/retry_throttle.cc + - src/core/ext/filters/client_channel/server_address.cc - src/core/ext/filters/client_channel/subchannel.cc - src/core/ext/filters/client_channel/subchannel_index.cc plugin: grpc_client_channel diff --git a/config.m4 b/config.m4 index 3db660aceea..16de5204bb2 100644 --- a/config.m4 +++ b/config.m4 @@ -348,7 +348,6 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -357,6 +356,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ diff --git a/config.w32 b/config.w32 index 7f8b6eee5fa..be10faab9cd 100644 --- a/config.w32 +++ b/config.w32 @@ -323,7 +323,6 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " + "src\\core\\ext\\filters\\client_channel\\http_proxy.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy.cc " + - "src\\core\\ext\\filters\\client_channel\\lb_policy_factory.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy_registry.cc " + "src\\core\\ext\\filters\\client_channel\\parse_address.cc " + "src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " + @@ -332,6 +331,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " + "src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " + "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " + + "src\\core\\ext\\filters\\client_channel\\server_address.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " + "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index e939bead1b7..30fcb51ee19 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -356,6 +356,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', + 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 1d4e1ae35c0..5ab7a49cd27 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -354,6 +354,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', + 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', @@ -786,7 +787,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -795,6 +795,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -974,6 +975,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', + 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', diff --git a/grpc.gemspec b/grpc.gemspec index 92b1e0be689..1ee7bec8e7d 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -290,6 +290,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h ) s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h ) s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h ) + s.files += %w( src/core/ext/filters/client_channel/server_address.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.h ) @@ -725,7 +726,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc ) - s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.cc ) s.files += %w( src/core/ext/filters/client_channel/parse_address.cc ) s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc ) @@ -734,6 +734,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc ) + s.files += %w( src/core/ext/filters/client_channel/server_address.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc ) diff --git a/grpc.gyp b/grpc.gyp index 2b841354baf..d435eeadc78 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -540,7 +540,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -549,6 +548,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -799,7 +799,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -808,6 +807,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -1039,7 +1039,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -1048,6 +1047,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -1292,7 +1292,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -1301,6 +1300,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/package.xml b/package.xml index bdcb12bfc5e..68fc7433cb4 100644 --- a/package.xml +++ b/package.xml @@ -295,6 +295,7 @@ + @@ -730,7 +731,6 @@ - @@ -739,6 +739,7 @@ + diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index ebc412b468d..70aac472314 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -38,6 +38,7 @@ #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/resolver_result_parsing.h" #include "src/core/ext/filters/client_channel/retry_throttle.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/deadline/deadline_filter.h" #include "src/core/lib/backoff/backoff.h" @@ -62,6 +63,7 @@ #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/status_metadata.h" +using grpc_core::ServerAddressList; using grpc_core::internal::ClientChannelMethodParams; using grpc_core::internal::ClientChannelMethodParamsTable; using grpc_core::internal::ProcessedResolverResult; @@ -383,16 +385,10 @@ static void create_new_lb_policy_locked( static void maybe_add_trace_message_for_address_changes_locked( channel_data* chand, TraceStringVector* trace_strings) { - int resolution_contains_addresses = false; - const grpc_arg* channel_arg = - grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); - if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { - grpc_lb_addresses* addresses = - static_cast(channel_arg->value.pointer.p); - if (addresses->num_addresses > 0) { - resolution_contains_addresses = true; - } - } + const ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(chand->resolver_result); + const bool resolution_contains_addresses = + addresses != nullptr && addresses->size() > 0; if (!resolution_contains_addresses && chand->previous_resolution_contained_addresses) { trace_strings->push_back(gpr_strdup("Address list became empty")); diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index 7034da6249c..6b76fe5d5d7 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -55,7 +55,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { grpc_client_channel_factory* client_channel_factory = nullptr; /// Channel args from the resolver. /// Note that the LB policy gets the set of addresses from the - /// GRPC_ARG_LB_ADDRESSES channel arg. + /// GRPC_ARG_SERVER_ADDRESS_LIST channel arg. grpc_channel_args* args = nullptr; /// Load balancing config from the resolver. grpc_json* lb_config = nullptr; @@ -80,11 +80,6 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Will be populated with context to pass to the subchannel call, if /// needed. grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT] = {}; - /// Upon success, \a *user_data will be set to whatever opaque information - /// may need to be propagated from the LB policy, or nullptr if not needed. - // TODO(roth): As part of revamping our metadata APIs, try to find a - // way to clean this up and C++-ify it. - void** user_data = nullptr; /// Next pointer. For internal use by LB policy. PickState* next = nullptr; }; @@ -95,7 +90,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Updates the policy with a new set of \a args and a new \a lb_config from /// the resolver. Note that the LB policy gets the set of addresses from the - /// GRPC_ARG_LB_ADDRESSES channel arg. + /// GRPC_ARG_SERVER_ADDRESS_LIST channel arg. virtual void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) GRPC_ABSTRACT; diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index a46579c7f74..a9a5965ed1c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -84,6 +84,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" @@ -113,6 +114,8 @@ #define GRPC_GRPCLB_RECONNECT_JITTER 0.2 #define GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS 10000 +#define GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN "grpc.grpclb_address_lb_token" + namespace grpc_core { TraceFlag grpc_lb_glb_trace(false, "glb"); @@ -121,7 +124,7 @@ namespace { class GrpcLb : public LoadBalancingPolicy { public: - GrpcLb(const grpc_lb_addresses* addresses, const Args& args); + explicit GrpcLb(const Args& args); void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) override; @@ -161,9 +164,6 @@ class GrpcLb : public LoadBalancingPolicy { // Our on_complete closure and the original one. grpc_closure on_complete; grpc_closure* original_on_complete; - // The LB token associated with the pick. This is set via user_data in - // the pick. - grpc_mdelem lb_token; // Stats for client-side load reporting. RefCountedPtr client_stats; // Next pending pick. @@ -329,7 +329,7 @@ class GrpcLb : public LoadBalancingPolicy { // 0 means not using fallback. int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - grpc_lb_addresses* fallback_backend_addresses_ = nullptr; + UniquePtr fallback_backend_addresses_; // Fallback timer. bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; @@ -349,7 +349,7 @@ class GrpcLb : public LoadBalancingPolicy { // serverlist parsing code // -// vtable for LB tokens in grpc_lb_addresses +// vtable for LB token channel arg. void* lb_token_copy(void* token) { return token == nullptr ? nullptr @@ -361,38 +361,11 @@ void lb_token_destroy(void* token) { } } int lb_token_cmp(void* token1, void* token2) { - if (token1 > token2) return 1; - if (token1 < token2) return -1; - return 0; + return GPR_ICMP(token1, token2); } -const grpc_lb_user_data_vtable lb_token_vtable = { +const grpc_arg_pointer_vtable lb_token_arg_vtable = { lb_token_copy, lb_token_destroy, lb_token_cmp}; -// Returns the backend addresses extracted from the given addresses. -grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { - // First pass: count the number of backend addresses. - size_t num_backends = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) { - ++num_backends; - } - } - // Second pass: actually populate the addresses and (empty) LB tokens. - grpc_lb_addresses* backend_addresses = - grpc_lb_addresses_create(num_backends, &lb_token_vtable); - size_t num_copied = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) continue; - const grpc_resolved_address* addr = &addresses->addresses[i].address; - grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, - addr->len, false /* is_balancer */, - nullptr /* balancer_name */, - (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); - ++num_copied; - } - return backend_addresses; -} - bool IsServerValid(const grpc_grpclb_server* server, size_t idx, bool log) { if (server->drop) return false; const grpc_grpclb_ip_address* ip = &server->ip_address; @@ -440,30 +413,16 @@ void ParseServer(const grpc_grpclb_server* server, } // Returns addresses extracted from \a serverlist. -grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { - size_t num_valid = 0; - /* first pass: count how many are valid in order to allocate the necessary - * memory in a single block */ +ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { + ServerAddressList addresses; for (size_t i = 0; i < serverlist->num_servers; ++i) { - if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; - } - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_valid, &lb_token_vtable); - /* second pass: actually populate the addresses and LB tokens (aka user data - * to the outside world) to be read by the RR policy during its creation. - * Given that the validity tests are very cheap, they are performed again - * instead of marking the valid ones during the first pass, as this would - * incurr in an allocation due to the arbitrary number of server */ - size_t addr_idx = 0; - for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { - const grpc_grpclb_server* server = serverlist->servers[sl_idx]; - if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; - GPR_ASSERT(addr_idx < num_valid); - /* address processing */ + const grpc_grpclb_server* server = serverlist->servers[i]; + if (!IsServerValid(serverlist->servers[i], i, false)) continue; + // Address processing. grpc_resolved_address addr; ParseServer(server, &addr); - /* lb token processing */ - void* user_data; + // LB token processing. + void* lb_token; if (server->has_load_balance_token) { const size_t lb_token_max_length = GPR_ARRAY_SIZE(server->load_balance_token); @@ -471,7 +430,7 @@ grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { strnlen(server->load_balance_token, lb_token_max_length); grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( server->load_balance_token, lb_token_length); - user_data = + lb_token = (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) .payload; } else { @@ -481,15 +440,16 @@ grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { "be used instead", uri); gpr_free(uri); - user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; } - grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, - false /* is_balancer */, - nullptr /* balancer_name */, user_data); - ++addr_idx; - } - GPR_ASSERT(addr_idx == num_valid); - return lb_addresses; + // Add address. + grpc_arg arg = grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token, + &lb_token_arg_vtable); + grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); + addresses.emplace_back(addr, args); + } + return addresses; } // @@ -829,8 +789,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( grpc_grpclb_destroy_serverlist(grpclb_policy->serverlist_); } else { // Dispose of the fallback. - grpc_lb_addresses_destroy(grpclb_policy->fallback_backend_addresses_); - grpclb_policy->fallback_backend_addresses_ = nullptr; + grpclb_policy->fallback_backend_addresses_.reset(); if (grpclb_policy->fallback_timer_callback_pending_) { grpc_timer_cancel(&grpclb_policy->lb_fallback_timer_); } @@ -910,31 +869,25 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked( // helper code for creating balancer channel // -grpc_lb_addresses* ExtractBalancerAddresses( - const grpc_lb_addresses* addresses) { - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; - } - // There must be at least one balancer address, or else the - // client_channel would not have chosen this LB policy. - GPR_ASSERT(num_grpclb_addrs > 0); - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_grpclb_addrs, nullptr); - size_t lb_addresses_idx = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) continue; - if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); +ServerAddressList ExtractBalancerAddresses(const ServerAddressList& addresses) { + ServerAddressList balancer_addresses; + for (size_t i = 0; i < addresses.size(); ++i) { + if (addresses[i].IsBalancer()) { + // Strip out the is_balancer channel arg, since we don't want to + // recursively use the grpclb policy in the channel used to talk to + // the balancers. Note that we do NOT strip out the balancer_name + // channel arg, since we need that to set the authority correctly + // to talk to the balancers. + static const char* args_to_remove[] = { + GRPC_ARG_ADDRESS_IS_BALANCER, + }; + balancer_addresses.emplace_back( + addresses[i].address(), + grpc_channel_args_copy_and_remove(addresses[i].args(), args_to_remove, + GPR_ARRAY_SIZE(args_to_remove))); } - grpc_lb_addresses_set_address( - lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, - addresses->addresses[i].address.len, false /* is balancer */, - addresses->addresses[i].balancer_name, nullptr /* user data */); } - GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); - return lb_addresses; + return balancer_addresses; } /* Returns the channel args for the LB channel, used to create a bidirectional @@ -946,10 +899,10 @@ grpc_lb_addresses* ExtractBalancerAddresses( * above the grpclb policy. * - \a args: other args inherited from the grpclb policy. */ grpc_channel_args* BuildBalancerChannelArgs( - const grpc_lb_addresses* addresses, + const ServerAddressList& addresses, FakeResolverResponseGenerator* response_generator, const grpc_channel_args* args) { - grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); + ServerAddressList balancer_addresses = ExtractBalancerAddresses(addresses); // Channel args to remove. static const char* args_to_remove[] = { // LB policy name, since we want to use the default (pick_first) in @@ -967,7 +920,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // is_balancer=true. We need the LB channel to return addresses with // is_balancer=false so that it does not wind up recursively using the // grpclb LB policy, as per the special case logic in client_channel.c. - GRPC_ARG_LB_ADDRESSES, + GRPC_ARG_SERVER_ADDRESS_LIST, // The fake resolver response generator, because we are replacing it // with the one from the grpclb policy, used to propagate updates to // the LB channel. @@ -983,10 +936,10 @@ grpc_channel_args* BuildBalancerChannelArgs( }; // Channel args to add. const grpc_arg args_to_add[] = { - // New LB addresses. + // New address list. // Note that we pass these in both when creating the LB channel // and via the fake resolver. The latter is what actually gets used. - grpc_lb_addresses_create_channel_arg(lb_addresses), + CreateServerAddressListChannelArg(&balancer_addresses), // The fake resolver response generator, which we use to inject // address updates into the LB channel. grpc_core::FakeResolverResponseGenerator::MakeChannelArg( @@ -1004,18 +957,14 @@ grpc_channel_args* BuildBalancerChannelArgs( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Make any necessary modifications for security. - new_args = grpc_lb_policy_grpclb_modify_lb_channel_args(new_args); - // Clean up. - grpc_lb_addresses_destroy(lb_addresses); - return new_args; + return grpc_lb_policy_grpclb_modify_lb_channel_args(new_args); } // // ctor and dtor // -GrpcLb::GrpcLb(const grpc_lb_addresses* addresses, - const LoadBalancingPolicy::Args& args) +GrpcLb::GrpcLb(const LoadBalancingPolicy::Args& args) : LoadBalancingPolicy(args), response_generator_(MakeRefCounted()), lb_call_backoff_( @@ -1072,9 +1021,6 @@ GrpcLb::~GrpcLb() { if (serverlist_ != nullptr) { grpc_grpclb_destroy_serverlist(serverlist_); } - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } grpc_subchannel_index_unref(); } @@ -1122,7 +1068,6 @@ void GrpcLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { while ((pp = pending_picks_) != nullptr) { pending_picks_ = pp->next; pp->pick->on_complete = pp->original_on_complete; - pp->pick->user_data = nullptr; grpc_error* error = GRPC_ERROR_NONE; if (new_policy->PickLocked(pp->pick, &error)) { // Synchronous return; schedule closure. @@ -1276,9 +1221,27 @@ void GrpcLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, notify); } +// Returns the backend addresses extracted from the given addresses. +UniquePtr ExtractBackendAddresses( + const ServerAddressList& addresses) { + void* lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + grpc_arg arg = grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token, + &lb_token_arg_vtable); + auto backend_addresses = MakeUnique(); + for (size_t i = 0; i < addresses.size(); ++i) { + if (!addresses[i].IsBalancer()) { + backend_addresses->emplace_back( + addresses[i].address(), + grpc_channel_args_copy_and_add(addresses[i].args(), &arg, 1)); + } + } + return backend_addresses; +} + void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); - if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { // Ignore this update. gpr_log( GPR_ERROR, @@ -1286,13 +1249,8 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { this); return; } - const grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); // Update fallback address list. - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } - fallback_backend_addresses_ = ExtractBackendAddresses(addresses); + fallback_backend_addresses_ = ExtractBackendAddresses(*addresses); // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, // since we use this to trigger the client_load_reporting filter. static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; @@ -1303,7 +1261,7 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); // Construct args for balancer channel. grpc_channel_args* lb_channel_args = - BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); + BuildBalancerChannelArgs(*addresses, response_generator_.get(), &args); // Create balancer channel if needed. if (lb_channel_ == nullptr) { char* uri_str; @@ -1509,12 +1467,17 @@ void DestroyClientStats(void* arg) { } void GrpcLb::PendingPickSetMetadataAndContext(PendingPick* pp) { - /* if connected_subchannel is nullptr, no pick has been made by the RR - * policy (e.g., all addresses failed to connect). There won't be any - * user_data/token available */ + // If connected_subchannel is nullptr, no pick has been made by the RR + // policy (e.g., all addresses failed to connect). There won't be any + // LB token available. if (pp->pick->connected_subchannel != nullptr) { - if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { - AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), + const grpc_arg* arg = + grpc_channel_args_find(pp->pick->connected_subchannel->args(), + GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN); + if (arg != nullptr) { + grpc_mdelem lb_token = { + reinterpret_cast(arg->value.pointer.p)}; + AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(lb_token), &pp->pick->lb_token_mdelem_storage, pp->pick->initial_metadata); } else { @@ -1598,12 +1561,10 @@ bool GrpcLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp, return true; } } - // Set client_stats and user_data. + // Set client_stats. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); } - GPR_ASSERT(pp->pick->user_data == nullptr); - pp->pick->user_data = (void**)&pp->lb_token; // Pick via the RR policy. bool pick_done = rr_policy_->PickLocked(pp->pick, error); if (pick_done) { @@ -1668,10 +1629,11 @@ void GrpcLb::CreateRoundRobinPolicyLocked(const Args& args) { } grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { - grpc_lb_addresses* addresses; + ServerAddressList tmp_addresses; + ServerAddressList* addresses = &tmp_addresses; bool is_backend_from_grpclb_load_balancer = false; if (serverlist_ != nullptr) { - addresses = ProcessServerlist(serverlist_); + tmp_addresses = ProcessServerlist(serverlist_); is_backend_from_grpclb_load_balancer = true; } else { // If CreateOrUpdateRoundRobinPolicyLocked() is invoked when we haven't @@ -1680,14 +1642,14 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { // empty, in which case the new round_robin policy will keep the requested // picks pending. GPR_ASSERT(fallback_backend_addresses_ != nullptr); - addresses = grpc_lb_addresses_copy(fallback_backend_addresses_); + addresses = fallback_backend_addresses_.get(); } GPR_ASSERT(addresses != nullptr); - // Replace the LB addresses in the channel args that we pass down to + // Replace the server address list in the channel args that we pass down to // the subchannel. - static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; + static const char* keys_to_remove[] = {GRPC_ARG_SERVER_ADDRESS_LIST}; grpc_arg args_to_add[3] = { - grpc_lb_addresses_create_channel_arg(addresses), + CreateServerAddressListChannelArg(addresses), // A channel arg indicating if the target is a backend inferred from a // grpclb load balancer. grpc_channel_arg_integer_create( @@ -1704,7 +1666,6 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, num_args_to_add); - grpc_lb_addresses_destroy(addresses); return args; } @@ -1837,19 +1798,18 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory { OrphanablePtr CreateLoadBalancingPolicy( const LoadBalancingPolicy::Args& args) const override { /* Count the number of gRPC-LB addresses. There must be at least one. */ - const grpc_arg* arg = - grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); - if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { - return nullptr; - } - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + const ServerAddressList* addresses = + FindServerAddressListChannelArg(args.args); + if (addresses == nullptr) return nullptr; + bool found_balancer = false; + for (size_t i = 0; i < addresses->size(); ++i) { + if ((*addresses)[i].IsBalancer()) { + found_balancer = true; + break; + } } - if (num_grpclb_addrs == 0) return nullptr; - return OrphanablePtr(New(addresses, args)); + if (!found_balancer) return nullptr; + return OrphanablePtr(New(args)); } const char* name() const override { return "grpclb"; } diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h index 825065a9c32..3b2dc370eb3 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include /// Makes any necessary modifications to \a args for use in the grpclb /// balancer channel. diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc index 441efd5e23b..6e8fbdcab77 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc @@ -26,6 +26,7 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -42,22 +43,23 @@ int BalancerNameCmp(const grpc_core::UniquePtr& a, } RefCountedPtr CreateTargetAuthorityTable( - grpc_lb_addresses* addresses) { + const ServerAddressList& addresses) { TargetAuthorityTable::Entry* target_authority_entries = - static_cast(gpr_zalloc( - sizeof(*target_authority_entries) * addresses->num_addresses)); - for (size_t i = 0; i < addresses->num_addresses; ++i) { + static_cast( + gpr_zalloc(sizeof(*target_authority_entries) * addresses.size())); + for (size_t i = 0; i < addresses.size(); ++i) { char* addr_str; - GPR_ASSERT(grpc_sockaddr_to_string( - &addr_str, &addresses->addresses[i].address, true) > 0); + GPR_ASSERT( + grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true) > 0); target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); - target_authority_entries[i].value.reset( - gpr_strdup(addresses->addresses[i].balancer_name)); gpr_free(addr_str); + char* balancer_name = grpc_channel_arg_get_string(grpc_channel_args_find( + addresses[i].args(), GRPC_ARG_ADDRESS_BALANCER_NAME)); + target_authority_entries[i].value.reset(gpr_strdup(balancer_name)); } RefCountedPtr target_authority_table = - TargetAuthorityTable::Create(addresses->num_addresses, - target_authority_entries, BalancerNameCmp); + TargetAuthorityTable::Create(addresses.size(), target_authority_entries, + BalancerNameCmp); gpr_free(target_authority_entries); return target_authority_table; } @@ -72,13 +74,12 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args( grpc_arg args_to_add[2]; size_t num_args_to_add = 0; // Add arg for targets info table. - const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != nullptr); - GPR_ASSERT(arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); + grpc_core::ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(args); + GPR_ASSERT(addresses != nullptr); grpc_core::RefCountedPtr - target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); + target_authority_table = + grpc_core::CreateTargetAuthorityTable(*addresses); args_to_add[num_args_to_add++] = grpc_core::CreateTargetAuthorityTableChannelArg( target_authority_table.get()); diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h index 9ca7b28d8e6..71d371c880a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" #define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index d1a05f12554..74c17612a28 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -24,6 +24,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/channel/channel_args.h" @@ -75,11 +76,9 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner) - : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, - combiner) {} + : SubchannelData(subchannel_list, address, subchannel, combiner) {} void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; @@ -95,7 +94,7 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData> { public: PickFirstSubchannelList(PickFirst* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) @@ -337,8 +336,8 @@ void PickFirst::UpdateChildRefsLocked() { void PickFirst::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) { AutoChildRefsUpdater guard(this); - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); - if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { if (subchannel_list_ == nullptr) { // If we don't have a current subchannel list, go into TRANSIENT FAILURE. grpc_connectivity_state_set( @@ -354,19 +353,17 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args, } return; } - const grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); if (grpc_lb_pick_first_trace.enabled()) { gpr_log(GPR_INFO, "Pick First %p received update with %" PRIuPTR " addresses", this, - addresses->num_addresses); + addresses->size()); } grpc_arg new_arg = grpc_channel_arg_integer_create( const_cast(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1); grpc_channel_args* new_args = grpc_channel_args_copy_and_add(&args, &new_arg, 1); auto subchannel_list = MakeOrphanable( - this, &grpc_lb_pick_first_trace, addresses, combiner(), + this, &grpc_lb_pick_first_trace, *addresses, combiner(), client_channel_factory(), *new_args); grpc_channel_args_destroy(new_args); if (subchannel_list->num_subchannels() == 0) { diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 2a169751317..63089afbd78 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -82,8 +82,6 @@ class RoundRobin : public LoadBalancingPolicy { // Data for a particular subchannel in a subchannel list. // This subclass adds the following functionality: - // - Tracks user_data associated with each address, which will be - // returned along with picks that select the subchannel. // - Tracks the previous connectivity state of the subchannel, so that // we know how many subchannels are in each state. class RoundRobinSubchannelData @@ -93,26 +91,9 @@ class RoundRobin : public LoadBalancingPolicy { RoundRobinSubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner) - : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, - combiner), - user_data_vtable_(user_data_vtable), - user_data_(user_data_vtable_ != nullptr - ? user_data_vtable_->copy(address.user_data) - : nullptr) {} - - void UnrefSubchannelLocked(const char* reason) override { - SubchannelData::UnrefSubchannelLocked(reason); - if (user_data_ != nullptr) { - GPR_ASSERT(user_data_vtable_ != nullptr); - user_data_vtable_->destroy(user_data_); - user_data_ = nullptr; - } - } - - void* user_data() const { return user_data_; } + : SubchannelData(subchannel_list, address, subchannel, combiner) {} grpc_connectivity_state connectivity_state() const { return last_connectivity_state_; @@ -125,8 +106,6 @@ class RoundRobin : public LoadBalancingPolicy { void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; - const grpc_lb_user_data_vtable* user_data_vtable_; - void* user_data_ = nullptr; grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_IDLE; }; @@ -137,7 +116,7 @@ class RoundRobin : public LoadBalancingPolicy { public: RoundRobinSubchannelList( RoundRobin* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : SubchannelList(policy, tracer, addresses, combiner, @@ -354,9 +333,6 @@ bool RoundRobin::DoPickLocked(PickState* pick) { subchannel_list_->subchannel(next_ready_index); GPR_ASSERT(sd->connected_subchannel() != nullptr); pick->connected_subchannel = sd->connected_subchannel()->Ref(); - if (pick->user_data != nullptr) { - *pick->user_data = sd->user_data(); - } if (grpc_lb_round_robin_trace.enabled()) { gpr_log(GPR_INFO, "[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, " @@ -667,9 +643,9 @@ void RoundRobin::NotifyOnStateChangeLocked(grpc_connectivity_state* current, void RoundRobin::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) { - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); AutoChildRefsUpdater guard(this); - if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", this); // If we don't have a current subchannel list, go into TRANSIENT_FAILURE. // Otherwise, keep using the current subchannel list (ignore this update). @@ -681,11 +657,9 @@ void RoundRobin::UpdateLocked(const grpc_channel_args& args, } return; } - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); if (grpc_lb_round_robin_trace.enabled()) { gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses", - this, addresses->num_addresses); + this, addresses->size()); } // Replace latest_pending_subchannel_list_. if (latest_pending_subchannel_list_ != nullptr) { @@ -696,7 +670,7 @@ void RoundRobin::UpdateLocked(const grpc_channel_args& args, } } latest_pending_subchannel_list_ = MakeOrphanable( - this, &grpc_lb_round_robin_trace, addresses, combiner(), + this, &grpc_lb_round_robin_trace, *addresses, combiner(), client_channel_factory(), args); // If we haven't started picking yet or the new list is empty, // immediately promote the new list to the current list. diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index f31401502c3..6f31a643c1d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -26,6 +26,7 @@ #include #include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/debug/trace.h" @@ -141,8 +142,7 @@ class SubchannelData { protected: SubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner); virtual ~SubchannelData(); @@ -156,9 +156,8 @@ class SubchannelData { grpc_connectivity_state connectivity_state, grpc_error* error) GRPC_ABSTRACT; - // Unrefs the subchannel. May be overridden by subclasses that need - // to perform extra cleanup when unreffing the subchannel. - virtual void UnrefSubchannelLocked(const char* reason); + // Unrefs the subchannel. + void UnrefSubchannelLocked(const char* reason); private: // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_. @@ -232,7 +231,7 @@ class SubchannelList : public InternallyRefCounted { protected: SubchannelList(LoadBalancingPolicy* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args); @@ -277,8 +276,7 @@ class SubchannelList : public InternallyRefCounted { template SubchannelData::SubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner) : subchannel_list_(subchannel_list), subchannel_(subchannel), @@ -488,7 +486,7 @@ void SubchannelData::ShutdownLocked() { template SubchannelList::SubchannelList( LoadBalancingPolicy* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : InternallyRefCounted(tracer), @@ -498,9 +496,9 @@ SubchannelList::SubchannelList( if (tracer_->enabled()) { gpr_log(GPR_INFO, "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", - tracer_->name(), policy, this, addresses->num_addresses); + tracer_->name(), policy, this, addresses.size()); } - subchannels_.reserve(addresses->num_addresses); + subchannels_.reserve(addresses.size()); // We need to remove the LB addresses in order to be able to compare the // subchannel keys of subchannels from a different batch of addresses. // We also remove the inhibit-health-checking arg, since we are @@ -508,19 +506,27 @@ SubchannelList::SubchannelList( inhibit_health_checking_ = grpc_channel_arg_get_bool( grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false); static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, - GRPC_ARG_LB_ADDRESSES, + GRPC_ARG_SERVER_ADDRESS_LIST, GRPC_ARG_INHIBIT_HEALTH_CHECKING}; // Create a subchannel for each address. grpc_subchannel_args sc_args; - for (size_t i = 0; i < addresses->num_addresses; i++) { - // If there were any balancer, we would have chosen grpclb policy instead. - GPR_ASSERT(!addresses->addresses[i].is_balancer); + for (size_t i = 0; i < addresses.size(); i++) { + // If there were any balancer addresses, we would have chosen grpclb + // policy, which does not use a SubchannelList. + GPR_ASSERT(!addresses[i].IsBalancer()); memset(&sc_args, 0, sizeof(grpc_subchannel_args)); - grpc_arg addr_arg = - grpc_create_subchannel_address_arg(&addresses->addresses[i].address); + InlinedVector args_to_add; + args_to_add.emplace_back( + grpc_create_subchannel_address_arg(&addresses[i].address())); + if (addresses[i].args() != nullptr) { + for (size_t j = 0; j < addresses[i].args()->num_args; ++j) { + args_to_add.emplace_back(addresses[i].args()->args[j]); + } + } grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( - &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, 1); - gpr_free(addr_arg.value.string); + &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), + args_to_add.data(), args_to_add.size()); + gpr_free(args_to_add[0].value.string); sc_args.args = new_args; grpc_subchannel* subchannel = grpc_client_channel_factory_create_subchannel( client_channel_factory, &sc_args); @@ -528,8 +534,7 @@ SubchannelList::SubchannelList( if (subchannel == nullptr) { // Subchannel could not be created. if (tracer_->enabled()) { - char* address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); + char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); gpr_log(GPR_INFO, "[%s %p] could not create subchannel for address uri %s, " "ignoring", @@ -539,8 +544,7 @@ SubchannelList::SubchannelList( continue; } if (tracer_->enabled()) { - char* address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); + char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR ": Created subchannel %p for address uri %s", @@ -548,8 +552,7 @@ SubchannelList::SubchannelList( address_uri); gpr_free(address_uri); } - subchannels_.emplace_back(this, addresses->user_data_vtable, - addresses->addresses[i], subchannel, combiner); + subchannels_.emplace_back(this, addresses[i], subchannel, combiner); } } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index faedc0a9194..3c25de2386c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -79,6 +79,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" @@ -116,7 +117,7 @@ namespace { class XdsLb : public LoadBalancingPolicy { public: - XdsLb(const grpc_lb_addresses* addresses, const Args& args); + explicit XdsLb(const Args& args); void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) override; @@ -156,9 +157,6 @@ class XdsLb : public LoadBalancingPolicy { // Our on_complete closure and the original one. grpc_closure on_complete; grpc_closure* original_on_complete; - // The LB token associated with the pick. This is set via user_data in - // the pick. - grpc_mdelem lb_token; // Stats for client-side load reporting. RefCountedPtr client_stats; // Next pending pick. @@ -256,7 +254,7 @@ class XdsLb : public LoadBalancingPolicy { grpc_error* error); // Pending pick methods. - static void PendingPickSetMetadataAndContext(PendingPick* pp); + static void PendingPickCleanup(PendingPick* pp); PendingPick* PendingPickCreate(PickState* pick); void AddPendingPick(PendingPick* pp); static void OnPendingPickComplete(void* arg, grpc_error* error); @@ -319,7 +317,7 @@ class XdsLb : public LoadBalancingPolicy { // 0 means not using fallback. int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - grpc_lb_addresses* fallback_backend_addresses_ = nullptr; + UniquePtr fallback_backend_addresses_; // Fallback timer. bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; @@ -339,47 +337,15 @@ class XdsLb : public LoadBalancingPolicy { // serverlist parsing code // -// vtable for LB tokens in grpc_lb_addresses -void* lb_token_copy(void* token) { - return token == nullptr - ? nullptr - : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload; -} -void lb_token_destroy(void* token) { - if (token != nullptr) { - GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token}); - } -} -int lb_token_cmp(void* token1, void* token2) { - if (token1 > token2) return 1; - if (token1 < token2) return -1; - return 0; -} -const grpc_lb_user_data_vtable lb_token_vtable = { - lb_token_copy, lb_token_destroy, lb_token_cmp}; - // Returns the backend addresses extracted from the given addresses. -grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { - // First pass: count the number of backend addresses. - size_t num_backends = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) { - ++num_backends; +UniquePtr ExtractBackendAddresses( + const ServerAddressList& addresses) { + auto backend_addresses = MakeUnique(); + for (size_t i = 0; i < addresses.size(); ++i) { + if (!addresses[i].IsBalancer()) { + backend_addresses->emplace_back(addresses[i]); } } - // Second pass: actually populate the addresses and (empty) LB tokens. - grpc_lb_addresses* backend_addresses = - grpc_lb_addresses_create(num_backends, &lb_token_vtable); - size_t num_copied = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) continue; - const grpc_resolved_address* addr = &addresses->addresses[i].address; - grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, - addr->len, false /* is_balancer */, - nullptr /* balancer_name */, - (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); - ++num_copied; - } return backend_addresses; } @@ -429,56 +395,17 @@ void ParseServer(const xds_grpclb_server* server, grpc_resolved_address* addr) { } // Returns addresses extracted from \a serverlist. -grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) { - size_t num_valid = 0; - /* first pass: count how many are valid in order to allocate the necessary - * memory in a single block */ +UniquePtr ProcessServerlist( + const xds_grpclb_serverlist* serverlist) { + auto addresses = MakeUnique(); for (size_t i = 0; i < serverlist->num_servers; ++i) { - if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; - } - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_valid, &lb_token_vtable); - /* second pass: actually populate the addresses and LB tokens (aka user data - * to the outside world) to be read by the child policy during its creation. - * Given that the validity tests are very cheap, they are performed again - * instead of marking the valid ones during the first pass, as this would - * incurr in an allocation due to the arbitrary number of server */ - size_t addr_idx = 0; - for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { - const xds_grpclb_server* server = serverlist->servers[sl_idx]; - if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; - GPR_ASSERT(addr_idx < num_valid); - /* address processing */ + const xds_grpclb_server* server = serverlist->servers[i]; + if (!IsServerValid(serverlist->servers[i], i, false)) continue; grpc_resolved_address addr; ParseServer(server, &addr); - /* lb token processing */ - void* user_data; - if (server->has_load_balance_token) { - const size_t lb_token_max_length = - GPR_ARRAY_SIZE(server->load_balance_token); - const size_t lb_token_length = - strnlen(server->load_balance_token, lb_token_max_length); - grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( - server->load_balance_token, lb_token_length); - user_data = - (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) - .payload; - } else { - char* uri = grpc_sockaddr_to_uri(&addr); - gpr_log(GPR_INFO, - "Missing LB token for backend address '%s'. The empty token will " - "be used instead", - uri); - gpr_free(uri); - user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; - } - grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, - false /* is_balancer */, - nullptr /* balancer_name */, user_data); - ++addr_idx; + addresses->emplace_back(addr, nullptr); } - GPR_ASSERT(addr_idx == num_valid); - return lb_addresses; + return addresses; } // @@ -789,8 +716,7 @@ void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked( xds_grpclb_destroy_serverlist(xdslb_policy->serverlist_); } else { /* or dispose of the fallback */ - grpc_lb_addresses_destroy(xdslb_policy->fallback_backend_addresses_); - xdslb_policy->fallback_backend_addresses_ = nullptr; + xdslb_policy->fallback_backend_addresses_.reset(); if (xdslb_policy->fallback_timer_callback_pending_) { grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_); } @@ -876,31 +802,15 @@ void XdsLb::BalancerCallState::OnBalancerStatusReceivedLocked( // helper code for creating balancer channel // -grpc_lb_addresses* ExtractBalancerAddresses( - const grpc_lb_addresses* addresses) { - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; - } - // There must be at least one balancer address, or else the - // client_channel would not have chosen this LB policy. - GPR_ASSERT(num_grpclb_addrs > 0); - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_grpclb_addrs, nullptr); - size_t lb_addresses_idx = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) continue; - if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); +UniquePtr ExtractBalancerAddresses( + const ServerAddressList& addresses) { + auto balancer_addresses = MakeUnique(); + for (size_t i = 0; i < addresses.size(); ++i) { + if (addresses[i].IsBalancer()) { + balancer_addresses->emplace_back(addresses[i]); } - grpc_lb_addresses_set_address( - lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, - addresses->addresses[i].address.len, false /* is balancer */, - addresses->addresses[i].balancer_name, nullptr /* user data */); } - GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); - return lb_addresses; + return balancer_addresses; } /* Returns the channel args for the LB channel, used to create a bidirectional @@ -912,10 +822,11 @@ grpc_lb_addresses* ExtractBalancerAddresses( * above the grpclb policy. * - \a args: other args inherited from the xds policy. */ grpc_channel_args* BuildBalancerChannelArgs( - const grpc_lb_addresses* addresses, + const ServerAddressList& addresses, FakeResolverResponseGenerator* response_generator, const grpc_channel_args* args) { - grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); + UniquePtr balancer_addresses = + ExtractBalancerAddresses(addresses); // Channel args to remove. static const char* args_to_remove[] = { // LB policy name, since we want to use the default (pick_first) in @@ -933,7 +844,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // is_balancer=true. We need the LB channel to return addresses with // is_balancer=false so that it does not wind up recursively using the // xds LB policy, as per the special case logic in client_channel.c. - GRPC_ARG_LB_ADDRESSES, + GRPC_ARG_SERVER_ADDRESS_LIST, // The fake resolver response generator, because we are replacing it // with the one from the xds policy, used to propagate updates to // the LB channel. @@ -949,10 +860,10 @@ grpc_channel_args* BuildBalancerChannelArgs( }; // Channel args to add. const grpc_arg args_to_add[] = { - // New LB addresses. + // New server address list. // Note that we pass these in both when creating the LB channel // and via the fake resolver. The latter is what actually gets used. - grpc_lb_addresses_create_channel_arg(lb_addresses), + CreateServerAddressListChannelArg(balancer_addresses.get()), // The fake resolver response generator, which we use to inject // address updates into the LB channel. grpc_core::FakeResolverResponseGenerator::MakeChannelArg( @@ -970,10 +881,7 @@ grpc_channel_args* BuildBalancerChannelArgs( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Make any necessary modifications for security. - new_args = grpc_lb_policy_xds_modify_lb_channel_args(new_args); - // Clean up. - grpc_lb_addresses_destroy(lb_addresses); - return new_args; + return grpc_lb_policy_xds_modify_lb_channel_args(new_args); } // @@ -981,8 +889,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // // TODO(vishalpowar): Use lb_config in args to configure LB policy. -XdsLb::XdsLb(const grpc_lb_addresses* addresses, - const LoadBalancingPolicy::Args& args) +XdsLb::XdsLb(const LoadBalancingPolicy::Args& args) : LoadBalancingPolicy(args), response_generator_(MakeRefCounted()), lb_call_backoff_( @@ -1038,9 +945,6 @@ XdsLb::~XdsLb() { if (serverlist_ != nullptr) { xds_grpclb_destroy_serverlist(serverlist_); } - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } grpc_subchannel_index_unref(); } @@ -1088,7 +992,6 @@ void XdsLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { while ((pp = pending_picks_) != nullptr) { pending_picks_ = pp->next; pp->pick->on_complete = pp->original_on_complete; - pp->pick->user_data = nullptr; grpc_error* error = GRPC_ERROR_NONE; if (new_policy->PickLocked(pp->pick, &error)) { // Synchronous return; schedule closure. @@ -1241,21 +1144,16 @@ void XdsLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, } void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); - if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { // Ignore this update. gpr_log(GPR_ERROR, "[xdslb %p] No valid LB addresses channel arg in update, ignoring.", this); return; } - const grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); // Update fallback address list. - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } - fallback_backend_addresses_ = ExtractBackendAddresses(addresses); + fallback_backend_addresses_ = ExtractBackendAddresses(*addresses); // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, // since we use this to trigger the client_load_reporting filter. static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; @@ -1266,7 +1164,7 @@ void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); // Construct args for balancer channel. grpc_channel_args* lb_channel_args = - BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); + BuildBalancerChannelArgs(*addresses, response_generator_.get(), &args); // Create balancer channel if needed. if (lb_channel_ == nullptr) { char* uri_str; @@ -1457,37 +1355,15 @@ void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg, // PendingPick // -// Adds lb_token of selected subchannel (address) to the call's initial -// metadata. -grpc_error* AddLbTokenToInitialMetadata( - grpc_mdelem lb_token, grpc_linked_mdelem* lb_token_mdelem_storage, - grpc_metadata_batch* initial_metadata) { - GPR_ASSERT(lb_token_mdelem_storage != nullptr); - GPR_ASSERT(!GRPC_MDISNULL(lb_token)); - return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage, - lb_token); -} - // Destroy function used when embedding client stats in call context. void DestroyClientStats(void* arg) { static_cast(arg)->Unref(); } -void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) { - /* if connected_subchannel is nullptr, no pick has been made by the - * child policy (e.g., all addresses failed to connect). There won't be any - * user_data/token available */ +void XdsLb::PendingPickCleanup(PendingPick* pp) { + // If connected_subchannel is nullptr, no pick has been made by the + // child policy (e.g., all addresses failed to connect). if (pp->pick->connected_subchannel != nullptr) { - if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { - AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), - &pp->pick->lb_token_mdelem_storage, - pp->pick->initial_metadata); - } else { - gpr_log(GPR_ERROR, - "[xdslb %p] No LB token for connected subchannel pick %p", - pp->xdslb_policy, pp->pick); - abort(); - } // Pass on client stats via context. Passes ownership of the reference. if (pp->client_stats != nullptr) { pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value = @@ -1505,7 +1381,7 @@ void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) { * order to unref the child policy instance upon its invocation */ void XdsLb::OnPendingPickComplete(void* arg, grpc_error* error) { PendingPick* pp = static_cast(arg); - PendingPickSetMetadataAndContext(pp); + PendingPickCleanup(pp); GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error)); Delete(pp); } @@ -1537,16 +1413,14 @@ void XdsLb::AddPendingPick(PendingPick* pp) { // completion callback even if the pick is available immediately. bool XdsLb::PickFromChildPolicyLocked(bool force_async, PendingPick* pp, grpc_error** error) { - // Set client_stats and user_data. + // Set client_stats. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); } - GPR_ASSERT(pp->pick->user_data == nullptr); - pp->pick->user_data = (void**)&pp->lb_token; // Pick via the child policy. bool pick_done = child_policy_->PickLocked(pp->pick, error); if (pick_done) { - PendingPickSetMetadataAndContext(pp); + PendingPickCleanup(pp); if (force_async) { GRPC_CLOSURE_SCHED(pp->original_on_complete, *error); *error = GRPC_ERROR_NONE; @@ -1608,20 +1482,19 @@ void XdsLb::CreateChildPolicyLocked(const Args& args) { } grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() { - grpc_lb_addresses* addresses; bool is_backend_from_grpclb_load_balancer = false; // This should never be invoked if we do not have serverlist_, as fallback // mode is disabled for xDS plugin. GPR_ASSERT(serverlist_ != nullptr); GPR_ASSERT(serverlist_->num_servers > 0); - addresses = ProcessServerlist(serverlist_); - is_backend_from_grpclb_load_balancer = true; + UniquePtr addresses = ProcessServerlist(serverlist_); GPR_ASSERT(addresses != nullptr); - // Replace the LB addresses in the channel args that we pass down to + is_backend_from_grpclb_load_balancer = true; + // Replace the server address list in the channel args that we pass down to // the subchannel. - static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; + static const char* keys_to_remove[] = {GRPC_ARG_SERVER_ADDRESS_LIST}; const grpc_arg args_to_add[] = { - grpc_lb_addresses_create_channel_arg(addresses), + CreateServerAddressListChannelArg(addresses.get()), // A channel arg indicating if the target is a backend inferred from a // grpclb load balancer. grpc_channel_arg_integer_create( @@ -1631,7 +1504,6 @@ grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() { grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); - grpc_lb_addresses_destroy(addresses); return args; } @@ -1765,19 +1637,18 @@ class XdsFactory : public LoadBalancingPolicyFactory { OrphanablePtr CreateLoadBalancingPolicy( const LoadBalancingPolicy::Args& args) const override { /* Count the number of gRPC-LB addresses. There must be at least one. */ - const grpc_arg* arg = - grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); - if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { - return nullptr; - } - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + const ServerAddressList* addresses = + FindServerAddressListChannelArg(args.args); + if (addresses == nullptr) return nullptr; + bool found_balancer_address = false; + for (size_t i = 0; i < addresses->size(); ++i) { + if ((*addresses)[i].IsBalancer()) { + found_balancer_address = true; + break; + } } - if (num_grpclb_addrs == 0) return nullptr; - return OrphanablePtr(New(addresses, args)); + if (!found_balancer_address) return nullptr; + return OrphanablePtr(New(args)); } const char* name() const override { return "xds_experimental"; } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h index 32c4acc8a3e..f713b7f563d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include /// Makes any necessary modifications to \a args for use in the xds /// balancer channel. diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc index 5ab72efce46..9a11f8e39fd 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc @@ -25,6 +25,7 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -41,22 +42,23 @@ int BalancerNameCmp(const grpc_core::UniquePtr& a, } RefCountedPtr CreateTargetAuthorityTable( - grpc_lb_addresses* addresses) { + const ServerAddressList& addresses) { TargetAuthorityTable::Entry* target_authority_entries = - static_cast(gpr_zalloc( - sizeof(*target_authority_entries) * addresses->num_addresses)); - for (size_t i = 0; i < addresses->num_addresses; ++i) { + static_cast( + gpr_zalloc(sizeof(*target_authority_entries) * addresses.size())); + for (size_t i = 0; i < addresses.size(); ++i) { char* addr_str; - GPR_ASSERT(grpc_sockaddr_to_string( - &addr_str, &addresses->addresses[i].address, true) > 0); + GPR_ASSERT( + grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true) > 0); target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); - target_authority_entries[i].value.reset( - gpr_strdup(addresses->addresses[i].balancer_name)); gpr_free(addr_str); + char* balancer_name = grpc_channel_arg_get_string(grpc_channel_args_find( + addresses[i].args(), GRPC_ARG_ADDRESS_BALANCER_NAME)); + target_authority_entries[i].value.reset(gpr_strdup(balancer_name)); } RefCountedPtr target_authority_table = - TargetAuthorityTable::Create(addresses->num_addresses, - target_authority_entries, BalancerNameCmp); + TargetAuthorityTable::Create(addresses.size(), target_authority_entries, + BalancerNameCmp); gpr_free(target_authority_entries); return target_authority_table; } @@ -71,13 +73,12 @@ grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( grpc_arg args_to_add[2]; size_t num_args_to_add = 0; // Add arg for targets info table. - const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != nullptr); - GPR_ASSERT(arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); + grpc_core::ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(args); + GPR_ASSERT(addresses != nullptr); grpc_core::RefCountedPtr - target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); + target_authority_table = + grpc_core::CreateTargetAuthorityTable(*addresses); args_to_add[num_args_to_add++] = grpc_core::CreateTargetAuthorityTableChannelArg( target_authority_table.get()); diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h index 9d08defa7ef..67049956417 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" #define XDS_SERVICE_NAME_MAX_LENGTH 128 diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.cc b/src/core/ext/filters/client_channel/lb_policy_factory.cc deleted file mode 100644 index 5c6363d2952..00000000000 --- a/src/core/ext/filters/client_channel/lb_policy_factory.cc +++ /dev/null @@ -1,163 +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. - * - */ - -#include - -#include - -#include -#include - -#include "src/core/lib/channel/channel_args.h" - -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" -#include "src/core/ext/filters/client_channel/parse_address.h" - -grpc_lb_addresses* grpc_lb_addresses_create( - size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) { - grpc_lb_addresses* addresses = - static_cast(gpr_zalloc(sizeof(grpc_lb_addresses))); - addresses->num_addresses = num_addresses; - addresses->user_data_vtable = user_data_vtable; - const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses; - addresses->addresses = - static_cast(gpr_zalloc(addresses_size)); - return addresses; -} - -grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses) { - grpc_lb_addresses* new_addresses = grpc_lb_addresses_create( - addresses->num_addresses, addresses->user_data_vtable); - memcpy(new_addresses->addresses, addresses->addresses, - sizeof(grpc_lb_address) * addresses->num_addresses); - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (new_addresses->addresses[i].balancer_name != nullptr) { - new_addresses->addresses[i].balancer_name = - gpr_strdup(new_addresses->addresses[i].balancer_name); - } - if (new_addresses->addresses[i].user_data != nullptr) { - new_addresses->addresses[i].user_data = addresses->user_data_vtable->copy( - new_addresses->addresses[i].user_data); - } - } - return new_addresses; -} - -void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, - const void* address, size_t address_len, - bool is_balancer, const char* balancer_name, - void* user_data) { - GPR_ASSERT(index < addresses->num_addresses); - if (user_data != nullptr) GPR_ASSERT(addresses->user_data_vtable != nullptr); - grpc_lb_address* target = &addresses->addresses[index]; - memcpy(target->address.addr, address, address_len); - target->address.len = static_cast(address_len); - target->is_balancer = is_balancer; - target->balancer_name = gpr_strdup(balancer_name); - target->user_data = user_data; -} - -bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, - size_t index, const grpc_uri* uri, - bool is_balancer, - const char* balancer_name, - void* user_data) { - grpc_resolved_address address; - if (!grpc_parse_uri(uri, &address)) return false; - grpc_lb_addresses_set_address(addresses, index, address.addr, address.len, - is_balancer, balancer_name, user_data); - return true; -} - -int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, - const grpc_lb_addresses* addresses2) { - if (addresses1->num_addresses > addresses2->num_addresses) return 1; - if (addresses1->num_addresses < addresses2->num_addresses) return -1; - if (addresses1->user_data_vtable > addresses2->user_data_vtable) return 1; - if (addresses1->user_data_vtable < addresses2->user_data_vtable) return -1; - for (size_t i = 0; i < addresses1->num_addresses; ++i) { - const grpc_lb_address* target1 = &addresses1->addresses[i]; - const grpc_lb_address* target2 = &addresses2->addresses[i]; - if (target1->address.len > target2->address.len) return 1; - if (target1->address.len < target2->address.len) return -1; - int retval = memcmp(target1->address.addr, target2->address.addr, - target1->address.len); - if (retval != 0) return retval; - if (target1->is_balancer > target2->is_balancer) return 1; - if (target1->is_balancer < target2->is_balancer) return -1; - const char* balancer_name1 = - target1->balancer_name != nullptr ? target1->balancer_name : ""; - const char* balancer_name2 = - target2->balancer_name != nullptr ? target2->balancer_name : ""; - retval = strcmp(balancer_name1, balancer_name2); - if (retval != 0) return retval; - if (addresses1->user_data_vtable != nullptr) { - retval = addresses1->user_data_vtable->cmp(target1->user_data, - target2->user_data); - if (retval != 0) return retval; - } - } - return 0; -} - -void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) { - for (size_t i = 0; i < addresses->num_addresses; ++i) { - gpr_free(addresses->addresses[i].balancer_name); - if (addresses->addresses[i].user_data != nullptr) { - addresses->user_data_vtable->destroy(addresses->addresses[i].user_data); - } - } - gpr_free(addresses->addresses); - gpr_free(addresses); -} - -static void* lb_addresses_copy(void* addresses) { - return grpc_lb_addresses_copy(static_cast(addresses)); -} -static void lb_addresses_destroy(void* addresses) { - grpc_lb_addresses_destroy(static_cast(addresses)); -} -static int lb_addresses_cmp(void* addresses1, void* addresses2) { - return grpc_lb_addresses_cmp(static_cast(addresses1), - static_cast(addresses2)); -} -static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = { - lb_addresses_copy, lb_addresses_destroy, lb_addresses_cmp}; - -grpc_arg grpc_lb_addresses_create_channel_arg( - const grpc_lb_addresses* addresses) { - return grpc_channel_arg_pointer_create( - (char*)GRPC_ARG_LB_ADDRESSES, (void*)addresses, &lb_addresses_arg_vtable); -} - -grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( - const grpc_channel_args* channel_args) { - const grpc_arg* lb_addresses_arg = - grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); - if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) - return nullptr; - return static_cast(lb_addresses_arg->value.pointer.p); -} - -bool grpc_lb_addresses_contains_balancer_address( - const grpc_lb_addresses& addresses) { - for (size_t i = 0; i < addresses.num_addresses; ++i) { - if (addresses.addresses[i].is_balancer) return true; - } - return false; -} diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h index a59deadb265..a165ebafaba 100644 --- a/src/core/ext/filters/client_channel/lb_policy_factory.h +++ b/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -21,91 +21,9 @@ #include -#include "src/core/lib/iomgr/resolve_address.h" - -#include "src/core/ext/filters/client_channel/client_channel_factory.h" #include "src/core/ext/filters/client_channel/lb_policy.h" -#include "src/core/lib/uri/uri_parser.h" - -// -// representation of an LB address -// - -// Channel arg key for grpc_lb_addresses. -#define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses" - -/** A resolved address alongside any LB related information associated with it. - * \a user_data, if not NULL, contains opaque data meant to be consumed by the - * gRPC LB policy. Note that no all LB policies support \a user_data as input. - * Those who don't will simply ignore it and will correspondingly return NULL in - * their namesake pick() output argument. */ -// TODO(roth): Once we figure out a better way of handling user_data in -// LB policies, convert these structs to C++ classes. -typedef struct grpc_lb_address { - grpc_resolved_address address; - bool is_balancer; - char* balancer_name; /* For secure naming. */ - void* user_data; -} grpc_lb_address; - -typedef struct grpc_lb_user_data_vtable { - void* (*copy)(void*); - void (*destroy)(void*); - int (*cmp)(void*, void*); -} grpc_lb_user_data_vtable; - -typedef struct grpc_lb_addresses { - size_t num_addresses; - grpc_lb_address* addresses; - const grpc_lb_user_data_vtable* user_data_vtable; -} grpc_lb_addresses; - -/** Returns a grpc_addresses struct with enough space for - \a num_addresses addresses. The \a user_data_vtable argument may be - NULL if no user data will be added. */ -grpc_lb_addresses* grpc_lb_addresses_create( - size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable); - -/** Creates a copy of \a addresses. */ -grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses); - -/** Sets the value of the address at index \a index of \a addresses. - * \a address is a socket address of length \a address_len. */ -void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, - const void* address, size_t address_len, - bool is_balancer, const char* balancer_name, - void* user_data); - -/** Sets the value of the address at index \a index of \a addresses from \a uri. - * Returns true upon success, false otherwise. */ -bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, - size_t index, const grpc_uri* uri, - bool is_balancer, - const char* balancer_name, - void* user_data); - -/** Compares \a addresses1 and \a addresses2. */ -int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, - const grpc_lb_addresses* addresses2); - -/** Destroys \a addresses. */ -void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses); - -/** Returns a channel arg containing \a addresses. */ -grpc_arg grpc_lb_addresses_create_channel_arg( - const grpc_lb_addresses* addresses); - -/** Returns the \a grpc_lb_addresses instance in \a channel_args or NULL */ -grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( - const grpc_channel_args* channel_args); - -// Returns true if addresses contains at least one balancer address. -bool grpc_lb_addresses_contains_balancer_address( - const grpc_lb_addresses& addresses); - -// -// LB policy factory -// +#include "src/core/lib/gprpp/abstract.h" +#include "src/core/lib/gprpp/orphanable.h" namespace grpc_core { diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index 4ebc2c8161c..c8425ae3365 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -33,6 +33,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -117,7 +118,7 @@ class AresDnsResolver : public Resolver { /// retry backoff state BackOff backoff_; /// currently resolving addresses - grpc_lb_addresses* lb_addresses_ = nullptr; + UniquePtr addresses_; /// currently resolving service config char* service_config_json_ = nullptr; // has shutdown been initiated @@ -314,13 +315,13 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->resolving_ = false; gpr_free(r->pending_request_); r->pending_request_ = nullptr; - if (r->lb_addresses_ != nullptr) { + if (r->addresses_ != nullptr) { static const char* args_to_remove[1]; size_t num_args_to_remove = 0; grpc_arg args_to_add[2]; size_t num_args_to_add = 0; args_to_add[num_args_to_add++] = - grpc_lb_addresses_create_channel_arg(r->lb_addresses_); + CreateServerAddressListChannelArg(r->addresses_.get()); char* service_config_string = nullptr; if (r->service_config_json_ != nullptr) { service_config_string = ChooseServiceConfig(r->service_config_json_); @@ -337,7 +338,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->channel_args_, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add); gpr_free(service_config_string); - grpc_lb_addresses_destroy(r->lb_addresses_); + r->addresses_.reset(); // Reset backoff state so that we start from the beginning when the // next request gets triggered. r->backoff_.Reset(); @@ -412,11 +413,10 @@ void AresDnsResolver::StartResolvingLocked() { self.release(); GPR_ASSERT(!resolving_); resolving_ = true; - lb_addresses_ = nullptr; service_config_json_ = nullptr; pending_request_ = grpc_dns_lookup_ares_locked( dns_server_, name_to_resolve_, kDefaultPort, interested_parties_, - &on_resolved_, &lb_addresses_, true /* check_grpclb */, + &on_resolved_, &addresses_, true /* check_grpclb */, request_service_config_ ? &service_config_json_ : nullptr, query_timeout_ms_, combiner()); last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now(); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc index f42b1e309df..8abc34c6edb 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc @@ -31,6 +31,7 @@ #include #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/timer.h" diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 55715869b63..1b1c2303da3 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -37,12 +37,16 @@ #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/nameser.h" #include "src/core/lib/iomgr/sockaddr_utils.h" +using grpc_core::ServerAddress; +using grpc_core::ServerAddressList; + static gpr_once g_basic_init = GPR_ONCE_INIT; static gpr_mu g_init_mu; @@ -58,7 +62,7 @@ struct grpc_ares_request { /** closure to call when the request completes */ grpc_closure* on_done; /** the pointer to receive the resolved addresses */ - grpc_lb_addresses** lb_addrs_out; + grpc_core::UniquePtr* addresses_out; /** the pointer to receive the service config in JSON */ char** service_config_json_out; /** the evernt driver used by this request */ @@ -87,12 +91,11 @@ typedef struct grpc_ares_hostbyname_request { static void do_basic_init(void) { gpr_mu_init(&g_init_mu); } -static void log_address_sorting_list(grpc_lb_addresses* lb_addrs, +static void log_address_sorting_list(const ServerAddressList& addresses, const char* input_output_str) { - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + for (size_t i = 0; i < addresses.size(); i++) { char* addr_str; - if (grpc_sockaddr_to_string(&addr_str, &lb_addrs->addresses[i].address, - true)) { + if (grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true)) { gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s", input_output_str, i, addr_str); gpr_free(addr_str); @@ -104,29 +107,28 @@ static void log_address_sorting_list(grpc_lb_addresses* lb_addrs, } } -void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) { +void grpc_cares_wrapper_address_sorting_sort(ServerAddressList* addresses) { if (grpc_trace_cares_address_sorting.enabled()) { - log_address_sorting_list(lb_addrs, "input"); + log_address_sorting_list(*addresses, "input"); } address_sorting_sortable* sortables = (address_sorting_sortable*)gpr_zalloc( - sizeof(address_sorting_sortable) * lb_addrs->num_addresses); - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { - sortables[i].user_data = &lb_addrs->addresses[i]; - memcpy(&sortables[i].dest_addr.addr, &lb_addrs->addresses[i].address.addr, - lb_addrs->addresses[i].address.len); - sortables[i].dest_addr.len = lb_addrs->addresses[i].address.len; + sizeof(address_sorting_sortable) * addresses->size()); + for (size_t i = 0; i < addresses->size(); ++i) { + sortables[i].user_data = &(*addresses)[i]; + memcpy(&sortables[i].dest_addr.addr, &(*addresses)[i].address().addr, + (*addresses)[i].address().len); + sortables[i].dest_addr.len = (*addresses)[i].address().len; } - address_sorting_rfc_6724_sort(sortables, lb_addrs->num_addresses); - grpc_lb_address* sorted_lb_addrs = (grpc_lb_address*)gpr_zalloc( - sizeof(grpc_lb_address) * lb_addrs->num_addresses); - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { - sorted_lb_addrs[i] = *(grpc_lb_address*)sortables[i].user_data; + address_sorting_rfc_6724_sort(sortables, addresses->size()); + ServerAddressList sorted; + sorted.reserve(addresses->size()); + for (size_t i = 0; i < addresses->size(); ++i) { + sorted.emplace_back(*static_cast(sortables[i].user_data)); } gpr_free(sortables); - gpr_free(lb_addrs->addresses); - lb_addrs->addresses = sorted_lb_addrs; + *addresses = std::move(sorted); if (grpc_trace_cares_address_sorting.enabled()) { - log_address_sorting_list(lb_addrs, "output"); + log_address_sorting_list(*addresses, "output"); } } @@ -145,9 +147,9 @@ void grpc_ares_complete_request_locked(grpc_ares_request* r) { /* Invoke on_done callback and destroy the request */ r->ev_driver = nullptr; - grpc_lb_addresses* lb_addrs = *(r->lb_addrs_out); - if (lb_addrs != nullptr) { - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + ServerAddressList* addresses = r->addresses_out->get(); + if (addresses != nullptr) { + grpc_cares_wrapper_address_sorting_sort(addresses); } GRPC_CLOSURE_SCHED(r->on_done, r->error); } @@ -181,33 +183,30 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, GRPC_ERROR_UNREF(r->error); r->error = GRPC_ERROR_NONE; r->success = true; - grpc_lb_addresses** lb_addresses = r->lb_addrs_out; - if (*lb_addresses == nullptr) { - *lb_addresses = grpc_lb_addresses_create(0, nullptr); - } - size_t prev_naddr = (*lb_addresses)->num_addresses; - size_t i; - for (i = 0; hostent->h_addr_list[i] != nullptr; i++) { + if (*r->addresses_out == nullptr) { + *r->addresses_out = grpc_core::MakeUnique(); } - (*lb_addresses)->num_addresses += i; - (*lb_addresses)->addresses = static_cast( - gpr_realloc((*lb_addresses)->addresses, - sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses)); - for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) { + ServerAddressList& addresses = **r->addresses_out; + for (size_t i = 0; hostent->h_addr_list[i] != nullptr; ++i) { + grpc_core::InlinedVector args_to_add; + if (hr->is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), hr->host)); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); switch (hostent->h_addrtype) { case AF_INET6: { size_t addr_len = sizeof(struct sockaddr_in6); struct sockaddr_in6 addr; memset(&addr, 0, addr_len); - memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr], + memcpy(&addr.sin6_addr, hostent->h_addr_list[i], sizeof(struct in6_addr)); addr.sin6_family = static_cast(hostent->h_addrtype); addr.sin6_port = hr->port; - grpc_lb_addresses_set_address( - *lb_addresses, i, &addr, addr_len, - hr->is_balancer /* is_balancer */, - hr->is_balancer ? hr->host : nullptr /* balancer_name */, - nullptr /* user_data */); + addresses.emplace_back(&addr, addr_len, args); char output[INET6_ADDRSTRLEN]; ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN); gpr_log(GPR_DEBUG, @@ -220,15 +219,11 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, size_t addr_len = sizeof(struct sockaddr_in); struct sockaddr_in addr; memset(&addr, 0, addr_len); - memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr], + memcpy(&addr.sin_addr, hostent->h_addr_list[i], sizeof(struct in_addr)); addr.sin_family = static_cast(hostent->h_addrtype); addr.sin_port = hr->port; - grpc_lb_addresses_set_address( - *lb_addresses, i, &addr, addr_len, - hr->is_balancer /* is_balancer */, - hr->is_balancer ? hr->host : nullptr /* balancer_name */, - nullptr /* user_data */); + addresses.emplace_back(&addr, addr_len, args); char output[INET_ADDRSTRLEN]; ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN); gpr_log(GPR_DEBUG, @@ -467,11 +462,10 @@ error_cleanup: gpr_free(port); } -static bool inner_resolve_as_ip_literal_locked(const char* name, - const char* default_port, - grpc_lb_addresses** addrs, - char** host, char** port, - char** hostport) { +static bool inner_resolve_as_ip_literal_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs, char** host, + char** port, char** hostport) { gpr_split_host_port(name, host, port); if (*host == nullptr) { gpr_log(GPR_ERROR, @@ -495,18 +489,16 @@ static bool inner_resolve_as_ip_literal_locked(const char* name, if (grpc_parse_ipv4_hostport(*hostport, &addr, false /* log errors */) || grpc_parse_ipv6_hostport(*hostport, &addr, false /* log errors */)) { GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_lb_addresses_create(1, nullptr); - grpc_lb_addresses_set_address( - *addrs, 0, addr.addr, addr.len, false /* is_balancer */, - nullptr /* balancer_name */, nullptr /* user_data */); + *addrs = grpc_core::MakeUnique(); + (*addrs)->emplace_back(addr.addr, addr.len, nullptr /* args */); return true; } return false; } -static bool resolve_as_ip_literal_locked(const char* name, - const char* default_port, - grpc_lb_addresses** addrs) { +static bool resolve_as_ip_literal_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { char* host = nullptr; char* port = nullptr; char* hostport = nullptr; @@ -521,13 +513,14 @@ static bool resolve_as_ip_literal_locked(const char* name, static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { grpc_ares_request* r = static_cast(gpr_zalloc(sizeof(grpc_ares_request))); r->ev_driver = nullptr; r->on_done = on_done; - r->lb_addrs_out = addrs; + r->addresses_out = addrs; r->service_config_json_out = service_config_json; r->success = false; r->error = GRPC_ERROR_NONE; @@ -553,8 +546,8 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) { @@ -599,8 +592,8 @@ typedef struct grpc_resolve_address_ares_request { grpc_combiner* combiner; /** the pointer to receive the resolved addresses */ grpc_resolved_addresses** addrs_out; - /** currently resolving lb addresses */ - grpc_lb_addresses* lb_addrs; + /** currently resolving addresses */ + grpc_core::UniquePtr addresses; /** closure to call when the resolve_address_ares request completes */ grpc_closure* on_resolve_address_done; /** a closure wrapping on_resolve_address_done, which should be invoked when @@ -613,7 +606,7 @@ typedef struct grpc_resolve_address_ares_request { /* pollset_set to be driven by */ grpc_pollset_set* interested_parties; /* underlying ares_request that the query is performed on */ - grpc_ares_request* ares_request; + grpc_ares_request* ares_request = nullptr; } grpc_resolve_address_ares_request; static void on_dns_lookup_done_locked(void* arg, grpc_error* error) { @@ -621,25 +614,24 @@ static void on_dns_lookup_done_locked(void* arg, grpc_error* error) { static_cast(arg); gpr_free(r->ares_request); grpc_resolved_addresses** resolved_addresses = r->addrs_out; - if (r->lb_addrs == nullptr || r->lb_addrs->num_addresses == 0) { + if (r->addresses == nullptr || r->addresses->empty()) { *resolved_addresses = nullptr; } else { *resolved_addresses = static_cast( gpr_zalloc(sizeof(grpc_resolved_addresses))); - (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses; + (*resolved_addresses)->naddrs = r->addresses->size(); (*resolved_addresses)->addrs = static_cast(gpr_zalloc( sizeof(grpc_resolved_address) * (*resolved_addresses)->naddrs)); - for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) { - GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer); - memcpy(&(*resolved_addresses)->addrs[i], - &r->lb_addrs->addresses[i].address, sizeof(grpc_resolved_address)); + for (size_t i = 0; i < (*resolved_addresses)->naddrs; ++i) { + GPR_ASSERT(!(*r->addresses)[i].IsBalancer()); + memcpy(&(*resolved_addresses)->addrs[i], &(*r->addresses)[i].address(), + sizeof(grpc_resolved_address)); } } GRPC_CLOSURE_SCHED(r->on_resolve_address_done, GRPC_ERROR_REF(error)); - if (r->lb_addrs != nullptr) grpc_lb_addresses_destroy(r->lb_addrs); GRPC_COMBINER_UNREF(r->combiner, "on_dns_lookup_done_cb"); - gpr_free(r); + grpc_core::Delete(r); } static void grpc_resolve_address_invoke_dns_lookup_ares_locked( @@ -648,7 +640,7 @@ static void grpc_resolve_address_invoke_dns_lookup_ares_locked( static_cast(arg); r->ares_request = grpc_dns_lookup_ares_locked( nullptr /* dns_server */, r->name, r->default_port, r->interested_parties, - &r->on_dns_lookup_done_locked, &r->lb_addrs, false /* check_grpclb */, + &r->on_dns_lookup_done_locked, &r->addresses, false /* check_grpclb */, nullptr /* service_config_json */, GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, r->combiner); } @@ -659,8 +651,7 @@ static void grpc_resolve_address_ares_impl(const char* name, grpc_closure* on_done, grpc_resolved_addresses** addrs) { grpc_resolve_address_ares_request* r = - static_cast( - gpr_zalloc(sizeof(grpc_resolve_address_ares_request))); + grpc_core::New(); r->combiner = grpc_combiner_create(); r->addrs_out = addrs; r->on_resolve_address_done = on_done; diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h index 9acef1d0ca9..28082504565 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -61,8 +61,9 @@ extern void (*grpc_resolve_address_ares)(const char* name, extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addresses, bool check_grpclb, - char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner); /* Cancel the pending grpc_ares_request \a request */ extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request); @@ -89,10 +90,12 @@ bool grpc_ares_query_ipv6(); * Returns a bool indicating whether or not such an action was performed. * See https://github.com/grpc/grpc/issues/15158. */ bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs); + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs); /* Sorts destinations in lb_addrs according to RFC 6724. */ -void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs); +void grpc_cares_wrapper_address_sorting_sort( + grpc_core::ServerAddressList* addresses); #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \ */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc index fc78b183044..1f4701c9994 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc @@ -29,16 +29,17 @@ struct grpc_ares_request { static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { return NULL; } grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {} diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc index 639eec2323f..028d8442169 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc @@ -27,7 +27,8 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs) { + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { return false; } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc index 7e34784691f..202452f1b2b 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc @@ -23,9 +23,9 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/socket_windows.h" @@ -33,8 +33,9 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } static bool inner_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs, - char** host, char** port) { + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs, char** host, + char** port) { gpr_split_host_port(name, host, port); if (*host == nullptr) { gpr_log(GPR_ERROR, @@ -55,7 +56,7 @@ static bool inner_maybe_resolve_localhost_manually_locked( } if (gpr_stricmp(*host, "localhost") == 0) { GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_lb_addresses_create(2, nullptr); + *addrs = grpc_core::MakeUnique(); uint16_t numeric_port = grpc_strhtons(*port); // Append the ipv6 loopback address. struct sockaddr_in6 ipv6_loopback_addr; @@ -63,10 +64,8 @@ static bool inner_maybe_resolve_localhost_manually_locked( ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1; ipv6_loopback_addr.sin6_family = AF_INET6; ipv6_loopback_addr.sin6_port = numeric_port; - grpc_lb_addresses_set_address( - *addrs, 0, &ipv6_loopback_addr, sizeof(ipv6_loopback_addr), - false /* is_balancer */, nullptr /* balancer_name */, - nullptr /* user_data */); + (*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr), + nullptr /* args */); // Append the ipv4 loopback address. struct sockaddr_in ipv4_loopback_addr; memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr)); @@ -74,19 +73,18 @@ static bool inner_maybe_resolve_localhost_manually_locked( ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01; ipv4_loopback_addr.sin_family = AF_INET; ipv4_loopback_addr.sin_port = numeric_port; - grpc_lb_addresses_set_address( - *addrs, 1, &ipv4_loopback_addr, sizeof(ipv4_loopback_addr), - false /* is_balancer */, nullptr /* balancer_name */, - nullptr /* user_data */); + (*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr), + nullptr /* args */); // Let the address sorter figure out which one should be tried first. - grpc_cares_wrapper_address_sorting_sort(*addrs); + grpc_cares_wrapper_address_sorting_sort(addrs->get()); return true; } return false; } bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs) { + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { char* host = nullptr; char* port = nullptr; bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port, diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc index 65ff1ec1a5b..c365f1abfd8 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -26,8 +26,8 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -198,18 +198,14 @@ void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(r->name_to_resolve_)); if (r->addresses_ != nullptr) { - grpc_lb_addresses* addresses = grpc_lb_addresses_create( - r->addresses_->naddrs, nullptr /* user_data_vtable */); + ServerAddressList addresses; for (size_t i = 0; i < r->addresses_->naddrs; ++i) { - grpc_lb_addresses_set_address( - addresses, i, &r->addresses_->addrs[i].addr, - r->addresses_->addrs[i].len, false /* is_balancer */, - nullptr /* balancer_name */, nullptr /* user_data */); + addresses.emplace_back(&r->addresses_->addrs[i].addr, + r->addresses_->addrs[i].len, nullptr /* args */); } - grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg new_arg = CreateServerAddressListChannelArg(&addresses); result = grpc_channel_args_copy_and_add(r->channel_args_, &new_arg, 1); grpc_resolved_addresses_destroy(r->addresses_); - grpc_lb_addresses_destroy(addresses); // Reset backoff state so that we start from the beginning when the // next request gets triggered. r->backoff_.Reset(); diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc index 3aa690bea41..258339491c1 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -28,12 +28,13 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h index 7f690593510..d86111c3829 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -19,10 +19,9 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted.h" -#include "src/core/lib/uri/uri_parser.h" +#include "src/core/lib/iomgr/error.h" #define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \ "grpc.fake_resolver.response_generator" diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc index 801734764b4..1654747a79f 100644 --- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc @@ -26,9 +26,9 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" @@ -45,7 +45,8 @@ namespace { class SockaddrResolver : public Resolver { public: /// Takes ownership of \a addresses. - SockaddrResolver(const ResolverArgs& args, grpc_lb_addresses* addresses); + SockaddrResolver(const ResolverArgs& args, + UniquePtr addresses); void NextLocked(grpc_channel_args** result, grpc_closure* on_complete) override; @@ -58,7 +59,7 @@ class SockaddrResolver : public Resolver { void MaybeFinishNextLocked(); /// the addresses that we've "resolved" - grpc_lb_addresses* addresses_ = nullptr; + UniquePtr addresses_; /// channel args grpc_channel_args* channel_args_ = nullptr; /// have we published? @@ -70,13 +71,12 @@ class SockaddrResolver : public Resolver { }; SockaddrResolver::SockaddrResolver(const ResolverArgs& args, - grpc_lb_addresses* addresses) + UniquePtr addresses) : Resolver(args.combiner), - addresses_(addresses), + addresses_(std::move(addresses)), channel_args_(grpc_channel_args_copy(args.args)) {} SockaddrResolver::~SockaddrResolver() { - grpc_lb_addresses_destroy(addresses_); grpc_channel_args_destroy(channel_args_); } @@ -100,7 +100,7 @@ void SockaddrResolver::ShutdownLocked() { void SockaddrResolver::MaybeFinishNextLocked() { if (next_completion_ != nullptr && !published_) { published_ = true; - grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses_); + grpc_arg arg = CreateServerAddressListChannelArg(addresses_.get()); *target_result_ = grpc_channel_args_copy_and_add(channel_args_, &arg, 1); GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE); next_completion_ = nullptr; @@ -127,27 +127,27 @@ OrphanablePtr CreateSockaddrResolver( grpc_slice_buffer path_parts; grpc_slice_buffer_init(&path_parts); grpc_slice_split(path_slice, ",", &path_parts); - grpc_lb_addresses* addresses = grpc_lb_addresses_create( - path_parts.count, nullptr /* user_data_vtable */); + auto addresses = MakeUnique(); bool errors_found = false; - for (size_t i = 0; i < addresses->num_addresses; i++) { + for (size_t i = 0; i < path_parts.count; i++) { grpc_uri ith_uri = *args.uri; - char* part_str = grpc_slice_to_c_string(path_parts.slices[i]); - ith_uri.path = part_str; - if (!parse(&ith_uri, &addresses->addresses[i].address)) { + UniquePtr part_str(grpc_slice_to_c_string(path_parts.slices[i])); + ith_uri.path = part_str.get(); + grpc_resolved_address addr; + if (!parse(&ith_uri, &addr)) { errors_found = true; /* GPR_TRUE */ + break; } - gpr_free(part_str); - if (errors_found) break; + addresses->emplace_back(addr, nullptr /* args */); } grpc_slice_buffer_destroy_internal(&path_parts); grpc_slice_unref_internal(path_slice); if (errors_found) { - grpc_lb_addresses_destroy(addresses); return OrphanablePtr(nullptr); } // Instantiate resolver. - return OrphanablePtr(New(args, addresses)); + return OrphanablePtr( + New(args, std::move(addresses))); } class IPv4ResolverFactory : public ResolverFactory { diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc index 4f7fd6b4243..22b06db45c4 100644 --- a/src/core/ext/filters/client_channel/resolver_result_parsing.cc +++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc @@ -30,9 +30,11 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/status_util.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/uri/uri_parser.h" // As per the retry design, we do not allow more than 5 retry attempts. #define MAX_MAX_RETRY_ATTEMPTS 5 @@ -99,12 +101,18 @@ void ProcessedResolverResult::ProcessLbPolicyName( } // Special case: If at least one balancer address is present, we use // the grpclb policy, regardless of what the resolver has returned. - const grpc_arg* channel_arg = - grpc_channel_args_find(resolver_result, GRPC_ARG_LB_ADDRESSES); - if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { - grpc_lb_addresses* addresses = - static_cast(channel_arg->value.pointer.p); - if (grpc_lb_addresses_contains_balancer_address(*addresses)) { + const ServerAddressList* addresses = + FindServerAddressListChannelArg(resolver_result); + if (addresses != nullptr) { + bool found_balancer_address = false; + for (size_t i = 0; i < addresses->size(); ++i) { + const ServerAddress& address = (*addresses)[i]; + if (address.IsBalancer()) { + found_balancer_address = true; + break; + } + } + if (found_balancer_address) { if (lb_policy_name_ != nullptr && strcmp(lb_policy_name_.get(), "grpclb") != 0) { gpr_log(GPR_INFO, diff --git a/src/core/ext/filters/client_channel/server_address.cc b/src/core/ext/filters/client_channel/server_address.cc new file mode 100644 index 00000000000..ec33cbbd956 --- /dev/null +++ b/src/core/ext/filters/client_channel/server_address.cc @@ -0,0 +1,103 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include "src/core/ext/filters/client_channel/server_address.h" + +#include + +namespace grpc_core { + +// +// ServerAddress +// + +ServerAddress::ServerAddress(const grpc_resolved_address& address, + grpc_channel_args* args) + : address_(address), args_(args) {} + +ServerAddress::ServerAddress(const void* address, size_t address_len, + grpc_channel_args* args) + : args_(args) { + memcpy(address_.addr, address, address_len); + address_.len = static_cast(address_len); +} + +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_); +} + +bool ServerAddress::IsBalancer() const { + return grpc_channel_arg_get_bool( + grpc_channel_args_find(args_, GRPC_ARG_ADDRESS_IS_BALANCER), false); +} + +// +// ServerAddressList +// + +namespace { + +void* ServerAddressListCopy(void* addresses) { + ServerAddressList* a = static_cast(addresses); + return New(*a); +} + +void ServerAddressListDestroy(void* addresses) { + ServerAddressList* a = static_cast(addresses); + Delete(a); +} + +int ServerAddressListCompare(void* addresses1, void* addresses2) { + ServerAddressList* a1 = static_cast(addresses1); + ServerAddressList* a2 = static_cast(addresses2); + if (a1->size() > a2->size()) return 1; + if (a1->size() < a2->size()) return -1; + for (size_t i = 0; i < a1->size(); ++i) { + int retval = (*a1)[i].Cmp((*a2)[i]); + if (retval != 0) return retval; + } + return 0; +} + +const grpc_arg_pointer_vtable server_addresses_arg_vtable = { + ServerAddressListCopy, ServerAddressListDestroy, ServerAddressListCompare}; + +} // namespace + +grpc_arg CreateServerAddressListChannelArg(const ServerAddressList* addresses) { + return grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_SERVER_ADDRESS_LIST), + const_cast(addresses), &server_addresses_arg_vtable); +} + +ServerAddressList* FindServerAddressListChannelArg( + const grpc_channel_args* channel_args) { + const grpc_arg* lb_addresses_arg = + grpc_channel_args_find(channel_args, GRPC_ARG_SERVER_ADDRESS_LIST); + if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) + return nullptr; + return static_cast(lb_addresses_arg->value.pointer.p); +} + +} // 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 new file mode 100644 index 00000000000..3a1bf1df67d --- /dev/null +++ b/src/core/ext/filters/client_channel/server_address.h @@ -0,0 +1,108 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H + +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gprpp/inlined_vector.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/uri/uri_parser.h" + +// Channel arg key for ServerAddressList. +#define GRPC_ARG_SERVER_ADDRESS_LIST "grpc.server_address_list" + +// Channel arg key for a bool indicating whether an address is a grpclb +// load balancer (as opposed to a backend). +#define GRPC_ARG_ADDRESS_IS_BALANCER "grpc.address_is_balancer" + +// Channel arg key for a string indicating an address's balancer name. +#define GRPC_ARG_ADDRESS_BALANCER_NAME "grpc.address_balancer_name" + +namespace grpc_core { + +// +// ServerAddress +// + +// A server address is a grpc_resolved_address with an associated set of +// channel args. Any args present here will be merged into the channel +// args when a subchannel is created for this address. +class ServerAddress { + public: + // Takes ownership of args. + ServerAddress(const grpc_resolved_address& address, grpc_channel_args* args); + ServerAddress(const void* address, size_t address_len, + grpc_channel_args* args); + + ~ServerAddress() { grpc_channel_args_destroy(args_); } + + // Copyable. + ServerAddress(const ServerAddress& other) + : address_(other.address_), args_(grpc_channel_args_copy(other.args_)) {} + ServerAddress& operator=(const ServerAddress& other) { + address_ = other.address_; + grpc_channel_args_destroy(args_); + args_ = grpc_channel_args_copy(other.args_); + return *this; + } + + // Movable. + ServerAddress(ServerAddress&& other) + : address_(other.address_), args_(other.args_) { + other.args_ = nullptr; + } + ServerAddress& operator=(ServerAddress&& other) { + address_ = other.address_; + args_ = other.args_; + other.args_ = nullptr; + return *this; + } + + bool operator==(const ServerAddress& other) const { return Cmp(other) == 0; } + + int Cmp(const ServerAddress& other) const; + + const grpc_resolved_address& address() const { return address_; } + const grpc_channel_args* args() const { return args_; } + + bool IsBalancer() const; + + private: + grpc_resolved_address address_; + grpc_channel_args* args_; +}; + +// +// ServerAddressList +// + +typedef InlinedVector ServerAddressList; + +// Returns a channel arg containing \a addresses. +grpc_arg CreateServerAddressListChannelArg(const ServerAddressList* addresses); + +// Returns the ServerListAddress instance in channel_args or NULL. +ServerAddressList* FindServerAddressListChannelArg( + const grpc_channel_args* channel_args); + +} // namespace grpc_core + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H */ diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 0817b1dd392..3100889e3fd 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -837,7 +837,7 @@ static bool publish_transport_locked(grpc_subchannel* c) { /* publish */ c->connected_subchannel.reset(grpc_core::New( - stk, c->channelz_subchannel, socket_uuid)); + stk, c->args, c->channelz_subchannel, socket_uuid)); gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p", c->connected_subchannel.get(), c); @@ -1068,16 +1068,18 @@ grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) { namespace grpc_core { ConnectedSubchannel::ConnectedSubchannel( - grpc_channel_stack* channel_stack, + grpc_channel_stack* channel_stack, const grpc_channel_args* args, grpc_core::RefCountedPtr channelz_subchannel, intptr_t socket_uuid) : RefCounted(&grpc_trace_stream_refcount), channel_stack_(channel_stack), + args_(grpc_channel_args_copy(args)), channelz_subchannel_(std::move(channelz_subchannel)), socket_uuid_(socket_uuid) {} ConnectedSubchannel::~ConnectedSubchannel() { + grpc_channel_args_destroy(args_); GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor"); } diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 69c2456ec20..14f87f2c68e 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -85,28 +85,31 @@ class ConnectedSubchannel : public RefCounted { size_t parent_data_size; }; - explicit ConnectedSubchannel( - grpc_channel_stack* channel_stack, + ConnectedSubchannel( + grpc_channel_stack* channel_stack, const grpc_channel_args* args, grpc_core::RefCountedPtr channelz_subchannel, intptr_t socket_uuid); ~ConnectedSubchannel(); - grpc_channel_stack* channel_stack() { return channel_stack_; } void NotifyOnStateChange(grpc_pollset_set* interested_parties, grpc_connectivity_state* state, grpc_closure* closure); void Ping(grpc_closure* on_initiate, grpc_closure* on_ack); grpc_error* CreateCall(const CallArgs& args, grpc_subchannel_call** call); - channelz::SubchannelNode* channelz_subchannel() { + + grpc_channel_stack* channel_stack() const { return channel_stack_; } + const grpc_channel_args* args() const { return args_; } + channelz::SubchannelNode* channelz_subchannel() const { return channelz_subchannel_.get(); } - intptr_t socket_uuid() { return socket_uuid_; } + intptr_t socket_uuid() const { return socket_uuid_; } size_t GetInitialCallSizeEstimate(size_t parent_data_size) const; private: grpc_channel_stack* channel_stack_; + grpc_channel_args* args_; // ref counted pointer to the channelz node in this connected subchannel's // owning subchannel. grpc_core::RefCountedPtr diff --git a/src/core/lib/iomgr/sockaddr_utils.cc b/src/core/lib/iomgr/sockaddr_utils.cc index 1b66dceb130..0839bdfef2d 100644 --- a/src/core/lib/iomgr/sockaddr_utils.cc +++ b/src/core/lib/iomgr/sockaddr_utils.cc @@ -217,6 +217,7 @@ void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port) { } char* grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) { + if (resolved_addr->len == 0) return nullptr; grpc_resolved_address addr_normalized; if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) { resolved_addr = &addr_normalized; diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index ce65c594fe2..c6ca970beee 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -322,7 +322,6 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -331,6 +330,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc index 76769b2b64a..1a7a7c9ccc9 100644 --- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc @@ -21,10 +21,10 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -63,8 +63,9 @@ static grpc_address_resolver_vtable test_resolver = {my_resolve_address, static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { gpr_mu_lock(&g_mu); GPR_ASSERT(0 == strcmp("test", addr)); grpc_error* error = GRPC_ERROR_NONE; @@ -74,9 +75,8 @@ static grpc_ares_request* my_dns_lookup_ares_locked( error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); } else { gpr_mu_unlock(&g_mu); - *lb_addrs = grpc_lb_addresses_create(1, nullptr); - grpc_lb_addresses_set_address(*lb_addrs, 0, nullptr, 0, false, nullptr, - nullptr); + *addresses = grpc_core::MakeUnique(); + (*addresses)->emplace_back(nullptr, 0, nullptr); } GRPC_CLOSURE_SCHED(on_done, error); return nullptr; diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc index cdbe33dbe79..16210b8164b 100644 --- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc @@ -22,6 +22,7 @@ #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/combiner.h" @@ -40,8 +41,9 @@ static grpc_combiner* g_combiner; static grpc_ares_request* (*g_default_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner); + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner); // Counter incremented by test_resolve_address_impl indicating the number of // times a system-level resolution has happened. @@ -90,11 +92,12 @@ static grpc_address_resolver_vtable test_resolver = { static grpc_ares_request* test_dns_lookup_ares_locked( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { grpc_ares_request* result = g_default_dns_lookup_ares_locked( - dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs, - check_grpclb, service_config_json, query_timeout_ms, combiner); + dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, + addresses, check_grpclb, service_config_json, query_timeout_ms, combiner); ++g_resolution_count; static grpc_millis last_resolution_time = 0; if (last_resolution_time == 0) { diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc index 6362b95e50e..3b06fe063ae 100644 --- a/test/core/client_channel/resolvers/fake_resolver_test.cc +++ b/test/core/client_channel/resolvers/fake_resolver_test.cc @@ -22,10 +22,10 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/combiner.h" @@ -63,12 +63,14 @@ void on_resolution_cb(void* arg, grpc_error* error) { // We only check the addresses channel arg because that's the only one // explicitly set by the test via // FakeResolverResponseGenerator::SetResponse(). - const grpc_lb_addresses* actual_lb_addresses = - grpc_lb_addresses_find_channel_arg(res->resolver_result); - const grpc_lb_addresses* expected_lb_addresses = - grpc_lb_addresses_find_channel_arg(res->expected_resolver_result); - GPR_ASSERT( - grpc_lb_addresses_cmp(actual_lb_addresses, expected_lb_addresses) == 0); + const grpc_core::ServerAddressList* actual_addresses = + grpc_core::FindServerAddressListChannelArg(res->resolver_result); + const grpc_core::ServerAddressList* expected_addresses = + grpc_core::FindServerAddressListChannelArg(res->expected_resolver_result); + GPR_ASSERT(actual_addresses->size() == expected_addresses->size()); + for (size_t i = 0; i < expected_addresses->size(); ++i) { + GPR_ASSERT((*actual_addresses)[i] == (*expected_addresses)[i]); + } grpc_channel_args_destroy(res->resolver_result); grpc_channel_args_destroy(res->expected_resolver_result); gpr_event_set(&res->ev, (void*)1); @@ -80,27 +82,35 @@ static grpc_channel_args* create_new_resolver_result() { const size_t num_addresses = 2; char* uri_string; char* balancer_name; - // Create grpc_lb_addresses. - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(num_addresses, nullptr); + // Create address list. + grpc_core::ServerAddressList addresses; for (size_t i = 0; i < num_addresses; ++i) { gpr_asprintf(&uri_string, "ipv4:127.0.0.1:100%" PRIuPTR, test_counter * num_addresses + i); grpc_uri* uri = grpc_uri_parse(uri_string, true); gpr_asprintf(&balancer_name, "balancer%" PRIuPTR, test_counter * num_addresses + i); - grpc_lb_addresses_set_address_from_uri( - addresses, i, uri, bool(num_addresses % 2), balancer_name, nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(uri, &address)); + grpc_core::InlinedVector args_to_add; + const bool is_balancer = num_addresses % 2; + if (is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), balancer_name)); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); + addresses.emplace_back(address.addr, address.len, args); gpr_free(balancer_name); grpc_uri_destroy(uri); gpr_free(uri_string); } - // Convert grpc_lb_addresses to grpc_channel_args. - const grpc_arg addresses_arg = - grpc_lb_addresses_create_channel_arg(addresses); + // Embed the address list in channel args. + const grpc_arg addresses_arg = CreateServerAddressListChannelArg(&addresses); grpc_channel_args* results = grpc_channel_args_copy_and_add(nullptr, &addresses_arg, 1); - grpc_lb_addresses_destroy(addresses); ++test_counter; return results; } diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index 9b6eddee6e1..fbf6379a698 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -24,8 +24,8 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -325,7 +325,7 @@ typedef struct addr_req { char* addr; grpc_closure* on_done; grpc_resolved_addresses** addrs; - grpc_lb_addresses** lb_addrs; + grpc_core::UniquePtr* addresses; } addr_req; static void finish_resolve(void* arg, grpc_error* error) { @@ -340,11 +340,9 @@ static void finish_resolve(void* arg, grpc_error* error) { gpr_malloc(sizeof(*addrs->addrs))); addrs->addrs[0].len = 0; *r->addrs = addrs; - } else if (r->lb_addrs != nullptr) { - grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(1, nullptr); - grpc_lb_addresses_set_address(lb_addrs, 0, nullptr, 0, false, nullptr, - nullptr); - *r->lb_addrs = lb_addrs; + } else if (r->addresses != nullptr) { + *r->addresses = grpc_core::MakeUnique(); + (*r->addresses)->emplace_back(nullptr, 0, nullptr); } GRPC_CLOSURE_SCHED(r->on_done, GRPC_ERROR_NONE); } else { @@ -354,18 +352,17 @@ static void finish_resolve(void* arg, grpc_error* error) { } gpr_free(r->addr); - gpr_free(r); + grpc_core::Delete(r); } void my_resolve_address(const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_resolved_addresses** addresses) { - addr_req* r = static_cast(gpr_malloc(sizeof(*r))); + grpc_resolved_addresses** addrs) { + addr_req* r = grpc_core::New(); r->addr = gpr_strdup(addr); r->on_done = on_done; - r->addrs = addresses; - r->lb_addrs = nullptr; + r->addrs = addrs; grpc_timer_init( &r->timer, GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(), GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx)); @@ -377,13 +374,14 @@ static grpc_address_resolver_vtable fuzzer_resolver = {my_resolve_address, grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - int query_timeout, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout, + grpc_combiner* combiner) { addr_req* r = static_cast(gpr_malloc(sizeof(*r))); r->addr = gpr_strdup(addr); r->on_done = on_done; r->addrs = nullptr; - r->lb_addrs = lb_addrs; + r->addresses = addresses; grpc_timer_init( &r->timer, GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(), GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx)); diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc index 66e8ca51614..7e3b418cd94 100644 --- a/test/core/end2end/goaway_server_test.cc +++ b/test/core/end2end/goaway_server_test.cc @@ -28,8 +28,8 @@ #include #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr.h" #include "test/core/end2end/cq_verifier.h" @@ -47,8 +47,9 @@ static int g_resolve_port = -1; static grpc_ares_request* (*iomgr_dns_lookup_ares_locked)( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addresses, bool check_grpclb, - char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner); static void (*iomgr_cancel_ares_request_locked)(grpc_ares_request* request); @@ -103,11 +104,12 @@ static grpc_address_resolver_vtable test_resolver = { static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { if (0 != strcmp(addr, "test")) { return iomgr_dns_lookup_ares_locked( - dns_server, addr, default_port, interested_parties, on_done, lb_addrs, + dns_server, addr, default_port, interested_parties, on_done, addresses, check_grpclb, service_config_json, query_timeout_ms, combiner); } @@ -117,15 +119,12 @@ static grpc_ares_request* my_dns_lookup_ares_locked( gpr_mu_unlock(&g_mu); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); } else { - *lb_addrs = grpc_lb_addresses_create(1, nullptr); - grpc_sockaddr_in* sa = - static_cast(gpr_zalloc(sizeof(grpc_sockaddr_in))); - sa->sin_family = GRPC_AF_INET; - sa->sin_addr.s_addr = 0x100007f; - sa->sin_port = grpc_htons(static_cast(g_resolve_port)); - grpc_lb_addresses_set_address(*lb_addrs, 0, sa, sizeof(*sa), false, nullptr, - nullptr); - gpr_free(sa); + *addresses = grpc_core::MakeUnique(); + grpc_sockaddr_in sa; + sa.sin_family = GRPC_AF_INET; + sa.sin_addr.s_addr = 0x100007f; + sa.sin_port = grpc_htons(static_cast(g_resolve_port)); + (*addresses)->emplace_back(&sa, sizeof(sa), nullptr); gpr_mu_unlock(&g_mu); } GRPC_CLOSURE_SCHED(on_done, error); diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc index 5dda748f5a5..c289e719eea 100644 --- a/test/core/end2end/no_server_test.cc +++ b/test/core/end2end/no_server_test.cc @@ -23,6 +23,7 @@ #include #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/lib/iomgr/exec_ctx.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/util/test_config.h" diff --git a/test/core/util/ubsan_suppressions.txt b/test/core/util/ubsan_suppressions.txt index 63898ea3b1c..8ed7d4d7fb6 100644 --- a/test/core/util/ubsan_suppressions.txt +++ b/test/core/util/ubsan_suppressions.txt @@ -25,7 +25,6 @@ alignment:absl::little_endian::Store64 alignment:absl::little_endian::Load64 float-divide-by-zero:grpc::testing::postprocess_scenario_result enum:grpc_op_string -nonnull-attribute:grpc_lb_addresses_copy signed-integer-overflow:chrono enum:grpc_http2_error_to_grpc_status -enum:grpc_chttp2_cancel_stream \ No newline at end of file +enum:grpc_chttp2_cancel_stream diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc index bf321d8a89e..124557eb567 100644 --- a/test/cpp/client/client_channel_stress_test.cc +++ b/test/cpp/client/client_channel_stress_test.cc @@ -34,7 +34,9 @@ #include #include +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -216,23 +218,31 @@ class ClientChannelStressTest { void SetNextResolution(const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(address_data.size(), nullptr); - for (size_t i = 0; i < address_data.size(); ++i) { + grpc_core::ServerAddressList addresses; + for (const auto& addr : address_data) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", address_data[i].port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", addr.port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_lb_addresses_set_address_from_uri( - addresses, i, lb_uri, address_data[i].is_balancer, - address_data[i].balancer_name.c_str(), nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + std::vector args_to_add; + if (addr.is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), + const_cast(addr.balancer_name.c_str()))); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); + addresses.emplace_back(address.addr, address.len, args); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } - grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetResponse(&fake_result); - grpc_lb_addresses_destroy(addresses); } void KeepSendingRequests() { diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index 759847be3e9..aed02edf044 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -35,7 +35,9 @@ #include #include +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/gpr/env.h" @@ -159,24 +161,22 @@ class ClientLbEnd2endTest : public ::testing::Test { } grpc_channel_args* BuildFakeResults(const std::vector& ports) { - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(ports.size(), nullptr); - for (size_t i = 0; i < ports.size(); ++i) { + grpc_core::ServerAddressList addresses; + for (const int& port : ports) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", ports[i]); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_lb_addresses_set_address_from_uri(addresses, i, lb_uri, - false /* is balancer */, - "" /* balancer name */, nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + addresses.emplace_back(address.addr, address.len, nullptr /* args */); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } const grpc_arg fake_addresses = - grpc_lb_addresses_create_channel_arg(addresses); + CreateServerAddressListChannelArg(&addresses); grpc_channel_args* fake_results = grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1); - grpc_lb_addresses_destroy(addresses); return fake_results; } diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index 9c4cd050619..bf990a07b5a 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -32,7 +32,9 @@ #include #include +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -486,18 +488,27 @@ class GrpclbEnd2endTest : public ::testing::Test { grpc::string balancer_name; }; - grpc_lb_addresses* CreateLbAddressesFromAddressDataList( + grpc_core::ServerAddressList CreateLbAddressesFromAddressDataList( const std::vector& address_data) { - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(address_data.size(), nullptr); - for (size_t i = 0; i < address_data.size(); ++i) { + grpc_core::ServerAddressList addresses; + for (const auto& addr : address_data) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", address_data[i].port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", addr.port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_lb_addresses_set_address_from_uri( - addresses, i, lb_uri, address_data[i].is_balancer, - address_data[i].balancer_name.c_str(), nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + std::vector args_to_add; + if (addr.is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), + const_cast(addr.balancer_name.c_str()))); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); + addresses.emplace_back(address.addr, address.len, args); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } @@ -506,23 +517,21 @@ class GrpclbEnd2endTest : public ::testing::Test { void SetNextResolution(const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses* addresses = + grpc_core::ServerAddressList addresses = CreateLbAddressesFromAddressDataList(address_data); - grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetResponse(&fake_result); - grpc_lb_addresses_destroy(addresses); } void SetNextReresolutionResponse( const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses* addresses = + grpc_core::ServerAddressList addresses = CreateLbAddressesFromAddressDataList(address_data); - grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetReresolutionResponse(&fake_result); - grpc_lb_addresses_destroy(addresses); } const std::vector GetBackendPorts(const size_t start_index = 0) const { diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc index 3eb0e7d7254..09e705df789 100644 --- a/test/cpp/naming/address_sorting_test.cc +++ b/test/cpp/naming/address_sorting_test.cc @@ -37,6 +37,7 @@ #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" @@ -167,30 +168,26 @@ void OverrideAddressSortingSourceAddrFactory( address_sorting_override_source_addr_factory_for_testing(factory); } -grpc_lb_addresses* BuildLbAddrInputs(std::vector test_addrs) { - grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, nullptr); - lb_addrs->addresses = - (grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size()); - lb_addrs->num_addresses = test_addrs.size(); - for (size_t i = 0; i < test_addrs.size(); i++) { - lb_addrs->addresses[i].address = - TestAddressToGrpcResolvedAddress(test_addrs[i]); +grpc_core::ServerAddressList BuildLbAddrInputs( + const std::vector& test_addrs) { + grpc_core::ServerAddressList addresses; + for (const auto& addr : test_addrs) { + addresses.emplace_back(TestAddressToGrpcResolvedAddress(addr), nullptr); } - return lb_addrs; + return addresses; } -void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, +void VerifyLbAddrOutputs(const grpc_core::ServerAddressList addresses, std::vector expected_addrs) { - EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size()); - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + EXPECT_EQ(addresses.size(), expected_addrs.size()); + for (size_t i = 0; i < addresses.size(); ++i) { char* ip_addr_str; - grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address, + grpc_sockaddr_to_string(&ip_addr_str, &addresses[i].address(), false /* normalize */); EXPECT_EQ(expected_addrs[i], ip_addr_str); gpr_free(ip_addr_str); } grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses_destroy(lb_addrs); } /* We need to run each test case inside of its own @@ -212,11 +209,11 @@ TEST_F(AddressSortingTest, TestDepriotizesUnreachableAddresses) { { {"1.2.3.4:443", {"4.3.2.1:443", AF_INET}}, }); - auto* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"1.2.3.4:443", AF_INET}, {"5.6.7.8:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "1.2.3.4:443", "5.6.7.8:443", @@ -235,7 +232,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "1.2.3.4:443", "[2607:f8b0:400a:801::1002]:443", @@ -251,11 +248,11 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, {"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2607:f8b0:400a:801::1002]:443", "1.2.3.4:443", @@ -275,11 +272,11 @@ TEST_F(AddressSortingTest, TestDepriotizesNonMatchingScope) { {"[fec0::5000]:443", {"[fec0::5001]:0", AF_INET6}}, // site-local and site-local scope }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2000:f8b0:400a:801::1002]:443", AF_INET6}, {"[fec0::5000]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fec0::5000]:443", "[2000:f8b0:400a:801::1002]:443", @@ -298,11 +295,11 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTable) { {"[2001::5001]:443", {"[2001::5002]:0", AF_INET6}}, // matching labels }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2002::5001]:443", AF_INET6}, {"[2001::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2001::5001]:443", "[2002::5001]:443", @@ -321,11 +318,11 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) { {"[2001::5001]:443", {"[2001::5002]:0", AF_INET6}}, // matching labels }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2001::5001]:443", AF_INET6}, {"[2002::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2001::5001]:443", "[2002::5001]:443", @@ -344,11 +341,11 @@ TEST_F(AddressSortingTest, {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, {"1.2.3.4:443", {"5.6.7.8:0", AF_INET}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs( lb_addrs, { // The AF_INET address should be IPv4-mapped by the sort, @@ -377,11 +374,11 @@ TEST_F(AddressSortingTest, {"[::1]:443", {"[::1]:0", AF_INET6}}, {v4_compat_dest, {v4_compat_src, AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {v4_compat_dest, AF_INET6}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", v4_compat_dest, @@ -400,11 +397,11 @@ TEST_F(AddressSortingTest, {"[1234::2]:443", {"[1234::2]:0", AF_INET6}}, {"[::1]:443", {"[::1]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[1234::2]:443", AF_INET6}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs( lb_addrs, { @@ -424,11 +421,11 @@ TEST_F(AddressSortingTest, {"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}}, {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2001::1234]:443", AF_INET6}, {"[2000::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs( lb_addrs, { // The 2000::/16 address should match the ::/0 prefix rule @@ -448,11 +445,11 @@ TEST_F( {"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}}, {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2001::1231]:443", AF_INET6}, {"[2000::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2000::5001]:443", "[2001::1231]:443", @@ -469,11 +466,11 @@ TEST_F(AddressSortingTest, {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, {"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[fec0::1234]:443", AF_INET6}, {"[fc00::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fc00::5001]:443", "[fec0::1234]:443", @@ -494,11 +491,11 @@ TEST_F( {"[::ffff:1.1.1.2]:443", {"[::ffff:1.1.1.3]:0", AF_INET6}}, {"[1234::2]:443", {"[1234::3]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[::ffff:1.1.1.2]:443", AF_INET6}, {"[1234::2]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { // ::ffff:0:2 should match the v4-mapped // precedence entry and be deprioritized. @@ -521,11 +518,11 @@ TEST_F(AddressSortingTest, TestPrefersSmallerScope) { {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"[fec0::1234]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fec0::1234]:443", "[3ffe::5001]:443", @@ -546,11 +543,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { {"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}}, {"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:5001::]:443", AF_INET6}, {"[3ffe:1234::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:1234::]:443", "[3ffe:5001::]:443", @@ -567,11 +564,11 @@ TEST_F(AddressSortingTest, {"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}}, {"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1234]:443", "[3ffe::5001]:443", @@ -587,11 +584,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { {"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}}, {"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:8000::]:443", AF_INET6}, {"[3ffe:2000::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:2000::]:443", "[3ffe:8000::]:443", @@ -607,11 +604,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { {"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}}, {"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:6::]:443", AF_INET6}, {"[3ffe:c::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:c::]:443", "[3ffe:6::]:443", @@ -629,11 +626,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { {"[3ffe:1111:1111:1110::]:443", {"[3ffe:1111:1111:1111::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:1111:1111:1110::]:443", AF_INET6}, {"[3ffe:1111:1111:1111::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:1111:1111:1111::]:443", "[3ffe:1111:1111:1110::]:443", @@ -651,11 +648,11 @@ TEST_F(AddressSortingTest, TestStableSort) { {"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}}, {"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1234]:443", "[3ffe::1235]:443", @@ -674,14 +671,14 @@ TEST_F(AddressSortingTest, TestStableSortFiveElements) { {"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}}, {"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::1231]:443", AF_INET6}, {"[3ffe::1232]:443", AF_INET6}, {"[3ffe::1233]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1231]:443", "[3ffe::1232]:443", @@ -695,14 +692,14 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExist) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::1231]:443", AF_INET6}, {"[3ffe::1232]:443", AF_INET6}, {"[3ffe::1233]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1231]:443", "[3ffe::1232]:443", @@ -716,11 +713,11 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[::ffff:5.6.7.8]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::ffff:5.6.7.8]:443", "1.2.3.4:443", @@ -744,11 +741,11 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { {"[fec0::2000]:443", {"[fec0::2001]:0", AF_INET6}}, {v4_compat_dest, {v4_compat_src, AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[fec0::2000]:443", AF_INET6}, {v4_compat_dest, AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { // The sort should be stable since @@ -765,11 +762,11 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { * (whether ipv4 loopback is available or not, an available ipv6 * loopback should be preferred). */ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[::1]:443", AF_INET6}, {"127.0.0.1:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", "127.0.0.1:443", @@ -779,11 +776,11 @@ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { /* Flip the order of the inputs above and expect the same output order * (try to rule out influence of arbitrary qsort ordering) */ TEST_F(AddressSortingTest, TestPrefersIpv6LoopbackInputsFlipped) { - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"127.0.0.1:443", AF_INET}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", "127.0.0.1:443", diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc index fe6fcb8d9cb..2ac2c237cea 100644 --- a/test/cpp/naming/resolver_component_test.cc +++ b/test/cpp/naming/resolver_component_test.cc @@ -41,6 +41,7 @@ #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" @@ -382,23 +383,19 @@ void CheckResolverResultLocked(void* argsp, grpc_error* err) { EXPECT_EQ(err, GRPC_ERROR_NONE); ArgsStruct* args = (ArgsStruct*)argsp; grpc_channel_args* channel_args = args->channel_args; - const grpc_arg* channel_arg = - grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(channel_arg != nullptr); - GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses* addresses = - (grpc_lb_addresses*)channel_arg->value.pointer.p; + grpc_core::ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(channel_args); gpr_log(GPR_INFO, "num addrs found: %" PRIdPTR ". expected %" PRIdPTR, - addresses->num_addresses, args->expected_addrs.size()); - GPR_ASSERT(addresses->num_addresses == args->expected_addrs.size()); + addresses->size(), args->expected_addrs.size()); + GPR_ASSERT(addresses->size() == args->expected_addrs.size()); std::vector found_lb_addrs; - for (size_t i = 0; i < addresses->num_addresses; i++) { - grpc_lb_address addr = addresses->addresses[i]; + for (size_t i = 0; i < addresses->size(); i++) { + grpc_core::ServerAddress& addr = (*addresses)[i]; char* str; - grpc_sockaddr_to_string(&str, &addr.address, 1 /* normalize */); + grpc_sockaddr_to_string(&str, &addr.address(), 1 /* normalize */); gpr_log(GPR_INFO, "%s", str); found_lb_addrs.emplace_back( - GrpcLBAddress(std::string(str), addr.is_balancer)); + GrpcLBAddress(std::string(str), addr.IsBalancer())); gpr_free(str); } if (args->expected_addrs.size() != found_lb_addrs.size()) { diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index dd5bead58ca..5011e19b03a 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -923,7 +923,6 @@ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h \ -src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_factory.h \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/lb_policy_registry.h \ @@ -959,6 +958,8 @@ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.h \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/retry_throttle.h \ +src/core/ext/filters/client_channel/server_address.cc \ +src/core/ext/filters/client_channel/server_address.h \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel.h \ src/core/ext/filters/client_channel/subchannel_index.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index a7231554e3d..c8a70f17c8d 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -10068,6 +10068,7 @@ "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.h", + "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h" ], @@ -10095,7 +10096,6 @@ "src/core/ext/filters/client_channel/http_proxy.h", "src/core/ext/filters/client_channel/lb_policy.cc", "src/core/ext/filters/client_channel/lb_policy.h", - "src/core/ext/filters/client_channel/lb_policy_factory.cc", "src/core/ext/filters/client_channel/lb_policy_factory.h", "src/core/ext/filters/client_channel/lb_policy_registry.cc", "src/core/ext/filters/client_channel/lb_policy_registry.h", @@ -10114,6 +10114,8 @@ "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.cc", "src/core/ext/filters/client_channel/retry_throttle.h", + "src/core/ext/filters/client_channel/server_address.cc", + "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.cc", From 7b81ae14a7c347f4971c319a93ba0690fe119ce9 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 7 Dec 2018 14:59:04 -0800 Subject: [PATCH 59/99] clang tidy and clang format --- .../transport/chttp2/server/insecure/server_chttp2_posix.cc | 2 +- src/core/ext/transport/inproc/inproc_transport.cc | 2 +- src/core/lib/surface/server.cc | 4 +++- test/core/bad_client/bad_client.cc | 2 +- test/core/end2end/fixtures/h2_sockpair+trace.cc | 2 +- test/core/end2end/fixtures/h2_sockpair.cc | 2 +- test/core/end2end/fixtures/h2_sockpair_1byte.cc | 2 +- test/core/end2end/fuzzers/api_fuzzer.cc | 2 +- test/core/end2end/fuzzers/server_fuzzer.cc | 2 +- test/cpp/end2end/client_interceptors_end2end_test.cc | 5 +++++ test/cpp/end2end/interceptors_util.cc | 1 + test/cpp/microbenchmarks/fullstack_fixtures.h | 2 +- test/cpp/performance/writes_per_rpc_test.cc | 2 +- 13 files changed, 19 insertions(+), 11 deletions(-) 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 b9024a87e24..c29c1e58cd9 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 @@ -61,7 +61,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server, grpc_endpoint_add_to_pollset(server_endpoint, pollsets[i]); } - grpc_server_setup_transport(server, transport, nullptr, server_args, 0); + grpc_server_setup_transport(server, transport, nullptr, server_args, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); } diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index 61968de4d58..0b9bf5dd11b 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -1236,7 +1236,7 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server, // TODO(ncteisen): design and support channelz GetSocket for inproc. grpc_server_setup_transport(server, server_transport, nullptr, server_args, - 0); + nullptr); grpc_channel* channel = grpc_channel_create( "inproc", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport); diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 5f7f630d16d..67b38e6f0c0 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -28,6 +28,8 @@ #include #include +#include + #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" #include "src/core/lib/debug/stats.h" @@ -1181,7 +1183,7 @@ void grpc_server_setup_transport( chand->server = s; server_ref(s); chand->channel = channel; - chand->socket_node = socket_node; + chand->socket_node = std::move(socket_node); size_t cq_idx; for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) { diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc index 4f5d2a2862b..ae1e42a4e0d 100644 --- a/test/core/bad_client/bad_client.cc +++ b/test/core/bad_client/bad_client.cc @@ -66,7 +66,7 @@ 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), 0); + grpc_server_get_channel_args(a->server), nullptr); } /* Sets the read_done event */ diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.cc b/test/core/end2end/fixtures/h2_sockpair+trace.cc index 4f393b22d05..45f78b59642 100644 --- a/test/core/end2end/fixtures/h2_sockpair+trace.cc +++ b/test/core/end2end/fixtures/h2_sockpair+trace.cc @@ -53,7 +53,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) { 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), 0); + grpc_server_get_channel_args(f->server), nullptr); } typedef struct { diff --git a/test/core/end2end/fixtures/h2_sockpair.cc b/test/core/end2end/fixtures/h2_sockpair.cc index 1627fe0eb49..77bce7ebb30 100644 --- a/test/core/end2end/fixtures/h2_sockpair.cc +++ b/test/core/end2end/fixtures/h2_sockpair.cc @@ -47,7 +47,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) { 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), 0); + grpc_server_get_channel_args(f->server), nullptr); } typedef struct { diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.cc b/test/core/end2end/fixtures/h2_sockpair_1byte.cc index 8f1024b774d..ac37841dc48 100644 --- a/test/core/end2end/fixtures/h2_sockpair_1byte.cc +++ b/test/core/end2end/fixtures/h2_sockpair_1byte.cc @@ -47,7 +47,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) { 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), 0); + grpc_server_get_channel_args(f->server), nullptr); } typedef struct { diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index 9b6eddee6e1..a3de56d4f9f 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -420,7 +420,7 @@ static void do_connect(void* arg, grpc_error* error) { grpc_transport* transport = grpc_create_chttp2_transport(nullptr, server, false); - grpc_server_setup_transport(g_server, transport, nullptr, nullptr, 0); + grpc_server_setup_transport(g_server, transport, nullptr, nullptr, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); GRPC_CLOSURE_SCHED(fc->closure, GRPC_ERROR_NONE); diff --git a/test/core/end2end/fuzzers/server_fuzzer.cc b/test/core/end2end/fuzzers/server_fuzzer.cc index bd686215ddb..d370dc7de85 100644 --- a/test/core/end2end/fuzzers/server_fuzzer.cc +++ b/test/core/end2end/fuzzers/server_fuzzer.cc @@ -62,7 +62,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, 0); + grpc_server_setup_transport(server, transport, nullptr, nullptr, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); grpc_call* call1 = nullptr; diff --git a/test/cpp/end2end/client_interceptors_end2end_test.cc b/test/cpp/end2end/client_interceptors_end2end_test.cc index 3a191d1e038..e11b2aa67f6 100644 --- a/test/cpp/end2end/client_interceptors_end2end_test.cc +++ b/test/cpp/end2end/client_interceptors_end2end_test.cc @@ -383,6 +383,7 @@ TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorHijackingTest) { std::vector> creators; // Add 20 dummy interceptors before hijacking interceptor + creators.reserve(20); for (auto i = 0; i < 20; i++) { creators.push_back(std::unique_ptr( new DummyInterceptorFactory())); @@ -423,6 +424,7 @@ TEST_F(ClientInterceptorsEnd2endTest, std::vector> creators; // Add 5 dummy interceptors before hijacking interceptor + creators.reserve(5); for (auto i = 0; i < 5; i++) { creators.push_back(std::unique_ptr( new DummyInterceptorFactory())); @@ -570,6 +572,7 @@ TEST_F(ClientGlobalInterceptorEnd2endTest, DummyGlobalInterceptor) { std::vector> creators; // Add 20 dummy interceptors + creators.reserve(20); for (auto i = 0; i < 20; i++) { creators.push_back(std::unique_ptr( new DummyInterceptorFactory())); @@ -595,6 +598,7 @@ TEST_F(ClientGlobalInterceptorEnd2endTest, LoggingGlobalInterceptor) { std::vector> creators; // Add 20 dummy interceptors + creators.reserve(20); for (auto i = 0; i < 20; i++) { creators.push_back(std::unique_ptr( new DummyInterceptorFactory())); @@ -620,6 +624,7 @@ TEST_F(ClientGlobalInterceptorEnd2endTest, HijackingGlobalInterceptor) { std::vector> creators; // Add 20 dummy interceptors + creators.reserve(20); for (auto i = 0; i < 20; i++) { creators.push_back(std::unique_ptr( new DummyInterceptorFactory())); diff --git a/test/cpp/end2end/interceptors_util.cc b/test/cpp/end2end/interceptors_util.cc index 5d59c1a4b72..e0ad7d1526c 100644 --- a/test/cpp/end2end/interceptors_util.cc +++ b/test/cpp/end2end/interceptors_util.cc @@ -137,6 +137,7 @@ CreateDummyClientInterceptors() { std::vector> creators; // Add 20 dummy interceptors before hijacking interceptor + creators.reserve(20); for (auto i = 0; i < 20; i++) { creators.push_back(std::unique_ptr( new DummyInterceptorFactory())); diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h index 71e8d9972bf..6bbf553bbd8 100644 --- a/test/cpp/microbenchmarks/fullstack_fixtures.h +++ b/test/cpp/microbenchmarks/fullstack_fixtures.h @@ -200,7 +200,7 @@ class EndpointPairFixture : public BaseFixture { } grpc_server_setup_transport(server_->c_server(), server_transport_, - nullptr, server_args, 0); + 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 3c5b3468848..7b22f23cf00 100644 --- a/test/cpp/performance/writes_per_rpc_test.cc +++ b/test/cpp/performance/writes_per_rpc_test.cc @@ -100,7 +100,7 @@ class EndpointPairFixture { } grpc_server_setup_transport(server_->c_server(), transport, nullptr, - server_args, 0); + server_args, nullptr); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); } From 27e2ba31bffa1c27fe12ad7d55e70b450eb777a8 Mon Sep 17 00:00:00 2001 From: hcaseyal Date: Fri, 7 Dec 2018 16:13:37 -0800 Subject: [PATCH 60/99] Revert "Allow encoding arbitrary channel args on a per-address basis." --- BUILD | 3 +- CMakeLists.txt | 12 +- Makefile | 12 +- build.yaml | 3 +- config.m4 | 2 +- config.w32 | 2 +- gRPC-C++.podspec | 1 - gRPC-Core.podspec | 4 +- grpc.gemspec | 3 +- grpc.gyp | 8 +- package.xml | 3 +- .../filters/client_channel/client_channel.cc | 16 +- .../ext/filters/client_channel/lb_policy.h | 9 +- .../client_channel/lb_policy/grpclb/grpclb.cc | 242 ++++++++++------- .../lb_policy/grpclb/grpclb_channel.h | 2 +- .../lb_policy/grpclb/grpclb_channel_secure.cc | 33 ++- .../lb_policy/grpclb/load_balancer_api.h | 2 +- .../lb_policy/pick_first/pick_first.cc | 19 +- .../lb_policy/round_robin/round_robin.cc | 40 ++- .../lb_policy/subchannel_list.h | 53 ++-- .../client_channel/lb_policy/xds/xds.cc | 247 +++++++++++++----- .../lb_policy/xds/xds_channel.h | 2 +- .../lb_policy/xds/xds_channel_secure.cc | 33 ++- .../lb_policy/xds/xds_load_balancer_api.h | 2 +- .../client_channel/lb_policy_factory.cc | 163 ++++++++++++ .../client_channel/lb_policy_factory.h | 86 +++++- .../resolver/dns/c_ares/dns_resolver_ares.cc | 12 +- .../dns/c_ares/grpc_ares_ev_driver.cc | 1 - .../resolver/dns/c_ares/grpc_ares_wrapper.cc | 149 ++++++----- .../resolver/dns/c_ares/grpc_ares_wrapper.h | 13 +- .../dns/c_ares/grpc_ares_wrapper_fallback.cc | 9 +- .../dns/c_ares/grpc_ares_wrapper_posix.cc | 3 +- .../dns/c_ares/grpc_ares_wrapper_windows.cc | 26 +- .../resolver/dns/native/dns_resolver.cc | 14 +- .../resolver/fake/fake_resolver.cc | 3 +- .../resolver/fake/fake_resolver.h | 3 +- .../resolver/sockaddr/sockaddr_resolver.cc | 34 +-- .../client_channel/resolver_result_parsing.cc | 20 +- .../filters/client_channel/server_address.cc | 103 -------- .../filters/client_channel/server_address.h | 108 -------- .../ext/filters/client_channel/subchannel.cc | 6 +- .../ext/filters/client_channel/subchannel.h | 13 +- src/core/lib/iomgr/sockaddr_utils.cc | 1 - src/python/grpcio/grpc_core_dependencies.py | 2 +- .../dns_resolver_connectivity_test.cc | 12 +- .../resolvers/dns_resolver_cooldown_test.cc | 15 +- .../resolvers/fake_resolver_test.cc | 42 ++- test/core/end2end/fuzzers/api_fuzzer.cc | 28 +- test/core/end2end/goaway_server_test.cc | 29 +- test/core/end2end/no_server_test.cc | 1 - test/core/util/ubsan_suppressions.txt | 3 +- test/cpp/client/client_channel_stress_test.cc | 28 +- test/cpp/end2end/client_lb_end2end_test.cc | 18 +- test/cpp/end2end/grpclb_end2end_test.cc | 37 +-- test/cpp/naming/address_sorting_test.cc | 127 ++++----- test/cpp/naming/resolver_component_test.cc | 21 +- tools/doxygen/Doxyfile.core.internal | 3 +- .../generated/sources_and_headers.json | 4 +- 58 files changed, 1044 insertions(+), 846 deletions(-) create mode 100644 src/core/ext/filters/client_channel/lb_policy_factory.cc delete mode 100644 src/core/ext/filters/client_channel/server_address.cc delete mode 100644 src/core/ext/filters/client_channel/server_address.h diff --git a/BUILD b/BUILD index 5550e583a87..9e3e594038d 100644 --- a/BUILD +++ b/BUILD @@ -1048,6 +1048,7 @@ grpc_cc_library( "src/core/ext/filters/client_channel/http_connect_handshaker.cc", "src/core/ext/filters/client_channel/http_proxy.cc", "src/core/ext/filters/client_channel/lb_policy.cc", + "src/core/ext/filters/client_channel/lb_policy_factory.cc", "src/core/ext/filters/client_channel/lb_policy_registry.cc", "src/core/ext/filters/client_channel/parse_address.cc", "src/core/ext/filters/client_channel/proxy_mapper.cc", @@ -1056,7 +1057,6 @@ grpc_cc_library( "src/core/ext/filters/client_channel/resolver_registry.cc", "src/core/ext/filters/client_channel/resolver_result_parsing.cc", "src/core/ext/filters/client_channel/retry_throttle.cc", - "src/core/ext/filters/client_channel/server_address.cc", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel_index.cc", ], @@ -1080,7 +1080,6 @@ grpc_cc_library( "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.h", - "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h", ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c660c77012..6b02d778d1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1240,6 +1240,7 @@ add_library(grpc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc + src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1248,7 +1249,6 @@ add_library(grpc src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -1592,6 +1592,7 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc + src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1600,7 +1601,6 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -1963,6 +1963,7 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc + src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1971,7 +1972,6 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -2283,6 +2283,7 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc + src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -2291,7 +2292,6 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -2617,6 +2617,7 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc + src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -2625,7 +2626,6 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -3469,6 +3469,7 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc + src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -3477,7 +3478,6 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc diff --git a/Makefile b/Makefile index 0163dc414a5..ed4e219f8b7 100644 --- a/Makefile +++ b/Makefile @@ -3735,6 +3735,7 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -3743,7 +3744,6 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4081,6 +4081,7 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4089,7 +4090,6 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4445,6 +4445,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4453,7 +4454,6 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4751,6 +4751,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4759,7 +4760,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -5058,6 +5058,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -5066,7 +5067,6 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -5885,6 +5885,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -5893,7 +5894,6 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ diff --git a/build.yaml b/build.yaml index 4521169e6c1..af70be8459a 100644 --- a/build.yaml +++ b/build.yaml @@ -589,7 +589,6 @@ filegroups: - src/core/ext/filters/client_channel/resolver_registry.h - src/core/ext/filters/client_channel/resolver_result_parsing.h - src/core/ext/filters/client_channel/retry_throttle.h - - src/core/ext/filters/client_channel/server_address.h - src/core/ext/filters/client_channel/subchannel.h - src/core/ext/filters/client_channel/subchannel_index.h src: @@ -604,6 +603,7 @@ filegroups: - src/core/ext/filters/client_channel/http_connect_handshaker.cc - src/core/ext/filters/client_channel/http_proxy.cc - src/core/ext/filters/client_channel/lb_policy.cc + - src/core/ext/filters/client_channel/lb_policy_factory.cc - src/core/ext/filters/client_channel/lb_policy_registry.cc - src/core/ext/filters/client_channel/parse_address.cc - src/core/ext/filters/client_channel/proxy_mapper.cc @@ -612,7 +612,6 @@ filegroups: - src/core/ext/filters/client_channel/resolver_registry.cc - src/core/ext/filters/client_channel/resolver_result_parsing.cc - src/core/ext/filters/client_channel/retry_throttle.cc - - src/core/ext/filters/client_channel/server_address.cc - src/core/ext/filters/client_channel/subchannel.cc - src/core/ext/filters/client_channel/subchannel_index.cc plugin: grpc_client_channel diff --git a/config.m4 b/config.m4 index 16de5204bb2..3db660aceea 100644 --- a/config.m4 +++ b/config.m4 @@ -348,6 +348,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ + src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -356,7 +357,6 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ - src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ diff --git a/config.w32 b/config.w32 index be10faab9cd..7f8b6eee5fa 100644 --- a/config.w32 +++ b/config.w32 @@ -323,6 +323,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " + "src\\core\\ext\\filters\\client_channel\\http_proxy.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy.cc " + + "src\\core\\ext\\filters\\client_channel\\lb_policy_factory.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy_registry.cc " + "src\\core\\ext\\filters\\client_channel\\parse_address.cc " + "src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " + @@ -331,7 +332,6 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " + "src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " + "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " + - "src\\core\\ext\\filters\\client_channel\\server_address.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " + "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 30fcb51ee19..e939bead1b7 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -356,7 +356,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', - 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 5ab7a49cd27..1d4e1ae35c0 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -354,7 +354,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', - 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', @@ -787,6 +786,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', + 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -795,7 +795,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', - 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -975,7 +974,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', - 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', diff --git a/grpc.gemspec b/grpc.gemspec index 1ee7bec8e7d..92b1e0be689 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -290,7 +290,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h ) s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h ) s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h ) - s.files += %w( src/core/ext/filters/client_channel/server_address.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.h ) @@ -726,6 +725,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc ) + s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.cc ) s.files += %w( src/core/ext/filters/client_channel/parse_address.cc ) s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc ) @@ -734,7 +734,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc ) - s.files += %w( src/core/ext/filters/client_channel/server_address.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc ) diff --git a/grpc.gyp b/grpc.gyp index 00f06a1e54e..564922ff727 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -540,6 +540,7 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', + 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -548,7 +549,6 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', - 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -799,6 +799,7 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', + 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -807,7 +808,6 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', - 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -1039,6 +1039,7 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', + 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -1047,7 +1048,6 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', - 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -1292,6 +1292,7 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', + 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -1300,7 +1301,6 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', - 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/package.xml b/package.xml index 68fc7433cb4..bdcb12bfc5e 100644 --- a/package.xml +++ b/package.xml @@ -295,7 +295,6 @@ - @@ -731,6 +730,7 @@ + @@ -739,7 +739,6 @@ - diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 70aac472314..ebc412b468d 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -38,7 +38,6 @@ #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/resolver_result_parsing.h" #include "src/core/ext/filters/client_channel/retry_throttle.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/deadline/deadline_filter.h" #include "src/core/lib/backoff/backoff.h" @@ -63,7 +62,6 @@ #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/status_metadata.h" -using grpc_core::ServerAddressList; using grpc_core::internal::ClientChannelMethodParams; using grpc_core::internal::ClientChannelMethodParamsTable; using grpc_core::internal::ProcessedResolverResult; @@ -385,10 +383,16 @@ static void create_new_lb_policy_locked( static void maybe_add_trace_message_for_address_changes_locked( channel_data* chand, TraceStringVector* trace_strings) { - const ServerAddressList* addresses = - grpc_core::FindServerAddressListChannelArg(chand->resolver_result); - const bool resolution_contains_addresses = - addresses != nullptr && addresses->size() > 0; + int resolution_contains_addresses = false; + const grpc_arg* channel_arg = + grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); + if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { + grpc_lb_addresses* addresses = + static_cast(channel_arg->value.pointer.p); + if (addresses->num_addresses > 0) { + resolution_contains_addresses = true; + } + } if (!resolution_contains_addresses && chand->previous_resolution_contained_addresses) { trace_strings->push_back(gpr_strdup("Address list became empty")); diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index 6b76fe5d5d7..7034da6249c 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -55,7 +55,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { grpc_client_channel_factory* client_channel_factory = nullptr; /// Channel args from the resolver. /// Note that the LB policy gets the set of addresses from the - /// GRPC_ARG_SERVER_ADDRESS_LIST channel arg. + /// GRPC_ARG_LB_ADDRESSES channel arg. grpc_channel_args* args = nullptr; /// Load balancing config from the resolver. grpc_json* lb_config = nullptr; @@ -80,6 +80,11 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Will be populated with context to pass to the subchannel call, if /// needed. grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT] = {}; + /// Upon success, \a *user_data will be set to whatever opaque information + /// may need to be propagated from the LB policy, or nullptr if not needed. + // TODO(roth): As part of revamping our metadata APIs, try to find a + // way to clean this up and C++-ify it. + void** user_data = nullptr; /// Next pointer. For internal use by LB policy. PickState* next = nullptr; }; @@ -90,7 +95,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Updates the policy with a new set of \a args and a new \a lb_config from /// the resolver. Note that the LB policy gets the set of addresses from the - /// GRPC_ARG_SERVER_ADDRESS_LIST channel arg. + /// GRPC_ARG_LB_ADDRESSES channel arg. virtual void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) GRPC_ABSTRACT; diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index a9a5965ed1c..a46579c7f74 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -84,7 +84,6 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" @@ -114,8 +113,6 @@ #define GRPC_GRPCLB_RECONNECT_JITTER 0.2 #define GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS 10000 -#define GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN "grpc.grpclb_address_lb_token" - namespace grpc_core { TraceFlag grpc_lb_glb_trace(false, "glb"); @@ -124,7 +121,7 @@ namespace { class GrpcLb : public LoadBalancingPolicy { public: - explicit GrpcLb(const Args& args); + GrpcLb(const grpc_lb_addresses* addresses, const Args& args); void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) override; @@ -164,6 +161,9 @@ class GrpcLb : public LoadBalancingPolicy { // Our on_complete closure and the original one. grpc_closure on_complete; grpc_closure* original_on_complete; + // The LB token associated with the pick. This is set via user_data in + // the pick. + grpc_mdelem lb_token; // Stats for client-side load reporting. RefCountedPtr client_stats; // Next pending pick. @@ -329,7 +329,7 @@ class GrpcLb : public LoadBalancingPolicy { // 0 means not using fallback. int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - UniquePtr fallback_backend_addresses_; + grpc_lb_addresses* fallback_backend_addresses_ = nullptr; // Fallback timer. bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; @@ -349,7 +349,7 @@ class GrpcLb : public LoadBalancingPolicy { // serverlist parsing code // -// vtable for LB token channel arg. +// vtable for LB tokens in grpc_lb_addresses void* lb_token_copy(void* token) { return token == nullptr ? nullptr @@ -361,11 +361,38 @@ void lb_token_destroy(void* token) { } } int lb_token_cmp(void* token1, void* token2) { - return GPR_ICMP(token1, token2); + if (token1 > token2) return 1; + if (token1 < token2) return -1; + return 0; } -const grpc_arg_pointer_vtable lb_token_arg_vtable = { +const grpc_lb_user_data_vtable lb_token_vtable = { lb_token_copy, lb_token_destroy, lb_token_cmp}; +// Returns the backend addresses extracted from the given addresses. +grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { + // First pass: count the number of backend addresses. + size_t num_backends = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) { + ++num_backends; + } + } + // Second pass: actually populate the addresses and (empty) LB tokens. + grpc_lb_addresses* backend_addresses = + grpc_lb_addresses_create(num_backends, &lb_token_vtable); + size_t num_copied = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) continue; + const grpc_resolved_address* addr = &addresses->addresses[i].address; + grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, + addr->len, false /* is_balancer */, + nullptr /* balancer_name */, + (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); + ++num_copied; + } + return backend_addresses; +} + bool IsServerValid(const grpc_grpclb_server* server, size_t idx, bool log) { if (server->drop) return false; const grpc_grpclb_ip_address* ip = &server->ip_address; @@ -413,16 +440,30 @@ void ParseServer(const grpc_grpclb_server* server, } // Returns addresses extracted from \a serverlist. -ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { - ServerAddressList addresses; +grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { + size_t num_valid = 0; + /* first pass: count how many are valid in order to allocate the necessary + * memory in a single block */ for (size_t i = 0; i < serverlist->num_servers; ++i) { - const grpc_grpclb_server* server = serverlist->servers[i]; - if (!IsServerValid(serverlist->servers[i], i, false)) continue; - // Address processing. + if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; + } + grpc_lb_addresses* lb_addresses = + grpc_lb_addresses_create(num_valid, &lb_token_vtable); + /* second pass: actually populate the addresses and LB tokens (aka user data + * to the outside world) to be read by the RR policy during its creation. + * Given that the validity tests are very cheap, they are performed again + * instead of marking the valid ones during the first pass, as this would + * incurr in an allocation due to the arbitrary number of server */ + size_t addr_idx = 0; + for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { + const grpc_grpclb_server* server = serverlist->servers[sl_idx]; + if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; + GPR_ASSERT(addr_idx < num_valid); + /* address processing */ grpc_resolved_address addr; ParseServer(server, &addr); - // LB token processing. - void* lb_token; + /* lb token processing */ + void* user_data; if (server->has_load_balance_token) { const size_t lb_token_max_length = GPR_ARRAY_SIZE(server->load_balance_token); @@ -430,7 +471,7 @@ ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { strnlen(server->load_balance_token, lb_token_max_length); grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( server->load_balance_token, lb_token_length); - lb_token = + user_data = (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) .payload; } else { @@ -440,16 +481,15 @@ ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { "be used instead", uri); gpr_free(uri); - lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; } - // Add address. - grpc_arg arg = grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token, - &lb_token_arg_vtable); - grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); - addresses.emplace_back(addr, args); - } - return addresses; + grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, + false /* is_balancer */, + nullptr /* balancer_name */, user_data); + ++addr_idx; + } + GPR_ASSERT(addr_idx == num_valid); + return lb_addresses; } // @@ -789,7 +829,8 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( grpc_grpclb_destroy_serverlist(grpclb_policy->serverlist_); } else { // Dispose of the fallback. - grpclb_policy->fallback_backend_addresses_.reset(); + grpc_lb_addresses_destroy(grpclb_policy->fallback_backend_addresses_); + grpclb_policy->fallback_backend_addresses_ = nullptr; if (grpclb_policy->fallback_timer_callback_pending_) { grpc_timer_cancel(&grpclb_policy->lb_fallback_timer_); } @@ -869,25 +910,31 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked( // helper code for creating balancer channel // -ServerAddressList ExtractBalancerAddresses(const ServerAddressList& addresses) { - ServerAddressList balancer_addresses; - for (size_t i = 0; i < addresses.size(); ++i) { - if (addresses[i].IsBalancer()) { - // Strip out the is_balancer channel arg, since we don't want to - // recursively use the grpclb policy in the channel used to talk to - // the balancers. Note that we do NOT strip out the balancer_name - // channel arg, since we need that to set the authority correctly - // to talk to the balancers. - static const char* args_to_remove[] = { - GRPC_ARG_ADDRESS_IS_BALANCER, - }; - balancer_addresses.emplace_back( - addresses[i].address(), - grpc_channel_args_copy_and_remove(addresses[i].args(), args_to_remove, - GPR_ARRAY_SIZE(args_to_remove))); +grpc_lb_addresses* ExtractBalancerAddresses( + const grpc_lb_addresses* addresses) { + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + } + // There must be at least one balancer address, or else the + // client_channel would not have chosen this LB policy. + GPR_ASSERT(num_grpclb_addrs > 0); + grpc_lb_addresses* lb_addresses = + grpc_lb_addresses_create(num_grpclb_addrs, nullptr); + size_t lb_addresses_idx = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) continue; + if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { + gpr_log(GPR_ERROR, + "This LB policy doesn't support user data. It will be ignored"); } + grpc_lb_addresses_set_address( + lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, + addresses->addresses[i].address.len, false /* is balancer */, + addresses->addresses[i].balancer_name, nullptr /* user data */); } - return balancer_addresses; + GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); + return lb_addresses; } /* Returns the channel args for the LB channel, used to create a bidirectional @@ -899,10 +946,10 @@ ServerAddressList ExtractBalancerAddresses(const ServerAddressList& addresses) { * above the grpclb policy. * - \a args: other args inherited from the grpclb policy. */ grpc_channel_args* BuildBalancerChannelArgs( - const ServerAddressList& addresses, + const grpc_lb_addresses* addresses, FakeResolverResponseGenerator* response_generator, const grpc_channel_args* args) { - ServerAddressList balancer_addresses = ExtractBalancerAddresses(addresses); + grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); // Channel args to remove. static const char* args_to_remove[] = { // LB policy name, since we want to use the default (pick_first) in @@ -920,7 +967,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // is_balancer=true. We need the LB channel to return addresses with // is_balancer=false so that it does not wind up recursively using the // grpclb LB policy, as per the special case logic in client_channel.c. - GRPC_ARG_SERVER_ADDRESS_LIST, + GRPC_ARG_LB_ADDRESSES, // The fake resolver response generator, because we are replacing it // with the one from the grpclb policy, used to propagate updates to // the LB channel. @@ -936,10 +983,10 @@ grpc_channel_args* BuildBalancerChannelArgs( }; // Channel args to add. const grpc_arg args_to_add[] = { - // New address list. + // New LB addresses. // Note that we pass these in both when creating the LB channel // and via the fake resolver. The latter is what actually gets used. - CreateServerAddressListChannelArg(&balancer_addresses), + grpc_lb_addresses_create_channel_arg(lb_addresses), // The fake resolver response generator, which we use to inject // address updates into the LB channel. grpc_core::FakeResolverResponseGenerator::MakeChannelArg( @@ -957,14 +1004,18 @@ grpc_channel_args* BuildBalancerChannelArgs( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Make any necessary modifications for security. - return grpc_lb_policy_grpclb_modify_lb_channel_args(new_args); + new_args = grpc_lb_policy_grpclb_modify_lb_channel_args(new_args); + // Clean up. + grpc_lb_addresses_destroy(lb_addresses); + return new_args; } // // ctor and dtor // -GrpcLb::GrpcLb(const LoadBalancingPolicy::Args& args) +GrpcLb::GrpcLb(const grpc_lb_addresses* addresses, + const LoadBalancingPolicy::Args& args) : LoadBalancingPolicy(args), response_generator_(MakeRefCounted()), lb_call_backoff_( @@ -1021,6 +1072,9 @@ GrpcLb::~GrpcLb() { if (serverlist_ != nullptr) { grpc_grpclb_destroy_serverlist(serverlist_); } + if (fallback_backend_addresses_ != nullptr) { + grpc_lb_addresses_destroy(fallback_backend_addresses_); + } grpc_subchannel_index_unref(); } @@ -1068,6 +1122,7 @@ void GrpcLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { while ((pp = pending_picks_) != nullptr) { pending_picks_ = pp->next; pp->pick->on_complete = pp->original_on_complete; + pp->pick->user_data = nullptr; grpc_error* error = GRPC_ERROR_NONE; if (new_policy->PickLocked(pp->pick, &error)) { // Synchronous return; schedule closure. @@ -1221,27 +1276,9 @@ void GrpcLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, notify); } -// Returns the backend addresses extracted from the given addresses. -UniquePtr ExtractBackendAddresses( - const ServerAddressList& addresses) { - void* lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; - grpc_arg arg = grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token, - &lb_token_arg_vtable); - auto backend_addresses = MakeUnique(); - for (size_t i = 0; i < addresses.size(); ++i) { - if (!addresses[i].IsBalancer()) { - backend_addresses->emplace_back( - addresses[i].address(), - grpc_channel_args_copy_and_add(addresses[i].args(), &arg, 1)); - } - } - return backend_addresses; -} - void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { - const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); - if (addresses == nullptr) { + const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); + if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { // Ignore this update. gpr_log( GPR_ERROR, @@ -1249,8 +1286,13 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { this); return; } + const grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); // Update fallback address list. - fallback_backend_addresses_ = ExtractBackendAddresses(*addresses); + if (fallback_backend_addresses_ != nullptr) { + grpc_lb_addresses_destroy(fallback_backend_addresses_); + } + fallback_backend_addresses_ = ExtractBackendAddresses(addresses); // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, // since we use this to trigger the client_load_reporting filter. static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; @@ -1261,7 +1303,7 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); // Construct args for balancer channel. grpc_channel_args* lb_channel_args = - BuildBalancerChannelArgs(*addresses, response_generator_.get(), &args); + BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); // Create balancer channel if needed. if (lb_channel_ == nullptr) { char* uri_str; @@ -1467,17 +1509,12 @@ void DestroyClientStats(void* arg) { } void GrpcLb::PendingPickSetMetadataAndContext(PendingPick* pp) { - // If connected_subchannel is nullptr, no pick has been made by the RR - // policy (e.g., all addresses failed to connect). There won't be any - // LB token available. + /* if connected_subchannel is nullptr, no pick has been made by the RR + * policy (e.g., all addresses failed to connect). There won't be any + * user_data/token available */ if (pp->pick->connected_subchannel != nullptr) { - const grpc_arg* arg = - grpc_channel_args_find(pp->pick->connected_subchannel->args(), - GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN); - if (arg != nullptr) { - grpc_mdelem lb_token = { - reinterpret_cast(arg->value.pointer.p)}; - AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(lb_token), + if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { + AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), &pp->pick->lb_token_mdelem_storage, pp->pick->initial_metadata); } else { @@ -1561,10 +1598,12 @@ bool GrpcLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp, return true; } } - // Set client_stats. + // Set client_stats and user_data. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); } + GPR_ASSERT(pp->pick->user_data == nullptr); + pp->pick->user_data = (void**)&pp->lb_token; // Pick via the RR policy. bool pick_done = rr_policy_->PickLocked(pp->pick, error); if (pick_done) { @@ -1629,11 +1668,10 @@ void GrpcLb::CreateRoundRobinPolicyLocked(const Args& args) { } grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { - ServerAddressList tmp_addresses; - ServerAddressList* addresses = &tmp_addresses; + grpc_lb_addresses* addresses; bool is_backend_from_grpclb_load_balancer = false; if (serverlist_ != nullptr) { - tmp_addresses = ProcessServerlist(serverlist_); + addresses = ProcessServerlist(serverlist_); is_backend_from_grpclb_load_balancer = true; } else { // If CreateOrUpdateRoundRobinPolicyLocked() is invoked when we haven't @@ -1642,14 +1680,14 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { // empty, in which case the new round_robin policy will keep the requested // picks pending. GPR_ASSERT(fallback_backend_addresses_ != nullptr); - addresses = fallback_backend_addresses_.get(); + addresses = grpc_lb_addresses_copy(fallback_backend_addresses_); } GPR_ASSERT(addresses != nullptr); - // Replace the server address list in the channel args that we pass down to + // Replace the LB addresses in the channel args that we pass down to // the subchannel. - static const char* keys_to_remove[] = {GRPC_ARG_SERVER_ADDRESS_LIST}; + static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; grpc_arg args_to_add[3] = { - CreateServerAddressListChannelArg(addresses), + grpc_lb_addresses_create_channel_arg(addresses), // A channel arg indicating if the target is a backend inferred from a // grpclb load balancer. grpc_channel_arg_integer_create( @@ -1666,6 +1704,7 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, num_args_to_add); + grpc_lb_addresses_destroy(addresses); return args; } @@ -1798,18 +1837,19 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory { OrphanablePtr CreateLoadBalancingPolicy( const LoadBalancingPolicy::Args& args) const override { /* Count the number of gRPC-LB addresses. There must be at least one. */ - const ServerAddressList* addresses = - FindServerAddressListChannelArg(args.args); - if (addresses == nullptr) return nullptr; - bool found_balancer = false; - for (size_t i = 0; i < addresses->size(); ++i) { - if ((*addresses)[i].IsBalancer()) { - found_balancer = true; - break; - } + const grpc_arg* arg = + grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); + if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { + return nullptr; + } + grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; } - if (!found_balancer) return nullptr; - return OrphanablePtr(New(args)); + if (num_grpclb_addrs == 0) return nullptr; + return OrphanablePtr(New(addresses, args)); } const char* name() const override { return "grpclb"; } diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h index 3b2dc370eb3..825065a9c32 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h @@ -21,7 +21,7 @@ #include -#include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" /// Makes any necessary modifications to \a args for use in the grpclb /// balancer channel. diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc index 6e8fbdcab77..441efd5e23b 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc @@ -26,7 +26,6 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -43,23 +42,22 @@ int BalancerNameCmp(const grpc_core::UniquePtr& a, } RefCountedPtr CreateTargetAuthorityTable( - const ServerAddressList& addresses) { + grpc_lb_addresses* addresses) { TargetAuthorityTable::Entry* target_authority_entries = - static_cast( - gpr_zalloc(sizeof(*target_authority_entries) * addresses.size())); - for (size_t i = 0; i < addresses.size(); ++i) { + static_cast(gpr_zalloc( + sizeof(*target_authority_entries) * addresses->num_addresses)); + for (size_t i = 0; i < addresses->num_addresses; ++i) { char* addr_str; - GPR_ASSERT( - grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true) > 0); + GPR_ASSERT(grpc_sockaddr_to_string( + &addr_str, &addresses->addresses[i].address, true) > 0); target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); + target_authority_entries[i].value.reset( + gpr_strdup(addresses->addresses[i].balancer_name)); gpr_free(addr_str); - char* balancer_name = grpc_channel_arg_get_string(grpc_channel_args_find( - addresses[i].args(), GRPC_ARG_ADDRESS_BALANCER_NAME)); - target_authority_entries[i].value.reset(gpr_strdup(balancer_name)); } RefCountedPtr target_authority_table = - TargetAuthorityTable::Create(addresses.size(), target_authority_entries, - BalancerNameCmp); + TargetAuthorityTable::Create(addresses->num_addresses, + target_authority_entries, BalancerNameCmp); gpr_free(target_authority_entries); return target_authority_table; } @@ -74,12 +72,13 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args( grpc_arg args_to_add[2]; size_t num_args_to_add = 0; // Add arg for targets info table. - grpc_core::ServerAddressList* addresses = - grpc_core::FindServerAddressListChannelArg(args); - GPR_ASSERT(addresses != nullptr); + const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); + GPR_ASSERT(arg != nullptr); + GPR_ASSERT(arg->type == GRPC_ARG_POINTER); + grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); grpc_core::RefCountedPtr - target_authority_table = - grpc_core::CreateTargetAuthorityTable(*addresses); + target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); args_to_add[num_args_to_add++] = grpc_core::CreateTargetAuthorityTableChannelArg( target_authority_table.get()); diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h index 71d371c880a..9ca7b28d8e6 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" -#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 74c17612a28..d1a05f12554 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -24,7 +24,6 @@ #include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/channel/channel_args.h" @@ -76,9 +75,11 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, grpc_subchannel* subchannel, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, grpc_combiner* combiner) - : SubchannelData(subchannel_list, address, subchannel, combiner) {} + : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, + combiner) {} void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; @@ -94,7 +95,7 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData> { public: PickFirstSubchannelList(PickFirst* policy, TraceFlag* tracer, - const ServerAddressList& addresses, + const grpc_lb_addresses* addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) @@ -336,8 +337,8 @@ void PickFirst::UpdateChildRefsLocked() { void PickFirst::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) { AutoChildRefsUpdater guard(this); - const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); - if (addresses == nullptr) { + const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); + if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { if (subchannel_list_ == nullptr) { // If we don't have a current subchannel list, go into TRANSIENT FAILURE. grpc_connectivity_state_set( @@ -353,17 +354,19 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args, } return; } + const grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); if (grpc_lb_pick_first_trace.enabled()) { gpr_log(GPR_INFO, "Pick First %p received update with %" PRIuPTR " addresses", this, - addresses->size()); + addresses->num_addresses); } grpc_arg new_arg = grpc_channel_arg_integer_create( const_cast(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1); grpc_channel_args* new_args = grpc_channel_args_copy_and_add(&args, &new_arg, 1); auto subchannel_list = MakeOrphanable( - this, &grpc_lb_pick_first_trace, *addresses, combiner(), + this, &grpc_lb_pick_first_trace, addresses, combiner(), client_channel_factory(), *new_args); grpc_channel_args_destroy(new_args); if (subchannel_list->num_subchannels() == 0) { diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 63089afbd78..2a169751317 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -82,6 +82,8 @@ class RoundRobin : public LoadBalancingPolicy { // Data for a particular subchannel in a subchannel list. // This subclass adds the following functionality: + // - Tracks user_data associated with each address, which will be + // returned along with picks that select the subchannel. // - Tracks the previous connectivity state of the subchannel, so that // we know how many subchannels are in each state. class RoundRobinSubchannelData @@ -91,9 +93,26 @@ class RoundRobin : public LoadBalancingPolicy { RoundRobinSubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, grpc_subchannel* subchannel, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, grpc_combiner* combiner) - : SubchannelData(subchannel_list, address, subchannel, combiner) {} + : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, + combiner), + user_data_vtable_(user_data_vtable), + user_data_(user_data_vtable_ != nullptr + ? user_data_vtable_->copy(address.user_data) + : nullptr) {} + + void UnrefSubchannelLocked(const char* reason) override { + SubchannelData::UnrefSubchannelLocked(reason); + if (user_data_ != nullptr) { + GPR_ASSERT(user_data_vtable_ != nullptr); + user_data_vtable_->destroy(user_data_); + user_data_ = nullptr; + } + } + + void* user_data() const { return user_data_; } grpc_connectivity_state connectivity_state() const { return last_connectivity_state_; @@ -106,6 +125,8 @@ class RoundRobin : public LoadBalancingPolicy { void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; + const grpc_lb_user_data_vtable* user_data_vtable_; + void* user_data_ = nullptr; grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_IDLE; }; @@ -116,7 +137,7 @@ class RoundRobin : public LoadBalancingPolicy { public: RoundRobinSubchannelList( RoundRobin* policy, TraceFlag* tracer, - const ServerAddressList& addresses, grpc_combiner* combiner, + const grpc_lb_addresses* addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : SubchannelList(policy, tracer, addresses, combiner, @@ -333,6 +354,9 @@ bool RoundRobin::DoPickLocked(PickState* pick) { subchannel_list_->subchannel(next_ready_index); GPR_ASSERT(sd->connected_subchannel() != nullptr); pick->connected_subchannel = sd->connected_subchannel()->Ref(); + if (pick->user_data != nullptr) { + *pick->user_data = sd->user_data(); + } if (grpc_lb_round_robin_trace.enabled()) { gpr_log(GPR_INFO, "[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, " @@ -643,9 +667,9 @@ void RoundRobin::NotifyOnStateChangeLocked(grpc_connectivity_state* current, void RoundRobin::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) { + const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); AutoChildRefsUpdater guard(this); - const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); - if (addresses == nullptr) { + if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", this); // If we don't have a current subchannel list, go into TRANSIENT_FAILURE. // Otherwise, keep using the current subchannel list (ignore this update). @@ -657,9 +681,11 @@ void RoundRobin::UpdateLocked(const grpc_channel_args& args, } return; } + grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); if (grpc_lb_round_robin_trace.enabled()) { gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses", - this, addresses->size()); + this, addresses->num_addresses); } // Replace latest_pending_subchannel_list_. if (latest_pending_subchannel_list_ != nullptr) { @@ -670,7 +696,7 @@ void RoundRobin::UpdateLocked(const grpc_channel_args& args, } } latest_pending_subchannel_list_ = MakeOrphanable( - this, &grpc_lb_round_robin_trace, *addresses, combiner(), + this, &grpc_lb_round_robin_trace, addresses, combiner(), client_channel_factory(), args); // If we haven't started picking yet or the new list is empty, // immediately promote the new list to the current list. diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 6f31a643c1d..f31401502c3 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -26,7 +26,6 @@ #include #include "src/core/ext/filters/client_channel/lb_policy_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/debug/trace.h" @@ -142,7 +141,8 @@ class SubchannelData { protected: SubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, grpc_subchannel* subchannel, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, grpc_combiner* combiner); virtual ~SubchannelData(); @@ -156,8 +156,9 @@ class SubchannelData { grpc_connectivity_state connectivity_state, grpc_error* error) GRPC_ABSTRACT; - // Unrefs the subchannel. - void UnrefSubchannelLocked(const char* reason); + // Unrefs the subchannel. May be overridden by subclasses that need + // to perform extra cleanup when unreffing the subchannel. + virtual void UnrefSubchannelLocked(const char* reason); private: // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_. @@ -231,7 +232,7 @@ class SubchannelList : public InternallyRefCounted { protected: SubchannelList(LoadBalancingPolicy* policy, TraceFlag* tracer, - const ServerAddressList& addresses, grpc_combiner* combiner, + const grpc_lb_addresses* addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args); @@ -276,7 +277,8 @@ class SubchannelList : public InternallyRefCounted { template SubchannelData::SubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, grpc_subchannel* subchannel, + const grpc_lb_user_data_vtable* user_data_vtable, + const grpc_lb_address& address, grpc_subchannel* subchannel, grpc_combiner* combiner) : subchannel_list_(subchannel_list), subchannel_(subchannel), @@ -486,7 +488,7 @@ void SubchannelData::ShutdownLocked() { template SubchannelList::SubchannelList( LoadBalancingPolicy* policy, TraceFlag* tracer, - const ServerAddressList& addresses, grpc_combiner* combiner, + const grpc_lb_addresses* addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : InternallyRefCounted(tracer), @@ -496,9 +498,9 @@ SubchannelList::SubchannelList( if (tracer_->enabled()) { gpr_log(GPR_INFO, "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", - tracer_->name(), policy, this, addresses.size()); + tracer_->name(), policy, this, addresses->num_addresses); } - subchannels_.reserve(addresses.size()); + subchannels_.reserve(addresses->num_addresses); // We need to remove the LB addresses in order to be able to compare the // subchannel keys of subchannels from a different batch of addresses. // We also remove the inhibit-health-checking arg, since we are @@ -506,27 +508,19 @@ SubchannelList::SubchannelList( inhibit_health_checking_ = grpc_channel_arg_get_bool( grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false); static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, - GRPC_ARG_SERVER_ADDRESS_LIST, + GRPC_ARG_LB_ADDRESSES, GRPC_ARG_INHIBIT_HEALTH_CHECKING}; // Create a subchannel for each address. grpc_subchannel_args sc_args; - for (size_t i = 0; i < addresses.size(); i++) { - // If there were any balancer addresses, we would have chosen grpclb - // policy, which does not use a SubchannelList. - GPR_ASSERT(!addresses[i].IsBalancer()); + for (size_t i = 0; i < addresses->num_addresses; i++) { + // If there were any balancer, we would have chosen grpclb policy instead. + GPR_ASSERT(!addresses->addresses[i].is_balancer); memset(&sc_args, 0, sizeof(grpc_subchannel_args)); - InlinedVector args_to_add; - args_to_add.emplace_back( - grpc_create_subchannel_address_arg(&addresses[i].address())); - if (addresses[i].args() != nullptr) { - for (size_t j = 0; j < addresses[i].args()->num_args; ++j) { - args_to_add.emplace_back(addresses[i].args()->args[j]); - } - } + grpc_arg addr_arg = + grpc_create_subchannel_address_arg(&addresses->addresses[i].address); grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( - &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), - args_to_add.data(), args_to_add.size()); - gpr_free(args_to_add[0].value.string); + &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, 1); + gpr_free(addr_arg.value.string); sc_args.args = new_args; grpc_subchannel* subchannel = grpc_client_channel_factory_create_subchannel( client_channel_factory, &sc_args); @@ -534,7 +528,8 @@ SubchannelList::SubchannelList( if (subchannel == nullptr) { // Subchannel could not be created. if (tracer_->enabled()) { - char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); + char* address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); gpr_log(GPR_INFO, "[%s %p] could not create subchannel for address uri %s, " "ignoring", @@ -544,7 +539,8 @@ SubchannelList::SubchannelList( continue; } if (tracer_->enabled()) { - char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); + char* address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR ": Created subchannel %p for address uri %s", @@ -552,7 +548,8 @@ SubchannelList::SubchannelList( address_uri); gpr_free(address_uri); } - subchannels_.emplace_back(this, addresses[i], subchannel, combiner); + subchannels_.emplace_back(this, addresses->user_data_vtable, + addresses->addresses[i], subchannel, combiner); } } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index 3c25de2386c..faedc0a9194 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -79,7 +79,6 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" @@ -117,7 +116,7 @@ namespace { class XdsLb : public LoadBalancingPolicy { public: - explicit XdsLb(const Args& args); + XdsLb(const grpc_lb_addresses* addresses, const Args& args); void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) override; @@ -157,6 +156,9 @@ class XdsLb : public LoadBalancingPolicy { // Our on_complete closure and the original one. grpc_closure on_complete; grpc_closure* original_on_complete; + // The LB token associated with the pick. This is set via user_data in + // the pick. + grpc_mdelem lb_token; // Stats for client-side load reporting. RefCountedPtr client_stats; // Next pending pick. @@ -254,7 +256,7 @@ class XdsLb : public LoadBalancingPolicy { grpc_error* error); // Pending pick methods. - static void PendingPickCleanup(PendingPick* pp); + static void PendingPickSetMetadataAndContext(PendingPick* pp); PendingPick* PendingPickCreate(PickState* pick); void AddPendingPick(PendingPick* pp); static void OnPendingPickComplete(void* arg, grpc_error* error); @@ -317,7 +319,7 @@ class XdsLb : public LoadBalancingPolicy { // 0 means not using fallback. int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - UniquePtr fallback_backend_addresses_; + grpc_lb_addresses* fallback_backend_addresses_ = nullptr; // Fallback timer. bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; @@ -337,15 +339,47 @@ class XdsLb : public LoadBalancingPolicy { // serverlist parsing code // +// vtable for LB tokens in grpc_lb_addresses +void* lb_token_copy(void* token) { + return token == nullptr + ? nullptr + : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload; +} +void lb_token_destroy(void* token) { + if (token != nullptr) { + GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token}); + } +} +int lb_token_cmp(void* token1, void* token2) { + if (token1 > token2) return 1; + if (token1 < token2) return -1; + return 0; +} +const grpc_lb_user_data_vtable lb_token_vtable = { + lb_token_copy, lb_token_destroy, lb_token_cmp}; + // Returns the backend addresses extracted from the given addresses. -UniquePtr ExtractBackendAddresses( - const ServerAddressList& addresses) { - auto backend_addresses = MakeUnique(); - for (size_t i = 0; i < addresses.size(); ++i) { - if (!addresses[i].IsBalancer()) { - backend_addresses->emplace_back(addresses[i]); +grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { + // First pass: count the number of backend addresses. + size_t num_backends = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) { + ++num_backends; } } + // Second pass: actually populate the addresses and (empty) LB tokens. + grpc_lb_addresses* backend_addresses = + grpc_lb_addresses_create(num_backends, &lb_token_vtable); + size_t num_copied = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) continue; + const grpc_resolved_address* addr = &addresses->addresses[i].address; + grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, + addr->len, false /* is_balancer */, + nullptr /* balancer_name */, + (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); + ++num_copied; + } return backend_addresses; } @@ -395,17 +429,56 @@ void ParseServer(const xds_grpclb_server* server, grpc_resolved_address* addr) { } // Returns addresses extracted from \a serverlist. -UniquePtr ProcessServerlist( - const xds_grpclb_serverlist* serverlist) { - auto addresses = MakeUnique(); +grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) { + size_t num_valid = 0; + /* first pass: count how many are valid in order to allocate the necessary + * memory in a single block */ for (size_t i = 0; i < serverlist->num_servers; ++i) { - const xds_grpclb_server* server = serverlist->servers[i]; - if (!IsServerValid(serverlist->servers[i], i, false)) continue; + if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; + } + grpc_lb_addresses* lb_addresses = + grpc_lb_addresses_create(num_valid, &lb_token_vtable); + /* second pass: actually populate the addresses and LB tokens (aka user data + * to the outside world) to be read by the child policy during its creation. + * Given that the validity tests are very cheap, they are performed again + * instead of marking the valid ones during the first pass, as this would + * incurr in an allocation due to the arbitrary number of server */ + size_t addr_idx = 0; + for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { + const xds_grpclb_server* server = serverlist->servers[sl_idx]; + if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; + GPR_ASSERT(addr_idx < num_valid); + /* address processing */ grpc_resolved_address addr; ParseServer(server, &addr); - addresses->emplace_back(addr, nullptr); + /* lb token processing */ + void* user_data; + if (server->has_load_balance_token) { + const size_t lb_token_max_length = + GPR_ARRAY_SIZE(server->load_balance_token); + const size_t lb_token_length = + strnlen(server->load_balance_token, lb_token_max_length); + grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( + server->load_balance_token, lb_token_length); + user_data = + (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) + .payload; + } else { + char* uri = grpc_sockaddr_to_uri(&addr); + gpr_log(GPR_INFO, + "Missing LB token for backend address '%s'. The empty token will " + "be used instead", + uri); + gpr_free(uri); + user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + } + grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, + false /* is_balancer */, + nullptr /* balancer_name */, user_data); + ++addr_idx; } - return addresses; + GPR_ASSERT(addr_idx == num_valid); + return lb_addresses; } // @@ -716,7 +789,8 @@ void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked( xds_grpclb_destroy_serverlist(xdslb_policy->serverlist_); } else { /* or dispose of the fallback */ - xdslb_policy->fallback_backend_addresses_.reset(); + grpc_lb_addresses_destroy(xdslb_policy->fallback_backend_addresses_); + xdslb_policy->fallback_backend_addresses_ = nullptr; if (xdslb_policy->fallback_timer_callback_pending_) { grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_); } @@ -802,15 +876,31 @@ void XdsLb::BalancerCallState::OnBalancerStatusReceivedLocked( // helper code for creating balancer channel // -UniquePtr ExtractBalancerAddresses( - const ServerAddressList& addresses) { - auto balancer_addresses = MakeUnique(); - for (size_t i = 0; i < addresses.size(); ++i) { - if (addresses[i].IsBalancer()) { - balancer_addresses->emplace_back(addresses[i]); +grpc_lb_addresses* ExtractBalancerAddresses( + const grpc_lb_addresses* addresses) { + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + } + // There must be at least one balancer address, or else the + // client_channel would not have chosen this LB policy. + GPR_ASSERT(num_grpclb_addrs > 0); + grpc_lb_addresses* lb_addresses = + grpc_lb_addresses_create(num_grpclb_addrs, nullptr); + size_t lb_addresses_idx = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) continue; + if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { + gpr_log(GPR_ERROR, + "This LB policy doesn't support user data. It will be ignored"); } + grpc_lb_addresses_set_address( + lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, + addresses->addresses[i].address.len, false /* is balancer */, + addresses->addresses[i].balancer_name, nullptr /* user data */); } - return balancer_addresses; + GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); + return lb_addresses; } /* Returns the channel args for the LB channel, used to create a bidirectional @@ -822,11 +912,10 @@ UniquePtr ExtractBalancerAddresses( * above the grpclb policy. * - \a args: other args inherited from the xds policy. */ grpc_channel_args* BuildBalancerChannelArgs( - const ServerAddressList& addresses, + const grpc_lb_addresses* addresses, FakeResolverResponseGenerator* response_generator, const grpc_channel_args* args) { - UniquePtr balancer_addresses = - ExtractBalancerAddresses(addresses); + grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); // Channel args to remove. static const char* args_to_remove[] = { // LB policy name, since we want to use the default (pick_first) in @@ -844,7 +933,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // is_balancer=true. We need the LB channel to return addresses with // is_balancer=false so that it does not wind up recursively using the // xds LB policy, as per the special case logic in client_channel.c. - GRPC_ARG_SERVER_ADDRESS_LIST, + GRPC_ARG_LB_ADDRESSES, // The fake resolver response generator, because we are replacing it // with the one from the xds policy, used to propagate updates to // the LB channel. @@ -860,10 +949,10 @@ grpc_channel_args* BuildBalancerChannelArgs( }; // Channel args to add. const grpc_arg args_to_add[] = { - // New server address list. + // New LB addresses. // Note that we pass these in both when creating the LB channel // and via the fake resolver. The latter is what actually gets used. - CreateServerAddressListChannelArg(balancer_addresses.get()), + grpc_lb_addresses_create_channel_arg(lb_addresses), // The fake resolver response generator, which we use to inject // address updates into the LB channel. grpc_core::FakeResolverResponseGenerator::MakeChannelArg( @@ -881,7 +970,10 @@ grpc_channel_args* BuildBalancerChannelArgs( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Make any necessary modifications for security. - return grpc_lb_policy_xds_modify_lb_channel_args(new_args); + new_args = grpc_lb_policy_xds_modify_lb_channel_args(new_args); + // Clean up. + grpc_lb_addresses_destroy(lb_addresses); + return new_args; } // @@ -889,7 +981,8 @@ grpc_channel_args* BuildBalancerChannelArgs( // // TODO(vishalpowar): Use lb_config in args to configure LB policy. -XdsLb::XdsLb(const LoadBalancingPolicy::Args& args) +XdsLb::XdsLb(const grpc_lb_addresses* addresses, + const LoadBalancingPolicy::Args& args) : LoadBalancingPolicy(args), response_generator_(MakeRefCounted()), lb_call_backoff_( @@ -945,6 +1038,9 @@ XdsLb::~XdsLb() { if (serverlist_ != nullptr) { xds_grpclb_destroy_serverlist(serverlist_); } + if (fallback_backend_addresses_ != nullptr) { + grpc_lb_addresses_destroy(fallback_backend_addresses_); + } grpc_subchannel_index_unref(); } @@ -992,6 +1088,7 @@ void XdsLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { while ((pp = pending_picks_) != nullptr) { pending_picks_ = pp->next; pp->pick->on_complete = pp->original_on_complete; + pp->pick->user_data = nullptr; grpc_error* error = GRPC_ERROR_NONE; if (new_policy->PickLocked(pp->pick, &error)) { // Synchronous return; schedule closure. @@ -1144,16 +1241,21 @@ void XdsLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, } void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { - const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); - if (addresses == nullptr) { + const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); + if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { // Ignore this update. gpr_log(GPR_ERROR, "[xdslb %p] No valid LB addresses channel arg in update, ignoring.", this); return; } + const grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); // Update fallback address list. - fallback_backend_addresses_ = ExtractBackendAddresses(*addresses); + if (fallback_backend_addresses_ != nullptr) { + grpc_lb_addresses_destroy(fallback_backend_addresses_); + } + fallback_backend_addresses_ = ExtractBackendAddresses(addresses); // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, // since we use this to trigger the client_load_reporting filter. static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; @@ -1164,7 +1266,7 @@ void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); // Construct args for balancer channel. grpc_channel_args* lb_channel_args = - BuildBalancerChannelArgs(*addresses, response_generator_.get(), &args); + BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); // Create balancer channel if needed. if (lb_channel_ == nullptr) { char* uri_str; @@ -1355,15 +1457,37 @@ void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg, // PendingPick // +// Adds lb_token of selected subchannel (address) to the call's initial +// metadata. +grpc_error* AddLbTokenToInitialMetadata( + grpc_mdelem lb_token, grpc_linked_mdelem* lb_token_mdelem_storage, + grpc_metadata_batch* initial_metadata) { + GPR_ASSERT(lb_token_mdelem_storage != nullptr); + GPR_ASSERT(!GRPC_MDISNULL(lb_token)); + return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage, + lb_token); +} + // Destroy function used when embedding client stats in call context. void DestroyClientStats(void* arg) { static_cast(arg)->Unref(); } -void XdsLb::PendingPickCleanup(PendingPick* pp) { - // If connected_subchannel is nullptr, no pick has been made by the - // child policy (e.g., all addresses failed to connect). +void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) { + /* if connected_subchannel is nullptr, no pick has been made by the + * child policy (e.g., all addresses failed to connect). There won't be any + * user_data/token available */ if (pp->pick->connected_subchannel != nullptr) { + if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { + AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), + &pp->pick->lb_token_mdelem_storage, + pp->pick->initial_metadata); + } else { + gpr_log(GPR_ERROR, + "[xdslb %p] No LB token for connected subchannel pick %p", + pp->xdslb_policy, pp->pick); + abort(); + } // Pass on client stats via context. Passes ownership of the reference. if (pp->client_stats != nullptr) { pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value = @@ -1381,7 +1505,7 @@ void XdsLb::PendingPickCleanup(PendingPick* pp) { * order to unref the child policy instance upon its invocation */ void XdsLb::OnPendingPickComplete(void* arg, grpc_error* error) { PendingPick* pp = static_cast(arg); - PendingPickCleanup(pp); + PendingPickSetMetadataAndContext(pp); GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error)); Delete(pp); } @@ -1413,14 +1537,16 @@ void XdsLb::AddPendingPick(PendingPick* pp) { // completion callback even if the pick is available immediately. bool XdsLb::PickFromChildPolicyLocked(bool force_async, PendingPick* pp, grpc_error** error) { - // Set client_stats. + // Set client_stats and user_data. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); } + GPR_ASSERT(pp->pick->user_data == nullptr); + pp->pick->user_data = (void**)&pp->lb_token; // Pick via the child policy. bool pick_done = child_policy_->PickLocked(pp->pick, error); if (pick_done) { - PendingPickCleanup(pp); + PendingPickSetMetadataAndContext(pp); if (force_async) { GRPC_CLOSURE_SCHED(pp->original_on_complete, *error); *error = GRPC_ERROR_NONE; @@ -1482,19 +1608,20 @@ void XdsLb::CreateChildPolicyLocked(const Args& args) { } grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() { + grpc_lb_addresses* addresses; bool is_backend_from_grpclb_load_balancer = false; // This should never be invoked if we do not have serverlist_, as fallback // mode is disabled for xDS plugin. GPR_ASSERT(serverlist_ != nullptr); GPR_ASSERT(serverlist_->num_servers > 0); - UniquePtr addresses = ProcessServerlist(serverlist_); - GPR_ASSERT(addresses != nullptr); + addresses = ProcessServerlist(serverlist_); is_backend_from_grpclb_load_balancer = true; - // Replace the server address list in the channel args that we pass down to + GPR_ASSERT(addresses != nullptr); + // Replace the LB addresses in the channel args that we pass down to // the subchannel. - static const char* keys_to_remove[] = {GRPC_ARG_SERVER_ADDRESS_LIST}; + static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; const grpc_arg args_to_add[] = { - CreateServerAddressListChannelArg(addresses.get()), + grpc_lb_addresses_create_channel_arg(addresses), // A channel arg indicating if the target is a backend inferred from a // grpclb load balancer. grpc_channel_arg_integer_create( @@ -1504,6 +1631,7 @@ grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() { grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); + grpc_lb_addresses_destroy(addresses); return args; } @@ -1637,18 +1765,19 @@ class XdsFactory : public LoadBalancingPolicyFactory { OrphanablePtr CreateLoadBalancingPolicy( const LoadBalancingPolicy::Args& args) const override { /* Count the number of gRPC-LB addresses. There must be at least one. */ - const ServerAddressList* addresses = - FindServerAddressListChannelArg(args.args); - if (addresses == nullptr) return nullptr; - bool found_balancer_address = false; - for (size_t i = 0; i < addresses->size(); ++i) { - if ((*addresses)[i].IsBalancer()) { - found_balancer_address = true; - break; - } + const grpc_arg* arg = + grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); + if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { + return nullptr; + } + grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; } - if (!found_balancer_address) return nullptr; - return OrphanablePtr(New(args)); + if (num_grpclb_addrs == 0) return nullptr; + return OrphanablePtr(New(addresses, args)); } const char* name() const override { return "xds_experimental"; } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h index f713b7f563d..32c4acc8a3e 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h @@ -21,7 +21,7 @@ #include -#include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" /// Makes any necessary modifications to \a args for use in the xds /// balancer channel. diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc index 9a11f8e39fd..5ab72efce46 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc @@ -25,7 +25,6 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -42,23 +41,22 @@ int BalancerNameCmp(const grpc_core::UniquePtr& a, } RefCountedPtr CreateTargetAuthorityTable( - const ServerAddressList& addresses) { + grpc_lb_addresses* addresses) { TargetAuthorityTable::Entry* target_authority_entries = - static_cast( - gpr_zalloc(sizeof(*target_authority_entries) * addresses.size())); - for (size_t i = 0; i < addresses.size(); ++i) { + static_cast(gpr_zalloc( + sizeof(*target_authority_entries) * addresses->num_addresses)); + for (size_t i = 0; i < addresses->num_addresses; ++i) { char* addr_str; - GPR_ASSERT( - grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true) > 0); + GPR_ASSERT(grpc_sockaddr_to_string( + &addr_str, &addresses->addresses[i].address, true) > 0); target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); + target_authority_entries[i].value.reset( + gpr_strdup(addresses->addresses[i].balancer_name)); gpr_free(addr_str); - char* balancer_name = grpc_channel_arg_get_string(grpc_channel_args_find( - addresses[i].args(), GRPC_ARG_ADDRESS_BALANCER_NAME)); - target_authority_entries[i].value.reset(gpr_strdup(balancer_name)); } RefCountedPtr target_authority_table = - TargetAuthorityTable::Create(addresses.size(), target_authority_entries, - BalancerNameCmp); + TargetAuthorityTable::Create(addresses->num_addresses, + target_authority_entries, BalancerNameCmp); gpr_free(target_authority_entries); return target_authority_table; } @@ -73,12 +71,13 @@ grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( grpc_arg args_to_add[2]; size_t num_args_to_add = 0; // Add arg for targets info table. - grpc_core::ServerAddressList* addresses = - grpc_core::FindServerAddressListChannelArg(args); - GPR_ASSERT(addresses != nullptr); + const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); + GPR_ASSERT(arg != nullptr); + GPR_ASSERT(arg->type == GRPC_ARG_POINTER); + grpc_lb_addresses* addresses = + static_cast(arg->value.pointer.p); grpc_core::RefCountedPtr - target_authority_table = - grpc_core::CreateTargetAuthorityTable(*addresses); + target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); args_to_add[num_args_to_add++] = grpc_core::CreateTargetAuthorityTableChannelArg( target_authority_table.get()); diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h index 67049956417..9d08defa7ef 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" -#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #define XDS_SERVICE_NAME_MAX_LENGTH 128 diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.cc b/src/core/ext/filters/client_channel/lb_policy_factory.cc new file mode 100644 index 00000000000..5c6363d2952 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy_factory.cc @@ -0,0 +1,163 @@ +/* + * + * 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. + * + */ + +#include + +#include + +#include +#include + +#include "src/core/lib/channel/channel_args.h" + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/parse_address.h" + +grpc_lb_addresses* grpc_lb_addresses_create( + size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) { + grpc_lb_addresses* addresses = + static_cast(gpr_zalloc(sizeof(grpc_lb_addresses))); + addresses->num_addresses = num_addresses; + addresses->user_data_vtable = user_data_vtable; + const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses; + addresses->addresses = + static_cast(gpr_zalloc(addresses_size)); + return addresses; +} + +grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses) { + grpc_lb_addresses* new_addresses = grpc_lb_addresses_create( + addresses->num_addresses, addresses->user_data_vtable); + memcpy(new_addresses->addresses, addresses->addresses, + sizeof(grpc_lb_address) * addresses->num_addresses); + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (new_addresses->addresses[i].balancer_name != nullptr) { + new_addresses->addresses[i].balancer_name = + gpr_strdup(new_addresses->addresses[i].balancer_name); + } + if (new_addresses->addresses[i].user_data != nullptr) { + new_addresses->addresses[i].user_data = addresses->user_data_vtable->copy( + new_addresses->addresses[i].user_data); + } + } + return new_addresses; +} + +void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, + const void* address, size_t address_len, + bool is_balancer, const char* balancer_name, + void* user_data) { + GPR_ASSERT(index < addresses->num_addresses); + if (user_data != nullptr) GPR_ASSERT(addresses->user_data_vtable != nullptr); + grpc_lb_address* target = &addresses->addresses[index]; + memcpy(target->address.addr, address, address_len); + target->address.len = static_cast(address_len); + target->is_balancer = is_balancer; + target->balancer_name = gpr_strdup(balancer_name); + target->user_data = user_data; +} + +bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, + size_t index, const grpc_uri* uri, + bool is_balancer, + const char* balancer_name, + void* user_data) { + grpc_resolved_address address; + if (!grpc_parse_uri(uri, &address)) return false; + grpc_lb_addresses_set_address(addresses, index, address.addr, address.len, + is_balancer, balancer_name, user_data); + return true; +} + +int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, + const grpc_lb_addresses* addresses2) { + if (addresses1->num_addresses > addresses2->num_addresses) return 1; + if (addresses1->num_addresses < addresses2->num_addresses) return -1; + if (addresses1->user_data_vtable > addresses2->user_data_vtable) return 1; + if (addresses1->user_data_vtable < addresses2->user_data_vtable) return -1; + for (size_t i = 0; i < addresses1->num_addresses; ++i) { + const grpc_lb_address* target1 = &addresses1->addresses[i]; + const grpc_lb_address* target2 = &addresses2->addresses[i]; + if (target1->address.len > target2->address.len) return 1; + if (target1->address.len < target2->address.len) return -1; + int retval = memcmp(target1->address.addr, target2->address.addr, + target1->address.len); + if (retval != 0) return retval; + if (target1->is_balancer > target2->is_balancer) return 1; + if (target1->is_balancer < target2->is_balancer) return -1; + const char* balancer_name1 = + target1->balancer_name != nullptr ? target1->balancer_name : ""; + const char* balancer_name2 = + target2->balancer_name != nullptr ? target2->balancer_name : ""; + retval = strcmp(balancer_name1, balancer_name2); + if (retval != 0) return retval; + if (addresses1->user_data_vtable != nullptr) { + retval = addresses1->user_data_vtable->cmp(target1->user_data, + target2->user_data); + if (retval != 0) return retval; + } + } + return 0; +} + +void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) { + for (size_t i = 0; i < addresses->num_addresses; ++i) { + gpr_free(addresses->addresses[i].balancer_name); + if (addresses->addresses[i].user_data != nullptr) { + addresses->user_data_vtable->destroy(addresses->addresses[i].user_data); + } + } + gpr_free(addresses->addresses); + gpr_free(addresses); +} + +static void* lb_addresses_copy(void* addresses) { + return grpc_lb_addresses_copy(static_cast(addresses)); +} +static void lb_addresses_destroy(void* addresses) { + grpc_lb_addresses_destroy(static_cast(addresses)); +} +static int lb_addresses_cmp(void* addresses1, void* addresses2) { + return grpc_lb_addresses_cmp(static_cast(addresses1), + static_cast(addresses2)); +} +static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = { + lb_addresses_copy, lb_addresses_destroy, lb_addresses_cmp}; + +grpc_arg grpc_lb_addresses_create_channel_arg( + const grpc_lb_addresses* addresses) { + return grpc_channel_arg_pointer_create( + (char*)GRPC_ARG_LB_ADDRESSES, (void*)addresses, &lb_addresses_arg_vtable); +} + +grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( + const grpc_channel_args* channel_args) { + const grpc_arg* lb_addresses_arg = + grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); + if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) + return nullptr; + return static_cast(lb_addresses_arg->value.pointer.p); +} + +bool grpc_lb_addresses_contains_balancer_address( + const grpc_lb_addresses& addresses) { + for (size_t i = 0; i < addresses.num_addresses; ++i) { + if (addresses.addresses[i].is_balancer) return true; + } + return false; +} diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h index a165ebafaba..a59deadb265 100644 --- a/src/core/ext/filters/client_channel/lb_policy_factory.h +++ b/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -21,9 +21,91 @@ #include +#include "src/core/lib/iomgr/resolve_address.h" + +#include "src/core/ext/filters/client_channel/client_channel_factory.h" #include "src/core/ext/filters/client_channel/lb_policy.h" -#include "src/core/lib/gprpp/abstract.h" -#include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/uri/uri_parser.h" + +// +// representation of an LB address +// + +// Channel arg key for grpc_lb_addresses. +#define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses" + +/** A resolved address alongside any LB related information associated with it. + * \a user_data, if not NULL, contains opaque data meant to be consumed by the + * gRPC LB policy. Note that no all LB policies support \a user_data as input. + * Those who don't will simply ignore it and will correspondingly return NULL in + * their namesake pick() output argument. */ +// TODO(roth): Once we figure out a better way of handling user_data in +// LB policies, convert these structs to C++ classes. +typedef struct grpc_lb_address { + grpc_resolved_address address; + bool is_balancer; + char* balancer_name; /* For secure naming. */ + void* user_data; +} grpc_lb_address; + +typedef struct grpc_lb_user_data_vtable { + void* (*copy)(void*); + void (*destroy)(void*); + int (*cmp)(void*, void*); +} grpc_lb_user_data_vtable; + +typedef struct grpc_lb_addresses { + size_t num_addresses; + grpc_lb_address* addresses; + const grpc_lb_user_data_vtable* user_data_vtable; +} grpc_lb_addresses; + +/** Returns a grpc_addresses struct with enough space for + \a num_addresses addresses. The \a user_data_vtable argument may be + NULL if no user data will be added. */ +grpc_lb_addresses* grpc_lb_addresses_create( + size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable); + +/** Creates a copy of \a addresses. */ +grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses); + +/** Sets the value of the address at index \a index of \a addresses. + * \a address is a socket address of length \a address_len. */ +void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, + const void* address, size_t address_len, + bool is_balancer, const char* balancer_name, + void* user_data); + +/** Sets the value of the address at index \a index of \a addresses from \a uri. + * Returns true upon success, false otherwise. */ +bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, + size_t index, const grpc_uri* uri, + bool is_balancer, + const char* balancer_name, + void* user_data); + +/** Compares \a addresses1 and \a addresses2. */ +int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, + const grpc_lb_addresses* addresses2); + +/** Destroys \a addresses. */ +void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses); + +/** Returns a channel arg containing \a addresses. */ +grpc_arg grpc_lb_addresses_create_channel_arg( + const grpc_lb_addresses* addresses); + +/** Returns the \a grpc_lb_addresses instance in \a channel_args or NULL */ +grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( + const grpc_channel_args* channel_args); + +// Returns true if addresses contains at least one balancer address. +bool grpc_lb_addresses_contains_balancer_address( + const grpc_lb_addresses& addresses); + +// +// LB policy factory +// namespace grpc_core { diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index c8425ae3365..4ebc2c8161c 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -33,7 +33,6 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -118,7 +117,7 @@ class AresDnsResolver : public Resolver { /// retry backoff state BackOff backoff_; /// currently resolving addresses - UniquePtr addresses_; + grpc_lb_addresses* lb_addresses_ = nullptr; /// currently resolving service config char* service_config_json_ = nullptr; // has shutdown been initiated @@ -315,13 +314,13 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->resolving_ = false; gpr_free(r->pending_request_); r->pending_request_ = nullptr; - if (r->addresses_ != nullptr) { + if (r->lb_addresses_ != nullptr) { static const char* args_to_remove[1]; size_t num_args_to_remove = 0; grpc_arg args_to_add[2]; size_t num_args_to_add = 0; args_to_add[num_args_to_add++] = - CreateServerAddressListChannelArg(r->addresses_.get()); + grpc_lb_addresses_create_channel_arg(r->lb_addresses_); char* service_config_string = nullptr; if (r->service_config_json_ != nullptr) { service_config_string = ChooseServiceConfig(r->service_config_json_); @@ -338,7 +337,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->channel_args_, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add); gpr_free(service_config_string); - r->addresses_.reset(); + grpc_lb_addresses_destroy(r->lb_addresses_); // Reset backoff state so that we start from the beginning when the // next request gets triggered. r->backoff_.Reset(); @@ -413,10 +412,11 @@ void AresDnsResolver::StartResolvingLocked() { self.release(); GPR_ASSERT(!resolving_); resolving_ = true; + lb_addresses_ = nullptr; service_config_json_ = nullptr; pending_request_ = grpc_dns_lookup_ares_locked( dns_server_, name_to_resolve_, kDefaultPort, interested_parties_, - &on_resolved_, &addresses_, true /* check_grpclb */, + &on_resolved_, &lb_addresses_, true /* check_grpclb */, request_service_config_ ? &service_config_json_ : nullptr, query_timeout_ms_, combiner()); last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now(); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc index 8abc34c6edb..f42b1e309df 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc @@ -31,7 +31,6 @@ #include #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/lib/gpr/string.h" -#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/timer.h" diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 1b1c2303da3..55715869b63 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -37,16 +37,12 @@ #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" -#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/nameser.h" #include "src/core/lib/iomgr/sockaddr_utils.h" -using grpc_core::ServerAddress; -using grpc_core::ServerAddressList; - static gpr_once g_basic_init = GPR_ONCE_INIT; static gpr_mu g_init_mu; @@ -62,7 +58,7 @@ struct grpc_ares_request { /** closure to call when the request completes */ grpc_closure* on_done; /** the pointer to receive the resolved addresses */ - grpc_core::UniquePtr* addresses_out; + grpc_lb_addresses** lb_addrs_out; /** the pointer to receive the service config in JSON */ char** service_config_json_out; /** the evernt driver used by this request */ @@ -91,11 +87,12 @@ typedef struct grpc_ares_hostbyname_request { static void do_basic_init(void) { gpr_mu_init(&g_init_mu); } -static void log_address_sorting_list(const ServerAddressList& addresses, +static void log_address_sorting_list(grpc_lb_addresses* lb_addrs, const char* input_output_str) { - for (size_t i = 0; i < addresses.size(); i++) { + for (size_t i = 0; i < lb_addrs->num_addresses; i++) { char* addr_str; - if (grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true)) { + if (grpc_sockaddr_to_string(&addr_str, &lb_addrs->addresses[i].address, + true)) { gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s", input_output_str, i, addr_str); gpr_free(addr_str); @@ -107,28 +104,29 @@ static void log_address_sorting_list(const ServerAddressList& addresses, } } -void grpc_cares_wrapper_address_sorting_sort(ServerAddressList* addresses) { +void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) { if (grpc_trace_cares_address_sorting.enabled()) { - log_address_sorting_list(*addresses, "input"); + log_address_sorting_list(lb_addrs, "input"); } address_sorting_sortable* sortables = (address_sorting_sortable*)gpr_zalloc( - sizeof(address_sorting_sortable) * addresses->size()); - for (size_t i = 0; i < addresses->size(); ++i) { - sortables[i].user_data = &(*addresses)[i]; - memcpy(&sortables[i].dest_addr.addr, &(*addresses)[i].address().addr, - (*addresses)[i].address().len); - sortables[i].dest_addr.len = (*addresses)[i].address().len; + sizeof(address_sorting_sortable) * lb_addrs->num_addresses); + for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + sortables[i].user_data = &lb_addrs->addresses[i]; + memcpy(&sortables[i].dest_addr.addr, &lb_addrs->addresses[i].address.addr, + lb_addrs->addresses[i].address.len); + sortables[i].dest_addr.len = lb_addrs->addresses[i].address.len; } - address_sorting_rfc_6724_sort(sortables, addresses->size()); - ServerAddressList sorted; - sorted.reserve(addresses->size()); - for (size_t i = 0; i < addresses->size(); ++i) { - sorted.emplace_back(*static_cast(sortables[i].user_data)); + address_sorting_rfc_6724_sort(sortables, lb_addrs->num_addresses); + grpc_lb_address* sorted_lb_addrs = (grpc_lb_address*)gpr_zalloc( + sizeof(grpc_lb_address) * lb_addrs->num_addresses); + for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + sorted_lb_addrs[i] = *(grpc_lb_address*)sortables[i].user_data; } gpr_free(sortables); - *addresses = std::move(sorted); + gpr_free(lb_addrs->addresses); + lb_addrs->addresses = sorted_lb_addrs; if (grpc_trace_cares_address_sorting.enabled()) { - log_address_sorting_list(*addresses, "output"); + log_address_sorting_list(lb_addrs, "output"); } } @@ -147,9 +145,9 @@ void grpc_ares_complete_request_locked(grpc_ares_request* r) { /* Invoke on_done callback and destroy the request */ r->ev_driver = nullptr; - ServerAddressList* addresses = r->addresses_out->get(); - if (addresses != nullptr) { - grpc_cares_wrapper_address_sorting_sort(addresses); + grpc_lb_addresses* lb_addrs = *(r->lb_addrs_out); + if (lb_addrs != nullptr) { + grpc_cares_wrapper_address_sorting_sort(lb_addrs); } GRPC_CLOSURE_SCHED(r->on_done, r->error); } @@ -183,30 +181,33 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, GRPC_ERROR_UNREF(r->error); r->error = GRPC_ERROR_NONE; r->success = true; - if (*r->addresses_out == nullptr) { - *r->addresses_out = grpc_core::MakeUnique(); + grpc_lb_addresses** lb_addresses = r->lb_addrs_out; + if (*lb_addresses == nullptr) { + *lb_addresses = grpc_lb_addresses_create(0, nullptr); } - ServerAddressList& addresses = **r->addresses_out; - for (size_t i = 0; hostent->h_addr_list[i] != nullptr; ++i) { - grpc_core::InlinedVector args_to_add; - if (hr->is_balancer) { - args_to_add.emplace_back(grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); - args_to_add.emplace_back(grpc_channel_arg_string_create( - const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), hr->host)); - } - grpc_channel_args* args = grpc_channel_args_copy_and_add( - nullptr, args_to_add.data(), args_to_add.size()); + size_t prev_naddr = (*lb_addresses)->num_addresses; + size_t i; + for (i = 0; hostent->h_addr_list[i] != nullptr; i++) { + } + (*lb_addresses)->num_addresses += i; + (*lb_addresses)->addresses = static_cast( + gpr_realloc((*lb_addresses)->addresses, + sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses)); + for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) { switch (hostent->h_addrtype) { case AF_INET6: { size_t addr_len = sizeof(struct sockaddr_in6); struct sockaddr_in6 addr; memset(&addr, 0, addr_len); - memcpy(&addr.sin6_addr, hostent->h_addr_list[i], + memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr], sizeof(struct in6_addr)); addr.sin6_family = static_cast(hostent->h_addrtype); addr.sin6_port = hr->port; - addresses.emplace_back(&addr, addr_len, args); + grpc_lb_addresses_set_address( + *lb_addresses, i, &addr, addr_len, + hr->is_balancer /* is_balancer */, + hr->is_balancer ? hr->host : nullptr /* balancer_name */, + nullptr /* user_data */); char output[INET6_ADDRSTRLEN]; ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN); gpr_log(GPR_DEBUG, @@ -219,11 +220,15 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, size_t addr_len = sizeof(struct sockaddr_in); struct sockaddr_in addr; memset(&addr, 0, addr_len); - memcpy(&addr.sin_addr, hostent->h_addr_list[i], + memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr], sizeof(struct in_addr)); addr.sin_family = static_cast(hostent->h_addrtype); addr.sin_port = hr->port; - addresses.emplace_back(&addr, addr_len, args); + grpc_lb_addresses_set_address( + *lb_addresses, i, &addr, addr_len, + hr->is_balancer /* is_balancer */, + hr->is_balancer ? hr->host : nullptr /* balancer_name */, + nullptr /* user_data */); char output[INET_ADDRSTRLEN]; ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN); gpr_log(GPR_DEBUG, @@ -462,10 +467,11 @@ error_cleanup: gpr_free(port); } -static bool inner_resolve_as_ip_literal_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs, char** host, - char** port, char** hostport) { +static bool inner_resolve_as_ip_literal_locked(const char* name, + const char* default_port, + grpc_lb_addresses** addrs, + char** host, char** port, + char** hostport) { gpr_split_host_port(name, host, port); if (*host == nullptr) { gpr_log(GPR_ERROR, @@ -489,16 +495,18 @@ static bool inner_resolve_as_ip_literal_locked( if (grpc_parse_ipv4_hostport(*hostport, &addr, false /* log errors */) || grpc_parse_ipv6_hostport(*hostport, &addr, false /* log errors */)) { GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_core::MakeUnique(); - (*addrs)->emplace_back(addr.addr, addr.len, nullptr /* args */); + *addrs = grpc_lb_addresses_create(1, nullptr); + grpc_lb_addresses_set_address( + *addrs, 0, addr.addr, addr.len, false /* is_balancer */, + nullptr /* balancer_name */, nullptr /* user_data */); return true; } return false; } -static bool resolve_as_ip_literal_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs) { +static bool resolve_as_ip_literal_locked(const char* name, + const char* default_port, + grpc_lb_addresses** addrs) { char* host = nullptr; char* port = nullptr; char* hostport = nullptr; @@ -513,14 +521,13 @@ static bool resolve_as_ip_literal_locked( static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addrs, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner) { + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) { grpc_ares_request* r = static_cast(gpr_zalloc(sizeof(grpc_ares_request))); r->ev_driver = nullptr; r->on_done = on_done; - r->addresses_out = addrs; + r->lb_addrs_out = addrs; r->service_config_json_out = service_config_json; r->success = false; r->error = GRPC_ERROR_NONE; @@ -546,8 +553,8 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addrs, - bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) { @@ -592,8 +599,8 @@ typedef struct grpc_resolve_address_ares_request { grpc_combiner* combiner; /** the pointer to receive the resolved addresses */ grpc_resolved_addresses** addrs_out; - /** currently resolving addresses */ - grpc_core::UniquePtr addresses; + /** currently resolving lb addresses */ + grpc_lb_addresses* lb_addrs; /** closure to call when the resolve_address_ares request completes */ grpc_closure* on_resolve_address_done; /** a closure wrapping on_resolve_address_done, which should be invoked when @@ -606,7 +613,7 @@ typedef struct grpc_resolve_address_ares_request { /* pollset_set to be driven by */ grpc_pollset_set* interested_parties; /* underlying ares_request that the query is performed on */ - grpc_ares_request* ares_request = nullptr; + grpc_ares_request* ares_request; } grpc_resolve_address_ares_request; static void on_dns_lookup_done_locked(void* arg, grpc_error* error) { @@ -614,24 +621,25 @@ static void on_dns_lookup_done_locked(void* arg, grpc_error* error) { static_cast(arg); gpr_free(r->ares_request); grpc_resolved_addresses** resolved_addresses = r->addrs_out; - if (r->addresses == nullptr || r->addresses->empty()) { + if (r->lb_addrs == nullptr || r->lb_addrs->num_addresses == 0) { *resolved_addresses = nullptr; } else { *resolved_addresses = static_cast( gpr_zalloc(sizeof(grpc_resolved_addresses))); - (*resolved_addresses)->naddrs = r->addresses->size(); + (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses; (*resolved_addresses)->addrs = static_cast(gpr_zalloc( sizeof(grpc_resolved_address) * (*resolved_addresses)->naddrs)); - for (size_t i = 0; i < (*resolved_addresses)->naddrs; ++i) { - GPR_ASSERT(!(*r->addresses)[i].IsBalancer()); - memcpy(&(*resolved_addresses)->addrs[i], &(*r->addresses)[i].address(), - sizeof(grpc_resolved_address)); + for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) { + GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer); + memcpy(&(*resolved_addresses)->addrs[i], + &r->lb_addrs->addresses[i].address, sizeof(grpc_resolved_address)); } } GRPC_CLOSURE_SCHED(r->on_resolve_address_done, GRPC_ERROR_REF(error)); + if (r->lb_addrs != nullptr) grpc_lb_addresses_destroy(r->lb_addrs); GRPC_COMBINER_UNREF(r->combiner, "on_dns_lookup_done_cb"); - grpc_core::Delete(r); + gpr_free(r); } static void grpc_resolve_address_invoke_dns_lookup_ares_locked( @@ -640,7 +648,7 @@ static void grpc_resolve_address_invoke_dns_lookup_ares_locked( static_cast(arg); r->ares_request = grpc_dns_lookup_ares_locked( nullptr /* dns_server */, r->name, r->default_port, r->interested_parties, - &r->on_dns_lookup_done_locked, &r->addresses, false /* check_grpclb */, + &r->on_dns_lookup_done_locked, &r->lb_addrs, false /* check_grpclb */, nullptr /* service_config_json */, GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, r->combiner); } @@ -651,7 +659,8 @@ static void grpc_resolve_address_ares_impl(const char* name, grpc_closure* on_done, grpc_resolved_addresses** addrs) { grpc_resolve_address_ares_request* r = - grpc_core::New(); + static_cast( + gpr_zalloc(sizeof(grpc_resolve_address_ares_request))); r->combiner = grpc_combiner_create(); r->addrs_out = addrs; r->on_resolve_address_done = on_done; diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h index 28082504565..9acef1d0ca9 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/server_address.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -61,9 +61,8 @@ extern void (*grpc_resolve_address_ares)(const char* name, extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner); + grpc_lb_addresses** addresses, bool check_grpclb, + char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); /* Cancel the pending grpc_ares_request \a request */ extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request); @@ -90,12 +89,10 @@ bool grpc_ares_query_ipv6(); * Returns a bool indicating whether or not such an action was performed. * See https://github.com/grpc/grpc/issues/15158. */ bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs); + const char* name, const char* default_port, grpc_lb_addresses** addrs); /* Sorts destinations in lb_addrs according to RFC 6724. */ -void grpc_cares_wrapper_address_sorting_sort( - grpc_core::ServerAddressList* addresses); +void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs); #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \ */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc index 1f4701c9994..fc78b183044 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc @@ -29,17 +29,16 @@ struct grpc_ares_request { static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addrs, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner) { + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) { return NULL; } grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addrs, - bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {} diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc index 028d8442169..639eec2323f 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc @@ -27,8 +27,7 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs) { + const char* name, const char* default_port, grpc_lb_addresses** addrs) { return false; } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc index 202452f1b2b..7e34784691f 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc @@ -23,9 +23,9 @@ #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/socket_windows.h" @@ -33,9 +33,8 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } static bool inner_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs, char** host, - char** port) { + const char* name, const char* default_port, grpc_lb_addresses** addrs, + char** host, char** port) { gpr_split_host_port(name, host, port); if (*host == nullptr) { gpr_log(GPR_ERROR, @@ -56,7 +55,7 @@ static bool inner_maybe_resolve_localhost_manually_locked( } if (gpr_stricmp(*host, "localhost") == 0) { GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_core::MakeUnique(); + *addrs = grpc_lb_addresses_create(2, nullptr); uint16_t numeric_port = grpc_strhtons(*port); // Append the ipv6 loopback address. struct sockaddr_in6 ipv6_loopback_addr; @@ -64,8 +63,10 @@ static bool inner_maybe_resolve_localhost_manually_locked( ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1; ipv6_loopback_addr.sin6_family = AF_INET6; ipv6_loopback_addr.sin6_port = numeric_port; - (*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr), - nullptr /* args */); + grpc_lb_addresses_set_address( + *addrs, 0, &ipv6_loopback_addr, sizeof(ipv6_loopback_addr), + false /* is_balancer */, nullptr /* balancer_name */, + nullptr /* user_data */); // Append the ipv4 loopback address. struct sockaddr_in ipv4_loopback_addr; memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr)); @@ -73,18 +74,19 @@ static bool inner_maybe_resolve_localhost_manually_locked( ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01; ipv4_loopback_addr.sin_family = AF_INET; ipv4_loopback_addr.sin_port = numeric_port; - (*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr), - nullptr /* args */); + grpc_lb_addresses_set_address( + *addrs, 1, &ipv4_loopback_addr, sizeof(ipv4_loopback_addr), + false /* is_balancer */, nullptr /* balancer_name */, + nullptr /* user_data */); // Let the address sorter figure out which one should be tried first. - grpc_cares_wrapper_address_sorting_sort(addrs->get()); + grpc_cares_wrapper_address_sorting_sort(*addrs); return true; } return false; } bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs) { + const char* name, const char* default_port, grpc_lb_addresses** addrs) { char* host = nullptr; char* port = nullptr; bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port, diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc index c365f1abfd8..65ff1ec1a5b 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -26,8 +26,8 @@ #include #include +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -198,14 +198,18 @@ void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(r->name_to_resolve_)); if (r->addresses_ != nullptr) { - ServerAddressList addresses; + grpc_lb_addresses* addresses = grpc_lb_addresses_create( + r->addresses_->naddrs, nullptr /* user_data_vtable */); for (size_t i = 0; i < r->addresses_->naddrs; ++i) { - addresses.emplace_back(&r->addresses_->addrs[i].addr, - r->addresses_->addrs[i].len, nullptr /* args */); + grpc_lb_addresses_set_address( + addresses, i, &r->addresses_->addrs[i].addr, + r->addresses_->addrs[i].len, false /* is_balancer */, + nullptr /* balancer_name */, nullptr /* user_data */); } - grpc_arg new_arg = CreateServerAddressListChannelArg(&addresses); + grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses); result = grpc_channel_args_copy_and_add(r->channel_args_, &new_arg, 1); grpc_resolved_addresses_destroy(r->addresses_); + grpc_lb_addresses_destroy(addresses); // Reset backoff state so that we start from the beginning when the // next request gets triggered. r->backoff_.Reset(); diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc index 258339491c1..3aa690bea41 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -28,13 +28,12 @@ #include #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" -#include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h index d86111c3829..7f690593510 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -19,9 +19,10 @@ #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted.h" -#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/uri/uri_parser.h" #define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \ "grpc.fake_resolver.response_generator" diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc index 1654747a79f..801734764b4 100644 --- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc @@ -26,9 +26,9 @@ #include #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" @@ -45,8 +45,7 @@ namespace { class SockaddrResolver : public Resolver { public: /// Takes ownership of \a addresses. - SockaddrResolver(const ResolverArgs& args, - UniquePtr addresses); + SockaddrResolver(const ResolverArgs& args, grpc_lb_addresses* addresses); void NextLocked(grpc_channel_args** result, grpc_closure* on_complete) override; @@ -59,7 +58,7 @@ class SockaddrResolver : public Resolver { void MaybeFinishNextLocked(); /// the addresses that we've "resolved" - UniquePtr addresses_; + grpc_lb_addresses* addresses_ = nullptr; /// channel args grpc_channel_args* channel_args_ = nullptr; /// have we published? @@ -71,12 +70,13 @@ class SockaddrResolver : public Resolver { }; SockaddrResolver::SockaddrResolver(const ResolverArgs& args, - UniquePtr addresses) + grpc_lb_addresses* addresses) : Resolver(args.combiner), - addresses_(std::move(addresses)), + addresses_(addresses), channel_args_(grpc_channel_args_copy(args.args)) {} SockaddrResolver::~SockaddrResolver() { + grpc_lb_addresses_destroy(addresses_); grpc_channel_args_destroy(channel_args_); } @@ -100,7 +100,7 @@ void SockaddrResolver::ShutdownLocked() { void SockaddrResolver::MaybeFinishNextLocked() { if (next_completion_ != nullptr && !published_) { published_ = true; - grpc_arg arg = CreateServerAddressListChannelArg(addresses_.get()); + grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses_); *target_result_ = grpc_channel_args_copy_and_add(channel_args_, &arg, 1); GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE); next_completion_ = nullptr; @@ -127,27 +127,27 @@ OrphanablePtr CreateSockaddrResolver( grpc_slice_buffer path_parts; grpc_slice_buffer_init(&path_parts); grpc_slice_split(path_slice, ",", &path_parts); - auto addresses = MakeUnique(); + grpc_lb_addresses* addresses = grpc_lb_addresses_create( + path_parts.count, nullptr /* user_data_vtable */); bool errors_found = false; - for (size_t i = 0; i < path_parts.count; i++) { + for (size_t i = 0; i < addresses->num_addresses; i++) { grpc_uri ith_uri = *args.uri; - UniquePtr part_str(grpc_slice_to_c_string(path_parts.slices[i])); - ith_uri.path = part_str.get(); - grpc_resolved_address addr; - if (!parse(&ith_uri, &addr)) { + char* part_str = grpc_slice_to_c_string(path_parts.slices[i]); + ith_uri.path = part_str; + if (!parse(&ith_uri, &addresses->addresses[i].address)) { errors_found = true; /* GPR_TRUE */ - break; } - addresses->emplace_back(addr, nullptr /* args */); + gpr_free(part_str); + if (errors_found) break; } grpc_slice_buffer_destroy_internal(&path_parts); grpc_slice_unref_internal(path_slice); if (errors_found) { + grpc_lb_addresses_destroy(addresses); return OrphanablePtr(nullptr); } // Instantiate resolver. - return OrphanablePtr( - New(args, std::move(addresses))); + return OrphanablePtr(New(args, addresses)); } class IPv4ResolverFactory : public ResolverFactory { diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc index 22b06db45c4..4f7fd6b4243 100644 --- a/src/core/ext/filters/client_channel/resolver_result_parsing.cc +++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc @@ -30,11 +30,9 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/status_util.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/memory.h" -#include "src/core/lib/uri/uri_parser.h" // As per the retry design, we do not allow more than 5 retry attempts. #define MAX_MAX_RETRY_ATTEMPTS 5 @@ -101,18 +99,12 @@ void ProcessedResolverResult::ProcessLbPolicyName( } // Special case: If at least one balancer address is present, we use // the grpclb policy, regardless of what the resolver has returned. - const ServerAddressList* addresses = - FindServerAddressListChannelArg(resolver_result); - if (addresses != nullptr) { - bool found_balancer_address = false; - for (size_t i = 0; i < addresses->size(); ++i) { - const ServerAddress& address = (*addresses)[i]; - if (address.IsBalancer()) { - found_balancer_address = true; - break; - } - } - if (found_balancer_address) { + const grpc_arg* channel_arg = + grpc_channel_args_find(resolver_result, GRPC_ARG_LB_ADDRESSES); + if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { + grpc_lb_addresses* addresses = + static_cast(channel_arg->value.pointer.p); + if (grpc_lb_addresses_contains_balancer_address(*addresses)) { if (lb_policy_name_ != nullptr && strcmp(lb_policy_name_.get(), "grpclb") != 0) { gpr_log(GPR_INFO, diff --git a/src/core/ext/filters/client_channel/server_address.cc b/src/core/ext/filters/client_channel/server_address.cc deleted file mode 100644 index ec33cbbd956..00000000000 --- a/src/core/ext/filters/client_channel/server_address.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include "src/core/ext/filters/client_channel/server_address.h" - -#include - -namespace grpc_core { - -// -// ServerAddress -// - -ServerAddress::ServerAddress(const grpc_resolved_address& address, - grpc_channel_args* args) - : address_(address), args_(args) {} - -ServerAddress::ServerAddress(const void* address, size_t address_len, - grpc_channel_args* args) - : args_(args) { - memcpy(address_.addr, address, address_len); - address_.len = static_cast(address_len); -} - -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_); -} - -bool ServerAddress::IsBalancer() const { - return grpc_channel_arg_get_bool( - grpc_channel_args_find(args_, GRPC_ARG_ADDRESS_IS_BALANCER), false); -} - -// -// ServerAddressList -// - -namespace { - -void* ServerAddressListCopy(void* addresses) { - ServerAddressList* a = static_cast(addresses); - return New(*a); -} - -void ServerAddressListDestroy(void* addresses) { - ServerAddressList* a = static_cast(addresses); - Delete(a); -} - -int ServerAddressListCompare(void* addresses1, void* addresses2) { - ServerAddressList* a1 = static_cast(addresses1); - ServerAddressList* a2 = static_cast(addresses2); - if (a1->size() > a2->size()) return 1; - if (a1->size() < a2->size()) return -1; - for (size_t i = 0; i < a1->size(); ++i) { - int retval = (*a1)[i].Cmp((*a2)[i]); - if (retval != 0) return retval; - } - return 0; -} - -const grpc_arg_pointer_vtable server_addresses_arg_vtable = { - ServerAddressListCopy, ServerAddressListDestroy, ServerAddressListCompare}; - -} // namespace - -grpc_arg CreateServerAddressListChannelArg(const ServerAddressList* addresses) { - return grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_SERVER_ADDRESS_LIST), - const_cast(addresses), &server_addresses_arg_vtable); -} - -ServerAddressList* FindServerAddressListChannelArg( - const grpc_channel_args* channel_args) { - const grpc_arg* lb_addresses_arg = - grpc_channel_args_find(channel_args, GRPC_ARG_SERVER_ADDRESS_LIST); - if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) - return nullptr; - return static_cast(lb_addresses_arg->value.pointer.p); -} - -} // 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 deleted file mode 100644 index 3a1bf1df67d..00000000000 --- a/src/core/ext/filters/client_channel/server_address.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H -#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H - -#include - -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gprpp/inlined_vector.h" -#include "src/core/lib/iomgr/resolve_address.h" -#include "src/core/lib/uri/uri_parser.h" - -// Channel arg key for ServerAddressList. -#define GRPC_ARG_SERVER_ADDRESS_LIST "grpc.server_address_list" - -// Channel arg key for a bool indicating whether an address is a grpclb -// load balancer (as opposed to a backend). -#define GRPC_ARG_ADDRESS_IS_BALANCER "grpc.address_is_balancer" - -// Channel arg key for a string indicating an address's balancer name. -#define GRPC_ARG_ADDRESS_BALANCER_NAME "grpc.address_balancer_name" - -namespace grpc_core { - -// -// ServerAddress -// - -// A server address is a grpc_resolved_address with an associated set of -// channel args. Any args present here will be merged into the channel -// args when a subchannel is created for this address. -class ServerAddress { - public: - // Takes ownership of args. - ServerAddress(const grpc_resolved_address& address, grpc_channel_args* args); - ServerAddress(const void* address, size_t address_len, - grpc_channel_args* args); - - ~ServerAddress() { grpc_channel_args_destroy(args_); } - - // Copyable. - ServerAddress(const ServerAddress& other) - : address_(other.address_), args_(grpc_channel_args_copy(other.args_)) {} - ServerAddress& operator=(const ServerAddress& other) { - address_ = other.address_; - grpc_channel_args_destroy(args_); - args_ = grpc_channel_args_copy(other.args_); - return *this; - } - - // Movable. - ServerAddress(ServerAddress&& other) - : address_(other.address_), args_(other.args_) { - other.args_ = nullptr; - } - ServerAddress& operator=(ServerAddress&& other) { - address_ = other.address_; - args_ = other.args_; - other.args_ = nullptr; - return *this; - } - - bool operator==(const ServerAddress& other) const { return Cmp(other) == 0; } - - int Cmp(const ServerAddress& other) const; - - const grpc_resolved_address& address() const { return address_; } - const grpc_channel_args* args() const { return args_; } - - bool IsBalancer() const; - - private: - grpc_resolved_address address_; - grpc_channel_args* args_; -}; - -// -// ServerAddressList -// - -typedef InlinedVector ServerAddressList; - -// Returns a channel arg containing \a addresses. -grpc_arg CreateServerAddressListChannelArg(const ServerAddressList* addresses); - -// Returns the ServerListAddress instance in channel_args or NULL. -ServerAddressList* FindServerAddressListChannelArg( - const grpc_channel_args* channel_args); - -} // namespace grpc_core - -#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H */ diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index 9077aa97539..af55f7710e2 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -837,7 +837,7 @@ static bool publish_transport_locked(grpc_subchannel* c) { /* publish */ c->connected_subchannel.reset(grpc_core::New( - stk, c->args, c->channelz_subchannel, socket_uuid)); + stk, c->channelz_subchannel, socket_uuid)); gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p", c->connected_subchannel.get(), c); @@ -1068,18 +1068,16 @@ grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) { namespace grpc_core { ConnectedSubchannel::ConnectedSubchannel( - grpc_channel_stack* channel_stack, const grpc_channel_args* args, + grpc_channel_stack* channel_stack, grpc_core::RefCountedPtr channelz_subchannel, intptr_t socket_uuid) : RefCounted(&grpc_trace_stream_refcount), channel_stack_(channel_stack), - args_(grpc_channel_args_copy(args)), channelz_subchannel_(std::move(channelz_subchannel)), socket_uuid_(socket_uuid) {} ConnectedSubchannel::~ConnectedSubchannel() { - grpc_channel_args_destroy(args_); GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor"); } diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 14f87f2c68e..69c2456ec20 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -85,31 +85,28 @@ class ConnectedSubchannel : public RefCounted { size_t parent_data_size; }; - ConnectedSubchannel( - grpc_channel_stack* channel_stack, const grpc_channel_args* args, + explicit ConnectedSubchannel( + grpc_channel_stack* channel_stack, grpc_core::RefCountedPtr channelz_subchannel, intptr_t socket_uuid); ~ConnectedSubchannel(); + grpc_channel_stack* channel_stack() { return channel_stack_; } void NotifyOnStateChange(grpc_pollset_set* interested_parties, grpc_connectivity_state* state, grpc_closure* closure); void Ping(grpc_closure* on_initiate, grpc_closure* on_ack); grpc_error* CreateCall(const CallArgs& args, grpc_subchannel_call** call); - - grpc_channel_stack* channel_stack() const { return channel_stack_; } - const grpc_channel_args* args() const { return args_; } - channelz::SubchannelNode* channelz_subchannel() const { + channelz::SubchannelNode* channelz_subchannel() { return channelz_subchannel_.get(); } - intptr_t socket_uuid() const { return socket_uuid_; } + intptr_t socket_uuid() { return socket_uuid_; } size_t GetInitialCallSizeEstimate(size_t parent_data_size) const; private: grpc_channel_stack* channel_stack_; - grpc_channel_args* args_; // ref counted pointer to the channelz node in this connected subchannel's // owning subchannel. grpc_core::RefCountedPtr diff --git a/src/core/lib/iomgr/sockaddr_utils.cc b/src/core/lib/iomgr/sockaddr_utils.cc index 0839bdfef2d..1b66dceb130 100644 --- a/src/core/lib/iomgr/sockaddr_utils.cc +++ b/src/core/lib/iomgr/sockaddr_utils.cc @@ -217,7 +217,6 @@ void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port) { } char* grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) { - if (resolved_addr->len == 0) return nullptr; grpc_resolved_address addr_normalized; if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) { resolved_addr = &addr_normalized; diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index c6ca970beee..ce65c594fe2 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -322,6 +322,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', + 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -330,7 +331,6 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', - 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc index 1a7a7c9ccc9..76769b2b64a 100644 --- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc @@ -21,10 +21,10 @@ #include #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -63,9 +63,8 @@ static grpc_address_resolver_vtable test_resolver = {my_resolve_address, static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner) { + grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) { gpr_mu_lock(&g_mu); GPR_ASSERT(0 == strcmp("test", addr)); grpc_error* error = GRPC_ERROR_NONE; @@ -75,8 +74,9 @@ static grpc_ares_request* my_dns_lookup_ares_locked( error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); } else { gpr_mu_unlock(&g_mu); - *addresses = grpc_core::MakeUnique(); - (*addresses)->emplace_back(nullptr, 0, nullptr); + *lb_addrs = grpc_lb_addresses_create(1, nullptr); + grpc_lb_addresses_set_address(*lb_addrs, 0, nullptr, 0, false, nullptr, + nullptr); } GRPC_CLOSURE_SCHED(on_done, error); return nullptr; diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc index 16210b8164b..cdbe33dbe79 100644 --- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc @@ -22,7 +22,6 @@ #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/combiner.h" @@ -41,9 +40,8 @@ static grpc_combiner* g_combiner; static grpc_ares_request* (*g_default_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner); + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner); // Counter incremented by test_resolve_address_impl indicating the number of // times a system-level resolution has happened. @@ -92,12 +90,11 @@ static grpc_address_resolver_vtable test_resolver = { static grpc_ares_request* test_dns_lookup_ares_locked( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner) { + grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) { grpc_ares_request* result = g_default_dns_lookup_ares_locked( - dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, - addresses, check_grpclb, service_config_json, query_timeout_ms, combiner); + dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs, + check_grpclb, service_config_json, query_timeout_ms, combiner); ++g_resolution_count; static grpc_millis last_resolution_time = 0; if (last_resolution_time == 0) { diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc index 3b06fe063ae..6362b95e50e 100644 --- a/test/core/client_channel/resolvers/fake_resolver_test.cc +++ b/test/core/client_channel/resolvers/fake_resolver_test.cc @@ -22,10 +22,10 @@ #include #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/combiner.h" @@ -63,14 +63,12 @@ void on_resolution_cb(void* arg, grpc_error* error) { // We only check the addresses channel arg because that's the only one // explicitly set by the test via // FakeResolverResponseGenerator::SetResponse(). - const grpc_core::ServerAddressList* actual_addresses = - grpc_core::FindServerAddressListChannelArg(res->resolver_result); - const grpc_core::ServerAddressList* expected_addresses = - grpc_core::FindServerAddressListChannelArg(res->expected_resolver_result); - GPR_ASSERT(actual_addresses->size() == expected_addresses->size()); - for (size_t i = 0; i < expected_addresses->size(); ++i) { - GPR_ASSERT((*actual_addresses)[i] == (*expected_addresses)[i]); - } + const grpc_lb_addresses* actual_lb_addresses = + grpc_lb_addresses_find_channel_arg(res->resolver_result); + const grpc_lb_addresses* expected_lb_addresses = + grpc_lb_addresses_find_channel_arg(res->expected_resolver_result); + GPR_ASSERT( + grpc_lb_addresses_cmp(actual_lb_addresses, expected_lb_addresses) == 0); grpc_channel_args_destroy(res->resolver_result); grpc_channel_args_destroy(res->expected_resolver_result); gpr_event_set(&res->ev, (void*)1); @@ -82,35 +80,27 @@ static grpc_channel_args* create_new_resolver_result() { const size_t num_addresses = 2; char* uri_string; char* balancer_name; - // Create address list. - grpc_core::ServerAddressList addresses; + // Create grpc_lb_addresses. + grpc_lb_addresses* addresses = + grpc_lb_addresses_create(num_addresses, nullptr); for (size_t i = 0; i < num_addresses; ++i) { gpr_asprintf(&uri_string, "ipv4:127.0.0.1:100%" PRIuPTR, test_counter * num_addresses + i); grpc_uri* uri = grpc_uri_parse(uri_string, true); gpr_asprintf(&balancer_name, "balancer%" PRIuPTR, test_counter * num_addresses + i); - grpc_resolved_address address; - GPR_ASSERT(grpc_parse_uri(uri, &address)); - grpc_core::InlinedVector args_to_add; - const bool is_balancer = num_addresses % 2; - if (is_balancer) { - args_to_add.emplace_back(grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); - args_to_add.emplace_back(grpc_channel_arg_string_create( - const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), balancer_name)); - } - grpc_channel_args* args = grpc_channel_args_copy_and_add( - nullptr, args_to_add.data(), args_to_add.size()); - addresses.emplace_back(address.addr, address.len, args); + grpc_lb_addresses_set_address_from_uri( + addresses, i, uri, bool(num_addresses % 2), balancer_name, nullptr); gpr_free(balancer_name); grpc_uri_destroy(uri); gpr_free(uri_string); } - // Embed the address list in channel args. - const grpc_arg addresses_arg = CreateServerAddressListChannelArg(&addresses); + // Convert grpc_lb_addresses to grpc_channel_args. + const grpc_arg addresses_arg = + grpc_lb_addresses_create_channel_arg(addresses); grpc_channel_args* results = grpc_channel_args_copy_and_add(nullptr, &addresses_arg, 1); + grpc_lb_addresses_destroy(addresses); ++test_counter; return results; } diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index fbf6379a698..9b6eddee6e1 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -24,8 +24,8 @@ #include #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -325,7 +325,7 @@ typedef struct addr_req { char* addr; grpc_closure* on_done; grpc_resolved_addresses** addrs; - grpc_core::UniquePtr* addresses; + grpc_lb_addresses** lb_addrs; } addr_req; static void finish_resolve(void* arg, grpc_error* error) { @@ -340,9 +340,11 @@ static void finish_resolve(void* arg, grpc_error* error) { gpr_malloc(sizeof(*addrs->addrs))); addrs->addrs[0].len = 0; *r->addrs = addrs; - } else if (r->addresses != nullptr) { - *r->addresses = grpc_core::MakeUnique(); - (*r->addresses)->emplace_back(nullptr, 0, nullptr); + } else if (r->lb_addrs != nullptr) { + grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(1, nullptr); + grpc_lb_addresses_set_address(lb_addrs, 0, nullptr, 0, false, nullptr, + nullptr); + *r->lb_addrs = lb_addrs; } GRPC_CLOSURE_SCHED(r->on_done, GRPC_ERROR_NONE); } else { @@ -352,17 +354,18 @@ static void finish_resolve(void* arg, grpc_error* error) { } gpr_free(r->addr); - grpc_core::Delete(r); + gpr_free(r); } void my_resolve_address(const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_resolved_addresses** addrs) { - addr_req* r = grpc_core::New(); + grpc_resolved_addresses** addresses) { + addr_req* r = static_cast(gpr_malloc(sizeof(*r))); r->addr = gpr_strdup(addr); r->on_done = on_done; - r->addrs = addrs; + r->addrs = addresses; + r->lb_addrs = nullptr; grpc_timer_init( &r->timer, GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(), GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx)); @@ -374,14 +377,13 @@ static grpc_address_resolver_vtable fuzzer_resolver = {my_resolve_address, grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout, - grpc_combiner* combiner) { + grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, + int query_timeout, grpc_combiner* combiner) { addr_req* r = static_cast(gpr_malloc(sizeof(*r))); r->addr = gpr_strdup(addr); r->on_done = on_done; r->addrs = nullptr; - r->addresses = addresses; + r->lb_addrs = lb_addrs; grpc_timer_init( &r->timer, GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(), GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx)); diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc index 7e3b418cd94..66e8ca51614 100644 --- a/test/core/end2end/goaway_server_test.cc +++ b/test/core/end2end/goaway_server_test.cc @@ -28,8 +28,8 @@ #include #include #include +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr.h" #include "test/core/end2end/cq_verifier.h" @@ -47,9 +47,8 @@ static int g_resolve_port = -1; static grpc_ares_request* (*iomgr_dns_lookup_ares_locked)( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner); + grpc_lb_addresses** addresses, bool check_grpclb, + char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); static void (*iomgr_cancel_ares_request_locked)(grpc_ares_request* request); @@ -104,12 +103,11 @@ static grpc_address_resolver_vtable test_resolver = { static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_core::UniquePtr* addresses, - bool check_grpclb, char** service_config_json, int query_timeout_ms, - grpc_combiner* combiner) { + grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, + int query_timeout_ms, grpc_combiner* combiner) { if (0 != strcmp(addr, "test")) { return iomgr_dns_lookup_ares_locked( - dns_server, addr, default_port, interested_parties, on_done, addresses, + dns_server, addr, default_port, interested_parties, on_done, lb_addrs, check_grpclb, service_config_json, query_timeout_ms, combiner); } @@ -119,12 +117,15 @@ static grpc_ares_request* my_dns_lookup_ares_locked( gpr_mu_unlock(&g_mu); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); } else { - *addresses = grpc_core::MakeUnique(); - grpc_sockaddr_in sa; - sa.sin_family = GRPC_AF_INET; - sa.sin_addr.s_addr = 0x100007f; - sa.sin_port = grpc_htons(static_cast(g_resolve_port)); - (*addresses)->emplace_back(&sa, sizeof(sa), nullptr); + *lb_addrs = grpc_lb_addresses_create(1, nullptr); + grpc_sockaddr_in* sa = + static_cast(gpr_zalloc(sizeof(grpc_sockaddr_in))); + sa->sin_family = GRPC_AF_INET; + sa->sin_addr.s_addr = 0x100007f; + sa->sin_port = grpc_htons(static_cast(g_resolve_port)); + grpc_lb_addresses_set_address(*lb_addrs, 0, sa, sizeof(*sa), false, nullptr, + nullptr); + gpr_free(sa); gpr_mu_unlock(&g_mu); } GRPC_CLOSURE_SCHED(on_done, error); diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc index c289e719eea..5dda748f5a5 100644 --- a/test/core/end2end/no_server_test.cc +++ b/test/core/end2end/no_server_test.cc @@ -23,7 +23,6 @@ #include #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" -#include "src/core/lib/iomgr/exec_ctx.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/util/test_config.h" diff --git a/test/core/util/ubsan_suppressions.txt b/test/core/util/ubsan_suppressions.txt index 8ed7d4d7fb6..63898ea3b1c 100644 --- a/test/core/util/ubsan_suppressions.txt +++ b/test/core/util/ubsan_suppressions.txt @@ -25,6 +25,7 @@ alignment:absl::little_endian::Store64 alignment:absl::little_endian::Load64 float-divide-by-zero:grpc::testing::postprocess_scenario_result enum:grpc_op_string +nonnull-attribute:grpc_lb_addresses_copy signed-integer-overflow:chrono enum:grpc_http2_error_to_grpc_status -enum:grpc_chttp2_cancel_stream +enum:grpc_chttp2_cancel_stream \ No newline at end of file diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc index 124557eb567..bf321d8a89e 100644 --- a/test/cpp/client/client_channel_stress_test.cc +++ b/test/cpp/client/client_channel_stress_test.cc @@ -34,9 +34,7 @@ #include #include -#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -218,31 +216,23 @@ class ClientChannelStressTest { void SetNextResolution(const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_core::ServerAddressList addresses; - for (const auto& addr : address_data) { + grpc_lb_addresses* addresses = + grpc_lb_addresses_create(address_data.size(), nullptr); + for (size_t i = 0; i < address_data.size(); ++i) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", addr.port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", address_data[i].port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_resolved_address address; - GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); - std::vector args_to_add; - if (addr.is_balancer) { - args_to_add.emplace_back(grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); - args_to_add.emplace_back(grpc_channel_arg_string_create( - const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), - const_cast(addr.balancer_name.c_str()))); - } - grpc_channel_args* args = grpc_channel_args_copy_and_add( - nullptr, args_to_add.data(), args_to_add.size()); - addresses.emplace_back(address.addr, address.len, args); + grpc_lb_addresses_set_address_from_uri( + addresses, i, lb_uri, address_data[i].is_balancer, + address_data[i].balancer_name.c_str(), nullptr); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } - grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); + grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetResponse(&fake_result); + grpc_lb_addresses_destroy(addresses); } void KeepSendingRequests() { diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index 929c2bb5899..1dfa91a76c7 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -35,9 +35,7 @@ #include #include -#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/gpr/env.h" @@ -161,22 +159,24 @@ class ClientLbEnd2endTest : public ::testing::Test { } grpc_channel_args* BuildFakeResults(const std::vector& ports) { - grpc_core::ServerAddressList addresses; - for (const int& port : ports) { + grpc_lb_addresses* addresses = + grpc_lb_addresses_create(ports.size(), nullptr); + for (size_t i = 0; i < ports.size(); ++i) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", ports[i]); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_resolved_address address; - GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); - addresses.emplace_back(address.addr, address.len, nullptr /* args */); + grpc_lb_addresses_set_address_from_uri(addresses, i, lb_uri, + false /* is balancer */, + "" /* balancer name */, nullptr); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } const grpc_arg fake_addresses = - CreateServerAddressListChannelArg(&addresses); + grpc_lb_addresses_create_channel_arg(addresses); grpc_channel_args* fake_results = grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1); + grpc_lb_addresses_destroy(addresses); return fake_results; } diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index bf990a07b5a..9c4cd050619 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -32,9 +32,7 @@ #include #include -#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -488,27 +486,18 @@ class GrpclbEnd2endTest : public ::testing::Test { grpc::string balancer_name; }; - grpc_core::ServerAddressList CreateLbAddressesFromAddressDataList( + grpc_lb_addresses* CreateLbAddressesFromAddressDataList( const std::vector& address_data) { - grpc_core::ServerAddressList addresses; - for (const auto& addr : address_data) { + grpc_lb_addresses* addresses = + grpc_lb_addresses_create(address_data.size(), nullptr); + for (size_t i = 0; i < address_data.size(); ++i) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", addr.port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", address_data[i].port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_resolved_address address; - GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); - std::vector args_to_add; - if (addr.is_balancer) { - args_to_add.emplace_back(grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); - args_to_add.emplace_back(grpc_channel_arg_string_create( - const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), - const_cast(addr.balancer_name.c_str()))); - } - grpc_channel_args* args = grpc_channel_args_copy_and_add( - nullptr, args_to_add.data(), args_to_add.size()); - addresses.emplace_back(address.addr, address.len, args); + grpc_lb_addresses_set_address_from_uri( + addresses, i, lb_uri, address_data[i].is_balancer, + address_data[i].balancer_name.c_str(), nullptr); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } @@ -517,21 +506,23 @@ class GrpclbEnd2endTest : public ::testing::Test { void SetNextResolution(const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_core::ServerAddressList addresses = + grpc_lb_addresses* addresses = CreateLbAddressesFromAddressDataList(address_data); - grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); + grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetResponse(&fake_result); + grpc_lb_addresses_destroy(addresses); } void SetNextReresolutionResponse( const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_core::ServerAddressList addresses = + grpc_lb_addresses* addresses = CreateLbAddressesFromAddressDataList(address_data); - grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); + grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetReresolutionResponse(&fake_result); + grpc_lb_addresses_destroy(addresses); } const std::vector GetBackendPorts(const size_t start_index = 0) const { diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc index 09e705df789..3eb0e7d7254 100644 --- a/test/cpp/naming/address_sorting_test.cc +++ b/test/cpp/naming/address_sorting_test.cc @@ -37,7 +37,6 @@ #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" @@ -168,26 +167,30 @@ void OverrideAddressSortingSourceAddrFactory( address_sorting_override_source_addr_factory_for_testing(factory); } -grpc_core::ServerAddressList BuildLbAddrInputs( - const std::vector& test_addrs) { - grpc_core::ServerAddressList addresses; - for (const auto& addr : test_addrs) { - addresses.emplace_back(TestAddressToGrpcResolvedAddress(addr), nullptr); +grpc_lb_addresses* BuildLbAddrInputs(std::vector test_addrs) { + grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, nullptr); + lb_addrs->addresses = + (grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size()); + lb_addrs->num_addresses = test_addrs.size(); + for (size_t i = 0; i < test_addrs.size(); i++) { + lb_addrs->addresses[i].address = + TestAddressToGrpcResolvedAddress(test_addrs[i]); } - return addresses; + return lb_addrs; } -void VerifyLbAddrOutputs(const grpc_core::ServerAddressList addresses, +void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, std::vector expected_addrs) { - EXPECT_EQ(addresses.size(), expected_addrs.size()); - for (size_t i = 0; i < addresses.size(); ++i) { + EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size()); + for (size_t i = 0; i < lb_addrs->num_addresses; i++) { char* ip_addr_str; - grpc_sockaddr_to_string(&ip_addr_str, &addresses[i].address(), + grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address, false /* normalize */); EXPECT_EQ(expected_addrs[i], ip_addr_str); gpr_free(ip_addr_str); } grpc_core::ExecCtx exec_ctx; + grpc_lb_addresses_destroy(lb_addrs); } /* We need to run each test case inside of its own @@ -209,11 +212,11 @@ TEST_F(AddressSortingTest, TestDepriotizesUnreachableAddresses) { { {"1.2.3.4:443", {"4.3.2.1:443", AF_INET}}, }); - auto lb_addrs = BuildLbAddrInputs({ + auto* lb_addrs = BuildLbAddrInputs({ {"1.2.3.4:443", AF_INET}, {"5.6.7.8:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "1.2.3.4:443", "5.6.7.8:443", @@ -232,7 +235,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "1.2.3.4:443", "[2607:f8b0:400a:801::1002]:443", @@ -248,11 +251,11 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, {"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2607:f8b0:400a:801::1002]:443", "1.2.3.4:443", @@ -272,11 +275,11 @@ TEST_F(AddressSortingTest, TestDepriotizesNonMatchingScope) { {"[fec0::5000]:443", {"[fec0::5001]:0", AF_INET6}}, // site-local and site-local scope }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[2000:f8b0:400a:801::1002]:443", AF_INET6}, {"[fec0::5000]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fec0::5000]:443", "[2000:f8b0:400a:801::1002]:443", @@ -295,11 +298,11 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTable) { {"[2001::5001]:443", {"[2001::5002]:0", AF_INET6}}, // matching labels }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[2002::5001]:443", AF_INET6}, {"[2001::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2001::5001]:443", "[2002::5001]:443", @@ -318,11 +321,11 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) { {"[2001::5001]:443", {"[2001::5002]:0", AF_INET6}}, // matching labels }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[2001::5001]:443", AF_INET6}, {"[2002::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2001::5001]:443", "[2002::5001]:443", @@ -341,11 +344,11 @@ TEST_F(AddressSortingTest, {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, {"1.2.3.4:443", {"5.6.7.8:0", AF_INET}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs( lb_addrs, { // The AF_INET address should be IPv4-mapped by the sort, @@ -374,11 +377,11 @@ TEST_F(AddressSortingTest, {"[::1]:443", {"[::1]:0", AF_INET6}}, {v4_compat_dest, {v4_compat_src, AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {v4_compat_dest, AF_INET6}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", v4_compat_dest, @@ -397,11 +400,11 @@ TEST_F(AddressSortingTest, {"[1234::2]:443", {"[1234::2]:0", AF_INET6}}, {"[::1]:443", {"[::1]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[1234::2]:443", AF_INET6}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs( lb_addrs, { @@ -421,11 +424,11 @@ TEST_F(AddressSortingTest, {"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}}, {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[2001::1234]:443", AF_INET6}, {"[2000::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs( lb_addrs, { // The 2000::/16 address should match the ::/0 prefix rule @@ -445,11 +448,11 @@ TEST_F( {"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}}, {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[2001::1231]:443", AF_INET6}, {"[2000::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2000::5001]:443", "[2001::1231]:443", @@ -466,11 +469,11 @@ TEST_F(AddressSortingTest, {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, {"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[fec0::1234]:443", AF_INET6}, {"[fc00::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fc00::5001]:443", "[fec0::1234]:443", @@ -491,11 +494,11 @@ TEST_F( {"[::ffff:1.1.1.2]:443", {"[::ffff:1.1.1.3]:0", AF_INET6}}, {"[1234::2]:443", {"[1234::3]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[::ffff:1.1.1.2]:443", AF_INET6}, {"[1234::2]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { // ::ffff:0:2 should match the v4-mapped // precedence entry and be deprioritized. @@ -518,11 +521,11 @@ TEST_F(AddressSortingTest, TestPrefersSmallerScope) { {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"[fec0::1234]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fec0::1234]:443", "[3ffe::5001]:443", @@ -543,11 +546,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { {"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}}, {"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe:5001::]:443", AF_INET6}, {"[3ffe:1234::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:1234::]:443", "[3ffe:5001::]:443", @@ -564,11 +567,11 @@ TEST_F(AddressSortingTest, {"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}}, {"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1234]:443", "[3ffe::5001]:443", @@ -584,11 +587,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { {"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}}, {"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe:8000::]:443", AF_INET6}, {"[3ffe:2000::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:2000::]:443", "[3ffe:8000::]:443", @@ -604,11 +607,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { {"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}}, {"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe:6::]:443", AF_INET6}, {"[3ffe:c::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:c::]:443", "[3ffe:6::]:443", @@ -626,11 +629,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { {"[3ffe:1111:1111:1110::]:443", {"[3ffe:1111:1111:1111::]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe:1111:1111:1110::]:443", AF_INET6}, {"[3ffe:1111:1111:1111::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:1111:1111:1111::]:443", "[3ffe:1111:1111:1110::]:443", @@ -648,11 +651,11 @@ TEST_F(AddressSortingTest, TestStableSort) { {"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}}, {"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1234]:443", "[3ffe::1235]:443", @@ -671,14 +674,14 @@ TEST_F(AddressSortingTest, TestStableSortFiveElements) { {"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}}, {"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe::1231]:443", AF_INET6}, {"[3ffe::1232]:443", AF_INET6}, {"[3ffe::1233]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1231]:443", "[3ffe::1232]:443", @@ -692,14 +695,14 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExist) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[3ffe::1231]:443", AF_INET6}, {"[3ffe::1232]:443", AF_INET6}, {"[3ffe::1233]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1231]:443", "[3ffe::1232]:443", @@ -713,11 +716,11 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[::ffff:5.6.7.8]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::ffff:5.6.7.8]:443", "1.2.3.4:443", @@ -741,11 +744,11 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { {"[fec0::2000]:443", {"[fec0::2001]:0", AF_INET6}}, {v4_compat_dest, {v4_compat_src, AF_INET6}}, }); - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[fec0::2000]:443", AF_INET6}, {v4_compat_dest, AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { // The sort should be stable since @@ -762,11 +765,11 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { * (whether ipv4 loopback is available or not, an available ipv6 * loopback should be preferred). */ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"[::1]:443", AF_INET6}, {"127.0.0.1:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", "127.0.0.1:443", @@ -776,11 +779,11 @@ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { /* Flip the order of the inputs above and expect the same output order * (try to rule out influence of arbitrary qsort ordering) */ TEST_F(AddressSortingTest, TestPrefersIpv6LoopbackInputsFlipped) { - auto lb_addrs = BuildLbAddrInputs({ + grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ {"127.0.0.1:443", AF_INET}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(&lb_addrs); + grpc_cares_wrapper_address_sorting_sort(lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", "127.0.0.1:443", diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc index 2ac2c237cea..fe6fcb8d9cb 100644 --- a/test/cpp/naming/resolver_component_test.cc +++ b/test/cpp/naming/resolver_component_test.cc @@ -41,7 +41,6 @@ #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" @@ -383,19 +382,23 @@ void CheckResolverResultLocked(void* argsp, grpc_error* err) { EXPECT_EQ(err, GRPC_ERROR_NONE); ArgsStruct* args = (ArgsStruct*)argsp; grpc_channel_args* channel_args = args->channel_args; - grpc_core::ServerAddressList* addresses = - grpc_core::FindServerAddressListChannelArg(channel_args); + const grpc_arg* channel_arg = + grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); + GPR_ASSERT(channel_arg != nullptr); + GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); + grpc_lb_addresses* addresses = + (grpc_lb_addresses*)channel_arg->value.pointer.p; gpr_log(GPR_INFO, "num addrs found: %" PRIdPTR ". expected %" PRIdPTR, - addresses->size(), args->expected_addrs.size()); - GPR_ASSERT(addresses->size() == args->expected_addrs.size()); + addresses->num_addresses, args->expected_addrs.size()); + GPR_ASSERT(addresses->num_addresses == args->expected_addrs.size()); std::vector found_lb_addrs; - for (size_t i = 0; i < addresses->size(); i++) { - grpc_core::ServerAddress& addr = (*addresses)[i]; + for (size_t i = 0; i < addresses->num_addresses; i++) { + grpc_lb_address addr = addresses->addresses[i]; char* str; - grpc_sockaddr_to_string(&str, &addr.address(), 1 /* normalize */); + grpc_sockaddr_to_string(&str, &addr.address, 1 /* normalize */); gpr_log(GPR_INFO, "%s", str); found_lb_addrs.emplace_back( - GrpcLBAddress(std::string(str), addr.IsBalancer())); + GrpcLBAddress(std::string(str), addr.is_balancer)); gpr_free(str); } if (args->expected_addrs.size() != found_lb_addrs.size()) { diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 5011e19b03a..dd5bead58ca 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -923,6 +923,7 @@ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h \ +src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_factory.h \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/lb_policy_registry.h \ @@ -958,8 +959,6 @@ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.h \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/retry_throttle.h \ -src/core/ext/filters/client_channel/server_address.cc \ -src/core/ext/filters/client_channel/server_address.h \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel.h \ src/core/ext/filters/client_channel/subchannel_index.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 2451101f58d..0a7a4daf7de 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -10074,7 +10074,6 @@ "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.h", - "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h" ], @@ -10102,6 +10101,7 @@ "src/core/ext/filters/client_channel/http_proxy.h", "src/core/ext/filters/client_channel/lb_policy.cc", "src/core/ext/filters/client_channel/lb_policy.h", + "src/core/ext/filters/client_channel/lb_policy_factory.cc", "src/core/ext/filters/client_channel/lb_policy_factory.h", "src/core/ext/filters/client_channel/lb_policy_registry.cc", "src/core/ext/filters/client_channel/lb_policy_registry.h", @@ -10120,8 +10120,6 @@ "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.cc", "src/core/ext/filters/client_channel/retry_throttle.h", - "src/core/ext/filters/client_channel/server_address.cc", - "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.cc", From cf4e900b82104fe792ca95f1f0b1308dc7a36b11 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Dec 2018 10:08:03 -0800 Subject: [PATCH 61/99] clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index e687a65da7d..ddc6ae054d3 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -253,7 +253,8 @@ extern id const kGRPCTrailersKey; + (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; /** - * Set the dispatch queue to be used for callbacks. Current implementation requires \a queue to be a serial queue. + * Set the dispatch queue to be used for callbacks. Current implementation requires \a queue to be a + * serial queue. * * This configuration is only effective before the call starts. */ From ef7d45d2ab2679ecd1ed08f6ce897063a4f783da Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Dec 2018 12:14:24 -0800 Subject: [PATCH 62/99] Add next_value and start_time --- src/core/lib/gpr/sync_posix.cc | 8 ++++++-- src/core/lib/iomgr/exec_ctx.cc | 13 +++++++++++++ src/core/lib/iomgr/timer_manager.cc | 6 ++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc index 4ded03055c8..6b6c6b6c4b7 100644 --- a/src/core/lib/gpr/sync_posix.cc +++ b/src/core/lib/gpr/sync_posix.cc @@ -39,7 +39,8 @@ void (*g_grpc_debug_timer_manager_stats)( int64_t abs_deadline_nsec_value, int64_t now1_sec_value, int64_t now1_nsec_value, int64_t now2_sec_value, int64_t now2_nsec_value, int64_t add_result_sec_value, int64_t add_result_nsec_value, - int64_t sub_result_sec_value, int64_t sub_result_nsec_value) = nullptr; + int64_t sub_result_sec_value, int64_t sub_result_nsec_value, + int64_t next_value, int64_t start_time_sec, int64_t start_time_nsec) = nullptr; int64_t g_timer_manager_init_count = 0; int64_t g_timer_manager_shutdown_count = 0; int64_t g_fork_count = 0; @@ -58,6 +59,9 @@ int64_t g_add_result_sec_value = -1; int64_t g_add_result_nsec_value = -1; int64_t g_sub_result_sec_value = -1; int64_t g_sub_result_nsec_value = -1; +int64_t g_next_value = -1; +int64_t g_start_time_sec = -1; +int64_t g_start_time_nsec = -1; #endif // GRPC_DEBUG_TIMER_MANAGER #ifdef GPR_LOW_LEVEL_COUNTERS @@ -212,7 +216,7 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { g_abs_deadline_nsec_value, g_now1_sec_value, g_now1_nsec_value, g_now2_sec_value, g_now2_nsec_value, g_add_result_sec_value, g_add_result_nsec_value, g_sub_result_sec_value, - g_sub_result_nsec_value); + g_sub_result_nsec_value, g_next_value, g_start_time_sec, g_start_time_nsec); } } #endif diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc index d68fa0714bf..683dd2f6493 100644 --- a/src/core/lib/iomgr/exec_ctx.cc +++ b/src/core/lib/iomgr/exec_ctx.cc @@ -53,6 +53,13 @@ static void exec_ctx_sched(grpc_closure* closure, grpc_error* error) { static gpr_timespec g_start_time; +// For debug of the timer manager crash only. +// TODO (mxyan): remove after bug is fixed. +#ifdef GRPC_DEBUG_TIMER_MANAGER +extern int64_t g_start_time_sec; +extern int64_t g_start_time_nsec; +#endif // GRPC_DEBUG_TIMER_MANAGER + static grpc_millis timespec_to_millis_round_down(gpr_timespec ts) { ts = gpr_time_sub(ts, g_start_time); double x = GPR_MS_PER_SEC * static_cast(ts.tv_sec) + @@ -117,6 +124,12 @@ void ExecCtx::TestOnlyGlobalInit(gpr_timespec new_val) { void ExecCtx::GlobalInit(void) { g_start_time = gpr_now(GPR_CLOCK_MONOTONIC); + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. +#ifdef GRPC_DEBUG_TIMER_MANAGER + g_start_time_sec = g_start_time.tv_sec; + g_start_time_nsec = g_start_time.tv_nsec; +#endif gpr_tls_init(&exec_ctx_); } diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc index ceba79f6783..143a96c9bc2 100644 --- a/src/core/lib/iomgr/timer_manager.cc +++ b/src/core/lib/iomgr/timer_manager.cc @@ -67,6 +67,7 @@ static void timer_thread(void* completed_thread_ptr); extern int64_t g_timer_manager_init_count; extern int64_t g_timer_manager_shutdown_count; extern int64_t g_fork_count; +extern int64_t g_next_value; #endif // GRPC_DEBUG_TIMER_MANAGER static void gc_completed_threads(void) { @@ -193,6 +194,11 @@ static bool wait_until(grpc_millis next) { gpr_log(GPR_INFO, "sleep until kicked"); } + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. +#ifdef GRPC_DEBUG_TIMER_MANAGER + g_next_value = next; +#endif gpr_cv_wait(&g_cv_wait, &g_mu, grpc_millis_to_timespec(next, GPR_CLOCK_MONOTONIC)); From e9dd13bfcf8d5e699582b92376548038ab635c7c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Dec 2018 12:51:33 -0800 Subject: [PATCH 63/99] clang-format --- src/core/lib/gpr/sync_posix.cc | 6 ++++-- src/core/lib/iomgr/timer_manager.cc | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc index 6b6c6b6c4b7..c09a7598acb 100644 --- a/src/core/lib/gpr/sync_posix.cc +++ b/src/core/lib/gpr/sync_posix.cc @@ -40,7 +40,8 @@ void (*g_grpc_debug_timer_manager_stats)( int64_t now1_nsec_value, int64_t now2_sec_value, int64_t now2_nsec_value, int64_t add_result_sec_value, int64_t add_result_nsec_value, int64_t sub_result_sec_value, int64_t sub_result_nsec_value, - int64_t next_value, int64_t start_time_sec, int64_t start_time_nsec) = nullptr; + int64_t next_value, int64_t start_time_sec, + int64_t start_time_nsec) = nullptr; int64_t g_timer_manager_init_count = 0; int64_t g_timer_manager_shutdown_count = 0; int64_t g_fork_count = 0; @@ -216,7 +217,8 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { g_abs_deadline_nsec_value, g_now1_sec_value, g_now1_nsec_value, g_now2_sec_value, g_now2_nsec_value, g_add_result_sec_value, g_add_result_nsec_value, g_sub_result_sec_value, - g_sub_result_nsec_value, g_next_value, g_start_time_sec, g_start_time_nsec); + g_sub_result_nsec_value, g_next_value, g_start_time_sec, + g_start_time_nsec); } } #endif diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc index 143a96c9bc2..cb123298cf5 100644 --- a/src/core/lib/iomgr/timer_manager.cc +++ b/src/core/lib/iomgr/timer_manager.cc @@ -194,8 +194,8 @@ static bool wait_until(grpc_millis next) { gpr_log(GPR_INFO, "sleep until kicked"); } - // For debug of the timer manager crash only. - // TODO (mxyan): remove after bug is fixed. + // For debug of the timer manager crash only. + // TODO (mxyan): remove after bug is fixed. #ifdef GRPC_DEBUG_TIMER_MANAGER g_next_value = next; #endif From f52e54235294cb71c09d880e8f78a6661b2803f2 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Mon, 10 Dec 2018 12:45:00 -0800 Subject: [PATCH 64/99] Add pagination to serversockets --- src/core/lib/channel/channelz.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 0cb28905181..8d449ee6721 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -204,16 +204,27 @@ ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes) ServerNode::~ServerNode() {} char* ServerNode::RenderServerSockets(intptr_t start_socket_id) { + const int kPaginationLimit = 100; grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; ChildSocketsList socket_refs; grpc_server_populate_server_sockets(server_, &socket_refs, start_socket_id); + int sockets_added = 0; + bool reached_pagination_limit = false; if (!socket_refs.empty()) { // create list of socket refs grpc_json* array_parent = grpc_json_create_child( nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); for (size_t i = 0; i < socket_refs.size(); ++i) { + // check if we are over pagination limit to determine if we need to set + // the "end" element. If we don't go through this block, we know that + // when the loop terminates, we have <= to kPaginationLimit. + if (sockets_added == kPaginationLimit) { + reached_pagination_limit = true; + break; + } + sockets_added++; grpc_json* socket_ref_json = grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); @@ -223,11 +234,10 @@ char* ServerNode::RenderServerSockets(intptr_t start_socket_id) { socket_refs[i]->remote(), GRPC_JSON_STRING, false); } } - // For now we do not have any pagination rules. In the future we could - // pick a constant for max_channels_sent for a GetServers request. - // Tracking: https://github.com/grpc/grpc/issues/16019. - json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr, - GRPC_JSON_TRUE, false); + if (!reached_pagination_limit) { + json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr, + GRPC_JSON_TRUE, false); + } char* json_str = grpc_json_dump_to_string(top_level_json, 0); grpc_json_destroy(top_level_json); return json_str; From c5f344deaf84bd074419d42ed4af47e7c9ca6b42 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 11 Dec 2018 07:48:14 -0800 Subject: [PATCH 65/99] Revert "Revert "Allow encoding arbitrary channel args on a per-address basis."" --- BUILD | 3 +- CMakeLists.txt | 12 +- Makefile | 12 +- build.yaml | 3 +- config.m4 | 2 +- config.w32 | 2 +- gRPC-C++.podspec | 1 + gRPC-Core.podspec | 4 +- grpc.gemspec | 3 +- grpc.gyp | 8 +- package.xml | 3 +- .../filters/client_channel/client_channel.cc | 16 +- .../ext/filters/client_channel/lb_policy.h | 9 +- .../client_channel/lb_policy/grpclb/grpclb.cc | 242 +++++++---------- .../lb_policy/grpclb/grpclb_channel.h | 2 +- .../lb_policy/grpclb/grpclb_channel_secure.cc | 33 +-- .../lb_policy/grpclb/load_balancer_api.h | 2 +- .../lb_policy/pick_first/pick_first.cc | 19 +- .../lb_policy/round_robin/round_robin.cc | 40 +-- .../lb_policy/subchannel_list.h | 53 ++-- .../client_channel/lb_policy/xds/xds.cc | 247 +++++------------- .../lb_policy/xds/xds_channel.h | 2 +- .../lb_policy/xds/xds_channel_secure.cc | 33 +-- .../lb_policy/xds/xds_load_balancer_api.h | 2 +- .../client_channel/lb_policy_factory.cc | 163 ------------ .../client_channel/lb_policy_factory.h | 86 +----- .../resolver/dns/c_ares/dns_resolver_ares.cc | 12 +- .../dns/c_ares/grpc_ares_ev_driver.cc | 1 + .../resolver/dns/c_ares/grpc_ares_wrapper.cc | 149 +++++------ .../resolver/dns/c_ares/grpc_ares_wrapper.h | 13 +- .../dns/c_ares/grpc_ares_wrapper_fallback.cc | 9 +- .../dns/c_ares/grpc_ares_wrapper_posix.cc | 3 +- .../dns/c_ares/grpc_ares_wrapper_windows.cc | 26 +- .../resolver/dns/native/dns_resolver.cc | 14 +- .../resolver/fake/fake_resolver.cc | 3 +- .../resolver/fake/fake_resolver.h | 3 +- .../resolver/sockaddr/sockaddr_resolver.cc | 34 +-- .../client_channel/resolver_result_parsing.cc | 20 +- .../filters/client_channel/server_address.cc | 103 ++++++++ .../filters/client_channel/server_address.h | 108 ++++++++ .../ext/filters/client_channel/subchannel.cc | 6 +- .../ext/filters/client_channel/subchannel.h | 13 +- src/core/lib/iomgr/sockaddr_utils.cc | 1 + src/python/grpcio/grpc_core_dependencies.py | 2 +- .../dns_resolver_connectivity_test.cc | 12 +- .../resolvers/dns_resolver_cooldown_test.cc | 15 +- .../resolvers/fake_resolver_test.cc | 42 +-- test/core/end2end/fuzzers/api_fuzzer.cc | 28 +- test/core/end2end/goaway_server_test.cc | 29 +- test/core/end2end/no_server_test.cc | 1 + test/core/util/ubsan_suppressions.txt | 3 +- test/cpp/client/client_channel_stress_test.cc | 28 +- test/cpp/end2end/client_lb_end2end_test.cc | 18 +- test/cpp/end2end/grpclb_end2end_test.cc | 37 ++- test/cpp/naming/address_sorting_test.cc | 127 +++++---- test/cpp/naming/resolver_component_test.cc | 21 +- tools/doxygen/Doxyfile.core.internal | 3 +- .../generated/sources_and_headers.json | 4 +- 58 files changed, 846 insertions(+), 1044 deletions(-) delete mode 100644 src/core/ext/filters/client_channel/lb_policy_factory.cc create mode 100644 src/core/ext/filters/client_channel/server_address.cc create mode 100644 src/core/ext/filters/client_channel/server_address.h diff --git a/BUILD b/BUILD index 9e3e594038d..5550e583a87 100644 --- a/BUILD +++ b/BUILD @@ -1048,7 +1048,6 @@ grpc_cc_library( "src/core/ext/filters/client_channel/http_connect_handshaker.cc", "src/core/ext/filters/client_channel/http_proxy.cc", "src/core/ext/filters/client_channel/lb_policy.cc", - "src/core/ext/filters/client_channel/lb_policy_factory.cc", "src/core/ext/filters/client_channel/lb_policy_registry.cc", "src/core/ext/filters/client_channel/parse_address.cc", "src/core/ext/filters/client_channel/proxy_mapper.cc", @@ -1057,6 +1056,7 @@ grpc_cc_library( "src/core/ext/filters/client_channel/resolver_registry.cc", "src/core/ext/filters/client_channel/resolver_result_parsing.cc", "src/core/ext/filters/client_channel/retry_throttle.cc", + "src/core/ext/filters/client_channel/server_address.cc", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel_index.cc", ], @@ -1080,6 +1080,7 @@ grpc_cc_library( "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.h", + "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h", ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b02d778d1d..9c660c77012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1240,7 +1240,6 @@ add_library(grpc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1249,6 +1248,7 @@ add_library(grpc src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -1592,7 +1592,6 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1601,6 +1600,7 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -1963,7 +1963,6 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -1972,6 +1971,7 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -2283,7 +2283,6 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -2292,6 +2291,7 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -2617,7 +2617,6 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -2626,6 +2625,7 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc @@ -3469,7 +3469,6 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc src/core/ext/filters/client_channel/lb_policy.cc - src/core/ext/filters/client_channel/lb_policy_factory.cc src/core/ext/filters/client_channel/lb_policy_registry.cc src/core/ext/filters/client_channel/parse_address.cc src/core/ext/filters/client_channel/proxy_mapper.cc @@ -3478,6 +3477,7 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/resolver_registry.cc src/core/ext/filters/client_channel/resolver_result_parsing.cc src/core/ext/filters/client_channel/retry_throttle.cc + src/core/ext/filters/client_channel/server_address.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc src/core/ext/filters/deadline/deadline_filter.cc diff --git a/Makefile b/Makefile index ed4e219f8b7..0163dc414a5 100644 --- a/Makefile +++ b/Makefile @@ -3735,7 +3735,6 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -3744,6 +3743,7 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4081,7 +4081,6 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4090,6 +4089,7 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4445,7 +4445,6 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4454,6 +4453,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -4751,7 +4751,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -4760,6 +4759,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -5058,7 +5058,6 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -5067,6 +5066,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ @@ -5885,7 +5885,6 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -5894,6 +5893,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ diff --git a/build.yaml b/build.yaml index af70be8459a..4521169e6c1 100644 --- a/build.yaml +++ b/build.yaml @@ -589,6 +589,7 @@ filegroups: - src/core/ext/filters/client_channel/resolver_registry.h - src/core/ext/filters/client_channel/resolver_result_parsing.h - src/core/ext/filters/client_channel/retry_throttle.h + - src/core/ext/filters/client_channel/server_address.h - src/core/ext/filters/client_channel/subchannel.h - src/core/ext/filters/client_channel/subchannel_index.h src: @@ -603,7 +604,6 @@ filegroups: - src/core/ext/filters/client_channel/http_connect_handshaker.cc - src/core/ext/filters/client_channel/http_proxy.cc - src/core/ext/filters/client_channel/lb_policy.cc - - src/core/ext/filters/client_channel/lb_policy_factory.cc - src/core/ext/filters/client_channel/lb_policy_registry.cc - src/core/ext/filters/client_channel/parse_address.cc - src/core/ext/filters/client_channel/proxy_mapper.cc @@ -612,6 +612,7 @@ filegroups: - src/core/ext/filters/client_channel/resolver_registry.cc - src/core/ext/filters/client_channel/resolver_result_parsing.cc - src/core/ext/filters/client_channel/retry_throttle.cc + - src/core/ext/filters/client_channel/server_address.cc - src/core/ext/filters/client_channel/subchannel.cc - src/core/ext/filters/client_channel/subchannel_index.cc plugin: grpc_client_channel diff --git a/config.m4 b/config.m4 index 3db660aceea..16de5204bb2 100644 --- a/config.m4 +++ b/config.m4 @@ -348,7 +348,6 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ src/core/ext/filters/client_channel/lb_policy.cc \ - src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/parse_address.cc \ src/core/ext/filters/client_channel/proxy_mapper.cc \ @@ -357,6 +356,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/resolver_registry.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \ + src/core/ext/filters/client_channel/server_address.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ diff --git a/config.w32 b/config.w32 index 7f8b6eee5fa..be10faab9cd 100644 --- a/config.w32 +++ b/config.w32 @@ -323,7 +323,6 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " + "src\\core\\ext\\filters\\client_channel\\http_proxy.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy.cc " + - "src\\core\\ext\\filters\\client_channel\\lb_policy_factory.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy_registry.cc " + "src\\core\\ext\\filters\\client_channel\\parse_address.cc " + "src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " + @@ -332,6 +331,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " + "src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " + "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " + + "src\\core\\ext\\filters\\client_channel\\server_address.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " + "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index e939bead1b7..30fcb51ee19 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -356,6 +356,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', + 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 1d4e1ae35c0..5ab7a49cd27 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -354,6 +354,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', + 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', @@ -786,7 +787,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -795,6 +795,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -974,6 +975,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/resolver_registry.h', 'src/core/ext/filters/client_channel/resolver_result_parsing.h', 'src/core/ext/filters/client_channel/retry_throttle.h', + 'src/core/ext/filters/client_channel/server_address.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', 'src/core/ext/filters/deadline/deadline_filter.h', diff --git a/grpc.gemspec b/grpc.gemspec index 92b1e0be689..1ee7bec8e7d 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -290,6 +290,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h ) s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h ) s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h ) + s.files += %w( src/core/ext/filters/client_channel/server_address.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.h ) @@ -725,7 +726,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc ) - s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.cc ) s.files += %w( src/core/ext/filters/client_channel/parse_address.cc ) s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc ) @@ -734,6 +734,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc ) + s.files += %w( src/core/ext/filters/client_channel/server_address.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc ) diff --git a/grpc.gyp b/grpc.gyp index 564922ff727..00f06a1e54e 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -540,7 +540,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -549,6 +548,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -799,7 +799,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -808,6 +807,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -1039,7 +1039,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -1048,6 +1047,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', @@ -1292,7 +1292,6 @@ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -1301,6 +1300,7 @@ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/package.xml b/package.xml index bdcb12bfc5e..68fc7433cb4 100644 --- a/package.xml +++ b/package.xml @@ -295,6 +295,7 @@ + @@ -730,7 +731,6 @@ - @@ -739,6 +739,7 @@ + diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index ebc412b468d..70aac472314 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -38,6 +38,7 @@ #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/resolver_result_parsing.h" #include "src/core/ext/filters/client_channel/retry_throttle.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/deadline/deadline_filter.h" #include "src/core/lib/backoff/backoff.h" @@ -62,6 +63,7 @@ #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/status_metadata.h" +using grpc_core::ServerAddressList; using grpc_core::internal::ClientChannelMethodParams; using grpc_core::internal::ClientChannelMethodParamsTable; using grpc_core::internal::ProcessedResolverResult; @@ -383,16 +385,10 @@ static void create_new_lb_policy_locked( static void maybe_add_trace_message_for_address_changes_locked( channel_data* chand, TraceStringVector* trace_strings) { - int resolution_contains_addresses = false; - const grpc_arg* channel_arg = - grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); - if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { - grpc_lb_addresses* addresses = - static_cast(channel_arg->value.pointer.p); - if (addresses->num_addresses > 0) { - resolution_contains_addresses = true; - } - } + const ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(chand->resolver_result); + const bool resolution_contains_addresses = + addresses != nullptr && addresses->size() > 0; if (!resolution_contains_addresses && chand->previous_resolution_contained_addresses) { trace_strings->push_back(gpr_strdup("Address list became empty")); diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index 7034da6249c..6b76fe5d5d7 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -55,7 +55,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { grpc_client_channel_factory* client_channel_factory = nullptr; /// Channel args from the resolver. /// Note that the LB policy gets the set of addresses from the - /// GRPC_ARG_LB_ADDRESSES channel arg. + /// GRPC_ARG_SERVER_ADDRESS_LIST channel arg. grpc_channel_args* args = nullptr; /// Load balancing config from the resolver. grpc_json* lb_config = nullptr; @@ -80,11 +80,6 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Will be populated with context to pass to the subchannel call, if /// needed. grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT] = {}; - /// Upon success, \a *user_data will be set to whatever opaque information - /// may need to be propagated from the LB policy, or nullptr if not needed. - // TODO(roth): As part of revamping our metadata APIs, try to find a - // way to clean this up and C++-ify it. - void** user_data = nullptr; /// Next pointer. For internal use by LB policy. PickState* next = nullptr; }; @@ -95,7 +90,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Updates the policy with a new set of \a args and a new \a lb_config from /// the resolver. Note that the LB policy gets the set of addresses from the - /// GRPC_ARG_LB_ADDRESSES channel arg. + /// GRPC_ARG_SERVER_ADDRESS_LIST channel arg. virtual void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) GRPC_ABSTRACT; diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index a46579c7f74..a9a5965ed1c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -84,6 +84,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" @@ -113,6 +114,8 @@ #define GRPC_GRPCLB_RECONNECT_JITTER 0.2 #define GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS 10000 +#define GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN "grpc.grpclb_address_lb_token" + namespace grpc_core { TraceFlag grpc_lb_glb_trace(false, "glb"); @@ -121,7 +124,7 @@ namespace { class GrpcLb : public LoadBalancingPolicy { public: - GrpcLb(const grpc_lb_addresses* addresses, const Args& args); + explicit GrpcLb(const Args& args); void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) override; @@ -161,9 +164,6 @@ class GrpcLb : public LoadBalancingPolicy { // Our on_complete closure and the original one. grpc_closure on_complete; grpc_closure* original_on_complete; - // The LB token associated with the pick. This is set via user_data in - // the pick. - grpc_mdelem lb_token; // Stats for client-side load reporting. RefCountedPtr client_stats; // Next pending pick. @@ -329,7 +329,7 @@ class GrpcLb : public LoadBalancingPolicy { // 0 means not using fallback. int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - grpc_lb_addresses* fallback_backend_addresses_ = nullptr; + UniquePtr fallback_backend_addresses_; // Fallback timer. bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; @@ -349,7 +349,7 @@ class GrpcLb : public LoadBalancingPolicy { // serverlist parsing code // -// vtable for LB tokens in grpc_lb_addresses +// vtable for LB token channel arg. void* lb_token_copy(void* token) { return token == nullptr ? nullptr @@ -361,38 +361,11 @@ void lb_token_destroy(void* token) { } } int lb_token_cmp(void* token1, void* token2) { - if (token1 > token2) return 1; - if (token1 < token2) return -1; - return 0; + return GPR_ICMP(token1, token2); } -const grpc_lb_user_data_vtable lb_token_vtable = { +const grpc_arg_pointer_vtable lb_token_arg_vtable = { lb_token_copy, lb_token_destroy, lb_token_cmp}; -// Returns the backend addresses extracted from the given addresses. -grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { - // First pass: count the number of backend addresses. - size_t num_backends = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) { - ++num_backends; - } - } - // Second pass: actually populate the addresses and (empty) LB tokens. - grpc_lb_addresses* backend_addresses = - grpc_lb_addresses_create(num_backends, &lb_token_vtable); - size_t num_copied = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) continue; - const grpc_resolved_address* addr = &addresses->addresses[i].address; - grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, - addr->len, false /* is_balancer */, - nullptr /* balancer_name */, - (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); - ++num_copied; - } - return backend_addresses; -} - bool IsServerValid(const grpc_grpclb_server* server, size_t idx, bool log) { if (server->drop) return false; const grpc_grpclb_ip_address* ip = &server->ip_address; @@ -440,30 +413,16 @@ void ParseServer(const grpc_grpclb_server* server, } // Returns addresses extracted from \a serverlist. -grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { - size_t num_valid = 0; - /* first pass: count how many are valid in order to allocate the necessary - * memory in a single block */ +ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { + ServerAddressList addresses; for (size_t i = 0; i < serverlist->num_servers; ++i) { - if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; - } - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_valid, &lb_token_vtable); - /* second pass: actually populate the addresses and LB tokens (aka user data - * to the outside world) to be read by the RR policy during its creation. - * Given that the validity tests are very cheap, they are performed again - * instead of marking the valid ones during the first pass, as this would - * incurr in an allocation due to the arbitrary number of server */ - size_t addr_idx = 0; - for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { - const grpc_grpclb_server* server = serverlist->servers[sl_idx]; - if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; - GPR_ASSERT(addr_idx < num_valid); - /* address processing */ + const grpc_grpclb_server* server = serverlist->servers[i]; + if (!IsServerValid(serverlist->servers[i], i, false)) continue; + // Address processing. grpc_resolved_address addr; ParseServer(server, &addr); - /* lb token processing */ - void* user_data; + // LB token processing. + void* lb_token; if (server->has_load_balance_token) { const size_t lb_token_max_length = GPR_ARRAY_SIZE(server->load_balance_token); @@ -471,7 +430,7 @@ grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { strnlen(server->load_balance_token, lb_token_max_length); grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( server->load_balance_token, lb_token_length); - user_data = + lb_token = (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) .payload; } else { @@ -481,15 +440,16 @@ grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) { "be used instead", uri); gpr_free(uri); - user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; } - grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, - false /* is_balancer */, - nullptr /* balancer_name */, user_data); - ++addr_idx; - } - GPR_ASSERT(addr_idx == num_valid); - return lb_addresses; + // Add address. + grpc_arg arg = grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token, + &lb_token_arg_vtable); + grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); + addresses.emplace_back(addr, args); + } + return addresses; } // @@ -829,8 +789,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( grpc_grpclb_destroy_serverlist(grpclb_policy->serverlist_); } else { // Dispose of the fallback. - grpc_lb_addresses_destroy(grpclb_policy->fallback_backend_addresses_); - grpclb_policy->fallback_backend_addresses_ = nullptr; + grpclb_policy->fallback_backend_addresses_.reset(); if (grpclb_policy->fallback_timer_callback_pending_) { grpc_timer_cancel(&grpclb_policy->lb_fallback_timer_); } @@ -910,31 +869,25 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked( // helper code for creating balancer channel // -grpc_lb_addresses* ExtractBalancerAddresses( - const grpc_lb_addresses* addresses) { - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; - } - // There must be at least one balancer address, or else the - // client_channel would not have chosen this LB policy. - GPR_ASSERT(num_grpclb_addrs > 0); - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_grpclb_addrs, nullptr); - size_t lb_addresses_idx = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) continue; - if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); +ServerAddressList ExtractBalancerAddresses(const ServerAddressList& addresses) { + ServerAddressList balancer_addresses; + for (size_t i = 0; i < addresses.size(); ++i) { + if (addresses[i].IsBalancer()) { + // Strip out the is_balancer channel arg, since we don't want to + // recursively use the grpclb policy in the channel used to talk to + // the balancers. Note that we do NOT strip out the balancer_name + // channel arg, since we need that to set the authority correctly + // to talk to the balancers. + static const char* args_to_remove[] = { + GRPC_ARG_ADDRESS_IS_BALANCER, + }; + balancer_addresses.emplace_back( + addresses[i].address(), + grpc_channel_args_copy_and_remove(addresses[i].args(), args_to_remove, + GPR_ARRAY_SIZE(args_to_remove))); } - grpc_lb_addresses_set_address( - lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, - addresses->addresses[i].address.len, false /* is balancer */, - addresses->addresses[i].balancer_name, nullptr /* user data */); } - GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); - return lb_addresses; + return balancer_addresses; } /* Returns the channel args for the LB channel, used to create a bidirectional @@ -946,10 +899,10 @@ grpc_lb_addresses* ExtractBalancerAddresses( * above the grpclb policy. * - \a args: other args inherited from the grpclb policy. */ grpc_channel_args* BuildBalancerChannelArgs( - const grpc_lb_addresses* addresses, + const ServerAddressList& addresses, FakeResolverResponseGenerator* response_generator, const grpc_channel_args* args) { - grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); + ServerAddressList balancer_addresses = ExtractBalancerAddresses(addresses); // Channel args to remove. static const char* args_to_remove[] = { // LB policy name, since we want to use the default (pick_first) in @@ -967,7 +920,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // is_balancer=true. We need the LB channel to return addresses with // is_balancer=false so that it does not wind up recursively using the // grpclb LB policy, as per the special case logic in client_channel.c. - GRPC_ARG_LB_ADDRESSES, + GRPC_ARG_SERVER_ADDRESS_LIST, // The fake resolver response generator, because we are replacing it // with the one from the grpclb policy, used to propagate updates to // the LB channel. @@ -983,10 +936,10 @@ grpc_channel_args* BuildBalancerChannelArgs( }; // Channel args to add. const grpc_arg args_to_add[] = { - // New LB addresses. + // New address list. // Note that we pass these in both when creating the LB channel // and via the fake resolver. The latter is what actually gets used. - grpc_lb_addresses_create_channel_arg(lb_addresses), + CreateServerAddressListChannelArg(&balancer_addresses), // The fake resolver response generator, which we use to inject // address updates into the LB channel. grpc_core::FakeResolverResponseGenerator::MakeChannelArg( @@ -1004,18 +957,14 @@ grpc_channel_args* BuildBalancerChannelArgs( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Make any necessary modifications for security. - new_args = grpc_lb_policy_grpclb_modify_lb_channel_args(new_args); - // Clean up. - grpc_lb_addresses_destroy(lb_addresses); - return new_args; + return grpc_lb_policy_grpclb_modify_lb_channel_args(new_args); } // // ctor and dtor // -GrpcLb::GrpcLb(const grpc_lb_addresses* addresses, - const LoadBalancingPolicy::Args& args) +GrpcLb::GrpcLb(const LoadBalancingPolicy::Args& args) : LoadBalancingPolicy(args), response_generator_(MakeRefCounted()), lb_call_backoff_( @@ -1072,9 +1021,6 @@ GrpcLb::~GrpcLb() { if (serverlist_ != nullptr) { grpc_grpclb_destroy_serverlist(serverlist_); } - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } grpc_subchannel_index_unref(); } @@ -1122,7 +1068,6 @@ void GrpcLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { while ((pp = pending_picks_) != nullptr) { pending_picks_ = pp->next; pp->pick->on_complete = pp->original_on_complete; - pp->pick->user_data = nullptr; grpc_error* error = GRPC_ERROR_NONE; if (new_policy->PickLocked(pp->pick, &error)) { // Synchronous return; schedule closure. @@ -1276,9 +1221,27 @@ void GrpcLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, notify); } +// Returns the backend addresses extracted from the given addresses. +UniquePtr ExtractBackendAddresses( + const ServerAddressList& addresses) { + void* lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + grpc_arg arg = grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token, + &lb_token_arg_vtable); + auto backend_addresses = MakeUnique(); + for (size_t i = 0; i < addresses.size(); ++i) { + if (!addresses[i].IsBalancer()) { + backend_addresses->emplace_back( + addresses[i].address(), + grpc_channel_args_copy_and_add(addresses[i].args(), &arg, 1)); + } + } + return backend_addresses; +} + void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); - if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { // Ignore this update. gpr_log( GPR_ERROR, @@ -1286,13 +1249,8 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { this); return; } - const grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); // Update fallback address list. - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } - fallback_backend_addresses_ = ExtractBackendAddresses(addresses); + fallback_backend_addresses_ = ExtractBackendAddresses(*addresses); // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, // since we use this to trigger the client_load_reporting filter. static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; @@ -1303,7 +1261,7 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); // Construct args for balancer channel. grpc_channel_args* lb_channel_args = - BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); + BuildBalancerChannelArgs(*addresses, response_generator_.get(), &args); // Create balancer channel if needed. if (lb_channel_ == nullptr) { char* uri_str; @@ -1509,12 +1467,17 @@ void DestroyClientStats(void* arg) { } void GrpcLb::PendingPickSetMetadataAndContext(PendingPick* pp) { - /* if connected_subchannel is nullptr, no pick has been made by the RR - * policy (e.g., all addresses failed to connect). There won't be any - * user_data/token available */ + // If connected_subchannel is nullptr, no pick has been made by the RR + // policy (e.g., all addresses failed to connect). There won't be any + // LB token available. if (pp->pick->connected_subchannel != nullptr) { - if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { - AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), + const grpc_arg* arg = + grpc_channel_args_find(pp->pick->connected_subchannel->args(), + GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN); + if (arg != nullptr) { + grpc_mdelem lb_token = { + reinterpret_cast(arg->value.pointer.p)}; + AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(lb_token), &pp->pick->lb_token_mdelem_storage, pp->pick->initial_metadata); } else { @@ -1598,12 +1561,10 @@ bool GrpcLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp, return true; } } - // Set client_stats and user_data. + // Set client_stats. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); } - GPR_ASSERT(pp->pick->user_data == nullptr); - pp->pick->user_data = (void**)&pp->lb_token; // Pick via the RR policy. bool pick_done = rr_policy_->PickLocked(pp->pick, error); if (pick_done) { @@ -1668,10 +1629,11 @@ void GrpcLb::CreateRoundRobinPolicyLocked(const Args& args) { } grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { - grpc_lb_addresses* addresses; + ServerAddressList tmp_addresses; + ServerAddressList* addresses = &tmp_addresses; bool is_backend_from_grpclb_load_balancer = false; if (serverlist_ != nullptr) { - addresses = ProcessServerlist(serverlist_); + tmp_addresses = ProcessServerlist(serverlist_); is_backend_from_grpclb_load_balancer = true; } else { // If CreateOrUpdateRoundRobinPolicyLocked() is invoked when we haven't @@ -1680,14 +1642,14 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { // empty, in which case the new round_robin policy will keep the requested // picks pending. GPR_ASSERT(fallback_backend_addresses_ != nullptr); - addresses = grpc_lb_addresses_copy(fallback_backend_addresses_); + addresses = fallback_backend_addresses_.get(); } GPR_ASSERT(addresses != nullptr); - // Replace the LB addresses in the channel args that we pass down to + // Replace the server address list in the channel args that we pass down to // the subchannel. - static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; + static const char* keys_to_remove[] = {GRPC_ARG_SERVER_ADDRESS_LIST}; grpc_arg args_to_add[3] = { - grpc_lb_addresses_create_channel_arg(addresses), + CreateServerAddressListChannelArg(addresses), // A channel arg indicating if the target is a backend inferred from a // grpclb load balancer. grpc_channel_arg_integer_create( @@ -1704,7 +1666,6 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() { grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, num_args_to_add); - grpc_lb_addresses_destroy(addresses); return args; } @@ -1837,19 +1798,18 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory { OrphanablePtr CreateLoadBalancingPolicy( const LoadBalancingPolicy::Args& args) const override { /* Count the number of gRPC-LB addresses. There must be at least one. */ - const grpc_arg* arg = - grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); - if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { - return nullptr; - } - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + const ServerAddressList* addresses = + FindServerAddressListChannelArg(args.args); + if (addresses == nullptr) return nullptr; + bool found_balancer = false; + for (size_t i = 0; i < addresses->size(); ++i) { + if ((*addresses)[i].IsBalancer()) { + found_balancer = true; + break; + } } - if (num_grpclb_addrs == 0) return nullptr; - return OrphanablePtr(New(addresses, args)); + if (!found_balancer) return nullptr; + return OrphanablePtr(New(args)); } const char* name() const override { return "grpclb"; } diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h index 825065a9c32..3b2dc370eb3 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include /// Makes any necessary modifications to \a args for use in the grpclb /// balancer channel. diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc index 441efd5e23b..6e8fbdcab77 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc @@ -26,6 +26,7 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -42,22 +43,23 @@ int BalancerNameCmp(const grpc_core::UniquePtr& a, } RefCountedPtr CreateTargetAuthorityTable( - grpc_lb_addresses* addresses) { + const ServerAddressList& addresses) { TargetAuthorityTable::Entry* target_authority_entries = - static_cast(gpr_zalloc( - sizeof(*target_authority_entries) * addresses->num_addresses)); - for (size_t i = 0; i < addresses->num_addresses; ++i) { + static_cast( + gpr_zalloc(sizeof(*target_authority_entries) * addresses.size())); + for (size_t i = 0; i < addresses.size(); ++i) { char* addr_str; - GPR_ASSERT(grpc_sockaddr_to_string( - &addr_str, &addresses->addresses[i].address, true) > 0); + GPR_ASSERT( + grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true) > 0); target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); - target_authority_entries[i].value.reset( - gpr_strdup(addresses->addresses[i].balancer_name)); gpr_free(addr_str); + char* balancer_name = grpc_channel_arg_get_string(grpc_channel_args_find( + addresses[i].args(), GRPC_ARG_ADDRESS_BALANCER_NAME)); + target_authority_entries[i].value.reset(gpr_strdup(balancer_name)); } RefCountedPtr target_authority_table = - TargetAuthorityTable::Create(addresses->num_addresses, - target_authority_entries, BalancerNameCmp); + TargetAuthorityTable::Create(addresses.size(), target_authority_entries, + BalancerNameCmp); gpr_free(target_authority_entries); return target_authority_table; } @@ -72,13 +74,12 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args( grpc_arg args_to_add[2]; size_t num_args_to_add = 0; // Add arg for targets info table. - const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != nullptr); - GPR_ASSERT(arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); + grpc_core::ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(args); + GPR_ASSERT(addresses != nullptr); grpc_core::RefCountedPtr - target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); + target_authority_table = + grpc_core::CreateTargetAuthorityTable(*addresses); args_to_add[num_args_to_add++] = grpc_core::CreateTargetAuthorityTableChannelArg( target_authority_table.get()); diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h index 9ca7b28d8e6..71d371c880a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" #define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index d1a05f12554..74c17612a28 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -24,6 +24,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/channel/channel_args.h" @@ -75,11 +76,9 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner) - : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, - combiner) {} + : SubchannelData(subchannel_list, address, subchannel, combiner) {} void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; @@ -95,7 +94,7 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData> { public: PickFirstSubchannelList(PickFirst* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) @@ -337,8 +336,8 @@ void PickFirst::UpdateChildRefsLocked() { void PickFirst::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) { AutoChildRefsUpdater guard(this); - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); - if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { if (subchannel_list_ == nullptr) { // If we don't have a current subchannel list, go into TRANSIENT FAILURE. grpc_connectivity_state_set( @@ -354,19 +353,17 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args, } return; } - const grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); if (grpc_lb_pick_first_trace.enabled()) { gpr_log(GPR_INFO, "Pick First %p received update with %" PRIuPTR " addresses", this, - addresses->num_addresses); + addresses->size()); } grpc_arg new_arg = grpc_channel_arg_integer_create( const_cast(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1); grpc_channel_args* new_args = grpc_channel_args_copy_and_add(&args, &new_arg, 1); auto subchannel_list = MakeOrphanable( - this, &grpc_lb_pick_first_trace, addresses, combiner(), + this, &grpc_lb_pick_first_trace, *addresses, combiner(), client_channel_factory(), *new_args); grpc_channel_args_destroy(new_args); if (subchannel_list->num_subchannels() == 0) { diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 2a169751317..63089afbd78 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -82,8 +82,6 @@ class RoundRobin : public LoadBalancingPolicy { // Data for a particular subchannel in a subchannel list. // This subclass adds the following functionality: - // - Tracks user_data associated with each address, which will be - // returned along with picks that select the subchannel. // - Tracks the previous connectivity state of the subchannel, so that // we know how many subchannels are in each state. class RoundRobinSubchannelData @@ -93,26 +91,9 @@ class RoundRobin : public LoadBalancingPolicy { RoundRobinSubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner) - : SubchannelData(subchannel_list, user_data_vtable, address, subchannel, - combiner), - user_data_vtable_(user_data_vtable), - user_data_(user_data_vtable_ != nullptr - ? user_data_vtable_->copy(address.user_data) - : nullptr) {} - - void UnrefSubchannelLocked(const char* reason) override { - SubchannelData::UnrefSubchannelLocked(reason); - if (user_data_ != nullptr) { - GPR_ASSERT(user_data_vtable_ != nullptr); - user_data_vtable_->destroy(user_data_); - user_data_ = nullptr; - } - } - - void* user_data() const { return user_data_; } + : SubchannelData(subchannel_list, address, subchannel, combiner) {} grpc_connectivity_state connectivity_state() const { return last_connectivity_state_; @@ -125,8 +106,6 @@ class RoundRobin : public LoadBalancingPolicy { void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state, grpc_error* error) override; - const grpc_lb_user_data_vtable* user_data_vtable_; - void* user_data_ = nullptr; grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_IDLE; }; @@ -137,7 +116,7 @@ class RoundRobin : public LoadBalancingPolicy { public: RoundRobinSubchannelList( RoundRobin* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : SubchannelList(policy, tracer, addresses, combiner, @@ -354,9 +333,6 @@ bool RoundRobin::DoPickLocked(PickState* pick) { subchannel_list_->subchannel(next_ready_index); GPR_ASSERT(sd->connected_subchannel() != nullptr); pick->connected_subchannel = sd->connected_subchannel()->Ref(); - if (pick->user_data != nullptr) { - *pick->user_data = sd->user_data(); - } if (grpc_lb_round_robin_trace.enabled()) { gpr_log(GPR_INFO, "[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, " @@ -667,9 +643,9 @@ void RoundRobin::NotifyOnStateChangeLocked(grpc_connectivity_state* current, void RoundRobin::UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) { - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); AutoChildRefsUpdater guard(this); - if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", this); // If we don't have a current subchannel list, go into TRANSIENT_FAILURE. // Otherwise, keep using the current subchannel list (ignore this update). @@ -681,11 +657,9 @@ void RoundRobin::UpdateLocked(const grpc_channel_args& args, } return; } - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); if (grpc_lb_round_robin_trace.enabled()) { gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses", - this, addresses->num_addresses); + this, addresses->size()); } // Replace latest_pending_subchannel_list_. if (latest_pending_subchannel_list_ != nullptr) { @@ -696,7 +670,7 @@ void RoundRobin::UpdateLocked(const grpc_channel_args& args, } } latest_pending_subchannel_list_ = MakeOrphanable( - this, &grpc_lb_round_robin_trace, addresses, combiner(), + this, &grpc_lb_round_robin_trace, *addresses, combiner(), client_channel_factory(), args); // If we haven't started picking yet or the new list is empty, // immediately promote the new list to the current list. diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index f31401502c3..6f31a643c1d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -26,6 +26,7 @@ #include #include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/debug/trace.h" @@ -141,8 +142,7 @@ class SubchannelData { protected: SubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner); virtual ~SubchannelData(); @@ -156,9 +156,8 @@ class SubchannelData { grpc_connectivity_state connectivity_state, grpc_error* error) GRPC_ABSTRACT; - // Unrefs the subchannel. May be overridden by subclasses that need - // to perform extra cleanup when unreffing the subchannel. - virtual void UnrefSubchannelLocked(const char* reason); + // Unrefs the subchannel. + void UnrefSubchannelLocked(const char* reason); private: // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_. @@ -232,7 +231,7 @@ class SubchannelList : public InternallyRefCounted { protected: SubchannelList(LoadBalancingPolicy* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args); @@ -277,8 +276,7 @@ class SubchannelList : public InternallyRefCounted { template SubchannelData::SubchannelData( SubchannelList* subchannel_list, - const grpc_lb_user_data_vtable* user_data_vtable, - const grpc_lb_address& address, grpc_subchannel* subchannel, + const ServerAddress& address, grpc_subchannel* subchannel, grpc_combiner* combiner) : subchannel_list_(subchannel_list), subchannel_(subchannel), @@ -488,7 +486,7 @@ void SubchannelData::ShutdownLocked() { template SubchannelList::SubchannelList( LoadBalancingPolicy* policy, TraceFlag* tracer, - const grpc_lb_addresses* addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, grpc_combiner* combiner, grpc_client_channel_factory* client_channel_factory, const grpc_channel_args& args) : InternallyRefCounted(tracer), @@ -498,9 +496,9 @@ SubchannelList::SubchannelList( if (tracer_->enabled()) { gpr_log(GPR_INFO, "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", - tracer_->name(), policy, this, addresses->num_addresses); + tracer_->name(), policy, this, addresses.size()); } - subchannels_.reserve(addresses->num_addresses); + subchannels_.reserve(addresses.size()); // We need to remove the LB addresses in order to be able to compare the // subchannel keys of subchannels from a different batch of addresses. // We also remove the inhibit-health-checking arg, since we are @@ -508,19 +506,27 @@ SubchannelList::SubchannelList( inhibit_health_checking_ = grpc_channel_arg_get_bool( grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false); static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, - GRPC_ARG_LB_ADDRESSES, + GRPC_ARG_SERVER_ADDRESS_LIST, GRPC_ARG_INHIBIT_HEALTH_CHECKING}; // Create a subchannel for each address. grpc_subchannel_args sc_args; - for (size_t i = 0; i < addresses->num_addresses; i++) { - // If there were any balancer, we would have chosen grpclb policy instead. - GPR_ASSERT(!addresses->addresses[i].is_balancer); + for (size_t i = 0; i < addresses.size(); i++) { + // If there were any balancer addresses, we would have chosen grpclb + // policy, which does not use a SubchannelList. + GPR_ASSERT(!addresses[i].IsBalancer()); memset(&sc_args, 0, sizeof(grpc_subchannel_args)); - grpc_arg addr_arg = - grpc_create_subchannel_address_arg(&addresses->addresses[i].address); + InlinedVector args_to_add; + args_to_add.emplace_back( + grpc_create_subchannel_address_arg(&addresses[i].address())); + if (addresses[i].args() != nullptr) { + for (size_t j = 0; j < addresses[i].args()->num_args; ++j) { + args_to_add.emplace_back(addresses[i].args()->args[j]); + } + } grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( - &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, 1); - gpr_free(addr_arg.value.string); + &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), + args_to_add.data(), args_to_add.size()); + gpr_free(args_to_add[0].value.string); sc_args.args = new_args; grpc_subchannel* subchannel = grpc_client_channel_factory_create_subchannel( client_channel_factory, &sc_args); @@ -528,8 +534,7 @@ SubchannelList::SubchannelList( if (subchannel == nullptr) { // Subchannel could not be created. if (tracer_->enabled()) { - char* address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); + char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); gpr_log(GPR_INFO, "[%s %p] could not create subchannel for address uri %s, " "ignoring", @@ -539,8 +544,7 @@ SubchannelList::SubchannelList( continue; } if (tracer_->enabled()) { - char* address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); + char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR ": Created subchannel %p for address uri %s", @@ -548,8 +552,7 @@ SubchannelList::SubchannelList( address_uri); gpr_free(address_uri); } - subchannels_.emplace_back(this, addresses->user_data_vtable, - addresses->addresses[i], subchannel, combiner); + subchannels_.emplace_back(this, addresses[i], subchannel, combiner); } } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index faedc0a9194..3c25de2386c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -79,6 +79,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" @@ -116,7 +117,7 @@ namespace { class XdsLb : public LoadBalancingPolicy { public: - XdsLb(const grpc_lb_addresses* addresses, const Args& args); + explicit XdsLb(const Args& args); void UpdateLocked(const grpc_channel_args& args, grpc_json* lb_config) override; @@ -156,9 +157,6 @@ class XdsLb : public LoadBalancingPolicy { // Our on_complete closure and the original one. grpc_closure on_complete; grpc_closure* original_on_complete; - // The LB token associated with the pick. This is set via user_data in - // the pick. - grpc_mdelem lb_token; // Stats for client-side load reporting. RefCountedPtr client_stats; // Next pending pick. @@ -256,7 +254,7 @@ class XdsLb : public LoadBalancingPolicy { grpc_error* error); // Pending pick methods. - static void PendingPickSetMetadataAndContext(PendingPick* pp); + static void PendingPickCleanup(PendingPick* pp); PendingPick* PendingPickCreate(PickState* pick); void AddPendingPick(PendingPick* pp); static void OnPendingPickComplete(void* arg, grpc_error* error); @@ -319,7 +317,7 @@ class XdsLb : public LoadBalancingPolicy { // 0 means not using fallback. int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - grpc_lb_addresses* fallback_backend_addresses_ = nullptr; + UniquePtr fallback_backend_addresses_; // Fallback timer. bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; @@ -339,47 +337,15 @@ class XdsLb : public LoadBalancingPolicy { // serverlist parsing code // -// vtable for LB tokens in grpc_lb_addresses -void* lb_token_copy(void* token) { - return token == nullptr - ? nullptr - : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload; -} -void lb_token_destroy(void* token) { - if (token != nullptr) { - GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token}); - } -} -int lb_token_cmp(void* token1, void* token2) { - if (token1 > token2) return 1; - if (token1 < token2) return -1; - return 0; -} -const grpc_lb_user_data_vtable lb_token_vtable = { - lb_token_copy, lb_token_destroy, lb_token_cmp}; - // Returns the backend addresses extracted from the given addresses. -grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) { - // First pass: count the number of backend addresses. - size_t num_backends = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) { - ++num_backends; +UniquePtr ExtractBackendAddresses( + const ServerAddressList& addresses) { + auto backend_addresses = MakeUnique(); + for (size_t i = 0; i < addresses.size(); ++i) { + if (!addresses[i].IsBalancer()) { + backend_addresses->emplace_back(addresses[i]); } } - // Second pass: actually populate the addresses and (empty) LB tokens. - grpc_lb_addresses* backend_addresses = - grpc_lb_addresses_create(num_backends, &lb_token_vtable); - size_t num_copied = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) continue; - const grpc_resolved_address* addr = &addresses->addresses[i].address; - grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr, - addr->len, false /* is_balancer */, - nullptr /* balancer_name */, - (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload); - ++num_copied; - } return backend_addresses; } @@ -429,56 +395,17 @@ void ParseServer(const xds_grpclb_server* server, grpc_resolved_address* addr) { } // Returns addresses extracted from \a serverlist. -grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) { - size_t num_valid = 0; - /* first pass: count how many are valid in order to allocate the necessary - * memory in a single block */ +UniquePtr ProcessServerlist( + const xds_grpclb_serverlist* serverlist) { + auto addresses = MakeUnique(); for (size_t i = 0; i < serverlist->num_servers; ++i) { - if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid; - } - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_valid, &lb_token_vtable); - /* second pass: actually populate the addresses and LB tokens (aka user data - * to the outside world) to be read by the child policy during its creation. - * Given that the validity tests are very cheap, they are performed again - * instead of marking the valid ones during the first pass, as this would - * incurr in an allocation due to the arbitrary number of server */ - size_t addr_idx = 0; - for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { - const xds_grpclb_server* server = serverlist->servers[sl_idx]; - if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue; - GPR_ASSERT(addr_idx < num_valid); - /* address processing */ + const xds_grpclb_server* server = serverlist->servers[i]; + if (!IsServerValid(serverlist->servers[i], i, false)) continue; grpc_resolved_address addr; ParseServer(server, &addr); - /* lb token processing */ - void* user_data; - if (server->has_load_balance_token) { - const size_t lb_token_max_length = - GPR_ARRAY_SIZE(server->load_balance_token); - const size_t lb_token_length = - strnlen(server->load_balance_token, lb_token_max_length); - grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( - server->load_balance_token, lb_token_length); - user_data = - (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) - .payload; - } else { - char* uri = grpc_sockaddr_to_uri(&addr); - gpr_log(GPR_INFO, - "Missing LB token for backend address '%s'. The empty token will " - "be used instead", - uri); - gpr_free(uri); - user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; - } - grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, - false /* is_balancer */, - nullptr /* balancer_name */, user_data); - ++addr_idx; + addresses->emplace_back(addr, nullptr); } - GPR_ASSERT(addr_idx == num_valid); - return lb_addresses; + return addresses; } // @@ -789,8 +716,7 @@ void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked( xds_grpclb_destroy_serverlist(xdslb_policy->serverlist_); } else { /* or dispose of the fallback */ - grpc_lb_addresses_destroy(xdslb_policy->fallback_backend_addresses_); - xdslb_policy->fallback_backend_addresses_ = nullptr; + xdslb_policy->fallback_backend_addresses_.reset(); if (xdslb_policy->fallback_timer_callback_pending_) { grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_); } @@ -876,31 +802,15 @@ void XdsLb::BalancerCallState::OnBalancerStatusReceivedLocked( // helper code for creating balancer channel // -grpc_lb_addresses* ExtractBalancerAddresses( - const grpc_lb_addresses* addresses) { - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; - } - // There must be at least one balancer address, or else the - // client_channel would not have chosen this LB policy. - GPR_ASSERT(num_grpclb_addrs > 0); - grpc_lb_addresses* lb_addresses = - grpc_lb_addresses_create(num_grpclb_addrs, nullptr); - size_t lb_addresses_idx = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) continue; - if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); +UniquePtr ExtractBalancerAddresses( + const ServerAddressList& addresses) { + auto balancer_addresses = MakeUnique(); + for (size_t i = 0; i < addresses.size(); ++i) { + if (addresses[i].IsBalancer()) { + balancer_addresses->emplace_back(addresses[i]); } - grpc_lb_addresses_set_address( - lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, - addresses->addresses[i].address.len, false /* is balancer */, - addresses->addresses[i].balancer_name, nullptr /* user data */); } - GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); - return lb_addresses; + return balancer_addresses; } /* Returns the channel args for the LB channel, used to create a bidirectional @@ -912,10 +822,11 @@ grpc_lb_addresses* ExtractBalancerAddresses( * above the grpclb policy. * - \a args: other args inherited from the xds policy. */ grpc_channel_args* BuildBalancerChannelArgs( - const grpc_lb_addresses* addresses, + const ServerAddressList& addresses, FakeResolverResponseGenerator* response_generator, const grpc_channel_args* args) { - grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses); + UniquePtr balancer_addresses = + ExtractBalancerAddresses(addresses); // Channel args to remove. static const char* args_to_remove[] = { // LB policy name, since we want to use the default (pick_first) in @@ -933,7 +844,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // is_balancer=true. We need the LB channel to return addresses with // is_balancer=false so that it does not wind up recursively using the // xds LB policy, as per the special case logic in client_channel.c. - GRPC_ARG_LB_ADDRESSES, + GRPC_ARG_SERVER_ADDRESS_LIST, // The fake resolver response generator, because we are replacing it // with the one from the xds policy, used to propagate updates to // the LB channel. @@ -949,10 +860,10 @@ grpc_channel_args* BuildBalancerChannelArgs( }; // Channel args to add. const grpc_arg args_to_add[] = { - // New LB addresses. + // New server address list. // Note that we pass these in both when creating the LB channel // and via the fake resolver. The latter is what actually gets used. - grpc_lb_addresses_create_channel_arg(lb_addresses), + CreateServerAddressListChannelArg(balancer_addresses.get()), // The fake resolver response generator, which we use to inject // address updates into the LB channel. grpc_core::FakeResolverResponseGenerator::MakeChannelArg( @@ -970,10 +881,7 @@ grpc_channel_args* BuildBalancerChannelArgs( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Make any necessary modifications for security. - new_args = grpc_lb_policy_xds_modify_lb_channel_args(new_args); - // Clean up. - grpc_lb_addresses_destroy(lb_addresses); - return new_args; + return grpc_lb_policy_xds_modify_lb_channel_args(new_args); } // @@ -981,8 +889,7 @@ grpc_channel_args* BuildBalancerChannelArgs( // // TODO(vishalpowar): Use lb_config in args to configure LB policy. -XdsLb::XdsLb(const grpc_lb_addresses* addresses, - const LoadBalancingPolicy::Args& args) +XdsLb::XdsLb(const LoadBalancingPolicy::Args& args) : LoadBalancingPolicy(args), response_generator_(MakeRefCounted()), lb_call_backoff_( @@ -1038,9 +945,6 @@ XdsLb::~XdsLb() { if (serverlist_ != nullptr) { xds_grpclb_destroy_serverlist(serverlist_); } - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } grpc_subchannel_index_unref(); } @@ -1088,7 +992,6 @@ void XdsLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) { while ((pp = pending_picks_) != nullptr) { pending_picks_ = pp->next; pp->pick->on_complete = pp->original_on_complete; - pp->pick->user_data = nullptr; grpc_error* error = GRPC_ERROR_NONE; if (new_policy->PickLocked(pp->pick, &error)) { // Synchronous return; schedule closure. @@ -1241,21 +1144,16 @@ void XdsLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current, } void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { - const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES); - if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) { + const ServerAddressList* addresses = FindServerAddressListChannelArg(&args); + if (addresses == nullptr) { // Ignore this update. gpr_log(GPR_ERROR, "[xdslb %p] No valid LB addresses channel arg in update, ignoring.", this); return; } - const grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); // Update fallback address list. - if (fallback_backend_addresses_ != nullptr) { - grpc_lb_addresses_destroy(fallback_backend_addresses_); - } - fallback_backend_addresses_ = ExtractBackendAddresses(addresses); + fallback_backend_addresses_ = ExtractBackendAddresses(*addresses); // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, // since we use this to trigger the client_load_reporting filter. static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; @@ -1266,7 +1164,7 @@ void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) { &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); // Construct args for balancer channel. grpc_channel_args* lb_channel_args = - BuildBalancerChannelArgs(addresses, response_generator_.get(), &args); + BuildBalancerChannelArgs(*addresses, response_generator_.get(), &args); // Create balancer channel if needed. if (lb_channel_ == nullptr) { char* uri_str; @@ -1457,37 +1355,15 @@ void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg, // PendingPick // -// Adds lb_token of selected subchannel (address) to the call's initial -// metadata. -grpc_error* AddLbTokenToInitialMetadata( - grpc_mdelem lb_token, grpc_linked_mdelem* lb_token_mdelem_storage, - grpc_metadata_batch* initial_metadata) { - GPR_ASSERT(lb_token_mdelem_storage != nullptr); - GPR_ASSERT(!GRPC_MDISNULL(lb_token)); - return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage, - lb_token); -} - // Destroy function used when embedding client stats in call context. void DestroyClientStats(void* arg) { static_cast(arg)->Unref(); } -void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) { - /* if connected_subchannel is nullptr, no pick has been made by the - * child policy (e.g., all addresses failed to connect). There won't be any - * user_data/token available */ +void XdsLb::PendingPickCleanup(PendingPick* pp) { + // If connected_subchannel is nullptr, no pick has been made by the + // child policy (e.g., all addresses failed to connect). if (pp->pick->connected_subchannel != nullptr) { - if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) { - AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token), - &pp->pick->lb_token_mdelem_storage, - pp->pick->initial_metadata); - } else { - gpr_log(GPR_ERROR, - "[xdslb %p] No LB token for connected subchannel pick %p", - pp->xdslb_policy, pp->pick); - abort(); - } // Pass on client stats via context. Passes ownership of the reference. if (pp->client_stats != nullptr) { pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value = @@ -1505,7 +1381,7 @@ void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) { * order to unref the child policy instance upon its invocation */ void XdsLb::OnPendingPickComplete(void* arg, grpc_error* error) { PendingPick* pp = static_cast(arg); - PendingPickSetMetadataAndContext(pp); + PendingPickCleanup(pp); GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error)); Delete(pp); } @@ -1537,16 +1413,14 @@ void XdsLb::AddPendingPick(PendingPick* pp) { // completion callback even if the pick is available immediately. bool XdsLb::PickFromChildPolicyLocked(bool force_async, PendingPick* pp, grpc_error** error) { - // Set client_stats and user_data. + // Set client_stats. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); } - GPR_ASSERT(pp->pick->user_data == nullptr); - pp->pick->user_data = (void**)&pp->lb_token; // Pick via the child policy. bool pick_done = child_policy_->PickLocked(pp->pick, error); if (pick_done) { - PendingPickSetMetadataAndContext(pp); + PendingPickCleanup(pp); if (force_async) { GRPC_CLOSURE_SCHED(pp->original_on_complete, *error); *error = GRPC_ERROR_NONE; @@ -1608,20 +1482,19 @@ void XdsLb::CreateChildPolicyLocked(const Args& args) { } grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() { - grpc_lb_addresses* addresses; bool is_backend_from_grpclb_load_balancer = false; // This should never be invoked if we do not have serverlist_, as fallback // mode is disabled for xDS plugin. GPR_ASSERT(serverlist_ != nullptr); GPR_ASSERT(serverlist_->num_servers > 0); - addresses = ProcessServerlist(serverlist_); - is_backend_from_grpclb_load_balancer = true; + UniquePtr addresses = ProcessServerlist(serverlist_); GPR_ASSERT(addresses != nullptr); - // Replace the LB addresses in the channel args that we pass down to + is_backend_from_grpclb_load_balancer = true; + // Replace the server address list in the channel args that we pass down to // the subchannel. - static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; + static const char* keys_to_remove[] = {GRPC_ARG_SERVER_ADDRESS_LIST}; const grpc_arg args_to_add[] = { - grpc_lb_addresses_create_channel_arg(addresses), + CreateServerAddressListChannelArg(addresses.get()), // A channel arg indicating if the target is a backend inferred from a // grpclb load balancer. grpc_channel_arg_integer_create( @@ -1631,7 +1504,6 @@ grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() { grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove( args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, GPR_ARRAY_SIZE(args_to_add)); - grpc_lb_addresses_destroy(addresses); return args; } @@ -1765,19 +1637,18 @@ class XdsFactory : public LoadBalancingPolicyFactory { OrphanablePtr CreateLoadBalancingPolicy( const LoadBalancingPolicy::Args& args) const override { /* Count the number of gRPC-LB addresses. There must be at least one. */ - const grpc_arg* arg = - grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES); - if (arg == nullptr || arg->type != GRPC_ARG_POINTER) { - return nullptr; - } - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + const ServerAddressList* addresses = + FindServerAddressListChannelArg(args.args); + if (addresses == nullptr) return nullptr; + bool found_balancer_address = false; + for (size_t i = 0; i < addresses->size(); ++i) { + if ((*addresses)[i].IsBalancer()) { + found_balancer_address = true; + break; + } } - if (num_grpclb_addrs == 0) return nullptr; - return OrphanablePtr(New(addresses, args)); + if (!found_balancer_address) return nullptr; + return OrphanablePtr(New(args)); } const char* name() const override { return "xds_experimental"; } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h index 32c4acc8a3e..f713b7f563d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include /// Makes any necessary modifications to \a args for use in the xds /// balancer channel. diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc index 5ab72efce46..9a11f8e39fd 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc @@ -25,6 +25,7 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -41,22 +42,23 @@ int BalancerNameCmp(const grpc_core::UniquePtr& a, } RefCountedPtr CreateTargetAuthorityTable( - grpc_lb_addresses* addresses) { + const ServerAddressList& addresses) { TargetAuthorityTable::Entry* target_authority_entries = - static_cast(gpr_zalloc( - sizeof(*target_authority_entries) * addresses->num_addresses)); - for (size_t i = 0; i < addresses->num_addresses; ++i) { + static_cast( + gpr_zalloc(sizeof(*target_authority_entries) * addresses.size())); + for (size_t i = 0; i < addresses.size(); ++i) { char* addr_str; - GPR_ASSERT(grpc_sockaddr_to_string( - &addr_str, &addresses->addresses[i].address, true) > 0); + GPR_ASSERT( + grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true) > 0); target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str); - target_authority_entries[i].value.reset( - gpr_strdup(addresses->addresses[i].balancer_name)); gpr_free(addr_str); + char* balancer_name = grpc_channel_arg_get_string(grpc_channel_args_find( + addresses[i].args(), GRPC_ARG_ADDRESS_BALANCER_NAME)); + target_authority_entries[i].value.reset(gpr_strdup(balancer_name)); } RefCountedPtr target_authority_table = - TargetAuthorityTable::Create(addresses->num_addresses, - target_authority_entries, BalancerNameCmp); + TargetAuthorityTable::Create(addresses.size(), target_authority_entries, + BalancerNameCmp); gpr_free(target_authority_entries); return target_authority_table; } @@ -71,13 +73,12 @@ grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( grpc_arg args_to_add[2]; size_t num_args_to_add = 0; // Add arg for targets info table. - const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != nullptr); - GPR_ASSERT(arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses* addresses = - static_cast(arg->value.pointer.p); + grpc_core::ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(args); + GPR_ASSERT(addresses != nullptr); grpc_core::RefCountedPtr - target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses); + target_authority_table = + grpc_core::CreateTargetAuthorityTable(*addresses); args_to_add[num_args_to_add++] = grpc_core::CreateTargetAuthorityTableChannelArg( target_authority_table.get()); diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h index 9d08defa7ef..67049956417 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" #define XDS_SERVICE_NAME_MAX_LENGTH 128 diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.cc b/src/core/ext/filters/client_channel/lb_policy_factory.cc deleted file mode 100644 index 5c6363d2952..00000000000 --- a/src/core/ext/filters/client_channel/lb_policy_factory.cc +++ /dev/null @@ -1,163 +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. - * - */ - -#include - -#include - -#include -#include - -#include "src/core/lib/channel/channel_args.h" - -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" -#include "src/core/ext/filters/client_channel/parse_address.h" - -grpc_lb_addresses* grpc_lb_addresses_create( - size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) { - grpc_lb_addresses* addresses = - static_cast(gpr_zalloc(sizeof(grpc_lb_addresses))); - addresses->num_addresses = num_addresses; - addresses->user_data_vtable = user_data_vtable; - const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses; - addresses->addresses = - static_cast(gpr_zalloc(addresses_size)); - return addresses; -} - -grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses) { - grpc_lb_addresses* new_addresses = grpc_lb_addresses_create( - addresses->num_addresses, addresses->user_data_vtable); - memcpy(new_addresses->addresses, addresses->addresses, - sizeof(grpc_lb_address) * addresses->num_addresses); - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (new_addresses->addresses[i].balancer_name != nullptr) { - new_addresses->addresses[i].balancer_name = - gpr_strdup(new_addresses->addresses[i].balancer_name); - } - if (new_addresses->addresses[i].user_data != nullptr) { - new_addresses->addresses[i].user_data = addresses->user_data_vtable->copy( - new_addresses->addresses[i].user_data); - } - } - return new_addresses; -} - -void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, - const void* address, size_t address_len, - bool is_balancer, const char* balancer_name, - void* user_data) { - GPR_ASSERT(index < addresses->num_addresses); - if (user_data != nullptr) GPR_ASSERT(addresses->user_data_vtable != nullptr); - grpc_lb_address* target = &addresses->addresses[index]; - memcpy(target->address.addr, address, address_len); - target->address.len = static_cast(address_len); - target->is_balancer = is_balancer; - target->balancer_name = gpr_strdup(balancer_name); - target->user_data = user_data; -} - -bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, - size_t index, const grpc_uri* uri, - bool is_balancer, - const char* balancer_name, - void* user_data) { - grpc_resolved_address address; - if (!grpc_parse_uri(uri, &address)) return false; - grpc_lb_addresses_set_address(addresses, index, address.addr, address.len, - is_balancer, balancer_name, user_data); - return true; -} - -int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, - const grpc_lb_addresses* addresses2) { - if (addresses1->num_addresses > addresses2->num_addresses) return 1; - if (addresses1->num_addresses < addresses2->num_addresses) return -1; - if (addresses1->user_data_vtable > addresses2->user_data_vtable) return 1; - if (addresses1->user_data_vtable < addresses2->user_data_vtable) return -1; - for (size_t i = 0; i < addresses1->num_addresses; ++i) { - const grpc_lb_address* target1 = &addresses1->addresses[i]; - const grpc_lb_address* target2 = &addresses2->addresses[i]; - if (target1->address.len > target2->address.len) return 1; - if (target1->address.len < target2->address.len) return -1; - int retval = memcmp(target1->address.addr, target2->address.addr, - target1->address.len); - if (retval != 0) return retval; - if (target1->is_balancer > target2->is_balancer) return 1; - if (target1->is_balancer < target2->is_balancer) return -1; - const char* balancer_name1 = - target1->balancer_name != nullptr ? target1->balancer_name : ""; - const char* balancer_name2 = - target2->balancer_name != nullptr ? target2->balancer_name : ""; - retval = strcmp(balancer_name1, balancer_name2); - if (retval != 0) return retval; - if (addresses1->user_data_vtable != nullptr) { - retval = addresses1->user_data_vtable->cmp(target1->user_data, - target2->user_data); - if (retval != 0) return retval; - } - } - return 0; -} - -void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) { - for (size_t i = 0; i < addresses->num_addresses; ++i) { - gpr_free(addresses->addresses[i].balancer_name); - if (addresses->addresses[i].user_data != nullptr) { - addresses->user_data_vtable->destroy(addresses->addresses[i].user_data); - } - } - gpr_free(addresses->addresses); - gpr_free(addresses); -} - -static void* lb_addresses_copy(void* addresses) { - return grpc_lb_addresses_copy(static_cast(addresses)); -} -static void lb_addresses_destroy(void* addresses) { - grpc_lb_addresses_destroy(static_cast(addresses)); -} -static int lb_addresses_cmp(void* addresses1, void* addresses2) { - return grpc_lb_addresses_cmp(static_cast(addresses1), - static_cast(addresses2)); -} -static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = { - lb_addresses_copy, lb_addresses_destroy, lb_addresses_cmp}; - -grpc_arg grpc_lb_addresses_create_channel_arg( - const grpc_lb_addresses* addresses) { - return grpc_channel_arg_pointer_create( - (char*)GRPC_ARG_LB_ADDRESSES, (void*)addresses, &lb_addresses_arg_vtable); -} - -grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( - const grpc_channel_args* channel_args) { - const grpc_arg* lb_addresses_arg = - grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); - if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) - return nullptr; - return static_cast(lb_addresses_arg->value.pointer.p); -} - -bool grpc_lb_addresses_contains_balancer_address( - const grpc_lb_addresses& addresses) { - for (size_t i = 0; i < addresses.num_addresses; ++i) { - if (addresses.addresses[i].is_balancer) return true; - } - return false; -} diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h index a59deadb265..a165ebafaba 100644 --- a/src/core/ext/filters/client_channel/lb_policy_factory.h +++ b/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -21,91 +21,9 @@ #include -#include "src/core/lib/iomgr/resolve_address.h" - -#include "src/core/ext/filters/client_channel/client_channel_factory.h" #include "src/core/ext/filters/client_channel/lb_policy.h" -#include "src/core/lib/uri/uri_parser.h" - -// -// representation of an LB address -// - -// Channel arg key for grpc_lb_addresses. -#define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses" - -/** A resolved address alongside any LB related information associated with it. - * \a user_data, if not NULL, contains opaque data meant to be consumed by the - * gRPC LB policy. Note that no all LB policies support \a user_data as input. - * Those who don't will simply ignore it and will correspondingly return NULL in - * their namesake pick() output argument. */ -// TODO(roth): Once we figure out a better way of handling user_data in -// LB policies, convert these structs to C++ classes. -typedef struct grpc_lb_address { - grpc_resolved_address address; - bool is_balancer; - char* balancer_name; /* For secure naming. */ - void* user_data; -} grpc_lb_address; - -typedef struct grpc_lb_user_data_vtable { - void* (*copy)(void*); - void (*destroy)(void*); - int (*cmp)(void*, void*); -} grpc_lb_user_data_vtable; - -typedef struct grpc_lb_addresses { - size_t num_addresses; - grpc_lb_address* addresses; - const grpc_lb_user_data_vtable* user_data_vtable; -} grpc_lb_addresses; - -/** Returns a grpc_addresses struct with enough space for - \a num_addresses addresses. The \a user_data_vtable argument may be - NULL if no user data will be added. */ -grpc_lb_addresses* grpc_lb_addresses_create( - size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable); - -/** Creates a copy of \a addresses. */ -grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses); - -/** Sets the value of the address at index \a index of \a addresses. - * \a address is a socket address of length \a address_len. */ -void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, - const void* address, size_t address_len, - bool is_balancer, const char* balancer_name, - void* user_data); - -/** Sets the value of the address at index \a index of \a addresses from \a uri. - * Returns true upon success, false otherwise. */ -bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, - size_t index, const grpc_uri* uri, - bool is_balancer, - const char* balancer_name, - void* user_data); - -/** Compares \a addresses1 and \a addresses2. */ -int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, - const grpc_lb_addresses* addresses2); - -/** Destroys \a addresses. */ -void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses); - -/** Returns a channel arg containing \a addresses. */ -grpc_arg grpc_lb_addresses_create_channel_arg( - const grpc_lb_addresses* addresses); - -/** Returns the \a grpc_lb_addresses instance in \a channel_args or NULL */ -grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( - const grpc_channel_args* channel_args); - -// Returns true if addresses contains at least one balancer address. -bool grpc_lb_addresses_contains_balancer_address( - const grpc_lb_addresses& addresses); - -// -// LB policy factory -// +#include "src/core/lib/gprpp/abstract.h" +#include "src/core/lib/gprpp/orphanable.h" namespace grpc_core { diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index 4ebc2c8161c..c8425ae3365 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -33,6 +33,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -117,7 +118,7 @@ class AresDnsResolver : public Resolver { /// retry backoff state BackOff backoff_; /// currently resolving addresses - grpc_lb_addresses* lb_addresses_ = nullptr; + UniquePtr addresses_; /// currently resolving service config char* service_config_json_ = nullptr; // has shutdown been initiated @@ -314,13 +315,13 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->resolving_ = false; gpr_free(r->pending_request_); r->pending_request_ = nullptr; - if (r->lb_addresses_ != nullptr) { + if (r->addresses_ != nullptr) { static const char* args_to_remove[1]; size_t num_args_to_remove = 0; grpc_arg args_to_add[2]; size_t num_args_to_add = 0; args_to_add[num_args_to_add++] = - grpc_lb_addresses_create_channel_arg(r->lb_addresses_); + CreateServerAddressListChannelArg(r->addresses_.get()); char* service_config_string = nullptr; if (r->service_config_json_ != nullptr) { service_config_string = ChooseServiceConfig(r->service_config_json_); @@ -337,7 +338,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->channel_args_, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add); gpr_free(service_config_string); - grpc_lb_addresses_destroy(r->lb_addresses_); + r->addresses_.reset(); // Reset backoff state so that we start from the beginning when the // next request gets triggered. r->backoff_.Reset(); @@ -412,11 +413,10 @@ void AresDnsResolver::StartResolvingLocked() { self.release(); GPR_ASSERT(!resolving_); resolving_ = true; - lb_addresses_ = nullptr; service_config_json_ = nullptr; pending_request_ = grpc_dns_lookup_ares_locked( dns_server_, name_to_resolve_, kDefaultPort, interested_parties_, - &on_resolved_, &lb_addresses_, true /* check_grpclb */, + &on_resolved_, &addresses_, true /* check_grpclb */, request_service_config_ ? &service_config_json_ : nullptr, query_timeout_ms_, combiner()); last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now(); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc index f42b1e309df..8abc34c6edb 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc @@ -31,6 +31,7 @@ #include #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/timer.h" diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 55715869b63..1b1c2303da3 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -37,12 +37,16 @@ #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/nameser.h" #include "src/core/lib/iomgr/sockaddr_utils.h" +using grpc_core::ServerAddress; +using grpc_core::ServerAddressList; + static gpr_once g_basic_init = GPR_ONCE_INIT; static gpr_mu g_init_mu; @@ -58,7 +62,7 @@ struct grpc_ares_request { /** closure to call when the request completes */ grpc_closure* on_done; /** the pointer to receive the resolved addresses */ - grpc_lb_addresses** lb_addrs_out; + grpc_core::UniquePtr* addresses_out; /** the pointer to receive the service config in JSON */ char** service_config_json_out; /** the evernt driver used by this request */ @@ -87,12 +91,11 @@ typedef struct grpc_ares_hostbyname_request { static void do_basic_init(void) { gpr_mu_init(&g_init_mu); } -static void log_address_sorting_list(grpc_lb_addresses* lb_addrs, +static void log_address_sorting_list(const ServerAddressList& addresses, const char* input_output_str) { - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + for (size_t i = 0; i < addresses.size(); i++) { char* addr_str; - if (grpc_sockaddr_to_string(&addr_str, &lb_addrs->addresses[i].address, - true)) { + if (grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true)) { gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s", input_output_str, i, addr_str); gpr_free(addr_str); @@ -104,29 +107,28 @@ static void log_address_sorting_list(grpc_lb_addresses* lb_addrs, } } -void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) { +void grpc_cares_wrapper_address_sorting_sort(ServerAddressList* addresses) { if (grpc_trace_cares_address_sorting.enabled()) { - log_address_sorting_list(lb_addrs, "input"); + log_address_sorting_list(*addresses, "input"); } address_sorting_sortable* sortables = (address_sorting_sortable*)gpr_zalloc( - sizeof(address_sorting_sortable) * lb_addrs->num_addresses); - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { - sortables[i].user_data = &lb_addrs->addresses[i]; - memcpy(&sortables[i].dest_addr.addr, &lb_addrs->addresses[i].address.addr, - lb_addrs->addresses[i].address.len); - sortables[i].dest_addr.len = lb_addrs->addresses[i].address.len; + sizeof(address_sorting_sortable) * addresses->size()); + for (size_t i = 0; i < addresses->size(); ++i) { + sortables[i].user_data = &(*addresses)[i]; + memcpy(&sortables[i].dest_addr.addr, &(*addresses)[i].address().addr, + (*addresses)[i].address().len); + sortables[i].dest_addr.len = (*addresses)[i].address().len; } - address_sorting_rfc_6724_sort(sortables, lb_addrs->num_addresses); - grpc_lb_address* sorted_lb_addrs = (grpc_lb_address*)gpr_zalloc( - sizeof(grpc_lb_address) * lb_addrs->num_addresses); - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { - sorted_lb_addrs[i] = *(grpc_lb_address*)sortables[i].user_data; + address_sorting_rfc_6724_sort(sortables, addresses->size()); + ServerAddressList sorted; + sorted.reserve(addresses->size()); + for (size_t i = 0; i < addresses->size(); ++i) { + sorted.emplace_back(*static_cast(sortables[i].user_data)); } gpr_free(sortables); - gpr_free(lb_addrs->addresses); - lb_addrs->addresses = sorted_lb_addrs; + *addresses = std::move(sorted); if (grpc_trace_cares_address_sorting.enabled()) { - log_address_sorting_list(lb_addrs, "output"); + log_address_sorting_list(*addresses, "output"); } } @@ -145,9 +147,9 @@ void grpc_ares_complete_request_locked(grpc_ares_request* r) { /* Invoke on_done callback and destroy the request */ r->ev_driver = nullptr; - grpc_lb_addresses* lb_addrs = *(r->lb_addrs_out); - if (lb_addrs != nullptr) { - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + ServerAddressList* addresses = r->addresses_out->get(); + if (addresses != nullptr) { + grpc_cares_wrapper_address_sorting_sort(addresses); } GRPC_CLOSURE_SCHED(r->on_done, r->error); } @@ -181,33 +183,30 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, GRPC_ERROR_UNREF(r->error); r->error = GRPC_ERROR_NONE; r->success = true; - grpc_lb_addresses** lb_addresses = r->lb_addrs_out; - if (*lb_addresses == nullptr) { - *lb_addresses = grpc_lb_addresses_create(0, nullptr); - } - size_t prev_naddr = (*lb_addresses)->num_addresses; - size_t i; - for (i = 0; hostent->h_addr_list[i] != nullptr; i++) { + if (*r->addresses_out == nullptr) { + *r->addresses_out = grpc_core::MakeUnique(); } - (*lb_addresses)->num_addresses += i; - (*lb_addresses)->addresses = static_cast( - gpr_realloc((*lb_addresses)->addresses, - sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses)); - for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) { + ServerAddressList& addresses = **r->addresses_out; + for (size_t i = 0; hostent->h_addr_list[i] != nullptr; ++i) { + grpc_core::InlinedVector args_to_add; + if (hr->is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), hr->host)); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); switch (hostent->h_addrtype) { case AF_INET6: { size_t addr_len = sizeof(struct sockaddr_in6); struct sockaddr_in6 addr; memset(&addr, 0, addr_len); - memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr], + memcpy(&addr.sin6_addr, hostent->h_addr_list[i], sizeof(struct in6_addr)); addr.sin6_family = static_cast(hostent->h_addrtype); addr.sin6_port = hr->port; - grpc_lb_addresses_set_address( - *lb_addresses, i, &addr, addr_len, - hr->is_balancer /* is_balancer */, - hr->is_balancer ? hr->host : nullptr /* balancer_name */, - nullptr /* user_data */); + addresses.emplace_back(&addr, addr_len, args); char output[INET6_ADDRSTRLEN]; ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN); gpr_log(GPR_DEBUG, @@ -220,15 +219,11 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, size_t addr_len = sizeof(struct sockaddr_in); struct sockaddr_in addr; memset(&addr, 0, addr_len); - memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr], + memcpy(&addr.sin_addr, hostent->h_addr_list[i], sizeof(struct in_addr)); addr.sin_family = static_cast(hostent->h_addrtype); addr.sin_port = hr->port; - grpc_lb_addresses_set_address( - *lb_addresses, i, &addr, addr_len, - hr->is_balancer /* is_balancer */, - hr->is_balancer ? hr->host : nullptr /* balancer_name */, - nullptr /* user_data */); + addresses.emplace_back(&addr, addr_len, args); char output[INET_ADDRSTRLEN]; ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN); gpr_log(GPR_DEBUG, @@ -467,11 +462,10 @@ error_cleanup: gpr_free(port); } -static bool inner_resolve_as_ip_literal_locked(const char* name, - const char* default_port, - grpc_lb_addresses** addrs, - char** host, char** port, - char** hostport) { +static bool inner_resolve_as_ip_literal_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs, char** host, + char** port, char** hostport) { gpr_split_host_port(name, host, port); if (*host == nullptr) { gpr_log(GPR_ERROR, @@ -495,18 +489,16 @@ static bool inner_resolve_as_ip_literal_locked(const char* name, if (grpc_parse_ipv4_hostport(*hostport, &addr, false /* log errors */) || grpc_parse_ipv6_hostport(*hostport, &addr, false /* log errors */)) { GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_lb_addresses_create(1, nullptr); - grpc_lb_addresses_set_address( - *addrs, 0, addr.addr, addr.len, false /* is_balancer */, - nullptr /* balancer_name */, nullptr /* user_data */); + *addrs = grpc_core::MakeUnique(); + (*addrs)->emplace_back(addr.addr, addr.len, nullptr /* args */); return true; } return false; } -static bool resolve_as_ip_literal_locked(const char* name, - const char* default_port, - grpc_lb_addresses** addrs) { +static bool resolve_as_ip_literal_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { char* host = nullptr; char* port = nullptr; char* hostport = nullptr; @@ -521,13 +513,14 @@ static bool resolve_as_ip_literal_locked(const char* name, static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { grpc_ares_request* r = static_cast(gpr_zalloc(sizeof(grpc_ares_request))); r->ev_driver = nullptr; r->on_done = on_done; - r->lb_addrs_out = addrs; + r->addresses_out = addrs; r->service_config_json_out = service_config_json; r->success = false; r->error = GRPC_ERROR_NONE; @@ -553,8 +546,8 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) { @@ -599,8 +592,8 @@ typedef struct grpc_resolve_address_ares_request { grpc_combiner* combiner; /** the pointer to receive the resolved addresses */ grpc_resolved_addresses** addrs_out; - /** currently resolving lb addresses */ - grpc_lb_addresses* lb_addrs; + /** currently resolving addresses */ + grpc_core::UniquePtr addresses; /** closure to call when the resolve_address_ares request completes */ grpc_closure* on_resolve_address_done; /** a closure wrapping on_resolve_address_done, which should be invoked when @@ -613,7 +606,7 @@ typedef struct grpc_resolve_address_ares_request { /* pollset_set to be driven by */ grpc_pollset_set* interested_parties; /* underlying ares_request that the query is performed on */ - grpc_ares_request* ares_request; + grpc_ares_request* ares_request = nullptr; } grpc_resolve_address_ares_request; static void on_dns_lookup_done_locked(void* arg, grpc_error* error) { @@ -621,25 +614,24 @@ static void on_dns_lookup_done_locked(void* arg, grpc_error* error) { static_cast(arg); gpr_free(r->ares_request); grpc_resolved_addresses** resolved_addresses = r->addrs_out; - if (r->lb_addrs == nullptr || r->lb_addrs->num_addresses == 0) { + if (r->addresses == nullptr || r->addresses->empty()) { *resolved_addresses = nullptr; } else { *resolved_addresses = static_cast( gpr_zalloc(sizeof(grpc_resolved_addresses))); - (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses; + (*resolved_addresses)->naddrs = r->addresses->size(); (*resolved_addresses)->addrs = static_cast(gpr_zalloc( sizeof(grpc_resolved_address) * (*resolved_addresses)->naddrs)); - for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) { - GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer); - memcpy(&(*resolved_addresses)->addrs[i], - &r->lb_addrs->addresses[i].address, sizeof(grpc_resolved_address)); + for (size_t i = 0; i < (*resolved_addresses)->naddrs; ++i) { + GPR_ASSERT(!(*r->addresses)[i].IsBalancer()); + memcpy(&(*resolved_addresses)->addrs[i], &(*r->addresses)[i].address(), + sizeof(grpc_resolved_address)); } } GRPC_CLOSURE_SCHED(r->on_resolve_address_done, GRPC_ERROR_REF(error)); - if (r->lb_addrs != nullptr) grpc_lb_addresses_destroy(r->lb_addrs); GRPC_COMBINER_UNREF(r->combiner, "on_dns_lookup_done_cb"); - gpr_free(r); + grpc_core::Delete(r); } static void grpc_resolve_address_invoke_dns_lookup_ares_locked( @@ -648,7 +640,7 @@ static void grpc_resolve_address_invoke_dns_lookup_ares_locked( static_cast(arg); r->ares_request = grpc_dns_lookup_ares_locked( nullptr /* dns_server */, r->name, r->default_port, r->interested_parties, - &r->on_dns_lookup_done_locked, &r->lb_addrs, false /* check_grpclb */, + &r->on_dns_lookup_done_locked, &r->addresses, false /* check_grpclb */, nullptr /* service_config_json */, GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, r->combiner); } @@ -659,8 +651,7 @@ static void grpc_resolve_address_ares_impl(const char* name, grpc_closure* on_done, grpc_resolved_addresses** addrs) { grpc_resolve_address_ares_request* r = - static_cast( - gpr_zalloc(sizeof(grpc_resolve_address_ares_request))); + grpc_core::New(); r->combiner = grpc_combiner_create(); r->addrs_out = addrs; r->on_resolve_address_done = on_done; diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h index 9acef1d0ca9..28082504565 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -21,7 +21,7 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -61,8 +61,9 @@ extern void (*grpc_resolve_address_ares)(const char* name, extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addresses, bool check_grpclb, - char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner); /* Cancel the pending grpc_ares_request \a request */ extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request); @@ -89,10 +90,12 @@ bool grpc_ares_query_ipv6(); * Returns a bool indicating whether or not such an action was performed. * See https://github.com/grpc/grpc/issues/15158. */ bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs); + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs); /* Sorts destinations in lb_addrs according to RFC 6724. */ -void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs); +void grpc_cares_wrapper_address_sorting_sort( + grpc_core::ServerAddressList* addresses); #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \ */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc index fc78b183044..1f4701c9994 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc @@ -29,16 +29,17 @@ struct grpc_ares_request { static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { return NULL; } grpc_ares_request* (*grpc_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, + grpc_core::UniquePtr* addrs, + bool check_grpclb, char** service_config_json, int query_timeout_ms, grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl; static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {} diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc index 639eec2323f..028d8442169 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc @@ -27,7 +27,8 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs) { + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { return false; } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc index 7e34784691f..202452f1b2b 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc @@ -23,9 +23,9 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/socket_windows.h" @@ -33,8 +33,9 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } static bool inner_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs, - char** host, char** port) { + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs, char** host, + char** port) { gpr_split_host_port(name, host, port); if (*host == nullptr) { gpr_log(GPR_ERROR, @@ -55,7 +56,7 @@ static bool inner_maybe_resolve_localhost_manually_locked( } if (gpr_stricmp(*host, "localhost") == 0) { GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_lb_addresses_create(2, nullptr); + *addrs = grpc_core::MakeUnique(); uint16_t numeric_port = grpc_strhtons(*port); // Append the ipv6 loopback address. struct sockaddr_in6 ipv6_loopback_addr; @@ -63,10 +64,8 @@ static bool inner_maybe_resolve_localhost_manually_locked( ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1; ipv6_loopback_addr.sin6_family = AF_INET6; ipv6_loopback_addr.sin6_port = numeric_port; - grpc_lb_addresses_set_address( - *addrs, 0, &ipv6_loopback_addr, sizeof(ipv6_loopback_addr), - false /* is_balancer */, nullptr /* balancer_name */, - nullptr /* user_data */); + (*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr), + nullptr /* args */); // Append the ipv4 loopback address. struct sockaddr_in ipv4_loopback_addr; memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr)); @@ -74,19 +73,18 @@ static bool inner_maybe_resolve_localhost_manually_locked( ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01; ipv4_loopback_addr.sin_family = AF_INET; ipv4_loopback_addr.sin_port = numeric_port; - grpc_lb_addresses_set_address( - *addrs, 1, &ipv4_loopback_addr, sizeof(ipv4_loopback_addr), - false /* is_balancer */, nullptr /* balancer_name */, - nullptr /* user_data */); + (*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr), + nullptr /* args */); // Let the address sorter figure out which one should be tried first. - grpc_cares_wrapper_address_sorting_sort(*addrs); + grpc_cares_wrapper_address_sorting_sort(addrs->get()); return true; } return false; } bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, grpc_lb_addresses** addrs) { + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { char* host = nullptr; char* port = nullptr; bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port, diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc index 65ff1ec1a5b..c365f1abfd8 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -26,8 +26,8 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -198,18 +198,14 @@ void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(r->name_to_resolve_)); if (r->addresses_ != nullptr) { - grpc_lb_addresses* addresses = grpc_lb_addresses_create( - r->addresses_->naddrs, nullptr /* user_data_vtable */); + ServerAddressList addresses; for (size_t i = 0; i < r->addresses_->naddrs; ++i) { - grpc_lb_addresses_set_address( - addresses, i, &r->addresses_->addrs[i].addr, - r->addresses_->addrs[i].len, false /* is_balancer */, - nullptr /* balancer_name */, nullptr /* user_data */); + addresses.emplace_back(&r->addresses_->addrs[i].addr, + r->addresses_->addrs[i].len, nullptr /* args */); } - grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg new_arg = CreateServerAddressListChannelArg(&addresses); result = grpc_channel_args_copy_and_add(r->channel_args_, &new_arg, 1); grpc_resolved_addresses_destroy(r->addresses_); - grpc_lb_addresses_destroy(addresses); // Reset backoff state so that we start from the beginning when the // next request gets triggered. r->backoff_.Reset(); diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc index 3aa690bea41..258339491c1 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -28,12 +28,13 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h index 7f690593510..d86111c3829 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -19,10 +19,9 @@ #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted.h" -#include "src/core/lib/uri/uri_parser.h" +#include "src/core/lib/iomgr/error.h" #define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \ "grpc.fake_resolver.response_generator" diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc index 801734764b4..1654747a79f 100644 --- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc @@ -26,9 +26,9 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" @@ -45,7 +45,8 @@ namespace { class SockaddrResolver : public Resolver { public: /// Takes ownership of \a addresses. - SockaddrResolver(const ResolverArgs& args, grpc_lb_addresses* addresses); + SockaddrResolver(const ResolverArgs& args, + UniquePtr addresses); void NextLocked(grpc_channel_args** result, grpc_closure* on_complete) override; @@ -58,7 +59,7 @@ class SockaddrResolver : public Resolver { void MaybeFinishNextLocked(); /// the addresses that we've "resolved" - grpc_lb_addresses* addresses_ = nullptr; + UniquePtr addresses_; /// channel args grpc_channel_args* channel_args_ = nullptr; /// have we published? @@ -70,13 +71,12 @@ class SockaddrResolver : public Resolver { }; SockaddrResolver::SockaddrResolver(const ResolverArgs& args, - grpc_lb_addresses* addresses) + UniquePtr addresses) : Resolver(args.combiner), - addresses_(addresses), + addresses_(std::move(addresses)), channel_args_(grpc_channel_args_copy(args.args)) {} SockaddrResolver::~SockaddrResolver() { - grpc_lb_addresses_destroy(addresses_); grpc_channel_args_destroy(channel_args_); } @@ -100,7 +100,7 @@ void SockaddrResolver::ShutdownLocked() { void SockaddrResolver::MaybeFinishNextLocked() { if (next_completion_ != nullptr && !published_) { published_ = true; - grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses_); + grpc_arg arg = CreateServerAddressListChannelArg(addresses_.get()); *target_result_ = grpc_channel_args_copy_and_add(channel_args_, &arg, 1); GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE); next_completion_ = nullptr; @@ -127,27 +127,27 @@ OrphanablePtr CreateSockaddrResolver( grpc_slice_buffer path_parts; grpc_slice_buffer_init(&path_parts); grpc_slice_split(path_slice, ",", &path_parts); - grpc_lb_addresses* addresses = grpc_lb_addresses_create( - path_parts.count, nullptr /* user_data_vtable */); + auto addresses = MakeUnique(); bool errors_found = false; - for (size_t i = 0; i < addresses->num_addresses; i++) { + for (size_t i = 0; i < path_parts.count; i++) { grpc_uri ith_uri = *args.uri; - char* part_str = grpc_slice_to_c_string(path_parts.slices[i]); - ith_uri.path = part_str; - if (!parse(&ith_uri, &addresses->addresses[i].address)) { + UniquePtr part_str(grpc_slice_to_c_string(path_parts.slices[i])); + ith_uri.path = part_str.get(); + grpc_resolved_address addr; + if (!parse(&ith_uri, &addr)) { errors_found = true; /* GPR_TRUE */ + break; } - gpr_free(part_str); - if (errors_found) break; + addresses->emplace_back(addr, nullptr /* args */); } grpc_slice_buffer_destroy_internal(&path_parts); grpc_slice_unref_internal(path_slice); if (errors_found) { - grpc_lb_addresses_destroy(addresses); return OrphanablePtr(nullptr); } // Instantiate resolver. - return OrphanablePtr(New(args, addresses)); + return OrphanablePtr( + New(args, std::move(addresses))); } class IPv4ResolverFactory : public ResolverFactory { diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc index 4f7fd6b4243..22b06db45c4 100644 --- a/src/core/ext/filters/client_channel/resolver_result_parsing.cc +++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc @@ -30,9 +30,11 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/status_util.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/uri/uri_parser.h" // As per the retry design, we do not allow more than 5 retry attempts. #define MAX_MAX_RETRY_ATTEMPTS 5 @@ -99,12 +101,18 @@ void ProcessedResolverResult::ProcessLbPolicyName( } // Special case: If at least one balancer address is present, we use // the grpclb policy, regardless of what the resolver has returned. - const grpc_arg* channel_arg = - grpc_channel_args_find(resolver_result, GRPC_ARG_LB_ADDRESSES); - if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { - grpc_lb_addresses* addresses = - static_cast(channel_arg->value.pointer.p); - if (grpc_lb_addresses_contains_balancer_address(*addresses)) { + const ServerAddressList* addresses = + FindServerAddressListChannelArg(resolver_result); + if (addresses != nullptr) { + bool found_balancer_address = false; + for (size_t i = 0; i < addresses->size(); ++i) { + const ServerAddress& address = (*addresses)[i]; + if (address.IsBalancer()) { + found_balancer_address = true; + break; + } + } + if (found_balancer_address) { if (lb_policy_name_ != nullptr && strcmp(lb_policy_name_.get(), "grpclb") != 0) { gpr_log(GPR_INFO, diff --git a/src/core/ext/filters/client_channel/server_address.cc b/src/core/ext/filters/client_channel/server_address.cc new file mode 100644 index 00000000000..ec33cbbd956 --- /dev/null +++ b/src/core/ext/filters/client_channel/server_address.cc @@ -0,0 +1,103 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include "src/core/ext/filters/client_channel/server_address.h" + +#include + +namespace grpc_core { + +// +// ServerAddress +// + +ServerAddress::ServerAddress(const grpc_resolved_address& address, + grpc_channel_args* args) + : address_(address), args_(args) {} + +ServerAddress::ServerAddress(const void* address, size_t address_len, + grpc_channel_args* args) + : args_(args) { + memcpy(address_.addr, address, address_len); + address_.len = static_cast(address_len); +} + +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_); +} + +bool ServerAddress::IsBalancer() const { + return grpc_channel_arg_get_bool( + grpc_channel_args_find(args_, GRPC_ARG_ADDRESS_IS_BALANCER), false); +} + +// +// ServerAddressList +// + +namespace { + +void* ServerAddressListCopy(void* addresses) { + ServerAddressList* a = static_cast(addresses); + return New(*a); +} + +void ServerAddressListDestroy(void* addresses) { + ServerAddressList* a = static_cast(addresses); + Delete(a); +} + +int ServerAddressListCompare(void* addresses1, void* addresses2) { + ServerAddressList* a1 = static_cast(addresses1); + ServerAddressList* a2 = static_cast(addresses2); + if (a1->size() > a2->size()) return 1; + if (a1->size() < a2->size()) return -1; + for (size_t i = 0; i < a1->size(); ++i) { + int retval = (*a1)[i].Cmp((*a2)[i]); + if (retval != 0) return retval; + } + return 0; +} + +const grpc_arg_pointer_vtable server_addresses_arg_vtable = { + ServerAddressListCopy, ServerAddressListDestroy, ServerAddressListCompare}; + +} // namespace + +grpc_arg CreateServerAddressListChannelArg(const ServerAddressList* addresses) { + return grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_SERVER_ADDRESS_LIST), + const_cast(addresses), &server_addresses_arg_vtable); +} + +ServerAddressList* FindServerAddressListChannelArg( + const grpc_channel_args* channel_args) { + const grpc_arg* lb_addresses_arg = + grpc_channel_args_find(channel_args, GRPC_ARG_SERVER_ADDRESS_LIST); + if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) + return nullptr; + return static_cast(lb_addresses_arg->value.pointer.p); +} + +} // 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 new file mode 100644 index 00000000000..3a1bf1df67d --- /dev/null +++ b/src/core/ext/filters/client_channel/server_address.h @@ -0,0 +1,108 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H + +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gprpp/inlined_vector.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/uri/uri_parser.h" + +// Channel arg key for ServerAddressList. +#define GRPC_ARG_SERVER_ADDRESS_LIST "grpc.server_address_list" + +// Channel arg key for a bool indicating whether an address is a grpclb +// load balancer (as opposed to a backend). +#define GRPC_ARG_ADDRESS_IS_BALANCER "grpc.address_is_balancer" + +// Channel arg key for a string indicating an address's balancer name. +#define GRPC_ARG_ADDRESS_BALANCER_NAME "grpc.address_balancer_name" + +namespace grpc_core { + +// +// ServerAddress +// + +// A server address is a grpc_resolved_address with an associated set of +// channel args. Any args present here will be merged into the channel +// args when a subchannel is created for this address. +class ServerAddress { + public: + // Takes ownership of args. + ServerAddress(const grpc_resolved_address& address, grpc_channel_args* args); + ServerAddress(const void* address, size_t address_len, + grpc_channel_args* args); + + ~ServerAddress() { grpc_channel_args_destroy(args_); } + + // Copyable. + ServerAddress(const ServerAddress& other) + : address_(other.address_), args_(grpc_channel_args_copy(other.args_)) {} + ServerAddress& operator=(const ServerAddress& other) { + address_ = other.address_; + grpc_channel_args_destroy(args_); + args_ = grpc_channel_args_copy(other.args_); + return *this; + } + + // Movable. + ServerAddress(ServerAddress&& other) + : address_(other.address_), args_(other.args_) { + other.args_ = nullptr; + } + ServerAddress& operator=(ServerAddress&& other) { + address_ = other.address_; + args_ = other.args_; + other.args_ = nullptr; + return *this; + } + + bool operator==(const ServerAddress& other) const { return Cmp(other) == 0; } + + int Cmp(const ServerAddress& other) const; + + const grpc_resolved_address& address() const { return address_; } + const grpc_channel_args* args() const { return args_; } + + bool IsBalancer() const; + + private: + grpc_resolved_address address_; + grpc_channel_args* args_; +}; + +// +// ServerAddressList +// + +typedef InlinedVector ServerAddressList; + +// Returns a channel arg containing \a addresses. +grpc_arg CreateServerAddressListChannelArg(const ServerAddressList* addresses); + +// Returns the ServerListAddress instance in channel_args or NULL. +ServerAddressList* FindServerAddressListChannelArg( + const grpc_channel_args* channel_args); + +} // namespace grpc_core + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H */ diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index af55f7710e2..9077aa97539 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -837,7 +837,7 @@ static bool publish_transport_locked(grpc_subchannel* c) { /* publish */ c->connected_subchannel.reset(grpc_core::New( - stk, c->channelz_subchannel, socket_uuid)); + stk, c->args, c->channelz_subchannel, socket_uuid)); gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p", c->connected_subchannel.get(), c); @@ -1068,16 +1068,18 @@ grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) { namespace grpc_core { ConnectedSubchannel::ConnectedSubchannel( - grpc_channel_stack* channel_stack, + grpc_channel_stack* channel_stack, const grpc_channel_args* args, grpc_core::RefCountedPtr channelz_subchannel, intptr_t socket_uuid) : RefCounted(&grpc_trace_stream_refcount), channel_stack_(channel_stack), + args_(grpc_channel_args_copy(args)), channelz_subchannel_(std::move(channelz_subchannel)), socket_uuid_(socket_uuid) {} ConnectedSubchannel::~ConnectedSubchannel() { + grpc_channel_args_destroy(args_); GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor"); } diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 69c2456ec20..14f87f2c68e 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -85,28 +85,31 @@ class ConnectedSubchannel : public RefCounted { size_t parent_data_size; }; - explicit ConnectedSubchannel( - grpc_channel_stack* channel_stack, + ConnectedSubchannel( + grpc_channel_stack* channel_stack, const grpc_channel_args* args, grpc_core::RefCountedPtr channelz_subchannel, intptr_t socket_uuid); ~ConnectedSubchannel(); - grpc_channel_stack* channel_stack() { return channel_stack_; } void NotifyOnStateChange(grpc_pollset_set* interested_parties, grpc_connectivity_state* state, grpc_closure* closure); void Ping(grpc_closure* on_initiate, grpc_closure* on_ack); grpc_error* CreateCall(const CallArgs& args, grpc_subchannel_call** call); - channelz::SubchannelNode* channelz_subchannel() { + + grpc_channel_stack* channel_stack() const { return channel_stack_; } + const grpc_channel_args* args() const { return args_; } + channelz::SubchannelNode* channelz_subchannel() const { return channelz_subchannel_.get(); } - intptr_t socket_uuid() { return socket_uuid_; } + intptr_t socket_uuid() const { return socket_uuid_; } size_t GetInitialCallSizeEstimate(size_t parent_data_size) const; private: grpc_channel_stack* channel_stack_; + grpc_channel_args* args_; // ref counted pointer to the channelz node in this connected subchannel's // owning subchannel. grpc_core::RefCountedPtr diff --git a/src/core/lib/iomgr/sockaddr_utils.cc b/src/core/lib/iomgr/sockaddr_utils.cc index 1b66dceb130..0839bdfef2d 100644 --- a/src/core/lib/iomgr/sockaddr_utils.cc +++ b/src/core/lib/iomgr/sockaddr_utils.cc @@ -217,6 +217,7 @@ void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port) { } char* grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) { + if (resolved_addr->len == 0) return nullptr; grpc_resolved_address addr_normalized; if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) { resolved_addr = &addr_normalized; diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index ce65c594fe2..c6ca970beee 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -322,7 +322,6 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', 'src/core/ext/filters/client_channel/lb_policy.cc', - 'src/core/ext/filters/client_channel/lb_policy_factory.cc', 'src/core/ext/filters/client_channel/lb_policy_registry.cc', 'src/core/ext/filters/client_channel/parse_address.cc', 'src/core/ext/filters/client_channel/proxy_mapper.cc', @@ -331,6 +330,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/resolver_registry.cc', 'src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc', + 'src/core/ext/filters/client_channel/server_address.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc index 76769b2b64a..1a7a7c9ccc9 100644 --- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc @@ -21,10 +21,10 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -63,8 +63,9 @@ static grpc_address_resolver_vtable test_resolver = {my_resolve_address, static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { gpr_mu_lock(&g_mu); GPR_ASSERT(0 == strcmp("test", addr)); grpc_error* error = GRPC_ERROR_NONE; @@ -74,9 +75,8 @@ static grpc_ares_request* my_dns_lookup_ares_locked( error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); } else { gpr_mu_unlock(&g_mu); - *lb_addrs = grpc_lb_addresses_create(1, nullptr); - grpc_lb_addresses_set_address(*lb_addrs, 0, nullptr, 0, false, nullptr, - nullptr); + *addresses = grpc_core::MakeUnique(); + (*addresses)->emplace_back(nullptr, 0, nullptr); } GRPC_CLOSURE_SCHED(on_done, error); return nullptr; diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc index cdbe33dbe79..16210b8164b 100644 --- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc @@ -22,6 +22,7 @@ #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/combiner.h" @@ -40,8 +41,9 @@ static grpc_combiner* g_combiner; static grpc_ares_request* (*g_default_dns_lookup_ares_locked)( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner); + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner); // Counter incremented by test_resolve_address_impl indicating the number of // times a system-level resolution has happened. @@ -90,11 +92,12 @@ static grpc_address_resolver_vtable test_resolver = { static grpc_ares_request* test_dns_lookup_ares_locked( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { grpc_ares_request* result = g_default_dns_lookup_ares_locked( - dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs, - check_grpclb, service_config_json, query_timeout_ms, combiner); + dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, + addresses, check_grpclb, service_config_json, query_timeout_ms, combiner); ++g_resolution_count; static grpc_millis last_resolution_time = 0; if (last_resolution_time == 0) { diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc index 6362b95e50e..3b06fe063ae 100644 --- a/test/core/client_channel/resolvers/fake_resolver_test.cc +++ b/test/core/client_channel/resolvers/fake_resolver_test.cc @@ -22,10 +22,10 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/combiner.h" @@ -63,12 +63,14 @@ void on_resolution_cb(void* arg, grpc_error* error) { // We only check the addresses channel arg because that's the only one // explicitly set by the test via // FakeResolverResponseGenerator::SetResponse(). - const grpc_lb_addresses* actual_lb_addresses = - grpc_lb_addresses_find_channel_arg(res->resolver_result); - const grpc_lb_addresses* expected_lb_addresses = - grpc_lb_addresses_find_channel_arg(res->expected_resolver_result); - GPR_ASSERT( - grpc_lb_addresses_cmp(actual_lb_addresses, expected_lb_addresses) == 0); + const grpc_core::ServerAddressList* actual_addresses = + grpc_core::FindServerAddressListChannelArg(res->resolver_result); + const grpc_core::ServerAddressList* expected_addresses = + grpc_core::FindServerAddressListChannelArg(res->expected_resolver_result); + GPR_ASSERT(actual_addresses->size() == expected_addresses->size()); + for (size_t i = 0; i < expected_addresses->size(); ++i) { + GPR_ASSERT((*actual_addresses)[i] == (*expected_addresses)[i]); + } grpc_channel_args_destroy(res->resolver_result); grpc_channel_args_destroy(res->expected_resolver_result); gpr_event_set(&res->ev, (void*)1); @@ -80,27 +82,35 @@ static grpc_channel_args* create_new_resolver_result() { const size_t num_addresses = 2; char* uri_string; char* balancer_name; - // Create grpc_lb_addresses. - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(num_addresses, nullptr); + // Create address list. + grpc_core::ServerAddressList addresses; for (size_t i = 0; i < num_addresses; ++i) { gpr_asprintf(&uri_string, "ipv4:127.0.0.1:100%" PRIuPTR, test_counter * num_addresses + i); grpc_uri* uri = grpc_uri_parse(uri_string, true); gpr_asprintf(&balancer_name, "balancer%" PRIuPTR, test_counter * num_addresses + i); - grpc_lb_addresses_set_address_from_uri( - addresses, i, uri, bool(num_addresses % 2), balancer_name, nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(uri, &address)); + grpc_core::InlinedVector args_to_add; + const bool is_balancer = num_addresses % 2; + if (is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), balancer_name)); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); + addresses.emplace_back(address.addr, address.len, args); gpr_free(balancer_name); grpc_uri_destroy(uri); gpr_free(uri_string); } - // Convert grpc_lb_addresses to grpc_channel_args. - const grpc_arg addresses_arg = - grpc_lb_addresses_create_channel_arg(addresses); + // Embed the address list in channel args. + const grpc_arg addresses_arg = CreateServerAddressListChannelArg(&addresses); grpc_channel_args* results = grpc_channel_args_copy_and_add(nullptr, &addresses_arg, 1); - grpc_lb_addresses_destroy(addresses); ++test_counter; return results; } diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index a3de56d4f9f..fe471279841 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -24,8 +24,8 @@ #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" @@ -325,7 +325,7 @@ typedef struct addr_req { char* addr; grpc_closure* on_done; grpc_resolved_addresses** addrs; - grpc_lb_addresses** lb_addrs; + grpc_core::UniquePtr* addresses; } addr_req; static void finish_resolve(void* arg, grpc_error* error) { @@ -340,11 +340,9 @@ static void finish_resolve(void* arg, grpc_error* error) { gpr_malloc(sizeof(*addrs->addrs))); addrs->addrs[0].len = 0; *r->addrs = addrs; - } else if (r->lb_addrs != nullptr) { - grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(1, nullptr); - grpc_lb_addresses_set_address(lb_addrs, 0, nullptr, 0, false, nullptr, - nullptr); - *r->lb_addrs = lb_addrs; + } else if (r->addresses != nullptr) { + *r->addresses = grpc_core::MakeUnique(); + (*r->addresses)->emplace_back(nullptr, 0, nullptr); } GRPC_CLOSURE_SCHED(r->on_done, GRPC_ERROR_NONE); } else { @@ -354,18 +352,17 @@ static void finish_resolve(void* arg, grpc_error* error) { } gpr_free(r->addr); - gpr_free(r); + grpc_core::Delete(r); } void my_resolve_address(const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_resolved_addresses** addresses) { - addr_req* r = static_cast(gpr_malloc(sizeof(*r))); + grpc_resolved_addresses** addrs) { + addr_req* r = grpc_core::New(); r->addr = gpr_strdup(addr); r->on_done = on_done; - r->addrs = addresses; - r->lb_addrs = nullptr; + r->addrs = addrs; grpc_timer_init( &r->timer, GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(), GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx)); @@ -377,13 +374,14 @@ static grpc_address_resolver_vtable fuzzer_resolver = {my_resolve_address, grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - int query_timeout, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout, + grpc_combiner* combiner) { addr_req* r = static_cast(gpr_malloc(sizeof(*r))); r->addr = gpr_strdup(addr); r->on_done = on_done; r->addrs = nullptr; - r->lb_addrs = lb_addrs; + r->addresses = addresses; grpc_timer_init( &r->timer, GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(), GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx)); diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc index 66e8ca51614..7e3b418cd94 100644 --- a/test/core/end2end/goaway_server_test.cc +++ b/test/core/end2end/goaway_server_test.cc @@ -28,8 +28,8 @@ #include #include #include -#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr.h" #include "test/core/end2end/cq_verifier.h" @@ -47,8 +47,9 @@ static int g_resolve_port = -1; static grpc_ares_request* (*iomgr_dns_lookup_ares_locked)( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** addresses, bool check_grpclb, - char** service_config_json, int query_timeout_ms, grpc_combiner* combiner); + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner); static void (*iomgr_cancel_ares_request_locked)(grpc_ares_request* request); @@ -103,11 +104,12 @@ static grpc_address_resolver_vtable test_resolver = { static grpc_ares_request* my_dns_lookup_ares_locked( const char* dns_server, const char* addr, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, - grpc_lb_addresses** lb_addrs, bool check_grpclb, char** service_config_json, - int query_timeout_ms, grpc_combiner* combiner) { + grpc_core::UniquePtr* addresses, + bool check_grpclb, char** service_config_json, int query_timeout_ms, + grpc_combiner* combiner) { if (0 != strcmp(addr, "test")) { return iomgr_dns_lookup_ares_locked( - dns_server, addr, default_port, interested_parties, on_done, lb_addrs, + dns_server, addr, default_port, interested_parties, on_done, addresses, check_grpclb, service_config_json, query_timeout_ms, combiner); } @@ -117,15 +119,12 @@ static grpc_ares_request* my_dns_lookup_ares_locked( gpr_mu_unlock(&g_mu); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); } else { - *lb_addrs = grpc_lb_addresses_create(1, nullptr); - grpc_sockaddr_in* sa = - static_cast(gpr_zalloc(sizeof(grpc_sockaddr_in))); - sa->sin_family = GRPC_AF_INET; - sa->sin_addr.s_addr = 0x100007f; - sa->sin_port = grpc_htons(static_cast(g_resolve_port)); - grpc_lb_addresses_set_address(*lb_addrs, 0, sa, sizeof(*sa), false, nullptr, - nullptr); - gpr_free(sa); + *addresses = grpc_core::MakeUnique(); + grpc_sockaddr_in sa; + sa.sin_family = GRPC_AF_INET; + sa.sin_addr.s_addr = 0x100007f; + sa.sin_port = grpc_htons(static_cast(g_resolve_port)); + (*addresses)->emplace_back(&sa, sizeof(sa), nullptr); gpr_mu_unlock(&g_mu); } GRPC_CLOSURE_SCHED(on_done, error); diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc index 5dda748f5a5..c289e719eea 100644 --- a/test/core/end2end/no_server_test.cc +++ b/test/core/end2end/no_server_test.cc @@ -23,6 +23,7 @@ #include #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/lib/iomgr/exec_ctx.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/util/test_config.h" diff --git a/test/core/util/ubsan_suppressions.txt b/test/core/util/ubsan_suppressions.txt index 63898ea3b1c..8ed7d4d7fb6 100644 --- a/test/core/util/ubsan_suppressions.txt +++ b/test/core/util/ubsan_suppressions.txt @@ -25,7 +25,6 @@ alignment:absl::little_endian::Store64 alignment:absl::little_endian::Load64 float-divide-by-zero:grpc::testing::postprocess_scenario_result enum:grpc_op_string -nonnull-attribute:grpc_lb_addresses_copy signed-integer-overflow:chrono enum:grpc_http2_error_to_grpc_status -enum:grpc_chttp2_cancel_stream \ No newline at end of file +enum:grpc_chttp2_cancel_stream diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc index bf321d8a89e..124557eb567 100644 --- a/test/cpp/client/client_channel_stress_test.cc +++ b/test/cpp/client/client_channel_stress_test.cc @@ -34,7 +34,9 @@ #include #include +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -216,23 +218,31 @@ class ClientChannelStressTest { void SetNextResolution(const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(address_data.size(), nullptr); - for (size_t i = 0; i < address_data.size(); ++i) { + grpc_core::ServerAddressList addresses; + for (const auto& addr : address_data) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", address_data[i].port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", addr.port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_lb_addresses_set_address_from_uri( - addresses, i, lb_uri, address_data[i].is_balancer, - address_data[i].balancer_name.c_str(), nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + std::vector args_to_add; + if (addr.is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), + const_cast(addr.balancer_name.c_str()))); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); + addresses.emplace_back(address.addr, address.len, args); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } - grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetResponse(&fake_result); - grpc_lb_addresses_destroy(addresses); } void KeepSendingRequests() { diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index 1dfa91a76c7..929c2bb5899 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -35,7 +35,9 @@ #include #include +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/gpr/env.h" @@ -159,24 +161,22 @@ class ClientLbEnd2endTest : public ::testing::Test { } grpc_channel_args* BuildFakeResults(const std::vector& ports) { - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(ports.size(), nullptr); - for (size_t i = 0; i < ports.size(); ++i) { + grpc_core::ServerAddressList addresses; + for (const int& port : ports) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", ports[i]); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_lb_addresses_set_address_from_uri(addresses, i, lb_uri, - false /* is balancer */, - "" /* balancer name */, nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + addresses.emplace_back(address.addr, address.len, nullptr /* args */); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } const grpc_arg fake_addresses = - grpc_lb_addresses_create_channel_arg(addresses); + CreateServerAddressListChannelArg(&addresses); grpc_channel_args* fake_results = grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1); - grpc_lb_addresses_destroy(addresses); return fake_results; } diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index 9c4cd050619..bf990a07b5a 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -32,7 +32,9 @@ #include #include +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -486,18 +488,27 @@ class GrpclbEnd2endTest : public ::testing::Test { grpc::string balancer_name; }; - grpc_lb_addresses* CreateLbAddressesFromAddressDataList( + grpc_core::ServerAddressList CreateLbAddressesFromAddressDataList( const std::vector& address_data) { - grpc_lb_addresses* addresses = - grpc_lb_addresses_create(address_data.size(), nullptr); - for (size_t i = 0; i < address_data.size(); ++i) { + grpc_core::ServerAddressList addresses; + for (const auto& addr : address_data) { char* lb_uri_str; - gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", address_data[i].port); + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", addr.port); grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); GPR_ASSERT(lb_uri != nullptr); - grpc_lb_addresses_set_address_from_uri( - addresses, i, lb_uri, address_data[i].is_balancer, - address_data[i].balancer_name.c_str(), nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + std::vector args_to_add; + if (addr.is_balancer) { + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BALANCER), 1)); + args_to_add.emplace_back(grpc_channel_arg_string_create( + const_cast(GRPC_ARG_ADDRESS_BALANCER_NAME), + const_cast(addr.balancer_name.c_str()))); + } + grpc_channel_args* args = grpc_channel_args_copy_and_add( + nullptr, args_to_add.data(), args_to_add.size()); + addresses.emplace_back(address.addr, address.len, args); grpc_uri_destroy(lb_uri); gpr_free(lb_uri_str); } @@ -506,23 +517,21 @@ class GrpclbEnd2endTest : public ::testing::Test { void SetNextResolution(const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses* addresses = + grpc_core::ServerAddressList addresses = CreateLbAddressesFromAddressDataList(address_data); - grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetResponse(&fake_result); - grpc_lb_addresses_destroy(addresses); } void SetNextReresolutionResponse( const std::vector& address_data) { grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses* addresses = + grpc_core::ServerAddressList addresses = CreateLbAddressesFromAddressDataList(address_data); - grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses); + grpc_arg fake_addresses = CreateServerAddressListChannelArg(&addresses); grpc_channel_args fake_result = {1, &fake_addresses}; response_generator_->SetReresolutionResponse(&fake_result); - grpc_lb_addresses_destroy(addresses); } const std::vector GetBackendPorts(const size_t start_index = 0) const { diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc index 3eb0e7d7254..09e705df789 100644 --- a/test/cpp/naming/address_sorting_test.cc +++ b/test/cpp/naming/address_sorting_test.cc @@ -37,6 +37,7 @@ #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" @@ -167,30 +168,26 @@ void OverrideAddressSortingSourceAddrFactory( address_sorting_override_source_addr_factory_for_testing(factory); } -grpc_lb_addresses* BuildLbAddrInputs(std::vector test_addrs) { - grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, nullptr); - lb_addrs->addresses = - (grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size()); - lb_addrs->num_addresses = test_addrs.size(); - for (size_t i = 0; i < test_addrs.size(); i++) { - lb_addrs->addresses[i].address = - TestAddressToGrpcResolvedAddress(test_addrs[i]); +grpc_core::ServerAddressList BuildLbAddrInputs( + const std::vector& test_addrs) { + grpc_core::ServerAddressList addresses; + for (const auto& addr : test_addrs) { + addresses.emplace_back(TestAddressToGrpcResolvedAddress(addr), nullptr); } - return lb_addrs; + return addresses; } -void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, +void VerifyLbAddrOutputs(const grpc_core::ServerAddressList addresses, std::vector expected_addrs) { - EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size()); - for (size_t i = 0; i < lb_addrs->num_addresses; i++) { + EXPECT_EQ(addresses.size(), expected_addrs.size()); + for (size_t i = 0; i < addresses.size(); ++i) { char* ip_addr_str; - grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address, + grpc_sockaddr_to_string(&ip_addr_str, &addresses[i].address(), false /* normalize */); EXPECT_EQ(expected_addrs[i], ip_addr_str); gpr_free(ip_addr_str); } grpc_core::ExecCtx exec_ctx; - grpc_lb_addresses_destroy(lb_addrs); } /* We need to run each test case inside of its own @@ -212,11 +209,11 @@ TEST_F(AddressSortingTest, TestDepriotizesUnreachableAddresses) { { {"1.2.3.4:443", {"4.3.2.1:443", AF_INET}}, }); - auto* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"1.2.3.4:443", AF_INET}, {"5.6.7.8:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "1.2.3.4:443", "5.6.7.8:443", @@ -235,7 +232,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "1.2.3.4:443", "[2607:f8b0:400a:801::1002]:443", @@ -251,11 +248,11 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, {"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2607:f8b0:400a:801::1002]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2607:f8b0:400a:801::1002]:443", "1.2.3.4:443", @@ -275,11 +272,11 @@ TEST_F(AddressSortingTest, TestDepriotizesNonMatchingScope) { {"[fec0::5000]:443", {"[fec0::5001]:0", AF_INET6}}, // site-local and site-local scope }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2000:f8b0:400a:801::1002]:443", AF_INET6}, {"[fec0::5000]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fec0::5000]:443", "[2000:f8b0:400a:801::1002]:443", @@ -298,11 +295,11 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTable) { {"[2001::5001]:443", {"[2001::5002]:0", AF_INET6}}, // matching labels }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2002::5001]:443", AF_INET6}, {"[2001::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2001::5001]:443", "[2002::5001]:443", @@ -321,11 +318,11 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) { {"[2001::5001]:443", {"[2001::5002]:0", AF_INET6}}, // matching labels }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2001::5001]:443", AF_INET6}, {"[2002::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2001::5001]:443", "[2002::5001]:443", @@ -344,11 +341,11 @@ TEST_F(AddressSortingTest, {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, {"1.2.3.4:443", {"5.6.7.8:0", AF_INET}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs( lb_addrs, { // The AF_INET address should be IPv4-mapped by the sort, @@ -377,11 +374,11 @@ TEST_F(AddressSortingTest, {"[::1]:443", {"[::1]:0", AF_INET6}}, {v4_compat_dest, {v4_compat_src, AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {v4_compat_dest, AF_INET6}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", v4_compat_dest, @@ -400,11 +397,11 @@ TEST_F(AddressSortingTest, {"[1234::2]:443", {"[1234::2]:0", AF_INET6}}, {"[::1]:443", {"[::1]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[1234::2]:443", AF_INET6}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs( lb_addrs, { @@ -424,11 +421,11 @@ TEST_F(AddressSortingTest, {"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}}, {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2001::1234]:443", AF_INET6}, {"[2000::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs( lb_addrs, { // The 2000::/16 address should match the ::/0 prefix rule @@ -448,11 +445,11 @@ TEST_F( {"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}}, {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[2001::1231]:443", AF_INET6}, {"[2000::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[2000::5001]:443", "[2001::1231]:443", @@ -469,11 +466,11 @@ TEST_F(AddressSortingTest, {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, {"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[fec0::1234]:443", AF_INET6}, {"[fc00::5001]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fc00::5001]:443", "[fec0::1234]:443", @@ -494,11 +491,11 @@ TEST_F( {"[::ffff:1.1.1.2]:443", {"[::ffff:1.1.1.3]:0", AF_INET6}}, {"[1234::2]:443", {"[1234::3]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[::ffff:1.1.1.2]:443", AF_INET6}, {"[1234::2]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { // ::ffff:0:2 should match the v4-mapped // precedence entry and be deprioritized. @@ -521,11 +518,11 @@ TEST_F(AddressSortingTest, TestPrefersSmallerScope) { {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"[fec0::1234]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[fec0::1234]:443", "[3ffe::5001]:443", @@ -546,11 +543,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { {"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}}, {"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:5001::]:443", AF_INET6}, {"[3ffe:1234::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:1234::]:443", "[3ffe:5001::]:443", @@ -567,11 +564,11 @@ TEST_F(AddressSortingTest, {"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}}, {"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::5001]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1234]:443", "[3ffe::5001]:443", @@ -587,11 +584,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { {"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}}, {"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:8000::]:443", AF_INET6}, {"[3ffe:2000::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:2000::]:443", "[3ffe:8000::]:443", @@ -607,11 +604,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { {"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}}, {"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:6::]:443", AF_INET6}, {"[3ffe:c::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:c::]:443", "[3ffe:6::]:443", @@ -629,11 +626,11 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { {"[3ffe:1111:1111:1110::]:443", {"[3ffe:1111:1111:1111::]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe:1111:1111:1110::]:443", AF_INET6}, {"[3ffe:1111:1111:1111::]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe:1111:1111:1111::]:443", "[3ffe:1111:1111:1110::]:443", @@ -651,11 +648,11 @@ TEST_F(AddressSortingTest, TestStableSort) { {"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}}, {"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1234]:443", "[3ffe::1235]:443", @@ -674,14 +671,14 @@ TEST_F(AddressSortingTest, TestStableSortFiveElements) { {"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}}, {"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::1231]:443", AF_INET6}, {"[3ffe::1232]:443", AF_INET6}, {"[3ffe::1233]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1231]:443", "[3ffe::1232]:443", @@ -695,14 +692,14 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExist) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[3ffe::1231]:443", AF_INET6}, {"[3ffe::1232]:443", AF_INET6}, {"[3ffe::1233]:443", AF_INET6}, {"[3ffe::1234]:443", AF_INET6}, {"[3ffe::1235]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[3ffe::1231]:443", "[3ffe::1232]:443", @@ -716,11 +713,11 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { bool ipv4_supported = true; bool ipv6_supported = true; OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[::ffff:5.6.7.8]:443", AF_INET6}, {"1.2.3.4:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::ffff:5.6.7.8]:443", "1.2.3.4:443", @@ -744,11 +741,11 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { {"[fec0::2000]:443", {"[fec0::2001]:0", AF_INET6}}, {v4_compat_dest, {v4_compat_src, AF_INET6}}, }); - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[fec0::2000]:443", AF_INET6}, {v4_compat_dest, AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { // The sort should be stable since @@ -765,11 +762,11 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) { * (whether ipv4 loopback is available or not, an available ipv6 * loopback should be preferred). */ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"[::1]:443", AF_INET6}, {"127.0.0.1:443", AF_INET}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", "127.0.0.1:443", @@ -779,11 +776,11 @@ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) { /* Flip the order of the inputs above and expect the same output order * (try to rule out influence of arbitrary qsort ordering) */ TEST_F(AddressSortingTest, TestPrefersIpv6LoopbackInputsFlipped) { - grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ + auto lb_addrs = BuildLbAddrInputs({ {"127.0.0.1:443", AF_INET}, {"[::1]:443", AF_INET6}, }); - grpc_cares_wrapper_address_sorting_sort(lb_addrs); + grpc_cares_wrapper_address_sorting_sort(&lb_addrs); VerifyLbAddrOutputs(lb_addrs, { "[::1]:443", "127.0.0.1:443", diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc index fe6fcb8d9cb..2ac2c237cea 100644 --- a/test/cpp/naming/resolver_component_test.cc +++ b/test/cpp/naming/resolver_component_test.cc @@ -41,6 +41,7 @@ #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" @@ -382,23 +383,19 @@ void CheckResolverResultLocked(void* argsp, grpc_error* err) { EXPECT_EQ(err, GRPC_ERROR_NONE); ArgsStruct* args = (ArgsStruct*)argsp; grpc_channel_args* channel_args = args->channel_args; - const grpc_arg* channel_arg = - grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(channel_arg != nullptr); - GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses* addresses = - (grpc_lb_addresses*)channel_arg->value.pointer.p; + grpc_core::ServerAddressList* addresses = + grpc_core::FindServerAddressListChannelArg(channel_args); gpr_log(GPR_INFO, "num addrs found: %" PRIdPTR ". expected %" PRIdPTR, - addresses->num_addresses, args->expected_addrs.size()); - GPR_ASSERT(addresses->num_addresses == args->expected_addrs.size()); + addresses->size(), args->expected_addrs.size()); + GPR_ASSERT(addresses->size() == args->expected_addrs.size()); std::vector found_lb_addrs; - for (size_t i = 0; i < addresses->num_addresses; i++) { - grpc_lb_address addr = addresses->addresses[i]; + for (size_t i = 0; i < addresses->size(); i++) { + grpc_core::ServerAddress& addr = (*addresses)[i]; char* str; - grpc_sockaddr_to_string(&str, &addr.address, 1 /* normalize */); + grpc_sockaddr_to_string(&str, &addr.address(), 1 /* normalize */); gpr_log(GPR_INFO, "%s", str); found_lb_addrs.emplace_back( - GrpcLBAddress(std::string(str), addr.is_balancer)); + GrpcLBAddress(std::string(str), addr.IsBalancer())); gpr_free(str); } if (args->expected_addrs.size() != found_lb_addrs.size()) { diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index dd5bead58ca..5011e19b03a 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -923,7 +923,6 @@ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h \ -src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_factory.h \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ src/core/ext/filters/client_channel/lb_policy_registry.h \ @@ -959,6 +958,8 @@ src/core/ext/filters/client_channel/resolver_result_parsing.cc \ src/core/ext/filters/client_channel/resolver_result_parsing.h \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/retry_throttle.h \ +src/core/ext/filters/client_channel/server_address.cc \ +src/core/ext/filters/client_channel/server_address.h \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel.h \ src/core/ext/filters/client_channel/subchannel_index.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 0a7a4daf7de..2451101f58d 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -10074,6 +10074,7 @@ "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.h", + "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h" ], @@ -10101,7 +10102,6 @@ "src/core/ext/filters/client_channel/http_proxy.h", "src/core/ext/filters/client_channel/lb_policy.cc", "src/core/ext/filters/client_channel/lb_policy.h", - "src/core/ext/filters/client_channel/lb_policy_factory.cc", "src/core/ext/filters/client_channel/lb_policy_factory.h", "src/core/ext/filters/client_channel/lb_policy_registry.cc", "src/core/ext/filters/client_channel/lb_policy_registry.h", @@ -10120,6 +10120,8 @@ "src/core/ext/filters/client_channel/resolver_result_parsing.h", "src/core/ext/filters/client_channel/retry_throttle.cc", "src/core/ext/filters/client_channel/retry_throttle.h", + "src/core/ext/filters/client_channel/server_address.cc", + "src/core/ext/filters/client_channel/server_address.h", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.cc", From 07fc27c20d694021669f2d77449da0666b6b1626 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 11 Dec 2018 08:08:34 -0800 Subject: [PATCH 66/99] Update channelz proto --- src/proto/grpc/channelz/channelz.proto | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto index 6202e5e817d..9d73f375541 100644 --- a/src/proto/grpc/channelz/channelz.proto +++ b/src/proto/grpc/channelz/channelz.proto @@ -177,6 +177,7 @@ message SubchannelRef { // SocketRef is a reference to a Socket. message SocketRef { + // The globally unique id for this socket. Must be a positive number. int64 socket_id = 3; // An optional name associated with the socket. string name = 4; @@ -288,7 +289,8 @@ message SocketData { // include stream level or TCP level flow control info. google.protobuf.Int64Value remote_flow_control_window = 12; - // Socket options set on this socket. May be absent. + // Socket options set on this socket. May be absent if 'summary' is set + // on GetSocketRequest. repeated SocketOption option = 13; } @@ -439,12 +441,21 @@ service Channelz { message GetTopChannelsRequest { // start_channel_id indicates that only channels at or above this id should be // included in the results. + // To request the first page, this should be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. int64 start_channel_id = 1; + + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + int64 max_results = 2; } message GetTopChannelsResponse { // list of channels that the connection detail service knows about. Sorted in // ascending channel_id order. + // Must contain at least 1 result, otherwise 'end' must be true. repeated Channel channel = 1; // If set, indicates that the list of channels is the final list. Requesting // more channels can only return more if they are created after this RPC @@ -455,12 +466,21 @@ message GetTopChannelsResponse { message GetServersRequest { // start_server_id indicates that only servers at or above this id should be // included in the results. + // To request the first page, this must be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. int64 start_server_id = 1; + + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + int64 max_results = 2; } message GetServersResponse { // list of servers that the connection detail service knows about. Sorted in // ascending server_id order. + // Must contain at least 1 result, otherwise 'end' must be true. repeated Server server = 1; // If set, indicates that the list of servers is the final list. Requesting // more servers will only return more if they are created after this RPC @@ -483,12 +503,21 @@ message GetServerSocketsRequest { int64 server_id = 1; // start_socket_id indicates that only sockets at or above this id should be // included in the results. + // To request the first page, this must be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. int64 start_socket_id = 2; + + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + int64 max_results = 3; } message GetServerSocketsResponse { // list of socket refs that the connection detail service knows about. Sorted in // ascending socket_id order. + // Must contain at least 1 result, otherwise 'end' must be true. repeated SocketRef socket_ref = 1; // If set, indicates that the list of sockets is the final list. Requesting // more sockets will only return more if they are created after this RPC @@ -521,10 +550,15 @@ message GetSubchannelResponse { message GetSocketRequest { // socket_id is the identifier of the specific socket to get. int64 socket_id = 1; + + // If true, the response will contain only high level information + // that is inexpensive to obtain. Fields thay may be omitted are + // documented. + bool summary = 2; } message GetSocketResponse { // The Socket that corresponds to the requested socket_id. This field // should be set. Socket socket = 1; -} +} \ No newline at end of file From 7b1fc0faa23b2cc1807450498b8c69afb079c2d2 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 11 Dec 2018 08:22:51 -0800 Subject: [PATCH 67/99] Add max_results to ServerSockets --- include/grpc/grpc.h | 3 ++- src/core/lib/channel/channelz.cc | 10 ++++++---- src/core/lib/channel/channelz.h | 3 ++- src/core/lib/channel/channelz_registry.cc | 5 +++-- .../grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi | 8 +++++--- src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi | 3 ++- .../grpcio_channelz/grpc_channelz/v1/channelz.py | 3 ++- src/ruby/ext/grpc/rb_grpc_imports.generated.h | 2 +- test/core/end2end/tests/channelz.cc | 2 +- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index d3b74cabab5..fec7f5269e1 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -511,7 +511,8 @@ GRPCAPI char* grpc_channelz_get_server(intptr_t server_id); /* Gets all server sockets that exist in the server. */ GRPCAPI char* grpc_channelz_get_server_sockets(intptr_t server_id, - intptr_t start_socket_id); + intptr_t start_socket_id, + intptr_t max_results); /* Returns a single Channel, or else a NOT_FOUND code. The returned string is allocated and must be freed by the application. */ diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 8d449ee6721..3fcfa2a4125 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -203,8 +203,10 @@ ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes) ServerNode::~ServerNode() {} -char* ServerNode::RenderServerSockets(intptr_t start_socket_id) { - const int kPaginationLimit = 100; +char* ServerNode::RenderServerSockets(intptr_t start_socket_id, + intptr_t max_results) { + // if user does not set max_results, we choose 500. + int pagination_limit = max_results == 0 ? 500 : max_results; grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; @@ -219,8 +221,8 @@ char* ServerNode::RenderServerSockets(intptr_t start_socket_id) { for (size_t i = 0; i < socket_refs.size(); ++i) { // check if we are over pagination limit to determine if we need to set // the "end" element. If we don't go through this block, we know that - // when the loop terminates, we have <= to kPaginationLimit. - if (sockets_added == kPaginationLimit) { + // when the loop terminates, we have <= to pagination_limit. + if (sockets_added == pagination_limit) { reached_pagination_limit = true; break; } diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 96a4333083a..e43792126f0 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -210,7 +210,8 @@ class ServerNode : public BaseNode { grpc_json* RenderJson() override; - char* RenderServerSockets(intptr_t start_socket_id); + char* RenderServerSockets(intptr_t start_socket_id, + intptr_t pagination_limit); // proxy methods to composed classes. void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) { diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc index bc23b90a661..7cca247d64d 100644 --- a/src/core/lib/channel/channelz_registry.cc +++ b/src/core/lib/channel/channelz_registry.cc @@ -252,7 +252,8 @@ char* grpc_channelz_get_server(intptr_t server_id) { } char* grpc_channelz_get_server_sockets(intptr_t server_id, - intptr_t start_socket_id) { + intptr_t start_socket_id, + intptr_t max_results) { grpc_core::channelz::BaseNode* base_node = grpc_core::channelz::ChannelzRegistry::Get(server_id); if (base_node == nullptr || @@ -263,7 +264,7 @@ char* grpc_channelz_get_server_sockets(intptr_t server_id, // actually a server node grpc_core::channelz::ServerNode* server_node = static_cast(base_node); - return server_node->RenderServerSockets(start_socket_id); + return server_node->RenderServerSockets(start_socket_id, max_results); } char* grpc_channelz_get_channel(intptr_t channel_id) { diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi index 113f7976dd9..36c8cd121c7 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/channelz.pyx.pxi @@ -36,15 +36,17 @@ def channelz_get_server(server_id): ' server_id==%s is valid' % server_id) return c_returned_str -def channelz_get_server_sockets(server_id, start_socket_id): +def channelz_get_server_sockets(server_id, start_socket_id, max_results): cdef char *c_returned_str = grpc_channelz_get_server_sockets( server_id, start_socket_id, + max_results, ) if c_returned_str == NULL: raise ValueError('Failed to get server sockets, please ensure your' \ - ' server_id==%s and start_socket_id==%s is valid' % - (server_id, start_socket_id)) + ' server_id==%s and start_socket_id==%s and' \ + ' max_results==%s is valid' % + (server_id, start_socket_id, max_results)) return c_returned_str def channelz_get_channel(channel_id): diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi index 5bbc10af25d..fc7a9ba4395 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi @@ -389,7 +389,8 @@ cdef extern from "grpc/grpc.h": char* grpc_channelz_get_servers(intptr_t start_server_id) char* grpc_channelz_get_server(intptr_t server_id) char* grpc_channelz_get_server_sockets(intptr_t server_id, - intptr_t start_socket_id) + intptr_t start_socket_id, + intptr_t max_results) char* grpc_channelz_get_channel(intptr_t channel_id) char* grpc_channelz_get_subchannel(intptr_t subchannel_id) char* grpc_channelz_get_socket(intptr_t socket_id) diff --git a/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py b/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py index 573b9d0d5ac..00eca311dc1 100644 --- a/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py +++ b/src/python/grpcio_channelz/grpc_channelz/v1/channelz.py @@ -66,7 +66,8 @@ class ChannelzServicer(_channelz_pb2_grpc.ChannelzServicer): try: return json_format.Parse( cygrpc.channelz_get_server_sockets(request.server_id, - request.start_socket_id), + request.start_socket_id, + request.max_results), _channelz_pb2.GetServerSocketsResponse(), ) except ValueError as e: diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 56d222c7ec8..e61a35d09fa 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -272,7 +272,7 @@ extern grpc_channelz_get_servers_type grpc_channelz_get_servers_import; typedef char*(*grpc_channelz_get_server_type)(intptr_t server_id); extern grpc_channelz_get_server_type grpc_channelz_get_server_import; #define grpc_channelz_get_server grpc_channelz_get_server_import -typedef char*(*grpc_channelz_get_server_sockets_type)(intptr_t server_id, intptr_t start_socket_id); +typedef char*(*grpc_channelz_get_server_sockets_type)(intptr_t server_id, intptr_t start_socket_id, intptr_t max_results); extern grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import; #define grpc_channelz_get_server_sockets grpc_channelz_get_server_sockets_import typedef char*(*grpc_channelz_get_channel_type)(intptr_t channel_id); diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 49a0bc80112..169190eec06 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -259,7 +259,7 @@ static void test_channelz(grpc_end2end_test_config config) { GPR_ASSERT(nullptr == strstr(json, "\"severity\":\"CT_INFO\"")); gpr_free(json); - json = channelz_server->RenderServerSockets(0); + json = channelz_server->RenderServerSockets(0, 100); GPR_ASSERT(nullptr != strstr(json, "\"end\":true")); gpr_free(json); From a6ed43b41fec1201c3d239ee2910aac65cba9d90 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 11 Dec 2018 10:27:11 -0800 Subject: [PATCH 68/99] reviewer feedback --- src/core/lib/channel/channelz.cc | 20 ++++++-------------- src/proto/grpc/channelz/channelz.proto | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 3fcfa2a4125..10d5e1b581c 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -205,28 +205,20 @@ ServerNode::~ServerNode() {} char* ServerNode::RenderServerSockets(intptr_t start_socket_id, intptr_t max_results) { - // if user does not set max_results, we choose 500. - int pagination_limit = max_results == 0 ? 500 : max_results; + // if user does not set max_results, we choose 1000. + size_t pagination_limit = max_results == 0 ? 500 : max_results; grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; ChildSocketsList socket_refs; grpc_server_populate_server_sockets(server_, &socket_refs, start_socket_id); - int sockets_added = 0; - bool reached_pagination_limit = false; + // declared early so it can be used outside of the loop. + size_t i = 0; if (!socket_refs.empty()) { // create list of socket refs grpc_json* array_parent = grpc_json_create_child( nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); - for (size_t i = 0; i < socket_refs.size(); ++i) { - // check if we are over pagination limit to determine if we need to set - // the "end" element. If we don't go through this block, we know that - // when the loop terminates, we have <= to pagination_limit. - if (sockets_added == pagination_limit) { - reached_pagination_limit = true; - break; - } - sockets_added++; + for (i = 0; i < GPR_MIN(socket_refs.size(), pagination_limit); ++i) { grpc_json* socket_ref_json = grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); @@ -236,7 +228,7 @@ char* ServerNode::RenderServerSockets(intptr_t start_socket_id, socket_refs[i]->remote(), GRPC_JSON_STRING, false); } } - if (!reached_pagination_limit) { + if (i == socket_refs.size()) { json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE, false); } diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto index 9d73f375541..20de23f7fa3 100644 --- a/src/proto/grpc/channelz/channelz.proto +++ b/src/proto/grpc/channelz/channelz.proto @@ -561,4 +561,4 @@ message GetSocketResponse { // The Socket that corresponds to the requested socket_id. This field // should be set. Socket socket = 1; -} \ No newline at end of file +} From c7f7db65e0fdc058b4caa2b76baaa308465fda9e Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 11 Dec 2018 11:28:12 -0800 Subject: [PATCH 69/99] Add test and fix bug --- src/core/lib/channel/channelz.cc | 7 +- src/cpp/server/channelz/channelz_service.cc | 4 +- test/cpp/end2end/channelz_service_test.cc | 82 +++++++++++++++++++++ 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 10d5e1b581c..8a596ad4605 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -205,7 +205,7 @@ ServerNode::~ServerNode() {} char* ServerNode::RenderServerSockets(intptr_t start_socket_id, intptr_t max_results) { - // if user does not set max_results, we choose 1000. + // if user does not set max_results, we choose 500. size_t pagination_limit = max_results == 0 ? 500 : max_results; grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; @@ -219,9 +219,8 @@ char* ServerNode::RenderServerSockets(intptr_t start_socket_id, grpc_json* array_parent = grpc_json_create_child( nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); for (i = 0; i < GPR_MIN(socket_refs.size(), pagination_limit); ++i) { - grpc_json* socket_ref_json = - grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, - GRPC_JSON_OBJECT, false); + grpc_json* socket_ref_json = grpc_json_create_child( + nullptr, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); json_iterator = grpc_json_add_number_string_child( socket_ref_json, nullptr, "socketId", socket_refs[i]->uuid()); grpc_json_create_child(json_iterator, socket_ref_json, "name", diff --git a/src/cpp/server/channelz/channelz_service.cc b/src/cpp/server/channelz/channelz_service.cc index 9ecb9de7e4b..c44a9ac0de6 100644 --- a/src/cpp/server/channelz/channelz_service.cc +++ b/src/cpp/server/channelz/channelz_service.cc @@ -79,8 +79,8 @@ Status ChannelzService::GetServer(ServerContext* unused, Status ChannelzService::GetServerSockets( ServerContext* unused, const channelz::v1::GetServerSocketsRequest* request, channelz::v1::GetServerSocketsResponse* response) { - char* json_str = grpc_channelz_get_server_sockets(request->server_id(), - request->start_socket_id()); + char* json_str = grpc_channelz_get_server_sockets( + request->server_id(), request->start_socket_id(), request->max_results()); if (json_str == nullptr) { return Status(StatusCode::INTERNAL, "grpc_channelz_get_server_sockets returned null"); diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc index 29b59e4e5e1..425334d972e 100644 --- a/test/cpp/end2end/channelz_service_test.cc +++ b/test/cpp/end2end/channelz_service_test.cc @@ -54,6 +54,14 @@ using grpc::channelz::v1::GetSubchannelResponse; using grpc::channelz::v1::GetTopChannelsRequest; using grpc::channelz::v1::GetTopChannelsResponse; +// This code snippet can be used to print out any responses for +// visual debugging. +// +// +// string out_str; +// google::protobuf::TextFormat::PrintToString(resp, &out_str); +// std::cout << "resp: " << out_str << "\n"; + namespace grpc { namespace testing { namespace { @@ -164,6 +172,19 @@ class ChannelzServerTest : public ::testing::Test { echo_stub_ = grpc::testing::EchoTestService::NewStub(channel); } + std::unique_ptr NewEchoStub() { + static int salt = 0; + string target = "dns:localhost:" + to_string(proxy_port_); + ChannelArguments args; + // disable channelz. We only want to focus on proxy to backend outbound. + args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 0); + // This ensures that gRPC will not do connection sharing. + args.SetInt("salt", salt++); + std::shared_ptr channel = + CreateCustomChannel(target, InsecureChannelCredentials(), args); + return grpc::testing::EchoTestService::NewStub(channel); + } + void SendSuccessfulEcho(int channel_idx) { EchoRequest request; EchoResponse response; @@ -651,6 +672,67 @@ TEST_F(ChannelzServerTest, GetServerSocketsTest) { EXPECT_EQ(get_server_sockets_response.socket_ref_size(), 1); } +TEST_F(ChannelzServerTest, GetServerSocketsPaginationTest) { + ResetStubs(); + ConfigureProxy(1); + std::vector> stubs; + const int kNumServerSocketsCreated = 20; + for (int i = 0; i < kNumServerSocketsCreated; ++i) { + stubs.push_back(NewEchoStub()); + EchoRequest request; + EchoResponse response; + request.set_message("Hello channelz"); + request.mutable_param()->set_backend_channel_idx(0); + ClientContext context; + Status s = stubs.back()->Echo(&context, request, &response); + EXPECT_EQ(response.message(), request.message()); + EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message(); + } + GetServersRequest get_server_request; + GetServersResponse get_server_response; + get_server_request.set_start_server_id(0); + ClientContext get_server_context; + Status s = channelz_stub_->GetServers(&get_server_context, get_server_request, + &get_server_response); + EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message(); + EXPECT_EQ(get_server_response.server_size(), 1); + // Make a request that gets all of the serversockets + { + GetServerSocketsRequest get_server_sockets_request; + GetServerSocketsResponse get_server_sockets_response; + get_server_sockets_request.set_server_id( + get_server_response.server(0).ref().server_id()); + get_server_sockets_request.set_start_socket_id(0); + ClientContext get_server_sockets_context; + s = channelz_stub_->GetServerSockets(&get_server_sockets_context, + get_server_sockets_request, + &get_server_sockets_response); + EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message(); + // We add one to account the the channelz stub that will end up creating + // a serversocket. + EXPECT_EQ(get_server_sockets_response.socket_ref_size(), + kNumServerSocketsCreated + 1); + EXPECT_TRUE(get_server_sockets_response.end()); + } + // Now we make a request that exercises pagination. + { + GetServerSocketsRequest get_server_sockets_request; + GetServerSocketsResponse get_server_sockets_response; + get_server_sockets_request.set_server_id( + get_server_response.server(0).ref().server_id()); + get_server_sockets_request.set_start_socket_id(0); + const int kMaxResults = 10; + get_server_sockets_request.set_max_results(kMaxResults); + ClientContext get_server_sockets_context; + s = channelz_stub_->GetServerSockets(&get_server_sockets_context, + get_server_sockets_request, + &get_server_sockets_response); + EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message(); + EXPECT_EQ(get_server_sockets_response.socket_ref_size(), kMaxResults); + EXPECT_FALSE(get_server_sockets_response.end()); + } +} + TEST_F(ChannelzServerTest, GetServerListenSocketsTest) { ResetStubs(); ConfigureProxy(1); From 6b3baf26185847f02c11401c971647624ba3d039 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Tue, 11 Dec 2018 10:18:43 -0800 Subject: [PATCH 70/99] Add hooks for census context propagation Appease the yapf gods Reformat --- src/python/grpcio/grpc/_cython/BUILD.bazel | 47 ++++++------ .../grpc/_cython/_cygrpc/_hooks.pyx.pxi | 15 ++++ .../grpc/_cython/_cygrpc/channel.pyx.pxi | 27 ++++--- .../_cython/_cygrpc/propagation_bits.pxd.pxi | 20 ++++++ .../_cython/_cygrpc/propagation_bits.pyx.pxi | 20 ++++++ src/python/grpcio/grpc/_cython/cygrpc.pxd | 1 + src/python/grpcio/grpc/_cython/cygrpc.pyx | 1 + src/python/grpcio/grpc/_server.py | 72 ++++++++++--------- 8 files changed, 139 insertions(+), 64 deletions(-) create mode 100644 src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pxd.pxi create mode 100644 src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pyx.pxi diff --git a/src/python/grpcio/grpc/_cython/BUILD.bazel b/src/python/grpcio/grpc/_cython/BUILD.bazel index e318298d0ab..42db7b87213 100644 --- a/src/python/grpcio/grpc/_cython/BUILD.bazel +++ b/src/python/grpcio/grpc/_cython/BUILD.bazel @@ -6,46 +6,47 @@ pyx_library( name = "cygrpc", srcs = [ "__init__.py", - "cygrpc.pxd", - "cygrpc.pyx", + "_cygrpc/_hooks.pxd.pxi", "_cygrpc/_hooks.pyx.pxi", - "_cygrpc/grpc_string.pyx.pxi", + "_cygrpc/arguments.pxd.pxi", "_cygrpc/arguments.pyx.pxi", + "_cygrpc/call.pxd.pxi", "_cygrpc/call.pyx.pxi", - "_cygrpc/channelz.pyx.pxi", + "_cygrpc/channel.pxd.pxi", "_cygrpc/channel.pyx.pxi", - "_cygrpc/credentials.pyx.pxi", + "_cygrpc/channelz.pyx.pxi", + "_cygrpc/completion_queue.pxd.pxi", "_cygrpc/completion_queue.pyx.pxi", - "_cygrpc/event.pyx.pxi", - "_cygrpc/fork_posix.pyx.pxi", - "_cygrpc/metadata.pyx.pxi", - "_cygrpc/operation.pyx.pxi", - "_cygrpc/records.pyx.pxi", - "_cygrpc/security.pyx.pxi", - "_cygrpc/server.pyx.pxi", - "_cygrpc/tag.pyx.pxi", - "_cygrpc/time.pyx.pxi", - "_cygrpc/grpc_gevent.pyx.pxi", - "_cygrpc/grpc.pxi", - "_cygrpc/_hooks.pxd.pxi", - "_cygrpc/arguments.pxd.pxi", - "_cygrpc/call.pxd.pxi", - "_cygrpc/channel.pxd.pxi", "_cygrpc/credentials.pxd.pxi", - "_cygrpc/completion_queue.pxd.pxi", + "_cygrpc/credentials.pyx.pxi", "_cygrpc/event.pxd.pxi", + "_cygrpc/event.pyx.pxi", "_cygrpc/fork_posix.pxd.pxi", + "_cygrpc/fork_posix.pyx.pxi", + "_cygrpc/grpc.pxi", + "_cygrpc/grpc_gevent.pxd.pxi", + "_cygrpc/grpc_gevent.pyx.pxi", + "_cygrpc/grpc_string.pyx.pxi", "_cygrpc/metadata.pxd.pxi", + "_cygrpc/metadata.pyx.pxi", "_cygrpc/operation.pxd.pxi", + "_cygrpc/operation.pyx.pxi", + "_cygrpc/propagation_bits.pxd.pxi", + "_cygrpc/propagation_bits.pyx.pxi", "_cygrpc/records.pxd.pxi", + "_cygrpc/records.pyx.pxi", "_cygrpc/security.pxd.pxi", + "_cygrpc/security.pyx.pxi", "_cygrpc/server.pxd.pxi", + "_cygrpc/server.pyx.pxi", "_cygrpc/tag.pxd.pxi", + "_cygrpc/tag.pyx.pxi", "_cygrpc/time.pxd.pxi", - "_cygrpc/grpc_gevent.pxd.pxi", + "_cygrpc/time.pyx.pxi", + "cygrpc.pxd", + "cygrpc.pyx", ], deps = [ "//:grpc", ], ) - diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/_hooks.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/_hooks.pyx.pxi index 38cf629dc24..cd4a51a635e 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/_hooks.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/_hooks.pyx.pxi @@ -15,3 +15,18 @@ cdef object _custom_op_on_c_call(int op, grpc_call *call): raise NotImplementedError("No custom hooks are implemented") + +def install_census_context_from_call(Call call): + pass + +def uninstall_context(): + pass + +def build_context(): + pass + +cdef class CensusContext: + pass + +def set_census_context_on_call(_CallState call_state, CensusContext census_ctx): + pass diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi index a81ff4d823b..135d224095e 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi @@ -159,7 +159,8 @@ cdef void _call( _ChannelState channel_state, _CallState call_state, grpc_completion_queue *c_completion_queue, on_success, int flags, method, host, object deadline, CallCredentials credentials, - object operationses_and_user_tags, object metadata) except *: + object operationses_and_user_tags, object metadata, + object context) except *: """Invokes an RPC. Args: @@ -185,6 +186,7 @@ cdef void _call( which is an object to be used as a tag. A SendInitialMetadataOperation must be present in the first element of this value. metadata: The metadata for this call. + context: Context object for distributed tracing. """ cdef grpc_slice method_slice cdef grpc_slice host_slice @@ -208,6 +210,8 @@ cdef void _call( grpc_slice_unref(method_slice) if host_slice_ptr: grpc_slice_unref(host_slice) + if context is not None: + set_census_context_on_call(call_state, context) if credentials is not None: c_call_credentials = credentials.c() c_call_error = grpc_call_set_credentials( @@ -257,7 +261,8 @@ cdef class IntegratedCall: cdef IntegratedCall _integrated_call( _ChannelState state, int flags, method, host, object deadline, - object metadata, CallCredentials credentials, operationses_and_user_tags): + object metadata, CallCredentials credentials, operationses_and_user_tags, + object context): call_state = _CallState() def on_success(started_tags): @@ -266,7 +271,7 @@ cdef IntegratedCall _integrated_call( _call( state, call_state, state.c_call_completion_queue, on_success, flags, - method, host, deadline, credentials, operationses_and_user_tags, metadata) + method, host, deadline, credentials, operationses_and_user_tags, metadata, context) return IntegratedCall(state, call_state) @@ -308,7 +313,8 @@ cdef class SegregatedCall: cdef SegregatedCall _segregated_call( _ChannelState state, int flags, method, host, object deadline, - object metadata, CallCredentials credentials, operationses_and_user_tags): + object metadata, CallCredentials credentials, operationses_and_user_tags, + object context): cdef _CallState call_state = _CallState() cdef SegregatedCall segregated_call cdef grpc_completion_queue *c_completion_queue @@ -325,7 +331,8 @@ cdef SegregatedCall _segregated_call( try: _call( state, call_state, c_completion_queue, on_success, flags, method, host, - deadline, credentials, operationses_and_user_tags, metadata) + deadline, credentials, operationses_and_user_tags, metadata, + context) except: _destroy_c_completion_queue(c_completion_queue) raise @@ -443,10 +450,11 @@ cdef class Channel: def integrated_call( self, int flags, method, host, object deadline, object metadata, - CallCredentials credentials, operationses_and_tags): + CallCredentials credentials, operationses_and_tags, + object context = None): return _integrated_call( self._state, flags, method, host, deadline, metadata, credentials, - operationses_and_tags) + operationses_and_tags, context) def next_call_event(self): def on_success(tag): @@ -461,10 +469,11 @@ cdef class Channel: def segregated_call( self, int flags, method, host, object deadline, object metadata, - CallCredentials credentials, operationses_and_tags): + CallCredentials credentials, operationses_and_tags, + object context = None): return _segregated_call( self._state, flags, method, host, deadline, metadata, credentials, - operationses_and_tags) + operationses_and_tags, context) def check_connectivity_state(self, bint try_to_connect): with self._state.condition: diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pxd.pxi new file mode 100644 index 00000000000..cd6e94c816c --- /dev/null +++ b/src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pxd.pxi @@ -0,0 +1,20 @@ +# Copyright 2018 The 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. + +cdef extern from "grpc/impl/codegen/propagation_bits.h": + cdef int _GRPC_PROPAGATE_DEADLINE "GRPC_PROPAGATE_DEADLINE" + cdef int _GRPC_PROPAGATE_CENSUS_STATS_CONTEXT "GRPC_PROPAGATE_CENSUS_STATS_CONTEXT" + cdef int _GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT "GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT" + cdef int _GRPC_PROPAGATE_CANCELLATION "GRPC_PROPAGATE_CANCELLATION" + cdef int _GRPC_PROPAGATE_DEFAULTS "GRPC_PROPAGATE_DEFAULTS" diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pyx.pxi new file mode 100644 index 00000000000..2dcc76a2db2 --- /dev/null +++ b/src/python/grpcio/grpc/_cython/_cygrpc/propagation_bits.pyx.pxi @@ -0,0 +1,20 @@ +# Copyright 2018 The 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. + +class PropagationConstants: + GRPC_PROPAGATE_DEADLINE = _GRPC_PROPAGATE_DEADLINE + GRPC_PROPAGATE_CENSUS_STATS_CONTEXT = _GRPC_PROPAGATE_CENSUS_STATS_CONTEXT + GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT = _GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT + GRPC_PROPAGATE_CANCELLATION = _GRPC_PROPAGATE_CANCELLATION + GRPC_PROPAGATE_DEFAULTS = _GRPC_PROPAGATE_DEFAULTS diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd index 8258b857bc4..64cae6b34d6 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pxd +++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd @@ -29,6 +29,7 @@ include "_cygrpc/server.pxd.pxi" include "_cygrpc/tag.pxd.pxi" include "_cygrpc/time.pxd.pxi" include "_cygrpc/_hooks.pxd.pxi" +include "_cygrpc/propagation_bits.pxd.pxi" include "_cygrpc/grpc_gevent.pxd.pxi" diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx index 9ab919375c0..ce98fa3a8e6 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pyx +++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx @@ -36,6 +36,7 @@ include "_cygrpc/tag.pyx.pxi" include "_cygrpc/time.pyx.pxi" include "_cygrpc/_hooks.pyx.pxi" include "_cygrpc/channelz.pyx.pxi" +include "_cygrpc/propagation_bits.pyx.pxi" include "_cygrpc/grpc_gevent.pyx.pxi" diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index 7276a7fd90e..e939f615dfd 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -480,43 +480,51 @@ def _status(rpc_event, state, serialized_response): def _unary_response_in_pool(rpc_event, state, behavior, argument_thunk, request_deserializer, response_serializer): - argument = argument_thunk() - if argument is not None: - response, proceed = _call_behavior(rpc_event, state, behavior, argument, - request_deserializer) - if proceed: - serialized_response = _serialize_response( - rpc_event, state, response, response_serializer) - if serialized_response is not None: - _status(rpc_event, state, serialized_response) + cygrpc.install_census_context_from_call(rpc_event.call) + try: + argument = argument_thunk() + if argument is not None: + response, proceed = _call_behavior(rpc_event, state, behavior, + argument, request_deserializer) + if proceed: + serialized_response = _serialize_response( + rpc_event, state, response, response_serializer) + if serialized_response is not None: + _status(rpc_event, state, serialized_response) + finally: + cygrpc.uninstall_context() def _stream_response_in_pool(rpc_event, state, behavior, argument_thunk, request_deserializer, response_serializer): - argument = argument_thunk() - if argument is not None: - response_iterator, proceed = _call_behavior( - rpc_event, state, behavior, argument, request_deserializer) - if proceed: - while True: - response, proceed = _take_response_from_response_iterator( - rpc_event, state, response_iterator) - if proceed: - if response is None: - _status(rpc_event, state, None) - break - else: - serialized_response = _serialize_response( - rpc_event, state, response, response_serializer) - if serialized_response is not None: - proceed = _send_response(rpc_event, state, - serialized_response) - if not proceed: - break - else: + cygrpc.install_census_context_from_call(rpc_event.call) + try: + argument = argument_thunk() + if argument is not None: + response_iterator, proceed = _call_behavior( + rpc_event, state, behavior, argument, request_deserializer) + if proceed: + while True: + response, proceed = _take_response_from_response_iterator( + rpc_event, state, response_iterator) + if proceed: + if response is None: + _status(rpc_event, state, None) break - else: - break + else: + serialized_response = _serialize_response( + rpc_event, state, response, response_serializer) + if serialized_response is not None: + proceed = _send_response( + rpc_event, state, serialized_response) + if not proceed: + break + else: + break + else: + break + finally: + cygrpc.uninstall_context() def _handle_unary_unary(rpc_event, state, method_handler, thread_pool): From 3bc323977fb049ac0a10306ec9c964387b204d7c Mon Sep 17 00:00:00 2001 From: Moiz Haidry Date: Tue, 11 Dec 2018 13:12:39 -0800 Subject: [PATCH 71/99] Streaming support for callback server --- test/cpp/qps/server_callback.cc | 46 ++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/test/cpp/qps/server_callback.cc b/test/cpp/qps/server_callback.cc index 8bedd447392..4a346dd0178 100644 --- a/test/cpp/qps/server_callback.cc +++ b/test/cpp/qps/server_callback.cc @@ -34,13 +34,53 @@ class BenchmarkCallbackServiceImpl final : public BenchmarkService::ExperimentalCallbackService { public: void UnaryCall( - ServerContext* context, const SimpleRequest* request, - SimpleResponse* response, - experimental::ServerCallbackRpcController* controller) override { + ServerContext* context, const ::grpc::testing::SimpleRequest* request, + ::grpc::testing::SimpleResponse* response, + ::grpc::experimental::ServerCallbackRpcController* controller) override { auto s = SetResponse(request, response); controller->Finish(s); } + ::grpc::experimental::ServerBidiReactor<::grpc::testing::SimpleRequest, + ::grpc::testing::SimpleResponse>* + StreamingCall() override { + class Reactor + : public ::grpc::experimental::ServerBidiReactor< + ::grpc::testing::SimpleRequest, ::grpc::testing::SimpleResponse> { + public: + Reactor() {} + void OnStarted(ServerContext* context) override { StartRead(&request_); } + + void OnReadDone(bool ok) override { + if (!ok) { + Finish(::grpc::Status::OK); + return; + } + auto s = SetResponse(&request_, &response_); + if (!s.ok()) { + Finish(s); + return; + } + StartWrite(&response_); + } + + void OnWriteDone(bool ok) override { + if (!ok) { + Finish(::grpc::Status::OK); + return; + } + StartRead(&request_); + } + + void OnDone() override { delete (this); } + + private: + SimpleRequest request_; + SimpleResponse response_; + }; + return new Reactor; + } + private: static Status SetResponse(const SimpleRequest* request, SimpleResponse* response) { From 62027b7e14624283f758a7785a0a1347eda0a147 Mon Sep 17 00:00:00 2001 From: Vishal Powar Date: Fri, 30 Nov 2018 14:27:52 -0800 Subject: [PATCH 72/99] Changes add a script for generating C code and build rule for protobuf protos All these changes need to go together to make sense - changes to use new version of upb in bazel - allowing includes in build target option - script for generating c code for protos - generated code for example build - adding changes for non-bazel builds - change sanity tests to ignore the generated files. --- BUILD | 25 + CMakeLists.txt | 53 + Makefile | 38 +- bazel/grpc_build_system.bzl | 1 + bazel/grpc_deps.bzl | 6 +- build.yaml | 2 + grpc.gyp | 19 + .../upb-generated/google/protobuf/any.upb.c | 24 + .../upb-generated/google/protobuf/any.upb.h | 63 + .../google/protobuf/descriptor.upb.c | 549 +++++ .../google/protobuf/descriptor.upb.h | 1879 +++++++++++++++++ .../google/protobuf/duration.upb.c | 24 + .../google/protobuf/duration.upb.h | 65 + .../google/protobuf/struct.upb.c | 88 + .../google/protobuf/struct.upb.h | 226 ++ .../google/protobuf/timestamp.upb.c | 24 + .../google/protobuf/timestamp.upb.h | 65 + .../google/protobuf/wrappers.upb.c | 87 + .../google/protobuf/wrappers.upb.h | 305 +++ src/upb/gen_build_yaml.py | 69 + tools/buildgen/generate_build_additions.sh | 1 + tools/codegen/core/gen_upb_api.sh | 38 + tools/distrib/check_copyright.py | 14 + tools/distrib/check_include_guards.py | 14 + .../generated/sources_and_headers.json | 21 + tools/run_tests/sanity/check_port_platform.py | 3 + 26 files changed, 3699 insertions(+), 4 deletions(-) create mode 100644 src/core/ext/upb-generated/google/protobuf/any.upb.c create mode 100644 src/core/ext/upb-generated/google/protobuf/any.upb.h create mode 100644 src/core/ext/upb-generated/google/protobuf/descriptor.upb.c create mode 100644 src/core/ext/upb-generated/google/protobuf/descriptor.upb.h create mode 100644 src/core/ext/upb-generated/google/protobuf/duration.upb.c create mode 100644 src/core/ext/upb-generated/google/protobuf/duration.upb.h create mode 100644 src/core/ext/upb-generated/google/protobuf/struct.upb.c create mode 100644 src/core/ext/upb-generated/google/protobuf/struct.upb.h create mode 100644 src/core/ext/upb-generated/google/protobuf/timestamp.upb.c create mode 100644 src/core/ext/upb-generated/google/protobuf/timestamp.upb.h create mode 100644 src/core/ext/upb-generated/google/protobuf/wrappers.upb.c create mode 100644 src/core/ext/upb-generated/google/protobuf/wrappers.upb.h create mode 100755 src/upb/gen_build_yaml.py create mode 100755 tools/codegen/core/gen_upb_api.sh diff --git a/BUILD b/BUILD index 9a2c16c6012..0d789ae7c00 100644 --- a/BUILD +++ b/BUILD @@ -2272,4 +2272,29 @@ grpc_cc_library( ], ) +# TODO: Get this into build.yaml once we start using it. +grpc_cc_library( + name = "google_protobuf", + srcs = [ + "src/core/ext/upb-generated/google/protobuf/any.upb.c", + "src/core/ext/upb-generated/google/protobuf/descriptor.upb.c", + "src/core/ext/upb-generated/google/protobuf/duration.upb.c", + "src/core/ext/upb-generated/google/protobuf/struct.upb.c", + "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c", + "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c", + ], + hdrs = [ + "src/core/ext/upb-generated/google/protobuf/any.upb.h", + "src/core/ext/upb-generated/google/protobuf/descriptor.upb.h", + "src/core/ext/upb-generated/google/protobuf/duration.upb.h", + "src/core/ext/upb-generated/google/protobuf/struct.upb.h", + "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h", + "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h", + ], + language = "c++", + external_deps = [ + "upb_lib", + ], +) + grpc_generate_one_off_targets() diff --git a/CMakeLists.txt b/CMakeLists.txt index 1194d0072e3..a9562960920 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5476,6 +5476,59 @@ endif() endif (gRPC_BUILD_CSHARP_EXT) if (gRPC_BUILD_TESTS) +add_library(upb + third_party/upb/google/protobuf/descriptor.upb.c + third_party/upb/upb/decode.c + third_party/upb/upb/def.c + third_party/upb/upb/encode.c + third_party/upb/upb/handlers.c + third_party/upb/upb/msg.c + third_party/upb/upb/msgfactory.c + third_party/upb/upb/refcounted.c + third_party/upb/upb/sink.c + third_party/upb/upb/table.c + third_party/upb/upb/upb.c +) + +if(WIN32 AND MSVC) + set_target_properties(upb PROPERTIES COMPILE_PDB_NAME "upb" + COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ) + if (gRPC_INSTALL) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/upb.pdb + DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL + ) + endif() +endif() + + +target_include_directories(upb + PUBLIC $ $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} +) + # avoid dependency on libstdc++ + if (_gRPC_CORE_NOSTDCXX_FLAGS) + set_target_properties(upb PROPERTIES LINKER_LANGUAGE C) + # only use the flags for C++ source files + target_compile_options(upb PRIVATE $<$:${_gRPC_CORE_NOSTDCXX_FLAGS}>) + endif() +target_link_libraries(upb + ${_gRPC_SSL_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} +) + + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_library(bad_client_test test/core/bad_client/bad_client.cc ) diff --git a/Makefile b/Makefile index 7dfce79c922..e1ae7e7ad61 100644 --- a/Makefile +++ b/Makefile @@ -1411,7 +1411,7 @@ plugins: $(PROTOC_PLUGINS) privatelibs: privatelibs_c privatelibs_cxx -privatelibs_c: $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a +privatelibs_c: $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libupb.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc @@ -10113,6 +10113,42 @@ ifneq ($(NO_DEPS),true) endif +LIBUPB_SRC = \ + third_party/upb/google/protobuf/descriptor.upb.c \ + third_party/upb/upb/decode.c \ + third_party/upb/upb/def.c \ + third_party/upb/upb/encode.c \ + third_party/upb/upb/handlers.c \ + third_party/upb/upb/msg.c \ + third_party/upb/upb/msgfactory.c \ + third_party/upb/upb/refcounted.c \ + third_party/upb/upb/sink.c \ + third_party/upb/upb/table.c \ + third_party/upb/upb/upb.c \ + +PUBLIC_HEADERS_C += \ + +LIBUPB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBUPB_SRC)))) + +$(LIBUPB_OBJS): CFLAGS += -Ithird_party/upb -Wno-sign-conversion -Wno-shadow -Wno-conversion -Wno-implicit-fallthrough + +$(LIBDIR)/$(CONFIG)/libupb.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBUPB_OBJS) + $(E) "[AR] Creating $@" + $(Q) mkdir -p `dirname $@` + $(Q) rm -f $(LIBDIR)/$(CONFIG)/libupb.a + $(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libupb.a $(LIBUPB_OBJS) +ifeq ($(SYSTEM),Darwin) + $(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libupb.a +endif + + + + +ifneq ($(NO_DEPS),true) +-include $(LIBUPB_OBJS:.o=.dep) +endif + + LIBZ_SRC = \ third_party/zlib/adler32.c \ third_party/zlib/compress.c \ diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index 65fe5a10aa2..06b05f79525 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -99,6 +99,7 @@ def grpc_cc_library( linkopts = if_not_windows(["-pthread"]), includes = [ "include", + "src/core/ext/upb-generated", ], alwayslink = alwayslink, data = data, diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl index 3eacd2b0475..2738e39abf7 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -12,7 +12,7 @@ def grpc_deps(): ) native.bind( - name = "upblib", + name = "upb_lib", actual = "@upb//:upb", ) @@ -195,8 +195,8 @@ def grpc_deps(): if "upb" not in native.existing_rules(): http_archive( name = "upb", - strip_prefix = "upb-9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3", - url = "https://github.com/google/upb/archive/9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3.tar.gz", + strip_prefix = "upb-fb6f7e96895c3a9a8ae2e66516160937e7ac1779", + url = "https://github.com/google/upb/archive/fb6f7e96895c3a9a8ae2e66516160937e7ac1779.tar.gz", ) diff --git a/build.yaml b/build.yaml index 41c63d133a9..fa8d65b7606 100644 --- a/build.yaml +++ b/build.yaml @@ -5890,6 +5890,8 @@ defaults: -Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT CXXFLAGS: -Wnon-virtual-dtor LDFLAGS: -g + upb: + CFLAGS: -Ithird_party/upb -Wno-sign-conversion -Wno-shadow -Wno-conversion -Wno-implicit-fallthrough zlib: CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration -Wno-implicit-fallthrough $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden diff --git a/grpc.gyp b/grpc.gyp index 2b841354baf..10277110dd8 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -2638,6 +2638,25 @@ 'third_party/benchmark/src/timers.cc', ], }, + { + 'target_name': 'upb', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/upb/google/protobuf/descriptor.upb.c', + 'third_party/upb/upb/decode.c', + 'third_party/upb/upb/def.c', + 'third_party/upb/upb/encode.c', + 'third_party/upb/upb/handlers.c', + 'third_party/upb/upb/msg.c', + 'third_party/upb/upb/msgfactory.c', + 'third_party/upb/upb/refcounted.c', + 'third_party/upb/upb/sink.c', + 'third_party/upb/upb/table.c', + 'third_party/upb/upb/upb.c', + ], + }, { 'target_name': 'z', 'type': 'static_library', diff --git a/src/core/ext/upb-generated/google/protobuf/any.upb.c b/src/core/ext/upb-generated/google/protobuf/any.upb.c new file mode 100644 index 00000000000..1005a48e909 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/any.upb.c @@ -0,0 +1,24 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/any.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#include "google/protobuf/any.upb.h" +#include +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static const upb_msglayout_field google_protobuf_Any__fields[2] = { + {1, UPB_SIZE(0, 0), 0, 0, 9, 1}, + {2, UPB_SIZE(8, 16), 0, 0, 12, 1}, +}; + +const upb_msglayout google_protobuf_Any_msginit = { + NULL, &google_protobuf_Any__fields[0], UPB_SIZE(16, 32), 2, false, +}; + +#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/any.upb.h b/src/core/ext/upb-generated/google/protobuf/any.upb.h new file mode 100644 index 00000000000..d29265553f7 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/any.upb.h @@ -0,0 +1,63 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/any.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_ANY_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_ANY_PROTO_UPB_H_ + +#include "upb/msg.h" + +#include "upb/decode.h" +#include "upb/encode.h" +#include "upb/port_def.inc" +UPB_BEGIN_EXTERN_C + +struct google_protobuf_Any; +typedef struct google_protobuf_Any google_protobuf_Any; + +/* Enums */ + +/* google.protobuf.Any */ + +extern const upb_msglayout google_protobuf_Any_msginit; +UPB_INLINE google_protobuf_Any* google_protobuf_Any_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_Any_msginit, arena); +} +UPB_INLINE google_protobuf_Any* google_protobuf_Any_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_Any* ret = google_protobuf_Any_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Any_msginit)) ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Any_serialize(const google_protobuf_Any* msg, + upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Any_msginit, arena, len); +} + +UPB_INLINE upb_stringview +google_protobuf_Any_type_url(const google_protobuf_Any* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); +} +UPB_INLINE upb_stringview +google_protobuf_Any_value(const google_protobuf_Any* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} + +UPB_INLINE void google_protobuf_Any_set_type_url(google_protobuf_Any* msg, + upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; +} +UPB_INLINE void google_protobuf_Any_set_value(google_protobuf_Any* msg, + upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} + +UPB_END_EXTERN_C + +#include "upb/port_undef.inc" + +#endif /* GOOGLE_PROTOBUF_ANY_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c new file mode 100644 index 00000000000..f774873d614 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c @@ -0,0 +1,549 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#include "google/protobuf/descriptor.upb.h" +#include +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static const upb_msglayout* const google_protobuf_FileDescriptorSet_submsgs[1] = + { + &google_protobuf_FileDescriptorProto_msginit, +}; + +static const upb_msglayout_field google_protobuf_FileDescriptorSet__fields[1] = + { + {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_FileDescriptorSet_msginit = { + &google_protobuf_FileDescriptorSet_submsgs[0], + &google_protobuf_FileDescriptorSet__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +static const upb_msglayout* const + google_protobuf_FileDescriptorProto_submsgs[6] = { + &google_protobuf_DescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_msginit, + &google_protobuf_FieldDescriptorProto_msginit, + &google_protobuf_FileOptions_msginit, + &google_protobuf_ServiceDescriptorProto_msginit, + &google_protobuf_SourceCodeInfo_msginit, +}; + +static const upb_msglayout_field + google_protobuf_FileDescriptorProto__fields[12] = { + {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, + {2, UPB_SIZE(16, 32), 2, 0, 9, 1}, + {3, UPB_SIZE(40, 80), 0, 0, 9, 3}, + {4, UPB_SIZE(44, 88), 0, 0, 11, 3}, + {5, UPB_SIZE(48, 96), 0, 1, 11, 3}, + {6, UPB_SIZE(52, 104), 0, 4, 11, 3}, + {7, UPB_SIZE(56, 112), 0, 2, 11, 3}, + {8, UPB_SIZE(32, 64), 4, 3, 11, 1}, + {9, UPB_SIZE(36, 72), 5, 5, 11, 1}, + {10, UPB_SIZE(60, 120), 0, 0, 5, 3}, + {11, UPB_SIZE(64, 128), 0, 0, 5, 3}, + {12, UPB_SIZE(24, 48), 3, 0, 9, 1}, +}; + +const upb_msglayout google_protobuf_FileDescriptorProto_msginit = { + &google_protobuf_FileDescriptorProto_submsgs[0], + &google_protobuf_FileDescriptorProto__fields[0], + UPB_SIZE(72, 144), + 12, + false, +}; + +static const upb_msglayout* const google_protobuf_DescriptorProto_submsgs[8] = { + &google_protobuf_DescriptorProto_msginit, + &google_protobuf_DescriptorProto_ExtensionRange_msginit, + &google_protobuf_DescriptorProto_ReservedRange_msginit, + &google_protobuf_EnumDescriptorProto_msginit, + &google_protobuf_FieldDescriptorProto_msginit, + &google_protobuf_MessageOptions_msginit, + &google_protobuf_OneofDescriptorProto_msginit, +}; + +static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, {2, UPB_SIZE(20, 40), 0, 4, 11, 3}, + {3, UPB_SIZE(24, 48), 0, 0, 11, 3}, {4, UPB_SIZE(28, 56), 0, 3, 11, 3}, + {5, UPB_SIZE(32, 64), 0, 1, 11, 3}, {6, UPB_SIZE(36, 72), 0, 4, 11, 3}, + {7, UPB_SIZE(16, 32), 2, 5, 11, 1}, {8, UPB_SIZE(40, 80), 0, 6, 11, 3}, + {9, UPB_SIZE(44, 88), 0, 2, 11, 3}, {10, UPB_SIZE(48, 96), 0, 0, 9, 3}, +}; + +const upb_msglayout google_protobuf_DescriptorProto_msginit = { + &google_protobuf_DescriptorProto_submsgs[0], + &google_protobuf_DescriptorProto__fields[0], + UPB_SIZE(56, 112), + 10, + false, +}; + +static const upb_msglayout* const + google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { + &google_protobuf_ExtensionRangeOptions_msginit, +}; + +static const upb_msglayout_field + google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, + {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, + {3, UPB_SIZE(12, 16), 3, 0, 11, 1}, +}; + +const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit = { + &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], + &google_protobuf_DescriptorProto_ExtensionRange__fields[0], + UPB_SIZE(16, 24), + 3, + false, +}; + +static const upb_msglayout_field + google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, + {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, +}; + +const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit = { + NULL, + &google_protobuf_DescriptorProto_ReservedRange__fields[0], + UPB_SIZE(12, 12), + 2, + false, +}; + +static const upb_msglayout* const + google_protobuf_ExtensionRangeOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field + google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit = { + &google_protobuf_ExtensionRangeOptions_submsgs[0], + &google_protobuf_ExtensionRangeOptions__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +static const upb_msglayout* const + google_protobuf_FieldDescriptorProto_submsgs[1] = { + &google_protobuf_FieldOptions_msginit, +}; + +static const upb_msglayout_field + google_protobuf_FieldDescriptorProto__fields[10] = { + {1, UPB_SIZE(32, 32), 5, 0, 9, 1}, + {2, UPB_SIZE(40, 48), 6, 0, 9, 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(48, 64), 7, 0, 9, 1}, + {7, UPB_SIZE(56, 80), 8, 0, 9, 1}, + {8, UPB_SIZE(72, 112), 10, 0, 11, 1}, + {9, UPB_SIZE(28, 28), 4, 0, 5, 1}, + {10, UPB_SIZE(64, 96), 9, 0, 9, 1}, +}; + +const upb_msglayout google_protobuf_FieldDescriptorProto_msginit = { + &google_protobuf_FieldDescriptorProto_submsgs[0], + &google_protobuf_FieldDescriptorProto__fields[0], + UPB_SIZE(80, 128), + 10, + false, +}; + +static const upb_msglayout* const + google_protobuf_OneofDescriptorProto_submsgs[1] = { + &google_protobuf_OneofOptions_msginit, +}; + +static const upb_msglayout_field + google_protobuf_OneofDescriptorProto__fields[2] = { + {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, + {2, UPB_SIZE(16, 32), 2, 0, 11, 1}, +}; + +const upb_msglayout google_protobuf_OneofDescriptorProto_msginit = { + &google_protobuf_OneofDescriptorProto_submsgs[0], + &google_protobuf_OneofDescriptorProto__fields[0], + UPB_SIZE(24, 48), + 2, + false, +}; + +static const upb_msglayout* const + google_protobuf_EnumDescriptorProto_submsgs[3] = { + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, + &google_protobuf_EnumOptions_msginit, + &google_protobuf_EnumValueDescriptorProto_msginit, +}; + +static const upb_msglayout_field + google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, {2, UPB_SIZE(20, 40), 0, 2, 11, 3}, + {3, UPB_SIZE(16, 32), 2, 1, 11, 1}, {4, UPB_SIZE(24, 48), 0, 0, 11, 3}, + {5, UPB_SIZE(28, 56), 0, 0, 9, 3}, +}; + +const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = { + &google_protobuf_EnumDescriptorProto_submsgs[0], + &google_protobuf_EnumDescriptorProto__fields[0], + UPB_SIZE(32, 64), + 5, + false, +}; + +static const upb_msglayout_field + google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, + {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, +}; + +const upb_msglayout + google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { + NULL, + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], + UPB_SIZE(12, 12), + 2, + false, +}; + +static const upb_msglayout* const + google_protobuf_EnumValueDescriptorProto_submsgs[1] = { + &google_protobuf_EnumValueOptions_msginit, +}; + +static const upb_msglayout_field + google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(8, 16), 2, 0, 9, 1}, + {2, UPB_SIZE(4, 4), 1, 0, 5, 1}, + {3, UPB_SIZE(16, 32), 3, 0, 11, 1}, +}; + +const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit = { + &google_protobuf_EnumValueDescriptorProto_submsgs[0], + &google_protobuf_EnumValueDescriptorProto__fields[0], + UPB_SIZE(24, 48), + 3, + false, +}; + +static const upb_msglayout* const + google_protobuf_ServiceDescriptorProto_submsgs[2] = { + &google_protobuf_MethodDescriptorProto_msginit, + &google_protobuf_ServiceOptions_msginit, +}; + +static const upb_msglayout_field + google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, + {2, UPB_SIZE(20, 40), 0, 0, 11, 3}, + {3, UPB_SIZE(16, 32), 2, 1, 11, 1}, +}; + +const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit = { + &google_protobuf_ServiceDescriptorProto_submsgs[0], + &google_protobuf_ServiceDescriptorProto__fields[0], + UPB_SIZE(24, 48), + 3, + false, +}; + +static const upb_msglayout* const + google_protobuf_MethodDescriptorProto_submsgs[1] = { + &google_protobuf_MethodOptions_msginit, +}; + +static const upb_msglayout_field + google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(8, 16), 3, 0, 9, 1}, {2, UPB_SIZE(16, 32), 4, 0, 9, 1}, + {3, UPB_SIZE(24, 48), 5, 0, 9, 1}, {4, UPB_SIZE(32, 64), 6, 0, 11, 1}, + {5, UPB_SIZE(1, 1), 1, 0, 8, 1}, {6, UPB_SIZE(2, 2), 2, 0, 8, 1}, +}; + +const upb_msglayout google_protobuf_MethodDescriptorProto_msginit = { + &google_protobuf_MethodDescriptorProto_submsgs[0], + &google_protobuf_MethodDescriptorProto__fields[0], + UPB_SIZE(40, 80), + 6, + false, +}; + +static const upb_msglayout* const google_protobuf_FileOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { + {1, UPB_SIZE(32, 32), 11, 0, 9, 1}, + {8, UPB_SIZE(40, 48), 12, 0, 9, 1}, + {9, UPB_SIZE(8, 8), 1, 0, 14, 1}, + {10, UPB_SIZE(16, 16), 2, 0, 8, 1}, + {11, UPB_SIZE(48, 64), 13, 0, 9, 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}, + {20, UPB_SIZE(20, 20), 6, 0, 8, 1}, + {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(56, 80), 14, 0, 9, 1}, + {37, UPB_SIZE(64, 96), 15, 0, 9, 1}, + {39, UPB_SIZE(72, 112), 16, 0, 9, 1}, + {40, UPB_SIZE(80, 128), 17, 0, 9, 1}, + {41, UPB_SIZE(88, 144), 18, 0, 9, 1}, + {42, UPB_SIZE(24, 24), 10, 0, 8, 1}, + {44, UPB_SIZE(96, 160), 19, 0, 9, 1}, + {45, UPB_SIZE(104, 176), 20, 0, 9, 1}, + {999, UPB_SIZE(112, 192), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_FileOptions_msginit = { + &google_protobuf_FileOptions_submsgs[0], + &google_protobuf_FileOptions__fields[0], + UPB_SIZE(120, 208), + 21, + false, +}; + +static const upb_msglayout* const google_protobuf_MessageOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_MessageOptions__fields[5] = { + {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, {2, UPB_SIZE(2, 2), 2, 0, 8, 1}, + {3, UPB_SIZE(3, 3), 3, 0, 8, 1}, {7, UPB_SIZE(4, 4), 4, 0, 8, 1}, + {999, UPB_SIZE(8, 8), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_MessageOptions_msginit = { + &google_protobuf_MessageOptions_submsgs[0], + &google_protobuf_MessageOptions__fields[0], + UPB_SIZE(12, 16), + 5, + false, +}; + +static const upb_msglayout* const google_protobuf_FieldOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_FieldOptions__fields[7] = { + {1, UPB_SIZE(8, 8), 1, 0, 14, 1}, {2, UPB_SIZE(24, 24), 3, 0, 8, 1}, + {3, UPB_SIZE(25, 25), 4, 0, 8, 1}, {5, UPB_SIZE(26, 26), 5, 0, 8, 1}, + {6, UPB_SIZE(16, 16), 2, 0, 14, 1}, {10, UPB_SIZE(27, 27), 6, 0, 8, 1}, + {999, UPB_SIZE(28, 32), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_FieldOptions_msginit = { + &google_protobuf_FieldOptions_submsgs[0], + &google_protobuf_FieldOptions__fields[0], + UPB_SIZE(32, 40), + 7, + false, +}; + +static const upb_msglayout* const google_protobuf_OneofOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_OneofOptions__fields[1] = { + {999, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_OneofOptions_msginit = { + &google_protobuf_OneofOptions_submsgs[0], + &google_protobuf_OneofOptions__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +static const upb_msglayout* const google_protobuf_EnumOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_EnumOptions__fields[3] = { + {2, UPB_SIZE(1, 1), 1, 0, 8, 1}, + {3, UPB_SIZE(2, 2), 2, 0, 8, 1}, + {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_EnumOptions_msginit = { + &google_protobuf_EnumOptions_submsgs[0], + &google_protobuf_EnumOptions__fields[0], + UPB_SIZE(8, 16), + 3, + false, +}; + +static const upb_msglayout* const google_protobuf_EnumValueOptions_submsgs[1] = + { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_EnumValueOptions__fields[2] = { + {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, + {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_EnumValueOptions_msginit = { + &google_protobuf_EnumValueOptions_submsgs[0], + &google_protobuf_EnumValueOptions__fields[0], + UPB_SIZE(8, 16), + 2, + false, +}; + +static const upb_msglayout* const google_protobuf_ServiceOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_ServiceOptions__fields[2] = { + {33, UPB_SIZE(1, 1), 1, 0, 8, 1}, + {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_ServiceOptions_msginit = { + &google_protobuf_ServiceOptions_submsgs[0], + &google_protobuf_ServiceOptions__fields[0], + UPB_SIZE(8, 16), + 2, + false, +}; + +static const upb_msglayout* const google_protobuf_MethodOptions_submsgs[1] = { + &google_protobuf_UninterpretedOption_msginit, +}; + +static const upb_msglayout_field google_protobuf_MethodOptions__fields[3] = { + {33, UPB_SIZE(16, 16), 2, 0, 8, 1}, + {34, UPB_SIZE(8, 8), 1, 0, 14, 1}, + {999, UPB_SIZE(20, 24), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_MethodOptions_msginit = { + &google_protobuf_MethodOptions_submsgs[0], + &google_protobuf_MethodOptions__fields[0], + UPB_SIZE(24, 32), + 3, + false, +}; + +static const upb_msglayout* const + google_protobuf_UninterpretedOption_submsgs[1] = { + &google_protobuf_UninterpretedOption_NamePart_msginit, +}; + +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}, + {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}, +}; + +const upb_msglayout google_protobuf_UninterpretedOption_msginit = { + &google_protobuf_UninterpretedOption_submsgs[0], + &google_protobuf_UninterpretedOption__fields[0], + UPB_SIZE(64, 96), + 7, + false, +}; + +static const upb_msglayout_field + google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(8, 16), 2, 0, 9, 2}, + {2, UPB_SIZE(1, 1), 1, 0, 8, 2}, +}; + +const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit = { + NULL, + &google_protobuf_UninterpretedOption_NamePart__fields[0], + UPB_SIZE(16, 32), + 2, + false, +}; + +static const upb_msglayout* const google_protobuf_SourceCodeInfo_submsgs[1] = { + &google_protobuf_SourceCodeInfo_Location_msginit, +}; + +static const upb_msglayout_field google_protobuf_SourceCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_SourceCodeInfo_msginit = { + &google_protobuf_SourceCodeInfo_submsgs[0], + &google_protobuf_SourceCodeInfo__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +static const upb_msglayout_field + google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(24, 48), 0, 0, 5, 3}, {2, UPB_SIZE(28, 56), 0, 0, 5, 3}, + {3, UPB_SIZE(8, 16), 1, 0, 9, 1}, {4, UPB_SIZE(16, 32), 2, 0, 9, 1}, + {6, UPB_SIZE(32, 64), 0, 0, 9, 3}, +}; + +const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = { + NULL, + &google_protobuf_SourceCodeInfo_Location__fields[0], + UPB_SIZE(40, 80), + 5, + false, +}; + +static const upb_msglayout* const google_protobuf_GeneratedCodeInfo_submsgs[1] = + { + &google_protobuf_GeneratedCodeInfo_Annotation_msginit, +}; + +static const upb_msglayout_field google_protobuf_GeneratedCodeInfo__fields[1] = + { + {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = { + &google_protobuf_GeneratedCodeInfo_submsgs[0], + &google_protobuf_GeneratedCodeInfo__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +static const upb_msglayout_field + google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { + {1, UPB_SIZE(24, 32), 0, 0, 5, 3}, + {2, UPB_SIZE(16, 16), 3, 0, 9, 1}, + {3, UPB_SIZE(4, 4), 1, 0, 5, 1}, + {4, UPB_SIZE(8, 8), 2, 0, 5, 1}, +}; + +const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = { + NULL, + &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], + UPB_SIZE(32, 48), + 4, + false, +}; + +#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h new file mode 100644 index 00000000000..37f0139ce32 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h @@ -0,0 +1,1879 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ + +#include "upb/msg.h" + +#include "upb/decode.h" +#include "upb/encode.h" +#include "upb/port_def.inc" +UPB_BEGIN_EXTERN_C + +struct google_protobuf_FileDescriptorSet; +struct google_protobuf_FileDescriptorProto; +struct google_protobuf_DescriptorProto; +struct google_protobuf_DescriptorProto_ExtensionRange; +struct google_protobuf_DescriptorProto_ReservedRange; +struct google_protobuf_ExtensionRangeOptions; +struct google_protobuf_FieldDescriptorProto; +struct google_protobuf_OneofDescriptorProto; +struct google_protobuf_EnumDescriptorProto; +struct google_protobuf_EnumDescriptorProto_EnumReservedRange; +struct google_protobuf_EnumValueDescriptorProto; +struct google_protobuf_ServiceDescriptorProto; +struct google_protobuf_MethodDescriptorProto; +struct google_protobuf_FileOptions; +struct google_protobuf_MessageOptions; +struct google_protobuf_FieldOptions; +struct google_protobuf_OneofOptions; +struct google_protobuf_EnumOptions; +struct google_protobuf_EnumValueOptions; +struct google_protobuf_ServiceOptions; +struct google_protobuf_MethodOptions; +struct google_protobuf_UninterpretedOption; +struct google_protobuf_UninterpretedOption_NamePart; +struct google_protobuf_SourceCodeInfo; +struct google_protobuf_SourceCodeInfo_Location; +struct google_protobuf_GeneratedCodeInfo; +struct google_protobuf_GeneratedCodeInfo_Annotation; +typedef struct google_protobuf_FileDescriptorSet + google_protobuf_FileDescriptorSet; +typedef struct google_protobuf_FileDescriptorProto + google_protobuf_FileDescriptorProto; +typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; +typedef struct google_protobuf_DescriptorProto_ExtensionRange + google_protobuf_DescriptorProto_ExtensionRange; +typedef struct google_protobuf_DescriptorProto_ReservedRange + google_protobuf_DescriptorProto_ReservedRange; +typedef struct google_protobuf_ExtensionRangeOptions + google_protobuf_ExtensionRangeOptions; +typedef struct google_protobuf_FieldDescriptorProto + google_protobuf_FieldDescriptorProto; +typedef struct google_protobuf_OneofDescriptorProto + google_protobuf_OneofDescriptorProto; +typedef struct google_protobuf_EnumDescriptorProto + google_protobuf_EnumDescriptorProto; +typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange + google_protobuf_EnumDescriptorProto_EnumReservedRange; +typedef struct google_protobuf_EnumValueDescriptorProto + google_protobuf_EnumValueDescriptorProto; +typedef struct google_protobuf_ServiceDescriptorProto + google_protobuf_ServiceDescriptorProto; +typedef struct google_protobuf_MethodDescriptorProto + google_protobuf_MethodDescriptorProto; +typedef struct google_protobuf_FileOptions google_protobuf_FileOptions; +typedef struct google_protobuf_MessageOptions google_protobuf_MessageOptions; +typedef struct google_protobuf_FieldOptions google_protobuf_FieldOptions; +typedef struct google_protobuf_OneofOptions google_protobuf_OneofOptions; +typedef struct google_protobuf_EnumOptions google_protobuf_EnumOptions; +typedef struct google_protobuf_EnumValueOptions + google_protobuf_EnumValueOptions; +typedef struct google_protobuf_ServiceOptions google_protobuf_ServiceOptions; +typedef struct google_protobuf_MethodOptions google_protobuf_MethodOptions; +typedef struct google_protobuf_UninterpretedOption + google_protobuf_UninterpretedOption; +typedef struct google_protobuf_UninterpretedOption_NamePart + google_protobuf_UninterpretedOption_NamePart; +typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo; +typedef struct google_protobuf_SourceCodeInfo_Location + google_protobuf_SourceCodeInfo_Location; +typedef struct google_protobuf_GeneratedCodeInfo + google_protobuf_GeneratedCodeInfo; +typedef struct google_protobuf_GeneratedCodeInfo_Annotation + google_protobuf_GeneratedCodeInfo_Annotation; + +/* Enums */ + +typedef enum { + google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, + google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, + google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 +} google_protobuf_FieldDescriptorProto_Label; + +typedef enum { + google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, + google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, + google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, + google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, + google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, + google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, + google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, + google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, + google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, + google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, + google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, + google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, + google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, + google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, + google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, + google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 +} google_protobuf_FieldDescriptorProto_Type; + +typedef enum { + google_protobuf_FieldOptions_STRING = 0, + google_protobuf_FieldOptions_CORD = 1, + google_protobuf_FieldOptions_STRING_PIECE = 2 +} google_protobuf_FieldOptions_CType; + +typedef enum { + google_protobuf_FieldOptions_JS_NORMAL = 0, + google_protobuf_FieldOptions_JS_STRING = 1, + google_protobuf_FieldOptions_JS_NUMBER = 2 +} google_protobuf_FieldOptions_JSType; + +typedef enum { + google_protobuf_FileOptions_SPEED = 1, + google_protobuf_FileOptions_CODE_SIZE = 2, + google_protobuf_FileOptions_LITE_RUNTIME = 3 +} google_protobuf_FileOptions_OptimizeMode; + +typedef enum { + google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, + google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, + google_protobuf_MethodOptions_IDEMPOTENT = 2 +} google_protobuf_MethodOptions_IdempotencyLevel; + +/* google.protobuf.FileDescriptorSet */ + +extern const upb_msglayout google_protobuf_FileDescriptorSet_msginit; +UPB_INLINE google_protobuf_FileDescriptorSet* +google_protobuf_FileDescriptorSet_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_FileDescriptorSet_msginit, arena); +} +UPB_INLINE google_protobuf_FileDescriptorSet* +google_protobuf_FileDescriptorSet_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_FileDescriptorSet* ret = + google_protobuf_FileDescriptorSet_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_FileDescriptorSet_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize( + const google_protobuf_FileDescriptorSet* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_FileDescriptorSet_msginit, arena, + len); +} + +UPB_INLINE const upb_array* google_protobuf_FileDescriptorSet_file( + const google_protobuf_FileDescriptorSet* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_FileDescriptorSet_set_file( + google_protobuf_FileDescriptorSet* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.FileDescriptorProto */ + +extern const upb_msglayout google_protobuf_FileDescriptorProto_msginit; +UPB_INLINE google_protobuf_FileDescriptorProto* +google_protobuf_FileDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_FileDescriptorProto* +google_protobuf_FileDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_FileDescriptorProto* ret = + google_protobuf_FileDescriptorProto_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_FileDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize( + const google_protobuf_FileDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_FileDescriptorProto_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_FileDescriptorProto_name( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE upb_stringview google_protobuf_FileDescriptorProto_package( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)); +} +UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_dependency( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(40, 80)); +} +UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_message_type( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(44, 88)); +} +UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_enum_type( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(48, 96)); +} +UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_service( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(52, 104)); +} +UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_extension( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(56, 112)); +} +UPB_INLINE const google_protobuf_FileOptions* +google_protobuf_FileDescriptorProto_options( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_FileOptions*, + UPB_SIZE(32, 64)); +} +UPB_INLINE const google_protobuf_SourceCodeInfo* +google_protobuf_FileDescriptorProto_source_code_info( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_SourceCodeInfo*, + UPB_SIZE(36, 72)); +} +UPB_INLINE const upb_array* +google_protobuf_FileDescriptorProto_public_dependency( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(60, 120)); +} +UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_weak_dependency( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(64, 128)); +} +UPB_INLINE upb_stringview google_protobuf_FileDescriptorProto_syntax( + const google_protobuf_FileDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)); +} + +UPB_INLINE void google_protobuf_FileDescriptorProto_set_name( + google_protobuf_FileDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_package( + google_protobuf_FileDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_dependency( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(40, 80)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_message_type( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(44, 88)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_enum_type( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(48, 96)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_service( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(52, 104)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_extension( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(56, 112)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_options( + google_protobuf_FileDescriptorProto* msg, + google_protobuf_FileOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_FileOptions*, UPB_SIZE(32, 64)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info( + google_protobuf_FileDescriptorProto* msg, + google_protobuf_SourceCodeInfo* value) { + UPB_FIELD_AT(msg, google_protobuf_SourceCodeInfo*, UPB_SIZE(36, 72)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_public_dependency( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(60, 120)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_weak_dependency( + google_protobuf_FileDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(64, 128)) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax( + google_protobuf_FileDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)) = value; +} + +/* google.protobuf.DescriptorProto */ + +extern const upb_msglayout google_protobuf_DescriptorProto_msginit; +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_DescriptorProto* +google_protobuf_DescriptorProto_parsenew(upb_stringview buf, upb_arena* arena) { + google_protobuf_DescriptorProto* ret = + google_protobuf_DescriptorProto_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_DescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_DescriptorProto_serialize( + const google_protobuf_DescriptorProto* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_DescriptorProto_msginit, arena, len); +} + +UPB_INLINE upb_stringview google_protobuf_DescriptorProto_name( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_field( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 40)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_nested_type( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 48)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_enum_type( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 56)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_extension_range( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(32, 64)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_extension( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(36, 72)); +} +UPB_INLINE const google_protobuf_MessageOptions* +google_protobuf_DescriptorProto_options( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_MessageOptions*, + UPB_SIZE(16, 32)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_oneof_decl( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(40, 80)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_reserved_range( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(44, 88)); +} +UPB_INLINE const upb_array* google_protobuf_DescriptorProto_reserved_name( + const google_protobuf_DescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(48, 96)); +} + +UPB_INLINE void google_protobuf_DescriptorProto_set_name( + google_protobuf_DescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_field( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 40)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_nested_type( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 48)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_enum_type( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 56)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_extension_range( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(32, 64)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_extension( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(36, 72)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_options( + google_protobuf_DescriptorProto* msg, + google_protobuf_MessageOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_MessageOptions*, UPB_SIZE(16, 32)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_oneof_decl( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(40, 80)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_reserved_range( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(44, 88)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_reserved_name( + google_protobuf_DescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(48, 96)) = value; +} + +/* google.protobuf.DescriptorProto.ExtensionRange */ + +extern const upb_msglayout + google_protobuf_DescriptorProto_ExtensionRange_msginit; +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* +google_protobuf_DescriptorProto_ExtensionRange_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, + arena); +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* +google_protobuf_DescriptorProto_ExtensionRange_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_DescriptorProto_ExtensionRange* ret = + google_protobuf_DescriptorProto_ExtensionRange_new(arena); + return (ret && + upb_decode(buf, ret, + &google_protobuf_DescriptorProto_ExtensionRange_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize( + const google_protobuf_DescriptorProto_ExtensionRange* msg, upb_arena* arena, + size_t* len) { + return upb_encode( + msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena, len); +} + +UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start( + const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end( + const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); +} +UPB_INLINE const google_protobuf_ExtensionRangeOptions* +google_protobuf_DescriptorProto_ExtensionRange_options( + const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_ExtensionRangeOptions*, + UPB_SIZE(12, 16)); +} + +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start( + google_protobuf_DescriptorProto_ExtensionRange* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end( + google_protobuf_DescriptorProto_ExtensionRange* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options( + google_protobuf_DescriptorProto_ExtensionRange* msg, + google_protobuf_ExtensionRangeOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_ExtensionRangeOptions*, UPB_SIZE(12, 16)) = + value; +} + +/* google.protobuf.DescriptorProto.ReservedRange */ + +extern const upb_msglayout + google_protobuf_DescriptorProto_ReservedRange_msginit; +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* +google_protobuf_DescriptorProto_ReservedRange_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, + arena); +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* +google_protobuf_DescriptorProto_ReservedRange_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_DescriptorProto_ReservedRange* ret = + google_protobuf_DescriptorProto_ReservedRange_new(arena); + return (ret && + upb_decode(buf, ret, + &google_protobuf_DescriptorProto_ReservedRange_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize( + const google_protobuf_DescriptorProto_ReservedRange* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, + arena, len); +} + +UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start( + const google_protobuf_DescriptorProto_ReservedRange* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end( + const google_protobuf_DescriptorProto_ReservedRange* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); +} + +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start( + google_protobuf_DescriptorProto_ReservedRange* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end( + google_protobuf_DescriptorProto_ReservedRange* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; +} + +/* google.protobuf.ExtensionRangeOptions */ + +extern const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit; +UPB_INLINE google_protobuf_ExtensionRangeOptions* +google_protobuf_ExtensionRangeOptions_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); +} +UPB_INLINE google_protobuf_ExtensionRangeOptions* +google_protobuf_ExtensionRangeOptions_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_ExtensionRangeOptions* ret = + google_protobuf_ExtensionRangeOptions_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_ExtensionRangeOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize( + const google_protobuf_ExtensionRangeOptions* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, arena, + len); +} + +UPB_INLINE const upb_array* +google_protobuf_ExtensionRangeOptions_uninterpreted_option( + const google_protobuf_ExtensionRangeOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_ExtensionRangeOptions_set_uninterpreted_option( + google_protobuf_ExtensionRangeOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.FieldDescriptorProto */ + +extern const upb_msglayout google_protobuf_FieldDescriptorProto_msginit; +UPB_INLINE google_protobuf_FieldDescriptorProto* +google_protobuf_FieldDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_FieldDescriptorProto* +google_protobuf_FieldDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_FieldDescriptorProto* ret = + google_protobuf_FieldDescriptorProto_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_FieldDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize( + const google_protobuf_FieldDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_FieldDescriptorProto_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_name( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)); +} +UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_extendee( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(24, 24)); +} +UPB_INLINE google_protobuf_FieldDescriptorProto_Label +google_protobuf_FieldDescriptorProto_label( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Label, + UPB_SIZE(8, 8)); +} +UPB_INLINE google_protobuf_FieldDescriptorProto_Type +google_protobuf_FieldDescriptorProto_type( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Type, + UPB_SIZE(16, 16)); +} +UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_type_name( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)); +} +UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_default_value( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)); +} +UPB_INLINE const google_protobuf_FieldOptions* +google_protobuf_FieldDescriptorProto_options( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_FieldOptions*, + UPB_SIZE(72, 112)); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(28, 28)); +} +UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_json_name( + const google_protobuf_FieldDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)); +} + +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name( + google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee( + google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number( + google_protobuf_FieldDescriptorProto* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(24, 24)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label( + google_protobuf_FieldDescriptorProto* msg, + google_protobuf_FieldDescriptorProto_Label value) { + UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Label, + UPB_SIZE(8, 8)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type( + google_protobuf_FieldDescriptorProto* msg, + google_protobuf_FieldDescriptorProto_Type value) { + UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Type, + UPB_SIZE(16, 16)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name( + google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value( + google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options( + google_protobuf_FieldDescriptorProto* msg, + google_protobuf_FieldOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_FieldOptions*, UPB_SIZE(72, 112)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index( + google_protobuf_FieldDescriptorProto* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(28, 28)) = value; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name( + google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)) = value; +} + +/* google.protobuf.OneofDescriptorProto */ + +extern const upb_msglayout google_protobuf_OneofDescriptorProto_msginit; +UPB_INLINE google_protobuf_OneofDescriptorProto* +google_protobuf_OneofDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_OneofDescriptorProto* +google_protobuf_OneofDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_OneofDescriptorProto* ret = + google_protobuf_OneofDescriptorProto_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_OneofDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize( + const google_protobuf_OneofDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_OneofDescriptorProto_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_OneofDescriptorProto_name( + const google_protobuf_OneofDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE const google_protobuf_OneofOptions* +google_protobuf_OneofDescriptorProto_options( + const google_protobuf_OneofDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_OneofOptions*, + UPB_SIZE(16, 32)); +} + +UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name( + google_protobuf_OneofDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options( + google_protobuf_OneofDescriptorProto* msg, + google_protobuf_OneofOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_OneofOptions*, UPB_SIZE(16, 32)) = value; +} + +/* google.protobuf.EnumDescriptorProto */ + +extern const upb_msglayout google_protobuf_EnumDescriptorProto_msginit; +UPB_INLINE google_protobuf_EnumDescriptorProto* +google_protobuf_EnumDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_EnumDescriptorProto* +google_protobuf_EnumDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_EnumDescriptorProto* ret = + google_protobuf_EnumDescriptorProto_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_EnumDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize( + const google_protobuf_EnumDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_EnumDescriptorProto_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_EnumDescriptorProto_name( + const google_protobuf_EnumDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE const upb_array* google_protobuf_EnumDescriptorProto_value( + const google_protobuf_EnumDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_EnumOptions* +google_protobuf_EnumDescriptorProto_options( + const google_protobuf_EnumDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_EnumOptions*, + UPB_SIZE(16, 32)); +} +UPB_INLINE const upb_array* google_protobuf_EnumDescriptorProto_reserved_range( + const google_protobuf_EnumDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 48)); +} +UPB_INLINE const upb_array* google_protobuf_EnumDescriptorProto_reserved_name( + const google_protobuf_EnumDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 56)); +} + +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name( + google_protobuf_EnumDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_value( + google_protobuf_EnumDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 40)) = value; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options( + google_protobuf_EnumDescriptorProto* msg, + google_protobuf_EnumOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_EnumOptions*, UPB_SIZE(16, 32)) = value; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_reserved_range( + google_protobuf_EnumDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 48)) = value; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_reserved_name( + google_protobuf_EnumDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 56)) = value; +} + +/* google.protobuf.EnumDescriptorProto.EnumReservedRange */ + +extern const upb_msglayout + google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit; +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* +google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_arena* arena) { + return upb_msg_new( + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* +google_protobuf_EnumDescriptorProto_EnumReservedRange_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = + google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); + return (ret && + upb_decode( + buf, ret, + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* +google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize( + const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, + upb_arena* arena, size_t* len) { + return upb_encode( + msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, + arena, len); +} + +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start( + const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); +} +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end( + const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); +} + +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start( + google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end( + google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; +} + +/* google.protobuf.EnumValueDescriptorProto */ + +extern const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit; +UPB_INLINE google_protobuf_EnumValueDescriptorProto* +google_protobuf_EnumValueDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto* +google_protobuf_EnumValueDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_EnumValueDescriptorProto* ret = + google_protobuf_EnumValueDescriptorProto_new(arena); + return (ret && upb_decode(buf, ret, + &google_protobuf_EnumValueDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize( + const google_protobuf_EnumValueDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, + arena, len); +} + +UPB_INLINE upb_stringview google_protobuf_EnumValueDescriptorProto_name( + const google_protobuf_EnumValueDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number( + const google_protobuf_EnumValueDescriptorProto* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); +} +UPB_INLINE const google_protobuf_EnumValueOptions* +google_protobuf_EnumValueDescriptorProto_options( + const google_protobuf_EnumValueDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_EnumValueOptions*, + UPB_SIZE(16, 32)); +} + +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name( + google_protobuf_EnumValueDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number( + google_protobuf_EnumValueDescriptorProto* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options( + google_protobuf_EnumValueDescriptorProto* msg, + google_protobuf_EnumValueOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_EnumValueOptions*, UPB_SIZE(16, 32)) = + value; +} + +/* google.protobuf.ServiceDescriptorProto */ + +extern const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit; +UPB_INLINE google_protobuf_ServiceDescriptorProto* +google_protobuf_ServiceDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_ServiceDescriptorProto* +google_protobuf_ServiceDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_ServiceDescriptorProto* ret = + google_protobuf_ServiceDescriptorProto_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_ServiceDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize( + const google_protobuf_ServiceDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_ServiceDescriptorProto_name( + const google_protobuf_ServiceDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE const upb_array* google_protobuf_ServiceDescriptorProto_method( + const google_protobuf_ServiceDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_ServiceOptions* +google_protobuf_ServiceDescriptorProto_options( + const google_protobuf_ServiceDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_ServiceOptions*, + UPB_SIZE(16, 32)); +} + +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name( + google_protobuf_ServiceDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_method( + google_protobuf_ServiceDescriptorProto* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 40)) = value; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options( + google_protobuf_ServiceDescriptorProto* msg, + google_protobuf_ServiceOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_ServiceOptions*, UPB_SIZE(16, 32)) = value; +} + +/* google.protobuf.MethodDescriptorProto */ + +extern const upb_msglayout google_protobuf_MethodDescriptorProto_msginit; +UPB_INLINE google_protobuf_MethodDescriptorProto* +google_protobuf_MethodDescriptorProto_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); +} +UPB_INLINE google_protobuf_MethodDescriptorProto* +google_protobuf_MethodDescriptorProto_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_MethodDescriptorProto* ret = + google_protobuf_MethodDescriptorProto_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_MethodDescriptorProto_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize( + const google_protobuf_MethodDescriptorProto* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_MethodDescriptorProto_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_MethodDescriptorProto_name( + const google_protobuf_MethodDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE upb_stringview google_protobuf_MethodDescriptorProto_input_type( + const google_protobuf_MethodDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)); +} +UPB_INLINE upb_stringview google_protobuf_MethodDescriptorProto_output_type( + const google_protobuf_MethodDescriptorProto* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)); +} +UPB_INLINE const google_protobuf_MethodOptions* +google_protobuf_MethodDescriptorProto_options( + const google_protobuf_MethodDescriptorProto* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_MethodOptions*, + UPB_SIZE(32, 64)); +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming( + const google_protobuf_MethodDescriptorProto* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming( + const google_protobuf_MethodDescriptorProto* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)); +} + +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name( + google_protobuf_MethodDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type( + google_protobuf_MethodDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)) = value; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type( + google_protobuf_MethodDescriptorProto* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)) = value; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options( + google_protobuf_MethodDescriptorProto* msg, + google_protobuf_MethodOptions* value) { + UPB_FIELD_AT(msg, google_protobuf_MethodOptions*, UPB_SIZE(32, 64)) = value; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming( + google_protobuf_MethodDescriptorProto* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming( + google_protobuf_MethodDescriptorProto* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)) = value; +} + +/* google.protobuf.FileOptions */ + +extern const upb_msglayout google_protobuf_FileOptions_msginit; +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_FileOptions_msginit, arena); +} +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_FileOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_FileOptions_serialize( + const google_protobuf_FileOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_FileOptions_msginit, arena, len); +} + +UPB_INLINE upb_stringview google_protobuf_FileOptions_java_package( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_java_outer_classname( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)); +} +UPB_INLINE google_protobuf_FileOptions_OptimizeMode +google_protobuf_FileOptions_optimize_for( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, google_protobuf_FileOptions_OptimizeMode, + UPB_SIZE(8, 8)); +} +UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)); +} +UPB_INLINE upb_stringview +google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)); +} +UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(17, 17)); +} +UPB_INLINE bool google_protobuf_FileOptions_java_generic_services( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(18, 18)); +} +UPB_INLINE bool google_protobuf_FileOptions_py_generic_services( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(19, 19)); +} +UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(20, 20)); +} +UPB_INLINE bool google_protobuf_FileOptions_deprecated( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(21, 21)); +} +UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(22, 22)); +} +UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(23, 23)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_objc_class_prefix( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_csharp_namespace( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_swift_prefix( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(72, 112)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_php_class_prefix( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(80, 128)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_php_namespace( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(88, 144)); +} +UPB_INLINE bool google_protobuf_FileOptions_php_generic_services( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_php_metadata_namespace( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(96, 160)); +} +UPB_INLINE upb_stringview google_protobuf_FileOptions_ruby_package( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(104, 176)); +} +UPB_INLINE const upb_array* google_protobuf_FileOptions_uninterpreted_option( + const google_protobuf_FileOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(112, 192)); +} + +UPB_INLINE void google_protobuf_FileOptions_set_java_package( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_optimize_for( + google_protobuf_FileOptions* msg, + google_protobuf_FileOptions_OptimizeMode value) { + UPB_FIELD_AT(msg, google_protobuf_FileOptions_OptimizeMode, UPB_SIZE(8, 8)) = + value; +} +UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_go_package( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(17, 17)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(18, 18)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(19, 19)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(20, 20)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_deprecated( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(21, 21)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(22, 22)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(23, 23)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(72, 112)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(80, 128)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_php_namespace( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(88, 144)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services( + google_protobuf_FileOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(96, 160)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_ruby_package( + google_protobuf_FileOptions* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(104, 176)) = value; +} +UPB_INLINE void google_protobuf_FileOptions_set_uninterpreted_option( + google_protobuf_FileOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(112, 192)) = value; +} + +/* google.protobuf.MessageOptions */ + +extern const upb_msglayout google_protobuf_MessageOptions_msginit; +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); +} +UPB_INLINE google_protobuf_MessageOptions* +google_protobuf_MessageOptions_parsenew(upb_stringview buf, upb_arena* arena) { + google_protobuf_MessageOptions* ret = + google_protobuf_MessageOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_MessageOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_MessageOptions_serialize( + const google_protobuf_MessageOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_MessageOptions_msginit, arena, len); +} + +UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format( + const google_protobuf_MessageOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); +} +UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor( + const google_protobuf_MessageOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)); +} +UPB_INLINE bool google_protobuf_MessageOptions_deprecated( + const google_protobuf_MessageOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(3, 3)); +} +UPB_INLINE bool google_protobuf_MessageOptions_map_entry( + const google_protobuf_MessageOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(4, 4)); +} +UPB_INLINE const upb_array* google_protobuf_MessageOptions_uninterpreted_option( + const google_protobuf_MessageOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(8, 8)); +} + +UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format( + google_protobuf_MessageOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; +} +UPB_INLINE void +google_protobuf_MessageOptions_set_no_standard_descriptor_accessor( + google_protobuf_MessageOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)) = value; +} +UPB_INLINE void google_protobuf_MessageOptions_set_deprecated( + google_protobuf_MessageOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(3, 3)) = value; +} +UPB_INLINE void google_protobuf_MessageOptions_set_map_entry( + google_protobuf_MessageOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(4, 4)) = value; +} +UPB_INLINE void google_protobuf_MessageOptions_set_uninterpreted_option( + google_protobuf_MessageOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(8, 8)) = value; +} + +/* google.protobuf.FieldOptions */ + +extern const upb_msglayout google_protobuf_FieldOptions_msginit; +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); +} +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_FieldOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_FieldOptions_serialize( + const google_protobuf_FieldOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_FieldOptions_msginit, arena, len); +} + +UPB_INLINE google_protobuf_FieldOptions_CType +google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, google_protobuf_FieldOptions_CType, UPB_SIZE(8, 8)); +} +UPB_INLINE bool google_protobuf_FieldOptions_packed( + const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)); +} +UPB_INLINE bool google_protobuf_FieldOptions_deprecated( + const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(25, 25)); +} +UPB_INLINE bool google_protobuf_FieldOptions_lazy( + const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(26, 26)); +} +UPB_INLINE google_protobuf_FieldOptions_JSType +google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, google_protobuf_FieldOptions_JSType, + UPB_SIZE(16, 16)); +} +UPB_INLINE bool google_protobuf_FieldOptions_weak( + const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(27, 27)); +} +UPB_INLINE const upb_array* google_protobuf_FieldOptions_uninterpreted_option( + const google_protobuf_FieldOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 32)); +} + +UPB_INLINE void google_protobuf_FieldOptions_set_ctype( + google_protobuf_FieldOptions* msg, + google_protobuf_FieldOptions_CType value) { + UPB_FIELD_AT(msg, google_protobuf_FieldOptions_CType, UPB_SIZE(8, 8)) = value; +} +UPB_INLINE void google_protobuf_FieldOptions_set_packed( + google_protobuf_FieldOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)) = value; +} +UPB_INLINE void google_protobuf_FieldOptions_set_deprecated( + google_protobuf_FieldOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(25, 25)) = value; +} +UPB_INLINE void google_protobuf_FieldOptions_set_lazy( + google_protobuf_FieldOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(26, 26)) = value; +} +UPB_INLINE void google_protobuf_FieldOptions_set_jstype( + google_protobuf_FieldOptions* msg, + google_protobuf_FieldOptions_JSType value) { + UPB_FIELD_AT(msg, google_protobuf_FieldOptions_JSType, UPB_SIZE(16, 16)) = + value; +} +UPB_INLINE void google_protobuf_FieldOptions_set_weak( + google_protobuf_FieldOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(27, 27)) = value; +} +UPB_INLINE void google_protobuf_FieldOptions_set_uninterpreted_option( + google_protobuf_FieldOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 32)) = value; +} + +/* google.protobuf.OneofOptions */ + +extern const upb_msglayout google_protobuf_OneofOptions_msginit; +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); +} +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_OneofOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_OneofOptions_serialize( + const google_protobuf_OneofOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_OneofOptions_msginit, arena, len); +} + +UPB_INLINE const upb_array* google_protobuf_OneofOptions_uninterpreted_option( + const google_protobuf_OneofOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_OneofOptions_set_uninterpreted_option( + google_protobuf_OneofOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.EnumOptions */ + +extern const upb_msglayout google_protobuf_EnumOptions_msginit; +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); +} +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_EnumOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_EnumOptions_serialize( + const google_protobuf_EnumOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_EnumOptions_msginit, arena, len); +} + +UPB_INLINE bool google_protobuf_EnumOptions_allow_alias( + const google_protobuf_EnumOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); +} +UPB_INLINE bool google_protobuf_EnumOptions_deprecated( + const google_protobuf_EnumOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)); +} +UPB_INLINE const upb_array* google_protobuf_EnumOptions_uninterpreted_option( + const google_protobuf_EnumOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(4, 8)); +} + +UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias( + google_protobuf_EnumOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; +} +UPB_INLINE void google_protobuf_EnumOptions_set_deprecated( + google_protobuf_EnumOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)) = value; +} +UPB_INLINE void google_protobuf_EnumOptions_set_uninterpreted_option( + google_protobuf_EnumOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(4, 8)) = value; +} + +/* google.protobuf.EnumValueOptions */ + +extern const upb_msglayout google_protobuf_EnumValueOptions_msginit; +UPB_INLINE google_protobuf_EnumValueOptions* +google_protobuf_EnumValueOptions_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); +} +UPB_INLINE google_protobuf_EnumValueOptions* +google_protobuf_EnumValueOptions_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_EnumValueOptions* ret = + google_protobuf_EnumValueOptions_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_EnumValueOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_EnumValueOptions_serialize( + const google_protobuf_EnumValueOptions* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_EnumValueOptions_msginit, arena, len); +} + +UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated( + const google_protobuf_EnumValueOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); +} +UPB_INLINE const upb_array* +google_protobuf_EnumValueOptions_uninterpreted_option( + const google_protobuf_EnumValueOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(4, 8)); +} + +UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated( + google_protobuf_EnumValueOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_uninterpreted_option( + google_protobuf_EnumValueOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(4, 8)) = value; +} + +/* google.protobuf.ServiceOptions */ + +extern const upb_msglayout google_protobuf_ServiceOptions_msginit; +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); +} +UPB_INLINE google_protobuf_ServiceOptions* +google_protobuf_ServiceOptions_parsenew(upb_stringview buf, upb_arena* arena) { + google_protobuf_ServiceOptions* ret = + google_protobuf_ServiceOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_ServiceOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_ServiceOptions_serialize( + const google_protobuf_ServiceOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_ServiceOptions_msginit, arena, len); +} + +UPB_INLINE bool google_protobuf_ServiceOptions_deprecated( + const google_protobuf_ServiceOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); +} +UPB_INLINE const upb_array* google_protobuf_ServiceOptions_uninterpreted_option( + const google_protobuf_ServiceOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(4, 8)); +} + +UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated( + google_protobuf_ServiceOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; +} +UPB_INLINE void google_protobuf_ServiceOptions_set_uninterpreted_option( + google_protobuf_ServiceOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(4, 8)) = value; +} + +/* google.protobuf.MethodOptions */ + +extern const upb_msglayout google_protobuf_MethodOptions_msginit; +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); +} +UPB_INLINE google_protobuf_MethodOptions* +google_protobuf_MethodOptions_parsenew(upb_stringview buf, upb_arena* arena) { + google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_MethodOptions_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_MethodOptions_serialize( + const google_protobuf_MethodOptions* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_MethodOptions_msginit, arena, len); +} + +UPB_INLINE bool google_protobuf_MethodOptions_deprecated( + const google_protobuf_MethodOptions* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)); +} +UPB_INLINE google_protobuf_MethodOptions_IdempotencyLevel +google_protobuf_MethodOptions_idempotency_level( + const google_protobuf_MethodOptions* msg) { + return UPB_FIELD_AT(msg, google_protobuf_MethodOptions_IdempotencyLevel, + UPB_SIZE(8, 8)); +} +UPB_INLINE const upb_array* google_protobuf_MethodOptions_uninterpreted_option( + const google_protobuf_MethodOptions* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 24)); +} + +UPB_INLINE void google_protobuf_MethodOptions_set_deprecated( + google_protobuf_MethodOptions* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)) = value; +} +UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level( + google_protobuf_MethodOptions* msg, + google_protobuf_MethodOptions_IdempotencyLevel value) { + UPB_FIELD_AT(msg, google_protobuf_MethodOptions_IdempotencyLevel, + UPB_SIZE(8, 8)) = value; +} +UPB_INLINE void google_protobuf_MethodOptions_set_uninterpreted_option( + google_protobuf_MethodOptions* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 24)) = value; +} + +/* google.protobuf.UninterpretedOption */ + +extern const upb_msglayout google_protobuf_UninterpretedOption_msginit; +UPB_INLINE google_protobuf_UninterpretedOption* +google_protobuf_UninterpretedOption_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); +} +UPB_INLINE google_protobuf_UninterpretedOption* +google_protobuf_UninterpretedOption_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_UninterpretedOption* ret = + google_protobuf_UninterpretedOption_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_UninterpretedOption_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_serialize( + const google_protobuf_UninterpretedOption* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_UninterpretedOption_msginit, arena, + len); +} + +UPB_INLINE const upb_array* google_protobuf_UninterpretedOption_name( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(56, 80)); +} +UPB_INLINE upb_stringview google_protobuf_UninterpretedOption_identifier_value( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)); +} +UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(8, 8)); +} +UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(16, 16)); +} +UPB_INLINE double google_protobuf_UninterpretedOption_double_value( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, double, UPB_SIZE(24, 24)); +} +UPB_INLINE upb_stringview google_protobuf_UninterpretedOption_string_value( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)); +} +UPB_INLINE upb_stringview google_protobuf_UninterpretedOption_aggregate_value( + const google_protobuf_UninterpretedOption* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)); +} + +UPB_INLINE void google_protobuf_UninterpretedOption_set_name( + google_protobuf_UninterpretedOption* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(56, 80)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value( + google_protobuf_UninterpretedOption* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value( + google_protobuf_UninterpretedOption* msg, uint64_t value) { + UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(8, 8)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value( + google_protobuf_UninterpretedOption* msg, int64_t value) { + UPB_FIELD_AT(msg, int64_t, UPB_SIZE(16, 16)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value( + google_protobuf_UninterpretedOption* msg, double value) { + UPB_FIELD_AT(msg, double, UPB_SIZE(24, 24)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value( + google_protobuf_UninterpretedOption* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value( + google_protobuf_UninterpretedOption* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)) = value; +} + +/* google.protobuf.UninterpretedOption.NamePart */ + +extern const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit; +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* +google_protobuf_UninterpretedOption_NamePart_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, + arena); +} +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* +google_protobuf_UninterpretedOption_NamePart_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_UninterpretedOption_NamePart* ret = + google_protobuf_UninterpretedOption_NamePart_new(arena); + return (ret && + upb_decode(buf, ret, + &google_protobuf_UninterpretedOption_NamePart_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize( + const google_protobuf_UninterpretedOption_NamePart* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, + arena, len); +} + +UPB_INLINE upb_stringview +google_protobuf_UninterpretedOption_NamePart_name_part( + const google_protobuf_UninterpretedOption_NamePart* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension( + const google_protobuf_UninterpretedOption_NamePart* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); +} + +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part( + google_protobuf_UninterpretedOption_NamePart* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension( + google_protobuf_UninterpretedOption_NamePart* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; +} + +/* google.protobuf.SourceCodeInfo */ + +extern const upb_msglayout google_protobuf_SourceCodeInfo_msginit; +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo* +google_protobuf_SourceCodeInfo_parsenew(upb_stringview buf, upb_arena* arena) { + google_protobuf_SourceCodeInfo* ret = + google_protobuf_SourceCodeInfo_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_SourceCodeInfo_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize( + const google_protobuf_SourceCodeInfo* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_SourceCodeInfo_msginit, arena, len); +} + +UPB_INLINE const upb_array* google_protobuf_SourceCodeInfo_location( + const google_protobuf_SourceCodeInfo* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_SourceCodeInfo_set_location( + google_protobuf_SourceCodeInfo* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.SourceCodeInfo.Location */ + +extern const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit; +UPB_INLINE google_protobuf_SourceCodeInfo_Location* +google_protobuf_SourceCodeInfo_Location_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* +google_protobuf_SourceCodeInfo_Location_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = + google_protobuf_SourceCodeInfo_Location_new(arena); + return (ret && upb_decode(buf, ret, + &google_protobuf_SourceCodeInfo_Location_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize( + const google_protobuf_SourceCodeInfo_Location* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, + arena, len); +} + +UPB_INLINE const upb_array* google_protobuf_SourceCodeInfo_Location_path( + const google_protobuf_SourceCodeInfo_Location* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 48)); +} +UPB_INLINE const upb_array* google_protobuf_SourceCodeInfo_Location_span( + const google_protobuf_SourceCodeInfo_Location* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 56)); +} +UPB_INLINE upb_stringview +google_protobuf_SourceCodeInfo_Location_leading_comments( + const google_protobuf_SourceCodeInfo_Location* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); +} +UPB_INLINE upb_stringview +google_protobuf_SourceCodeInfo_Location_trailing_comments( + const google_protobuf_SourceCodeInfo_Location* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)); +} +UPB_INLINE const upb_array* +google_protobuf_SourceCodeInfo_Location_leading_detached_comments( + const google_protobuf_SourceCodeInfo_Location* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(32, 64)); +} + +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_path( + google_protobuf_SourceCodeInfo_Location* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 48)) = value; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_span( + google_protobuf_SourceCodeInfo_Location* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 56)) = value; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments( + google_protobuf_SourceCodeInfo_Location* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments( + google_protobuf_SourceCodeInfo_Location* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)) = value; +} +UPB_INLINE void +google_protobuf_SourceCodeInfo_Location_set_leading_detached_comments( + google_protobuf_SourceCodeInfo_Location* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(32, 64)) = value; +} + +/* google.protobuf.GeneratedCodeInfo */ + +extern const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit; +UPB_INLINE google_protobuf_GeneratedCodeInfo* +google_protobuf_GeneratedCodeInfo_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_GeneratedCodeInfo_msginit, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* +google_protobuf_GeneratedCodeInfo_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = + google_protobuf_GeneratedCodeInfo_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_GeneratedCodeInfo_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize( + const google_protobuf_GeneratedCodeInfo* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, arena, + len); +} + +UPB_INLINE const upb_array* google_protobuf_GeneratedCodeInfo_annotation( + const google_protobuf_GeneratedCodeInfo* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_GeneratedCodeInfo_set_annotation( + google_protobuf_GeneratedCodeInfo* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.GeneratedCodeInfo.Annotation */ + +extern const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit; +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* +google_protobuf_GeneratedCodeInfo_Annotation_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, + arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* +google_protobuf_GeneratedCodeInfo_Annotation_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = + google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + return (ret && + upb_decode(buf, ret, + &google_protobuf_GeneratedCodeInfo_Annotation_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize( + const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, + arena, len); +} + +UPB_INLINE const upb_array* google_protobuf_GeneratedCodeInfo_Annotation_path( + const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 32)); +} +UPB_INLINE upb_stringview +google_protobuf_GeneratedCodeInfo_Annotation_source_file( + const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 16)); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin( + const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end( + const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); +} + +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_path( + google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 32)) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file( + google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 16)) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin( + google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end( + google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; +} + +UPB_END_EXTERN_C + +#include "upb/port_undef.inc" + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/duration.upb.c b/src/core/ext/upb-generated/google/protobuf/duration.upb.c new file mode 100644 index 00000000000..b057ce5e4aa --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/duration.upb.c @@ -0,0 +1,24 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/duration.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#include "google/protobuf/duration.upb.h" +#include +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static const upb_msglayout_field google_protobuf_Duration__fields[2] = { + {1, UPB_SIZE(0, 0), 0, 0, 3, 1}, + {2, UPB_SIZE(8, 8), 0, 0, 5, 1}, +}; + +const upb_msglayout google_protobuf_Duration_msginit = { + NULL, &google_protobuf_Duration__fields[0], UPB_SIZE(16, 16), 2, false, +}; + +#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/duration.upb.h b/src/core/ext/upb-generated/google/protobuf/duration.upb.h new file mode 100644 index 00000000000..1f40b3aed24 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/duration.upb.h @@ -0,0 +1,65 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/duration.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_DURATION_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_DURATION_PROTO_UPB_H_ + +#include "upb/msg.h" + +#include "upb/decode.h" +#include "upb/encode.h" +#include "upb/port_def.inc" +UPB_BEGIN_EXTERN_C + +struct google_protobuf_Duration; +typedef struct google_protobuf_Duration google_protobuf_Duration; + +/* Enums */ + +/* google.protobuf.Duration */ + +extern const upb_msglayout google_protobuf_Duration_msginit; +UPB_INLINE google_protobuf_Duration* google_protobuf_Duration_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_Duration_msginit, arena); +} +UPB_INLINE google_protobuf_Duration* google_protobuf_Duration_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_Duration* ret = google_protobuf_Duration_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Duration_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Duration_serialize( + const google_protobuf_Duration* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Duration_msginit, arena, len); +} + +UPB_INLINE int64_t +google_protobuf_Duration_seconds(const google_protobuf_Duration* msg) { + return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)); +} +UPB_INLINE int32_t +google_protobuf_Duration_nanos(const google_protobuf_Duration* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); +} + +UPB_INLINE void google_protobuf_Duration_set_seconds( + google_protobuf_Duration* msg, int64_t value) { + UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)) = value; +} +UPB_INLINE void google_protobuf_Duration_set_nanos( + google_protobuf_Duration* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; +} + +UPB_END_EXTERN_C + +#include "upb/port_undef.inc" + +#endif /* GOOGLE_PROTOBUF_DURATION_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/struct.upb.c b/src/core/ext/upb-generated/google/protobuf/struct.upb.c new file mode 100644 index 00000000000..a0820e722a6 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/struct.upb.c @@ -0,0 +1,88 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/struct.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#include "google/protobuf/struct.upb.h" +#include +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static const upb_msglayout* const google_protobuf_Struct_submsgs[1] = { + &google_protobuf_Struct_FieldsEntry_msginit, +}; + +static const upb_msglayout_field google_protobuf_Struct__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_Struct_msginit = { + &google_protobuf_Struct_submsgs[0], + &google_protobuf_Struct__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +static const upb_msglayout* const + google_protobuf_Struct_FieldsEntry_submsgs[1] = { + &google_protobuf_Value_msginit, +}; + +static const upb_msglayout_field google_protobuf_Struct_FieldsEntry__fields[2] = + { + {1, UPB_SIZE(0, 0), 0, 0, 9, 1}, + {2, UPB_SIZE(8, 16), 0, 0, 11, 1}, +}; + +const upb_msglayout google_protobuf_Struct_FieldsEntry_msginit = { + &google_protobuf_Struct_FieldsEntry_submsgs[0], + &google_protobuf_Struct_FieldsEntry__fields[0], + UPB_SIZE(16, 32), + 2, + false, +}; + +static const upb_msglayout* const google_protobuf_Value_submsgs[2] = { + &google_protobuf_ListValue_msginit, + &google_protobuf_Struct_msginit, +}; + +static const upb_msglayout_field google_protobuf_Value__fields[6] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 14, 1}, + {2, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 1, 1}, + {3, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 9, 1}, + {4, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 8, 1}, + {5, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 1, 11, 1}, + {6, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 11, 1}, +}; + +const upb_msglayout google_protobuf_Value_msginit = { + &google_protobuf_Value_submsgs[0], + &google_protobuf_Value__fields[0], + UPB_SIZE(16, 32), + 6, + false, +}; + +static const upb_msglayout* const google_protobuf_ListValue_submsgs[1] = { + &google_protobuf_Value_msginit, +}; + +static const upb_msglayout_field google_protobuf_ListValue__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, +}; + +const upb_msglayout google_protobuf_ListValue_msginit = { + &google_protobuf_ListValue_submsgs[0], + &google_protobuf_ListValue__fields[0], + UPB_SIZE(4, 8), + 1, + false, +}; + +#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/struct.upb.h b/src/core/ext/upb-generated/google/protobuf/struct.upb.h new file mode 100644 index 00000000000..5493794f0e6 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/struct.upb.h @@ -0,0 +1,226 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/struct.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_STRUCT_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_STRUCT_PROTO_UPB_H_ + +#include "upb/msg.h" + +#include "upb/decode.h" +#include "upb/encode.h" +#include "upb/port_def.inc" +UPB_BEGIN_EXTERN_C + +struct google_protobuf_Struct; +struct google_protobuf_Struct_FieldsEntry; +struct google_protobuf_Value; +struct google_protobuf_ListValue; +typedef struct google_protobuf_Struct google_protobuf_Struct; +typedef struct google_protobuf_Struct_FieldsEntry + google_protobuf_Struct_FieldsEntry; +typedef struct google_protobuf_Value google_protobuf_Value; +typedef struct google_protobuf_ListValue google_protobuf_ListValue; + +/* Enums */ + +typedef enum { google_protobuf_NULL_VALUE = 0 } google_protobuf_NullValue; + +/* google.protobuf.Struct */ + +extern const upb_msglayout google_protobuf_Struct_msginit; +UPB_INLINE google_protobuf_Struct* google_protobuf_Struct_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_Struct_msginit, arena); +} +UPB_INLINE google_protobuf_Struct* google_protobuf_Struct_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_Struct* ret = google_protobuf_Struct_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Struct_msginit)) ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Struct_serialize( + const google_protobuf_Struct* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Struct_msginit, arena, len); +} + +UPB_INLINE const upb_array* google_protobuf_Struct_fields( + const google_protobuf_Struct* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_Struct_set_fields(google_protobuf_Struct* msg, + upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.Struct.FieldsEntry */ + +extern const upb_msglayout google_protobuf_Struct_FieldsEntry_msginit; +UPB_INLINE google_protobuf_Struct_FieldsEntry* +google_protobuf_Struct_FieldsEntry_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_Struct_FieldsEntry_msginit, arena); +} +UPB_INLINE google_protobuf_Struct_FieldsEntry* +google_protobuf_Struct_FieldsEntry_parsenew(upb_stringview buf, + upb_arena* arena) { + google_protobuf_Struct_FieldsEntry* ret = + google_protobuf_Struct_FieldsEntry_new(arena); + return (ret && + upb_decode(buf, ret, &google_protobuf_Struct_FieldsEntry_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Struct_FieldsEntry_serialize( + const google_protobuf_Struct_FieldsEntry* msg, upb_arena* arena, + size_t* len) { + return upb_encode(msg, &google_protobuf_Struct_FieldsEntry_msginit, arena, + len); +} + +UPB_INLINE upb_stringview google_protobuf_Struct_FieldsEntry_key( + const google_protobuf_Struct_FieldsEntry* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_Value* +google_protobuf_Struct_FieldsEntry_value( + const google_protobuf_Struct_FieldsEntry* msg) { + return UPB_FIELD_AT(msg, const google_protobuf_Value*, UPB_SIZE(8, 16)); +} + +UPB_INLINE void google_protobuf_Struct_FieldsEntry_set_key( + google_protobuf_Struct_FieldsEntry* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; +} +UPB_INLINE void google_protobuf_Struct_FieldsEntry_set_value( + google_protobuf_Struct_FieldsEntry* msg, google_protobuf_Value* value) { + UPB_FIELD_AT(msg, google_protobuf_Value*, UPB_SIZE(8, 16)) = value; +} + +/* google.protobuf.Value */ + +extern const upb_msglayout google_protobuf_Value_msginit; +UPB_INLINE google_protobuf_Value* google_protobuf_Value_new(upb_arena* arena) { + return upb_msg_new(&google_protobuf_Value_msginit, arena); +} +UPB_INLINE google_protobuf_Value* google_protobuf_Value_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_Value* ret = google_protobuf_Value_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Value_msginit)) ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Value_serialize( + const google_protobuf_Value* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Value_msginit, arena, len); +} + +typedef enum { + google_protobuf_Value_kind_null_value = 1, + google_protobuf_Value_kind_number_value = 2, + google_protobuf_Value_kind_string_value = 3, + google_protobuf_Value_kind_bool_value = 4, + google_protobuf_Value_kind_struct_value = 5, + google_protobuf_Value_kind_list_value = 6, + google_protobuf_Value_kind_NOT_SET = 0, +} google_protobuf_Value_kind_oneofcases; +UPB_INLINE google_protobuf_Value_kind_oneofcases +google_protobuf_Value_kind_case(const google_protobuf_Value* msg) { + return UPB_FIELD_AT(msg, int, UPB_SIZE(8, 16)); +} + +UPB_INLINE google_protobuf_NullValue +google_protobuf_Value_null_value(const google_protobuf_Value* msg) { + return UPB_READ_ONEOF(msg, google_protobuf_NullValue, UPB_SIZE(0, 0), + UPB_SIZE(8, 16), 1, google_protobuf_NULL_VALUE); +} +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 upb_stringview +google_protobuf_Value_string_value(const google_protobuf_Value* msg) { + return UPB_READ_ONEOF(msg, upb_stringview, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 3, + upb_stringview_make("", strlen(""))); +} +UPB_INLINE bool google_protobuf_Value_bool_value( + const google_protobuf_Value* msg) { + return UPB_READ_ONEOF(msg, bool, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 4, false); +} +UPB_INLINE const google_protobuf_Struct* google_protobuf_Value_struct_value( + const google_protobuf_Value* msg) { + return UPB_READ_ONEOF(msg, const google_protobuf_Struct*, UPB_SIZE(0, 0), + UPB_SIZE(8, 16), 5, NULL); +} +UPB_INLINE const google_protobuf_ListValue* google_protobuf_Value_list_value( + const google_protobuf_Value* msg) { + return UPB_READ_ONEOF(msg, const google_protobuf_ListValue*, UPB_SIZE(0, 0), + UPB_SIZE(8, 16), 6, NULL); +} + +UPB_INLINE void google_protobuf_Value_set_null_value( + google_protobuf_Value* msg, google_protobuf_NullValue value) { + UPB_WRITE_ONEOF(msg, google_protobuf_NullValue, UPB_SIZE(0, 0), value, + UPB_SIZE(8, 16), 1); +} +UPB_INLINE void google_protobuf_Value_set_number_value( + google_protobuf_Value* msg, double value) { + UPB_WRITE_ONEOF(msg, double, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 2); +} +UPB_INLINE void google_protobuf_Value_set_string_value( + google_protobuf_Value* msg, upb_stringview value) { + UPB_WRITE_ONEOF(msg, upb_stringview, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), + 3); +} +UPB_INLINE void google_protobuf_Value_set_bool_value(google_protobuf_Value* msg, + bool value) { + UPB_WRITE_ONEOF(msg, bool, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 4); +} +UPB_INLINE void google_protobuf_Value_set_struct_value( + google_protobuf_Value* msg, google_protobuf_Struct* value) { + UPB_WRITE_ONEOF(msg, google_protobuf_Struct*, UPB_SIZE(0, 0), value, + UPB_SIZE(8, 16), 5); +} +UPB_INLINE void google_protobuf_Value_set_list_value( + google_protobuf_Value* msg, google_protobuf_ListValue* value) { + UPB_WRITE_ONEOF(msg, google_protobuf_ListValue*, UPB_SIZE(0, 0), value, + UPB_SIZE(8, 16), 6); +} + +/* google.protobuf.ListValue */ + +extern const upb_msglayout google_protobuf_ListValue_msginit; +UPB_INLINE google_protobuf_ListValue* google_protobuf_ListValue_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_ListValue_msginit, arena); +} +UPB_INLINE google_protobuf_ListValue* google_protobuf_ListValue_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_ListValue* ret = google_protobuf_ListValue_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_ListValue_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_ListValue_serialize( + const google_protobuf_ListValue* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_ListValue_msginit, arena, len); +} + +UPB_INLINE const upb_array* google_protobuf_ListValue_values( + const google_protobuf_ListValue* msg) { + return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_ListValue_set_values( + google_protobuf_ListValue* msg, upb_array* value) { + UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; +} + +UPB_END_EXTERN_C + +#include "upb/port_undef.inc" + +#endif /* GOOGLE_PROTOBUF_STRUCT_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c b/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c new file mode 100644 index 00000000000..90d0aed7664 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c @@ -0,0 +1,24 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/timestamp.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#include "google/protobuf/timestamp.upb.h" +#include +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static const upb_msglayout_field google_protobuf_Timestamp__fields[2] = { + {1, UPB_SIZE(0, 0), 0, 0, 3, 1}, + {2, UPB_SIZE(8, 8), 0, 0, 5, 1}, +}; + +const upb_msglayout google_protobuf_Timestamp_msginit = { + NULL, &google_protobuf_Timestamp__fields[0], UPB_SIZE(16, 16), 2, false, +}; + +#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/timestamp.upb.h b/src/core/ext/upb-generated/google/protobuf/timestamp.upb.h new file mode 100644 index 00000000000..a524eb5b6d0 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/timestamp.upb.h @@ -0,0 +1,65 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/timestamp.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_TIMESTAMP_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_TIMESTAMP_PROTO_UPB_H_ + +#include "upb/msg.h" + +#include "upb/decode.h" +#include "upb/encode.h" +#include "upb/port_def.inc" +UPB_BEGIN_EXTERN_C + +struct google_protobuf_Timestamp; +typedef struct google_protobuf_Timestamp google_protobuf_Timestamp; + +/* Enums */ + +/* google.protobuf.Timestamp */ + +extern const upb_msglayout google_protobuf_Timestamp_msginit; +UPB_INLINE google_protobuf_Timestamp* google_protobuf_Timestamp_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_Timestamp_msginit, arena); +} +UPB_INLINE google_protobuf_Timestamp* google_protobuf_Timestamp_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_Timestamp* ret = google_protobuf_Timestamp_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Timestamp_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Timestamp_serialize( + const google_protobuf_Timestamp* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Timestamp_msginit, arena, len); +} + +UPB_INLINE int64_t +google_protobuf_Timestamp_seconds(const google_protobuf_Timestamp* msg) { + return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)); +} +UPB_INLINE int32_t +google_protobuf_Timestamp_nanos(const google_protobuf_Timestamp* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); +} + +UPB_INLINE void google_protobuf_Timestamp_set_seconds( + google_protobuf_Timestamp* msg, int64_t value) { + UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)) = value; +} +UPB_INLINE void google_protobuf_Timestamp_set_nanos( + google_protobuf_Timestamp* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; +} + +UPB_END_EXTERN_C + +#include "upb/port_undef.inc" + +#endif /* GOOGLE_PROTOBUF_TIMESTAMP_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c b/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c new file mode 100644 index 00000000000..3fa3bea1dbc --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c @@ -0,0 +1,87 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/wrappers.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#include "google/protobuf/wrappers.upb.h" +#include +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static const upb_msglayout_field google_protobuf_DoubleValue__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 1, 1}, +}; + +const upb_msglayout google_protobuf_DoubleValue_msginit = { + NULL, &google_protobuf_DoubleValue__fields[0], UPB_SIZE(8, 8), 1, false, +}; + +static const upb_msglayout_field google_protobuf_FloatValue__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 2, 1}, +}; + +const upb_msglayout google_protobuf_FloatValue_msginit = { + NULL, &google_protobuf_FloatValue__fields[0], UPB_SIZE(4, 4), 1, false, +}; + +static const upb_msglayout_field google_protobuf_Int64Value__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 3, 1}, +}; + +const upb_msglayout google_protobuf_Int64Value_msginit = { + NULL, &google_protobuf_Int64Value__fields[0], UPB_SIZE(8, 8), 1, false, +}; + +static const upb_msglayout_field google_protobuf_UInt64Value__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 4, 1}, +}; + +const upb_msglayout google_protobuf_UInt64Value_msginit = { + NULL, &google_protobuf_UInt64Value__fields[0], UPB_SIZE(8, 8), 1, false, +}; + +static const upb_msglayout_field google_protobuf_Int32Value__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 5, 1}, +}; + +const upb_msglayout google_protobuf_Int32Value_msginit = { + NULL, &google_protobuf_Int32Value__fields[0], UPB_SIZE(4, 4), 1, false, +}; + +static const upb_msglayout_field google_protobuf_UInt32Value__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 13, 1}, +}; + +const upb_msglayout google_protobuf_UInt32Value_msginit = { + NULL, &google_protobuf_UInt32Value__fields[0], UPB_SIZE(4, 4), 1, false, +}; + +static const upb_msglayout_field google_protobuf_BoolValue__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 8, 1}, +}; + +const upb_msglayout google_protobuf_BoolValue_msginit = { + NULL, &google_protobuf_BoolValue__fields[0], UPB_SIZE(1, 1), 1, false, +}; + +static const upb_msglayout_field google_protobuf_StringValue__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 9, 1}, +}; + +const upb_msglayout google_protobuf_StringValue_msginit = { + NULL, &google_protobuf_StringValue__fields[0], UPB_SIZE(8, 16), 1, false, +}; + +static const upb_msglayout_field google_protobuf_BytesValue__fields[1] = { + {1, UPB_SIZE(0, 0), 0, 0, 12, 1}, +}; + +const upb_msglayout google_protobuf_BytesValue_msginit = { + NULL, &google_protobuf_BytesValue__fields[0], UPB_SIZE(8, 16), 1, false, +}; + +#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/wrappers.upb.h b/src/core/ext/upb-generated/google/protobuf/wrappers.upb.h new file mode 100644 index 00000000000..3ae5d3b16e3 --- /dev/null +++ b/src/core/ext/upb-generated/google/protobuf/wrappers.upb.h @@ -0,0 +1,305 @@ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/wrappers.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_WRAPPERS_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_WRAPPERS_PROTO_UPB_H_ + +#include "upb/msg.h" + +#include "upb/decode.h" +#include "upb/encode.h" +#include "upb/port_def.inc" +UPB_BEGIN_EXTERN_C + +struct google_protobuf_DoubleValue; +struct google_protobuf_FloatValue; +struct google_protobuf_Int64Value; +struct google_protobuf_UInt64Value; +struct google_protobuf_Int32Value; +struct google_protobuf_UInt32Value; +struct google_protobuf_BoolValue; +struct google_protobuf_StringValue; +struct google_protobuf_BytesValue; +typedef struct google_protobuf_DoubleValue google_protobuf_DoubleValue; +typedef struct google_protobuf_FloatValue google_protobuf_FloatValue; +typedef struct google_protobuf_Int64Value google_protobuf_Int64Value; +typedef struct google_protobuf_UInt64Value google_protobuf_UInt64Value; +typedef struct google_protobuf_Int32Value google_protobuf_Int32Value; +typedef struct google_protobuf_UInt32Value google_protobuf_UInt32Value; +typedef struct google_protobuf_BoolValue google_protobuf_BoolValue; +typedef struct google_protobuf_StringValue google_protobuf_StringValue; +typedef struct google_protobuf_BytesValue google_protobuf_BytesValue; + +/* Enums */ + +/* google.protobuf.DoubleValue */ + +extern const upb_msglayout google_protobuf_DoubleValue_msginit; +UPB_INLINE google_protobuf_DoubleValue* google_protobuf_DoubleValue_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_DoubleValue_msginit, arena); +} +UPB_INLINE google_protobuf_DoubleValue* google_protobuf_DoubleValue_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_DoubleValue* ret = google_protobuf_DoubleValue_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_DoubleValue_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_DoubleValue_serialize( + const google_protobuf_DoubleValue* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_DoubleValue_msginit, arena, len); +} + +UPB_INLINE double google_protobuf_DoubleValue_value( + const google_protobuf_DoubleValue* msg) { + return UPB_FIELD_AT(msg, double, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_DoubleValue_set_value( + google_protobuf_DoubleValue* msg, double value) { + UPB_FIELD_AT(msg, double, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.FloatValue */ + +extern const upb_msglayout google_protobuf_FloatValue_msginit; +UPB_INLINE google_protobuf_FloatValue* google_protobuf_FloatValue_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_FloatValue_msginit, arena); +} +UPB_INLINE google_protobuf_FloatValue* google_protobuf_FloatValue_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_FloatValue* ret = google_protobuf_FloatValue_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_FloatValue_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_FloatValue_serialize( + const google_protobuf_FloatValue* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_FloatValue_msginit, arena, len); +} + +UPB_INLINE float google_protobuf_FloatValue_value( + const google_protobuf_FloatValue* msg) { + return UPB_FIELD_AT(msg, float, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_FloatValue_set_value( + google_protobuf_FloatValue* msg, float value) { + UPB_FIELD_AT(msg, float, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.Int64Value */ + +extern const upb_msglayout google_protobuf_Int64Value_msginit; +UPB_INLINE google_protobuf_Int64Value* google_protobuf_Int64Value_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_Int64Value_msginit, arena); +} +UPB_INLINE google_protobuf_Int64Value* google_protobuf_Int64Value_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_Int64Value* ret = google_protobuf_Int64Value_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Int64Value_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Int64Value_serialize( + const google_protobuf_Int64Value* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Int64Value_msginit, arena, len); +} + +UPB_INLINE int64_t +google_protobuf_Int64Value_value(const google_protobuf_Int64Value* msg) { + return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_Int64Value_set_value( + google_protobuf_Int64Value* msg, int64_t value) { + UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.UInt64Value */ + +extern const upb_msglayout google_protobuf_UInt64Value_msginit; +UPB_INLINE google_protobuf_UInt64Value* google_protobuf_UInt64Value_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_UInt64Value_msginit, arena); +} +UPB_INLINE google_protobuf_UInt64Value* google_protobuf_UInt64Value_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_UInt64Value* ret = google_protobuf_UInt64Value_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_UInt64Value_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_UInt64Value_serialize( + const google_protobuf_UInt64Value* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_UInt64Value_msginit, arena, len); +} + +UPB_INLINE uint64_t +google_protobuf_UInt64Value_value(const google_protobuf_UInt64Value* msg) { + return UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_UInt64Value_set_value( + google_protobuf_UInt64Value* msg, uint64_t value) { + UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.Int32Value */ + +extern const upb_msglayout google_protobuf_Int32Value_msginit; +UPB_INLINE google_protobuf_Int32Value* google_protobuf_Int32Value_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_Int32Value_msginit, arena); +} +UPB_INLINE google_protobuf_Int32Value* google_protobuf_Int32Value_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_Int32Value* ret = google_protobuf_Int32Value_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_Int32Value_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_Int32Value_serialize( + const google_protobuf_Int32Value* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_Int32Value_msginit, arena, len); +} + +UPB_INLINE int32_t +google_protobuf_Int32Value_value(const google_protobuf_Int32Value* msg) { + return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_Int32Value_set_value( + google_protobuf_Int32Value* msg, int32_t value) { + UPB_FIELD_AT(msg, int32_t, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.UInt32Value */ + +extern const upb_msglayout google_protobuf_UInt32Value_msginit; +UPB_INLINE google_protobuf_UInt32Value* google_protobuf_UInt32Value_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_UInt32Value_msginit, arena); +} +UPB_INLINE google_protobuf_UInt32Value* google_protobuf_UInt32Value_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_UInt32Value* ret = google_protobuf_UInt32Value_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_UInt32Value_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_UInt32Value_serialize( + const google_protobuf_UInt32Value* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_UInt32Value_msginit, arena, len); +} + +UPB_INLINE uint32_t +google_protobuf_UInt32Value_value(const google_protobuf_UInt32Value* msg) { + return UPB_FIELD_AT(msg, uint32_t, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_UInt32Value_set_value( + google_protobuf_UInt32Value* msg, uint32_t value) { + UPB_FIELD_AT(msg, uint32_t, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.BoolValue */ + +extern const upb_msglayout google_protobuf_BoolValue_msginit; +UPB_INLINE google_protobuf_BoolValue* google_protobuf_BoolValue_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_BoolValue_msginit, arena); +} +UPB_INLINE google_protobuf_BoolValue* google_protobuf_BoolValue_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_BoolValue* ret = google_protobuf_BoolValue_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_BoolValue_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_BoolValue_serialize( + const google_protobuf_BoolValue* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_BoolValue_msginit, arena, len); +} + +UPB_INLINE bool google_protobuf_BoolValue_value( + const google_protobuf_BoolValue* msg) { + return UPB_FIELD_AT(msg, bool, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_BoolValue_set_value( + google_protobuf_BoolValue* msg, bool value) { + UPB_FIELD_AT(msg, bool, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.StringValue */ + +extern const upb_msglayout google_protobuf_StringValue_msginit; +UPB_INLINE google_protobuf_StringValue* google_protobuf_StringValue_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_StringValue_msginit, arena); +} +UPB_INLINE google_protobuf_StringValue* google_protobuf_StringValue_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_StringValue* ret = google_protobuf_StringValue_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_StringValue_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_StringValue_serialize( + const google_protobuf_StringValue* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_StringValue_msginit, arena, len); +} + +UPB_INLINE upb_stringview +google_protobuf_StringValue_value(const google_protobuf_StringValue* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_StringValue_set_value( + google_protobuf_StringValue* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; +} + +/* google.protobuf.BytesValue */ + +extern const upb_msglayout google_protobuf_BytesValue_msginit; +UPB_INLINE google_protobuf_BytesValue* google_protobuf_BytesValue_new( + upb_arena* arena) { + return upb_msg_new(&google_protobuf_BytesValue_msginit, arena); +} +UPB_INLINE google_protobuf_BytesValue* google_protobuf_BytesValue_parsenew( + upb_stringview buf, upb_arena* arena) { + google_protobuf_BytesValue* ret = google_protobuf_BytesValue_new(arena); + return (ret && upb_decode(buf, ret, &google_protobuf_BytesValue_msginit)) + ? ret + : NULL; +} +UPB_INLINE char* google_protobuf_BytesValue_serialize( + const google_protobuf_BytesValue* msg, upb_arena* arena, size_t* len) { + return upb_encode(msg, &google_protobuf_BytesValue_msginit, arena, len); +} + +UPB_INLINE upb_stringview +google_protobuf_BytesValue_value(const google_protobuf_BytesValue* msg) { + return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); +} + +UPB_INLINE void google_protobuf_BytesValue_set_value( + google_protobuf_BytesValue* msg, upb_stringview value) { + UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; +} + +UPB_END_EXTERN_C + +#include "upb/port_undef.inc" + +#endif /* GOOGLE_PROTOBUF_WRAPPERS_PROTO_UPB_H_ */ diff --git a/src/upb/gen_build_yaml.py b/src/upb/gen_build_yaml.py new file mode 100755 index 00000000000..0dd7bfae109 --- /dev/null +++ b/src/upb/gen_build_yaml.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python2.7 + +# 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. + +# TODO: This should ideally be in upb submodule to avoid hardcoding this here. + +import re +import os +import sys +import yaml + +srcs = [ + "third_party/upb/google/protobuf/descriptor.upb.c", + "third_party/upb/upb/decode.c", + "third_party/upb/upb/def.c", + "third_party/upb/upb/encode.c", + "third_party/upb/upb/handlers.c", + "third_party/upb/upb/msg.c", + "third_party/upb/upb/msgfactory.c", + "third_party/upb/upb/refcounted.c", + "third_party/upb/upb/sink.c", + "third_party/upb/upb/table.c", + "third_party/upb/upb/upb.c", +] + +hdrs = [ + "third_party/upb/google/protobuf/descriptor.upb.h", + "third_party/upb/upb/decode.h", + "third_party/upb/upb/def.h", + "third_party/upb/upb/encode.h", + "third_party/upb/upb/handlers.h", + "third_party/upb/upb/msg.h", + "third_party/upb/upb/msgfactory.h", + "third_party/upb/upb/refcounted.h", + "third_party/upb/upb/sink.h", + "third_party/upb/upb/upb.h", +] + +os.chdir(os.path.dirname(sys.argv[0])+'/../..') + +out = {} + +try: + out['libs'] = [{ + 'name': 'upb', + 'defaults': 'upb', + 'build': 'private', + 'language': 'c', + 'secure': 'no', + 'src': srcs, + 'headers': hdrs, + }] +except: + pass + +print yaml.dump(out) + diff --git a/tools/buildgen/generate_build_additions.sh b/tools/buildgen/generate_build_additions.sh index 5a1f4a598a7..c99ad6ee552 100755 --- a/tools/buildgen/generate_build_additions.sh +++ b/tools/buildgen/generate_build_additions.sh @@ -19,6 +19,7 @@ gen_build_yaml_dirs=" \ src/boringssl \ src/benchmark \ src/proto \ + src/upb \ src/zlib \ src/c-ares \ test/core/bad_client \ diff --git a/tools/codegen/core/gen_upb_api.sh b/tools/codegen/core/gen_upb_api.sh new file mode 100755 index 00000000000..9457e06f124 --- /dev/null +++ b/tools/codegen/core/gen_upb_api.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Copyright 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. + +# REQUIRES: Bazel +set -ex +rm -rf src/core/ext/upb-generated +mkdir src/core/ext/upb-generated +cd third_party +cd upb +bazel build :protoc-gen-upb + +cd ../.. + +proto_files=( \ + "google/protobuf/any.proto" \ + "google/protobuf/struct.proto" \ + "google/protobuf/wrappers.proto" \ + "google/protobuf/descriptor.proto" \ + "google/protobuf/duration.proto" \ + "google/protobuf/timestamp.proto" ) + +for i in "${proto_files[@]}" +do + protoc -I=$PWD/third_party/data-plane-api -I=$PWD/third_party/googleapis -I=$PWD/third_party/protobuf -I=$PWD/third_party/protoc-gen-validate $i --upb_out=./src/core/ext/upb-generated --plugin=protoc-gen-upb=third_party/upb/bazel-bin/protoc-gen-upb +done diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py index 787bef1778e..fd93cf31e05 100755 --- a/tools/distrib/check_copyright.py +++ b/tools/distrib/check_copyright.py @@ -104,6 +104,20 @@ _EXEMPT = frozenset(( # Designer-generated source 'examples/csharp/HelloworldXamarin/Droid/Resources/Resource.designer.cs', 'examples/csharp/HelloworldXamarin/iOS/ViewController.designer.cs', + + # Upb generated source + 'src/core/ext/upb-generated/google/protobuf/any.upb.h', + 'src/core/ext/upb-generated/google/protobuf/any.upb.c', + 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.h', + 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.c', + 'src/core/ext/upb-generated/google/protobuf/duration.upb.h', + 'src/core/ext/upb-generated/google/protobuf/duration.upb.c', + 'src/core/ext/upb-generated/google/protobuf/struct.upb.h', + 'src/core/ext/upb-generated/google/protobuf/struct.upb.c', + 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.h', + 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c', + 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.h', + 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c', )) RE_YEAR = r'Copyright (?P[0-9]+\-)?(?P[0-9]+) ([Tt]he )?gRPC [Aa]uthors(\.|)' diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py index b8d530cce06..15b3478e555 100755 --- a/tools/distrib/check_include_guards.py +++ b/tools/distrib/check_include_guards.py @@ -165,6 +165,20 @@ KNOWN_BAD = set([ 'src/core/tsi/alts/handshaker/transport_security_common.pb.h', 'include/grpc++/ext/reflection.grpc.pb.h', 'include/grpc++/ext/reflection.pb.h', + + # Upb generated code + 'src/core/ext/upb-generated/google/protobuf/any.upb.h', + 'src/core/ext/upb-generated/google/protobuf/any.upb.c', + 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.h', + 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.c', + 'src/core/ext/upb-generated/google/protobuf/duration.upb.h', + 'src/core/ext/upb-generated/google/protobuf/duration.upb.c', + 'src/core/ext/upb-generated/google/protobuf/struct.upb.h', + 'src/core/ext/upb-generated/google/protobuf/struct.upb.c', + 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.h', + 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c', + 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.h', + 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c', ]) grep_filter = r"grep -E '^(include|src/core)/.*\.h$'" diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index d4d5d14f079..2fea807bbb0 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8825,6 +8825,27 @@ "third_party": false, "type": "lib" }, + { + "deps": [], + "headers": [ + "third_party/upb/google/protobuf/descriptor.upb.h", + "third_party/upb/upb/decode.h", + "third_party/upb/upb/def.h", + "third_party/upb/upb/encode.h", + "third_party/upb/upb/handlers.h", + "third_party/upb/upb/msg.h", + "third_party/upb/upb/msgfactory.h", + "third_party/upb/upb/refcounted.h", + "third_party/upb/upb/sink.h", + "third_party/upb/upb/upb.h" + ], + "is_filegroup": false, + "language": "c", + "name": "upb", + "src": [], + "third_party": false, + "type": "lib" + }, { "deps": [], "headers": [ diff --git a/tools/run_tests/sanity/check_port_platform.py b/tools/run_tests/sanity/check_port_platform.py index fff828eaee8..8c412700e45 100755 --- a/tools/run_tests/sanity/check_port_platform.py +++ b/tools/run_tests/sanity/check_port_platform.py @@ -35,6 +35,9 @@ def check_port_platform_inclusion(directory_root): continue if filename.endswith('.pb.h') or filename.endswith('.pb.c'): continue + # Skip check for upb generated code + if filename.endswith('.upb.h') or filename.endswith('.upb.c'): + continue with open(path) as f: all_lines_in_file = f.readlines() for index, l in enumerate(all_lines_in_file): From d550af373cc993ee80e9e350d60f4ca662b1ec28 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 12 Dec 2018 04:09:42 +0100 Subject: [PATCH 73/99] Moving ::grpc::Alarm to ::grpc_impl::Alarm. --- BUILD | 1 + CMakeLists.txt | 3 + Makefile | 3 + build.yaml | 1 + gRPC-C++.podspec | 1 + include/grpcpp/alarm.h | 93 +------------- include/grpcpp/alarm_impl.h | 116 ++++++++++++++++++ src/cpp/common/alarm.cc | 13 +- tools/doxygen/Doxyfile.c++ | 1 + tools/doxygen/Doxyfile.c++.internal | 1 + .../generated/sources_and_headers.json | 2 + 11 files changed, 140 insertions(+), 95 deletions(-) create mode 100644 include/grpcpp/alarm_impl.h diff --git a/BUILD b/BUILD index 9a2c16c6012..cb03e560d5e 100644 --- a/BUILD +++ b/BUILD @@ -204,6 +204,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpc++/support/sync_stream.h", "include/grpc++/support/time.h", "include/grpcpp/alarm.h", + "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 23b4bb77e75..e843397e008 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2985,6 +2985,7 @@ foreach(_hdr include/grpc++/support/sync_stream.h include/grpc++/support/time.h include/grpcpp/alarm.h + include/grpcpp/alarm_impl.h include/grpcpp/channel.h include/grpcpp/client_context.h include/grpcpp/completion_queue.h @@ -3569,6 +3570,7 @@ foreach(_hdr include/grpc++/support/sync_stream.h include/grpc++/support/time.h include/grpcpp/alarm.h + include/grpcpp/alarm_impl.h include/grpcpp/channel.h include/grpcpp/client_context.h include/grpcpp/completion_queue.h @@ -4504,6 +4506,7 @@ foreach(_hdr include/grpc++/support/sync_stream.h include/grpc++/support/time.h include/grpcpp/alarm.h + include/grpcpp/alarm_impl.h include/grpcpp/channel.h include/grpcpp/client_context.h include/grpcpp/completion_queue.h diff --git a/Makefile b/Makefile index 4f7cd130120..438e5729d58 100644 --- a/Makefile +++ b/Makefile @@ -5340,6 +5340,7 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/support/sync_stream.h \ include/grpc++/support/time.h \ include/grpcpp/alarm.h \ + include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ @@ -5933,6 +5934,7 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/support/sync_stream.h \ include/grpc++/support/time.h \ include/grpcpp/alarm.h \ + include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ @@ -6835,6 +6837,7 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/support/sync_stream.h \ include/grpc++/support/time.h \ include/grpcpp/alarm.h \ + include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ diff --git a/build.yaml b/build.yaml index 381e649b392..74a5f5e6dca 100644 --- a/build.yaml +++ b/build.yaml @@ -1323,6 +1323,7 @@ filegroups: - include/grpc++/support/sync_stream.h - include/grpc++/support/time.h - include/grpcpp/alarm.h + - include/grpcpp/alarm_impl.h - include/grpcpp/channel.h - include/grpcpp/client_context.h - include/grpcpp/completion_queue.h diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 6647201714c..3da94dda4b2 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -78,6 +78,7 @@ Pod::Spec.new do |s| ss.header_mappings_dir = 'include/grpcpp' ss.source_files = 'include/grpcpp/alarm.h', + 'include/grpcpp/alarm_impl.h', 'include/grpcpp/channel.h', 'include/grpcpp/client_context.h', 'include/grpcpp/completion_queue.h', diff --git a/include/grpcpp/alarm.h b/include/grpcpp/alarm.h index 365feb4eb95..2343c1149c5 100644 --- a/include/grpcpp/alarm.h +++ b/include/grpcpp/alarm.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,99 +16,14 @@ * */ -/// An Alarm posts the user provided tag to its associated completion queue upon -/// expiry or cancellation. #ifndef GRPCPP_ALARM_H #define GRPCPP_ALARM_H -#include - -#include -#include -#include -#include -#include -#include +#include namespace grpc { -/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h). -class Alarm : private GrpcLibraryCodegen { - public: - /// Create an unset completion queue alarm - Alarm(); - - /// Destroy the given completion queue alarm, cancelling it in the process. - ~Alarm(); - - /// DEPRECATED: Create and set a completion queue alarm instance associated to - /// \a cq. - /// This form is deprecated because it is inherently racy. - /// \internal We rely on the presence of \a cq for grpc initialization. If \a - /// cq were ever to be removed, a reference to a static - /// internal::GrpcLibraryInitializer instance would need to be introduced - /// here. \endinternal. - template - Alarm(CompletionQueue* cq, const T& deadline, void* tag) : Alarm() { - SetInternal(cq, TimePoint(deadline).raw_time(), tag); - } - - /// Trigger an alarm instance on completion queue \a cq at the specified time. - /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel), - /// an event with tag \a tag will be added to \a cq. If the alarm expired, the - /// event's success bit will be true, false otherwise (ie, upon cancellation). - template - void Set(CompletionQueue* cq, const T& deadline, void* tag) { - SetInternal(cq, TimePoint(deadline).raw_time(), tag); - } - - /// Alarms aren't copyable. - Alarm(const Alarm&) = delete; - Alarm& operator=(const Alarm&) = delete; - - /// Alarms are movable. - Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; } - Alarm& operator=(Alarm&& rhs) { - alarm_ = rhs.alarm_; - rhs.alarm_ = nullptr; - return *this; - } - - /// Cancel a completion queue alarm. Calling this function over an alarm that - /// has already fired has no effect. - void Cancel(); - - /// NOTE: class experimental_type is not part of the public API of this class - /// TODO(vjpai): Move these contents to the public API of Alarm when - /// they are no longer experimental - class experimental_type { - public: - explicit experimental_type(Alarm* alarm) : alarm_(alarm) {} - - /// Set an alarm to invoke callback \a f. The argument to the callback - /// states whether the alarm expired at \a deadline (true) or was cancelled - /// (false) - template - void Set(const T& deadline, std::function f) { - alarm_->SetInternal(TimePoint(deadline).raw_time(), std::move(f)); - } - - private: - Alarm* alarm_; - }; - - /// NOTE: The function experimental() is not stable public API. It is a view - /// to the experimental components of this class. It may be changed or removed - /// at any time. - experimental_type experimental() { return experimental_type(this); } - - private: - void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag); - void SetInternal(gpr_timespec deadline, std::function f); - - internal::CompletionQueueTag* alarm_; -}; - -} // namespace grpc +typedef ::grpc_impl::Alarm Alarm; +} #endif // GRPCPP_ALARM_H diff --git a/include/grpcpp/alarm_impl.h b/include/grpcpp/alarm_impl.h new file mode 100644 index 00000000000..7844e7c8866 --- /dev/null +++ b/include/grpcpp/alarm_impl.h @@ -0,0 +1,116 @@ +/* + * + * 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. + * + */ + +/// An Alarm posts the user provided tag to its associated completion queue upon +/// expiry or cancellation. +#ifndef GRPCPP_ALARM_IMPL_H +#define GRPCPP_ALARM_IMPL_H + +#include + +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h). +class Alarm : private ::grpc::GrpcLibraryCodegen { + public: + /// Create an unset completion queue alarm + Alarm(); + + /// Destroy the given completion queue alarm, cancelling it in the process. + ~Alarm(); + + /// DEPRECATED: Create and set a completion queue alarm instance associated to + /// \a cq. + /// This form is deprecated because it is inherently racy. + /// \internal We rely on the presence of \a cq for grpc initialization. If \a + /// cq were ever to be removed, a reference to a static + /// internal::GrpcLibraryInitializer instance would need to be introduced + /// here. \endinternal. + template + Alarm(::grpc::CompletionQueue* cq, const T& deadline, void* tag) : Alarm() { + SetInternal(cq, ::grpc::TimePoint(deadline).raw_time(), tag); + } + + /// Trigger an alarm instance on completion queue \a cq at the specified time. + /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel), + /// an event with tag \a tag will be added to \a cq. If the alarm expired, the + /// event's success bit will be true, false otherwise (ie, upon cancellation). + template + void Set(::grpc::CompletionQueue* cq, const T& deadline, void* tag) { + SetInternal(cq, ::grpc::TimePoint(deadline).raw_time(), tag); + } + + /// Alarms aren't copyable. + Alarm(const Alarm&) = delete; + Alarm& operator=(const Alarm&) = delete; + + /// Alarms are movable. + Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; } + Alarm& operator=(Alarm&& rhs) { + alarm_ = rhs.alarm_; + rhs.alarm_ = nullptr; + return *this; + } + + /// Cancel a completion queue alarm. Calling this function over an alarm that + /// has already fired has no effect. + void Cancel(); + + /// NOTE: class experimental_type is not part of the public API of this class + /// TODO(vjpai): Move these contents to the public API of Alarm when + /// they are no longer experimental + class experimental_type { + public: + explicit experimental_type(Alarm* alarm) : alarm_(alarm) {} + + /// Set an alarm to invoke callback \a f. The argument to the callback + /// states whether the alarm expired at \a deadline (true) or was cancelled + /// (false) + template + void Set(const T& deadline, std::function f) { + alarm_->SetInternal(::grpc::TimePoint(deadline).raw_time(), + std::move(f)); + } + + private: + Alarm* alarm_; + }; + + /// NOTE: The function experimental() is not stable public API. It is a view + /// to the experimental components of this class. It may be changed or removed + /// at any time. + experimental_type experimental() { return experimental_type(this); } + + private: + void SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline, + void* tag); + void SetInternal(gpr_timespec deadline, std::function f); + + ::grpc::internal::CompletionQueueTag* alarm_; +}; + +} // namespace grpc_impl + +#endif // GRPCPP_ALARM_IMPL_H diff --git a/src/cpp/common/alarm.cc b/src/cpp/common/alarm.cc index 5819a4210bd..148f0b9bc94 100644 --- a/src/cpp/common/alarm.cc +++ b/src/cpp/common/alarm.cc @@ -31,10 +31,10 @@ #include #include "src/core/lib/debug/trace.h" -namespace grpc { +namespace grpc_impl { namespace internal { -class AlarmImpl : public CompletionQueueTag { +class AlarmImpl : public ::grpc::internal::CompletionQueueTag { public: AlarmImpl() : cq_(nullptr), tag_(nullptr) { gpr_ref_init(&refs_, 1); @@ -51,7 +51,7 @@ class AlarmImpl : public CompletionQueueTag { Unref(); return true; } - void Set(CompletionQueue* cq, gpr_timespec deadline, void* tag) { + void Set(::grpc::CompletionQueue* cq, gpr_timespec deadline, void* tag) { grpc_core::ExecCtx exec_ctx; GRPC_CQ_INTERNAL_REF(cq->cq(), "alarm"); cq_ = cq->cq(); @@ -114,13 +114,14 @@ class AlarmImpl : public CompletionQueueTag { }; } // namespace internal -static internal::GrpcLibraryInitializer g_gli_initializer; +static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer; Alarm::Alarm() : alarm_(new internal::AlarmImpl()) { g_gli_initializer.summon(); } -void Alarm::SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag) { +void Alarm::SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline, + void* tag) { // Note that we know that alarm_ is actually an internal::AlarmImpl // but we declared it as the base pointer to avoid a forward declaration // or exposing core data structures in the C++ public headers. @@ -145,4 +146,4 @@ Alarm::~Alarm() { } void Alarm::Cancel() { static_cast(alarm_)->Cancel(); } -} // namespace grpc +} // namespace grpc_impl diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 5c19711ee91..a5f817997dc 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -925,6 +925,7 @@ include/grpc/support/thd_id.h \ include/grpc/support/time.h \ include/grpc/support/workaround_list.h \ include/grpcpp/alarm.h \ +include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 72b247c48da..7b10bdc699f 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -926,6 +926,7 @@ include/grpc/support/thd_id.h \ include/grpc/support/time.h \ include/grpc/support/workaround_list.h \ include/grpcpp/alarm.h \ +include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 4d9bbb0f09e..a72e574f1e4 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -11431,6 +11431,7 @@ "include/grpc++/support/sync_stream.h", "include/grpc++/support/time.h", "include/grpcpp/alarm.h", + "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", @@ -11536,6 +11537,7 @@ "include/grpc++/support/sync_stream.h", "include/grpc++/support/time.h", "include/grpcpp/alarm.h", + "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", From f3caa01bf383077946f1dc2570d382f3aaf79155 Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Wed, 12 Dec 2018 09:03:17 -0800 Subject: [PATCH 74/99] monthly update of grpc root certificates --- etc/roots.pem | 272 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 242 insertions(+), 30 deletions(-) diff --git a/etc/roots.pem b/etc/roots.pem index 3e6bbcd76ea..be598710ddd 100644 --- a/etc/roots.pem +++ b/etc/roots.pem @@ -329,36 +329,6 @@ OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- -# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association -# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association -# Label: "Visa eCommerce Root" -# Serial: 25952180776285836048024890241505565794 -# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02 -# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62 -# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22 ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr -MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl -cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv -bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw -CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h -dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l -cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h -2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E -lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV -ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq -299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t -vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL -dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF -AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR -zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 -LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd -7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw -++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt -398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- - # Issuer: CN=AAA Certificate Services O=Comodo CA Limited # Subject: CN=AAA Certificate Services O=Comodo CA Limited # Label: "Comodo AAA Services root" @@ -4340,3 +4310,245 @@ rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV 57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 -----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 146587175971765017618439757810265552097 +# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85 +# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8 +# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R2 O=Google Trust Services LLC +# Subject: CN=GTS Root R2 O=Google Trust Services LLC +# Label: "GTS Root R2" +# Serial: 146587176055767053814479386953112547951 +# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b +# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d +# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 146587176140553309517047991083707763997 +# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25 +# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5 +# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5 +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 146587176229350439916519468929765261721 +# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26 +# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb +# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- From 91e5f7c6474fd3d3939571a9406115ac330821e9 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Wed, 12 Dec 2018 09:38:44 -0800 Subject: [PATCH 75/99] Update urllib3 to avoid security vulnerability --- requirements.bazel.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 61e529a6ec8..7794aec752e 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -9,7 +9,7 @@ futures>=2.2.0 google-auth>=1.0.0 oauth2client==4.1.0 requests>=2.14.2 -urllib3==1.22 +urllib3>=1.23 chardet==3.0.4 certifi==2017.4.17 idna==2.7 From ac6795a57e05523b8fa220bc5cef26abb876aae5 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 12 Dec 2018 11:40:25 -0800 Subject: [PATCH 76/99] Revert "Changes add a script for generating C code and build rule for protobuf" This reverts commit 62027b7e14624283f758a7785a0a1347eda0a147. --- BUILD | 25 - CMakeLists.txt | 53 - Makefile | 38 +- bazel/grpc_build_system.bzl | 1 - bazel/grpc_deps.bzl | 6 +- build.yaml | 2 - grpc.gyp | 19 - .../upb-generated/google/protobuf/any.upb.c | 24 - .../upb-generated/google/protobuf/any.upb.h | 63 - .../google/protobuf/descriptor.upb.c | 549 ----- .../google/protobuf/descriptor.upb.h | 1879 ----------------- .../google/protobuf/duration.upb.c | 24 - .../google/protobuf/duration.upb.h | 65 - .../google/protobuf/struct.upb.c | 88 - .../google/protobuf/struct.upb.h | 226 -- .../google/protobuf/timestamp.upb.c | 24 - .../google/protobuf/timestamp.upb.h | 65 - .../google/protobuf/wrappers.upb.c | 87 - .../google/protobuf/wrappers.upb.h | 305 --- src/upb/gen_build_yaml.py | 69 - tools/buildgen/generate_build_additions.sh | 1 - tools/codegen/core/gen_upb_api.sh | 38 - tools/distrib/check_copyright.py | 14 - tools/distrib/check_include_guards.py | 14 - .../generated/sources_and_headers.json | 21 - tools/run_tests/sanity/check_port_platform.py | 3 - 26 files changed, 4 insertions(+), 3699 deletions(-) delete mode 100644 src/core/ext/upb-generated/google/protobuf/any.upb.c delete mode 100644 src/core/ext/upb-generated/google/protobuf/any.upb.h delete mode 100644 src/core/ext/upb-generated/google/protobuf/descriptor.upb.c delete mode 100644 src/core/ext/upb-generated/google/protobuf/descriptor.upb.h delete mode 100644 src/core/ext/upb-generated/google/protobuf/duration.upb.c delete mode 100644 src/core/ext/upb-generated/google/protobuf/duration.upb.h delete mode 100644 src/core/ext/upb-generated/google/protobuf/struct.upb.c delete mode 100644 src/core/ext/upb-generated/google/protobuf/struct.upb.h delete mode 100644 src/core/ext/upb-generated/google/protobuf/timestamp.upb.c delete mode 100644 src/core/ext/upb-generated/google/protobuf/timestamp.upb.h delete mode 100644 src/core/ext/upb-generated/google/protobuf/wrappers.upb.c delete mode 100644 src/core/ext/upb-generated/google/protobuf/wrappers.upb.h delete mode 100755 src/upb/gen_build_yaml.py delete mode 100755 tools/codegen/core/gen_upb_api.sh diff --git a/BUILD b/BUILD index 034e47d1a92..5550e583a87 100644 --- a/BUILD +++ b/BUILD @@ -2274,29 +2274,4 @@ grpc_cc_library( ], ) -# TODO: Get this into build.yaml once we start using it. -grpc_cc_library( - name = "google_protobuf", - srcs = [ - "src/core/ext/upb-generated/google/protobuf/any.upb.c", - "src/core/ext/upb-generated/google/protobuf/descriptor.upb.c", - "src/core/ext/upb-generated/google/protobuf/duration.upb.c", - "src/core/ext/upb-generated/google/protobuf/struct.upb.c", - "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c", - "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c", - ], - hdrs = [ - "src/core/ext/upb-generated/google/protobuf/any.upb.h", - "src/core/ext/upb-generated/google/protobuf/descriptor.upb.h", - "src/core/ext/upb-generated/google/protobuf/duration.upb.h", - "src/core/ext/upb-generated/google/protobuf/struct.upb.h", - "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h", - "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h", - ], - language = "c++", - external_deps = [ - "upb_lib", - ], -) - grpc_generate_one_off_targets() diff --git a/CMakeLists.txt b/CMakeLists.txt index 08240fe82b4..9c660c77012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5478,59 +5478,6 @@ endif() endif (gRPC_BUILD_CSHARP_EXT) if (gRPC_BUILD_TESTS) -add_library(upb - third_party/upb/google/protobuf/descriptor.upb.c - third_party/upb/upb/decode.c - third_party/upb/upb/def.c - third_party/upb/upb/encode.c - third_party/upb/upb/handlers.c - third_party/upb/upb/msg.c - third_party/upb/upb/msgfactory.c - third_party/upb/upb/refcounted.c - third_party/upb/upb/sink.c - third_party/upb/upb/table.c - third_party/upb/upb/upb.c -) - -if(WIN32 AND MSVC) - set_target_properties(upb PROPERTIES COMPILE_PDB_NAME "upb" - COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" - ) - if (gRPC_INSTALL) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/upb.pdb - DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL - ) - endif() -endif() - - -target_include_directories(upb - PUBLIC $ $ - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${_gRPC_SSL_INCLUDE_DIR} - PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} - PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} - PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} - PRIVATE ${_gRPC_CARES_INCLUDE_DIR} - PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} - PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} - PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} -) - # avoid dependency on libstdc++ - if (_gRPC_CORE_NOSTDCXX_FLAGS) - set_target_properties(upb PROPERTIES LINKER_LANGUAGE C) - # only use the flags for C++ source files - target_compile_options(upb PRIVATE $<$:${_gRPC_CORE_NOSTDCXX_FLAGS}>) - endif() -target_link_libraries(upb - ${_gRPC_SSL_LIBRARIES} - ${_gRPC_ALLTARGETS_LIBRARIES} -) - - -endif (gRPC_BUILD_TESTS) -if (gRPC_BUILD_TESTS) - add_library(bad_client_test test/core/bad_client/bad_client.cc ) diff --git a/Makefile b/Makefile index 950ac75695d..0163dc414a5 100644 --- a/Makefile +++ b/Makefile @@ -1411,7 +1411,7 @@ plugins: $(PROTOC_PLUGINS) privatelibs: privatelibs_c privatelibs_cxx -privatelibs_c: $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libupb.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a +privatelibs_c: $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libcxxabi.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc @@ -10117,42 +10117,6 @@ ifneq ($(NO_DEPS),true) endif -LIBUPB_SRC = \ - third_party/upb/google/protobuf/descriptor.upb.c \ - third_party/upb/upb/decode.c \ - third_party/upb/upb/def.c \ - third_party/upb/upb/encode.c \ - third_party/upb/upb/handlers.c \ - third_party/upb/upb/msg.c \ - third_party/upb/upb/msgfactory.c \ - third_party/upb/upb/refcounted.c \ - third_party/upb/upb/sink.c \ - third_party/upb/upb/table.c \ - third_party/upb/upb/upb.c \ - -PUBLIC_HEADERS_C += \ - -LIBUPB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBUPB_SRC)))) - -$(LIBUPB_OBJS): CFLAGS += -Ithird_party/upb -Wno-sign-conversion -Wno-shadow -Wno-conversion -Wno-implicit-fallthrough - -$(LIBDIR)/$(CONFIG)/libupb.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBUPB_OBJS) - $(E) "[AR] Creating $@" - $(Q) mkdir -p `dirname $@` - $(Q) rm -f $(LIBDIR)/$(CONFIG)/libupb.a - $(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libupb.a $(LIBUPB_OBJS) -ifeq ($(SYSTEM),Darwin) - $(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libupb.a -endif - - - - -ifneq ($(NO_DEPS),true) --include $(LIBUPB_OBJS:.o=.dep) -endif - - LIBZ_SRC = \ third_party/zlib/adler32.c \ third_party/zlib/compress.c \ diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index 06b05f79525..65fe5a10aa2 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -99,7 +99,6 @@ def grpc_cc_library( linkopts = if_not_windows(["-pthread"]), includes = [ "include", - "src/core/ext/upb-generated", ], alwayslink = alwayslink, data = data, diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl index 2738e39abf7..3eacd2b0475 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -12,7 +12,7 @@ def grpc_deps(): ) native.bind( - name = "upb_lib", + name = "upblib", actual = "@upb//:upb", ) @@ -195,8 +195,8 @@ def grpc_deps(): if "upb" not in native.existing_rules(): http_archive( name = "upb", - strip_prefix = "upb-fb6f7e96895c3a9a8ae2e66516160937e7ac1779", - url = "https://github.com/google/upb/archive/fb6f7e96895c3a9a8ae2e66516160937e7ac1779.tar.gz", + strip_prefix = "upb-9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3", + url = "https://github.com/google/upb/archive/9ce4a77f61c134bbed28bfd5be5cd7dc0e80f5e3.tar.gz", ) diff --git a/build.yaml b/build.yaml index b8c2fa6b020..4521169e6c1 100644 --- a/build.yaml +++ b/build.yaml @@ -5896,8 +5896,6 @@ defaults: -Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT CXXFLAGS: -Wnon-virtual-dtor LDFLAGS: -g - upb: - CFLAGS: -Ithird_party/upb -Wno-sign-conversion -Wno-shadow -Wno-conversion -Wno-implicit-fallthrough zlib: CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration -Wno-implicit-fallthrough $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden diff --git a/grpc.gyp b/grpc.gyp index d03c74d8dc1..00f06a1e54e 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -2640,25 +2640,6 @@ 'third_party/benchmark/src/timers.cc', ], }, - { - 'target_name': 'upb', - 'type': 'static_library', - 'dependencies': [ - ], - 'sources': [ - 'third_party/upb/google/protobuf/descriptor.upb.c', - 'third_party/upb/upb/decode.c', - 'third_party/upb/upb/def.c', - 'third_party/upb/upb/encode.c', - 'third_party/upb/upb/handlers.c', - 'third_party/upb/upb/msg.c', - 'third_party/upb/upb/msgfactory.c', - 'third_party/upb/upb/refcounted.c', - 'third_party/upb/upb/sink.c', - 'third_party/upb/upb/table.c', - 'third_party/upb/upb/upb.c', - ], - }, { 'target_name': 'z', 'type': 'static_library', diff --git a/src/core/ext/upb-generated/google/protobuf/any.upb.c b/src/core/ext/upb-generated/google/protobuf/any.upb.c deleted file mode 100644 index 1005a48e909..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/any.upb.c +++ /dev/null @@ -1,24 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/any.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include "google/protobuf/any.upb.h" -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -static const upb_msglayout_field google_protobuf_Any__fields[2] = { - {1, UPB_SIZE(0, 0), 0, 0, 9, 1}, - {2, UPB_SIZE(8, 16), 0, 0, 12, 1}, -}; - -const upb_msglayout google_protobuf_Any_msginit = { - NULL, &google_protobuf_Any__fields[0], UPB_SIZE(16, 32), 2, false, -}; - -#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/any.upb.h b/src/core/ext/upb-generated/google/protobuf/any.upb.h deleted file mode 100644 index d29265553f7..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/any.upb.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/any.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_ANY_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_ANY_PROTO_UPB_H_ - -#include "upb/msg.h" - -#include "upb/decode.h" -#include "upb/encode.h" -#include "upb/port_def.inc" -UPB_BEGIN_EXTERN_C - -struct google_protobuf_Any; -typedef struct google_protobuf_Any google_protobuf_Any; - -/* Enums */ - -/* google.protobuf.Any */ - -extern const upb_msglayout google_protobuf_Any_msginit; -UPB_INLINE google_protobuf_Any* google_protobuf_Any_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_Any_msginit, arena); -} -UPB_INLINE google_protobuf_Any* google_protobuf_Any_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_Any* ret = google_protobuf_Any_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Any_msginit)) ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Any_serialize(const google_protobuf_Any* msg, - upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Any_msginit, arena, len); -} - -UPB_INLINE upb_stringview -google_protobuf_Any_type_url(const google_protobuf_Any* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); -} -UPB_INLINE upb_stringview -google_protobuf_Any_value(const google_protobuf_Any* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} - -UPB_INLINE void google_protobuf_Any_set_type_url(google_protobuf_Any* msg, - upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; -} -UPB_INLINE void google_protobuf_Any_set_value(google_protobuf_Any* msg, - upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} - -UPB_END_EXTERN_C - -#include "upb/port_undef.inc" - -#endif /* GOOGLE_PROTOBUF_ANY_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c deleted file mode 100644 index f774873d614..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c +++ /dev/null @@ -1,549 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include "google/protobuf/descriptor.upb.h" -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -static const upb_msglayout* const google_protobuf_FileDescriptorSet_submsgs[1] = - { - &google_protobuf_FileDescriptorProto_msginit, -}; - -static const upb_msglayout_field google_protobuf_FileDescriptorSet__fields[1] = - { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_FileDescriptorSet_msginit = { - &google_protobuf_FileDescriptorSet_submsgs[0], - &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -static const upb_msglayout* const - google_protobuf_FileDescriptorProto_submsgs[6] = { - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_SourceCodeInfo_msginit, -}; - -static const upb_msglayout_field - google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, - {2, UPB_SIZE(16, 32), 2, 0, 9, 1}, - {3, UPB_SIZE(40, 80), 0, 0, 9, 3}, - {4, UPB_SIZE(44, 88), 0, 0, 11, 3}, - {5, UPB_SIZE(48, 96), 0, 1, 11, 3}, - {6, UPB_SIZE(52, 104), 0, 4, 11, 3}, - {7, UPB_SIZE(56, 112), 0, 2, 11, 3}, - {8, UPB_SIZE(32, 64), 4, 3, 11, 1}, - {9, UPB_SIZE(36, 72), 5, 5, 11, 1}, - {10, UPB_SIZE(60, 120), 0, 0, 5, 3}, - {11, UPB_SIZE(64, 128), 0, 0, 5, 3}, - {12, UPB_SIZE(24, 48), 3, 0, 9, 1}, -}; - -const upb_msglayout google_protobuf_FileDescriptorProto_msginit = { - &google_protobuf_FileDescriptorProto_submsgs[0], - &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(72, 144), - 12, - false, -}; - -static const upb_msglayout* const google_protobuf_DescriptorProto_submsgs[8] = { - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_OneofDescriptorProto_msginit, -}; - -static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, {2, UPB_SIZE(20, 40), 0, 4, 11, 3}, - {3, UPB_SIZE(24, 48), 0, 0, 11, 3}, {4, UPB_SIZE(28, 56), 0, 3, 11, 3}, - {5, UPB_SIZE(32, 64), 0, 1, 11, 3}, {6, UPB_SIZE(36, 72), 0, 4, 11, 3}, - {7, UPB_SIZE(16, 32), 2, 5, 11, 1}, {8, UPB_SIZE(40, 80), 0, 6, 11, 3}, - {9, UPB_SIZE(44, 88), 0, 2, 11, 3}, {10, UPB_SIZE(48, 96), 0, 0, 9, 3}, -}; - -const upb_msglayout google_protobuf_DescriptorProto_msginit = { - &google_protobuf_DescriptorProto_submsgs[0], - &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(56, 112), - 10, - false, -}; - -static const upb_msglayout* const - google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - &google_protobuf_ExtensionRangeOptions_msginit, -}; - -static const upb_msglayout_field - google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, - {3, UPB_SIZE(12, 16), 3, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit = { - &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], - &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), - 3, - false, -}; - -static const upb_msglayout_field - google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit = { - NULL, - &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(12, 12), - 2, - false, -}; - -static const upb_msglayout* const - google_protobuf_ExtensionRangeOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field - google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit = { - &google_protobuf_ExtensionRangeOptions_submsgs[0], - &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -static const upb_msglayout* const - google_protobuf_FieldDescriptorProto_submsgs[1] = { - &google_protobuf_FieldOptions_msginit, -}; - -static const upb_msglayout_field - google_protobuf_FieldDescriptorProto__fields[10] = { - {1, UPB_SIZE(32, 32), 5, 0, 9, 1}, - {2, UPB_SIZE(40, 48), 6, 0, 9, 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(48, 64), 7, 0, 9, 1}, - {7, UPB_SIZE(56, 80), 8, 0, 9, 1}, - {8, UPB_SIZE(72, 112), 10, 0, 11, 1}, - {9, UPB_SIZE(28, 28), 4, 0, 5, 1}, - {10, UPB_SIZE(64, 96), 9, 0, 9, 1}, -}; - -const upb_msglayout google_protobuf_FieldDescriptorProto_msginit = { - &google_protobuf_FieldDescriptorProto_submsgs[0], - &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(80, 128), - 10, - false, -}; - -static const upb_msglayout* const - google_protobuf_OneofDescriptorProto_submsgs[1] = { - &google_protobuf_OneofOptions_msginit, -}; - -static const upb_msglayout_field - google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, - {2, UPB_SIZE(16, 32), 2, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_OneofDescriptorProto_msginit = { - &google_protobuf_OneofDescriptorProto_submsgs[0], - &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(24, 48), - 2, - false, -}; - -static const upb_msglayout* const - google_protobuf_EnumDescriptorProto_submsgs[3] = { - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, -}; - -static const upb_msglayout_field - google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, {2, UPB_SIZE(20, 40), 0, 2, 11, 3}, - {3, UPB_SIZE(16, 32), 2, 1, 11, 1}, {4, UPB_SIZE(24, 48), 0, 0, 11, 3}, - {5, UPB_SIZE(28, 56), 0, 0, 9, 3}, -}; - -const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = { - &google_protobuf_EnumDescriptorProto_submsgs[0], - &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), - 5, - false, -}; - -static const upb_msglayout_field - google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, -}; - -const upb_msglayout - google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { - NULL, - &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(12, 12), - 2, - false, -}; - -static const upb_msglayout* const - google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - &google_protobuf_EnumValueOptions_msginit, -}; - -static const upb_msglayout_field - google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 16), 2, 0, 9, 1}, - {2, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {3, UPB_SIZE(16, 32), 3, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit = { - &google_protobuf_EnumValueDescriptorProto_submsgs[0], - &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 48), - 3, - false, -}; - -static const upb_msglayout* const - google_protobuf_ServiceDescriptorProto_submsgs[2] = { - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_ServiceOptions_msginit, -}; - -static const upb_msglayout_field - google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 16), 1, 0, 9, 1}, - {2, UPB_SIZE(20, 40), 0, 0, 11, 3}, - {3, UPB_SIZE(16, 32), 2, 1, 11, 1}, -}; - -const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit = { - &google_protobuf_ServiceDescriptorProto_submsgs[0], - &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), - 3, - false, -}; - -static const upb_msglayout* const - google_protobuf_MethodDescriptorProto_submsgs[1] = { - &google_protobuf_MethodOptions_msginit, -}; - -static const upb_msglayout_field - google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(8, 16), 3, 0, 9, 1}, {2, UPB_SIZE(16, 32), 4, 0, 9, 1}, - {3, UPB_SIZE(24, 48), 5, 0, 9, 1}, {4, UPB_SIZE(32, 64), 6, 0, 11, 1}, - {5, UPB_SIZE(1, 1), 1, 0, 8, 1}, {6, UPB_SIZE(2, 2), 2, 0, 8, 1}, -}; - -const upb_msglayout google_protobuf_MethodDescriptorProto_msginit = { - &google_protobuf_MethodDescriptorProto_submsgs[0], - &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(40, 80), - 6, - false, -}; - -static const upb_msglayout* const google_protobuf_FileOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(32, 32), 11, 0, 9, 1}, - {8, UPB_SIZE(40, 48), 12, 0, 9, 1}, - {9, UPB_SIZE(8, 8), 1, 0, 14, 1}, - {10, UPB_SIZE(16, 16), 2, 0, 8, 1}, - {11, UPB_SIZE(48, 64), 13, 0, 9, 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}, - {20, UPB_SIZE(20, 20), 6, 0, 8, 1}, - {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(56, 80), 14, 0, 9, 1}, - {37, UPB_SIZE(64, 96), 15, 0, 9, 1}, - {39, UPB_SIZE(72, 112), 16, 0, 9, 1}, - {40, UPB_SIZE(80, 128), 17, 0, 9, 1}, - {41, UPB_SIZE(88, 144), 18, 0, 9, 1}, - {42, UPB_SIZE(24, 24), 10, 0, 8, 1}, - {44, UPB_SIZE(96, 160), 19, 0, 9, 1}, - {45, UPB_SIZE(104, 176), 20, 0, 9, 1}, - {999, UPB_SIZE(112, 192), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_FileOptions_msginit = { - &google_protobuf_FileOptions_submsgs[0], - &google_protobuf_FileOptions__fields[0], - UPB_SIZE(120, 208), - 21, - false, -}; - -static const upb_msglayout* const google_protobuf_MessageOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, {2, UPB_SIZE(2, 2), 2, 0, 8, 1}, - {3, UPB_SIZE(3, 3), 3, 0, 8, 1}, {7, UPB_SIZE(4, 4), 4, 0, 8, 1}, - {999, UPB_SIZE(8, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_MessageOptions_msginit = { - &google_protobuf_MessageOptions_submsgs[0], - &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(12, 16), - 5, - false, -}; - -static const upb_msglayout* const google_protobuf_FieldOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_FieldOptions__fields[7] = { - {1, UPB_SIZE(8, 8), 1, 0, 14, 1}, {2, UPB_SIZE(24, 24), 3, 0, 8, 1}, - {3, UPB_SIZE(25, 25), 4, 0, 8, 1}, {5, UPB_SIZE(26, 26), 5, 0, 8, 1}, - {6, UPB_SIZE(16, 16), 2, 0, 14, 1}, {10, UPB_SIZE(27, 27), 6, 0, 8, 1}, - {999, UPB_SIZE(28, 32), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_FieldOptions_msginit = { - &google_protobuf_FieldOptions_submsgs[0], - &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(32, 40), - 7, - false, -}; - -static const upb_msglayout* const google_protobuf_OneofOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_OneofOptions_msginit = { - &google_protobuf_OneofOptions_submsgs[0], - &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -static const upb_msglayout* const google_protobuf_EnumOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {3, UPB_SIZE(2, 2), 2, 0, 8, 1}, - {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_EnumOptions_msginit = { - &google_protobuf_EnumOptions_submsgs[0], - &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), - 3, - false, -}; - -static const upb_msglayout* const google_protobuf_EnumValueOptions_submsgs[1] = - { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_EnumValueOptions_msginit = { - &google_protobuf_EnumValueOptions_submsgs[0], - &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), - 2, - false, -}; - -static const upb_msglayout* const google_protobuf_ServiceOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_ServiceOptions_msginit = { - &google_protobuf_ServiceOptions_submsgs[0], - &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), - 2, - false, -}; - -static const upb_msglayout* const google_protobuf_MethodOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(16, 16), 2, 0, 8, 1}, - {34, UPB_SIZE(8, 8), 1, 0, 14, 1}, - {999, UPB_SIZE(20, 24), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_MethodOptions_msginit = { - &google_protobuf_MethodOptions_submsgs[0], - &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(24, 32), - 3, - false, -}; - -static const upb_msglayout* const - google_protobuf_UninterpretedOption_submsgs[1] = { - &google_protobuf_UninterpretedOption_NamePart_msginit, -}; - -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}, - {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}, -}; - -const upb_msglayout google_protobuf_UninterpretedOption_msginit = { - &google_protobuf_UninterpretedOption_submsgs[0], - &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), - 7, - false, -}; - -static const upb_msglayout_field - google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(8, 16), 2, 0, 9, 2}, - {2, UPB_SIZE(1, 1), 1, 0, 8, 2}, -}; - -const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit = { - NULL, - &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), - 2, - false, -}; - -static const upb_msglayout* const google_protobuf_SourceCodeInfo_submsgs[1] = { - &google_protobuf_SourceCodeInfo_Location_msginit, -}; - -static const upb_msglayout_field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_SourceCodeInfo_msginit = { - &google_protobuf_SourceCodeInfo_submsgs[0], - &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -static const upb_msglayout_field - google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(24, 48), 0, 0, 5, 3}, {2, UPB_SIZE(28, 56), 0, 0, 5, 3}, - {3, UPB_SIZE(8, 16), 1, 0, 9, 1}, {4, UPB_SIZE(16, 32), 2, 0, 9, 1}, - {6, UPB_SIZE(32, 64), 0, 0, 9, 3}, -}; - -const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = { - NULL, - &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(40, 80), - 5, - false, -}; - -static const upb_msglayout* const google_protobuf_GeneratedCodeInfo_submsgs[1] = - { - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, -}; - -static const upb_msglayout_field google_protobuf_GeneratedCodeInfo__fields[1] = - { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = { - &google_protobuf_GeneratedCodeInfo_submsgs[0], - &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -static const upb_msglayout_field - google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(24, 32), 0, 0, 5, 3}, - {2, UPB_SIZE(16, 16), 3, 0, 9, 1}, - {3, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {4, UPB_SIZE(8, 8), 2, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = { - NULL, - &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(32, 48), - 4, - false, -}; - -#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h b/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h deleted file mode 100644 index 37f0139ce32..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h +++ /dev/null @@ -1,1879 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ - -#include "upb/msg.h" - -#include "upb/decode.h" -#include "upb/encode.h" -#include "upb/port_def.inc" -UPB_BEGIN_EXTERN_C - -struct google_protobuf_FileDescriptorSet; -struct google_protobuf_FileDescriptorProto; -struct google_protobuf_DescriptorProto; -struct google_protobuf_DescriptorProto_ExtensionRange; -struct google_protobuf_DescriptorProto_ReservedRange; -struct google_protobuf_ExtensionRangeOptions; -struct google_protobuf_FieldDescriptorProto; -struct google_protobuf_OneofDescriptorProto; -struct google_protobuf_EnumDescriptorProto; -struct google_protobuf_EnumDescriptorProto_EnumReservedRange; -struct google_protobuf_EnumValueDescriptorProto; -struct google_protobuf_ServiceDescriptorProto; -struct google_protobuf_MethodDescriptorProto; -struct google_protobuf_FileOptions; -struct google_protobuf_MessageOptions; -struct google_protobuf_FieldOptions; -struct google_protobuf_OneofOptions; -struct google_protobuf_EnumOptions; -struct google_protobuf_EnumValueOptions; -struct google_protobuf_ServiceOptions; -struct google_protobuf_MethodOptions; -struct google_protobuf_UninterpretedOption; -struct google_protobuf_UninterpretedOption_NamePart; -struct google_protobuf_SourceCodeInfo; -struct google_protobuf_SourceCodeInfo_Location; -struct google_protobuf_GeneratedCodeInfo; -struct google_protobuf_GeneratedCodeInfo_Annotation; -typedef struct google_protobuf_FileDescriptorSet - google_protobuf_FileDescriptorSet; -typedef struct google_protobuf_FileDescriptorProto - google_protobuf_FileDescriptorProto; -typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; -typedef struct google_protobuf_DescriptorProto_ExtensionRange - google_protobuf_DescriptorProto_ExtensionRange; -typedef struct google_protobuf_DescriptorProto_ReservedRange - google_protobuf_DescriptorProto_ReservedRange; -typedef struct google_protobuf_ExtensionRangeOptions - google_protobuf_ExtensionRangeOptions; -typedef struct google_protobuf_FieldDescriptorProto - google_protobuf_FieldDescriptorProto; -typedef struct google_protobuf_OneofDescriptorProto - google_protobuf_OneofDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto - google_protobuf_EnumDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange - google_protobuf_EnumDescriptorProto_EnumReservedRange; -typedef struct google_protobuf_EnumValueDescriptorProto - google_protobuf_EnumValueDescriptorProto; -typedef struct google_protobuf_ServiceDescriptorProto - google_protobuf_ServiceDescriptorProto; -typedef struct google_protobuf_MethodDescriptorProto - google_protobuf_MethodDescriptorProto; -typedef struct google_protobuf_FileOptions google_protobuf_FileOptions; -typedef struct google_protobuf_MessageOptions google_protobuf_MessageOptions; -typedef struct google_protobuf_FieldOptions google_protobuf_FieldOptions; -typedef struct google_protobuf_OneofOptions google_protobuf_OneofOptions; -typedef struct google_protobuf_EnumOptions google_protobuf_EnumOptions; -typedef struct google_protobuf_EnumValueOptions - google_protobuf_EnumValueOptions; -typedef struct google_protobuf_ServiceOptions google_protobuf_ServiceOptions; -typedef struct google_protobuf_MethodOptions google_protobuf_MethodOptions; -typedef struct google_protobuf_UninterpretedOption - google_protobuf_UninterpretedOption; -typedef struct google_protobuf_UninterpretedOption_NamePart - google_protobuf_UninterpretedOption_NamePart; -typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo; -typedef struct google_protobuf_SourceCodeInfo_Location - google_protobuf_SourceCodeInfo_Location; -typedef struct google_protobuf_GeneratedCodeInfo - google_protobuf_GeneratedCodeInfo; -typedef struct google_protobuf_GeneratedCodeInfo_Annotation - google_protobuf_GeneratedCodeInfo_Annotation; - -/* Enums */ - -typedef enum { - google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, - google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, - google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 -} google_protobuf_FieldDescriptorProto_Label; - -typedef enum { - google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, - google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, - google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, - google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, - google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, - google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, - google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, - google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, - google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, - google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, - google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, - google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, - google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, - google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, - google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, - google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, - google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, - google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 -} google_protobuf_FieldDescriptorProto_Type; - -typedef enum { - google_protobuf_FieldOptions_STRING = 0, - google_protobuf_FieldOptions_CORD = 1, - google_protobuf_FieldOptions_STRING_PIECE = 2 -} google_protobuf_FieldOptions_CType; - -typedef enum { - google_protobuf_FieldOptions_JS_NORMAL = 0, - google_protobuf_FieldOptions_JS_STRING = 1, - google_protobuf_FieldOptions_JS_NUMBER = 2 -} google_protobuf_FieldOptions_JSType; - -typedef enum { - google_protobuf_FileOptions_SPEED = 1, - google_protobuf_FileOptions_CODE_SIZE = 2, - google_protobuf_FileOptions_LITE_RUNTIME = 3 -} google_protobuf_FileOptions_OptimizeMode; - -typedef enum { - google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, - google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, - google_protobuf_MethodOptions_IDEMPOTENT = 2 -} google_protobuf_MethodOptions_IdempotencyLevel; - -/* google.protobuf.FileDescriptorSet */ - -extern const upb_msglayout google_protobuf_FileDescriptorSet_msginit; -UPB_INLINE google_protobuf_FileDescriptorSet* -google_protobuf_FileDescriptorSet_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_FileDescriptorSet_msginit, arena); -} -UPB_INLINE google_protobuf_FileDescriptorSet* -google_protobuf_FileDescriptorSet_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_FileDescriptorSet* ret = - google_protobuf_FileDescriptorSet_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_FileDescriptorSet_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize( - const google_protobuf_FileDescriptorSet* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_FileDescriptorSet_msginit, arena, - len); -} - -UPB_INLINE const upb_array* google_protobuf_FileDescriptorSet_file( - const google_protobuf_FileDescriptorSet* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_FileDescriptorSet_set_file( - google_protobuf_FileDescriptorSet* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.FileDescriptorProto */ - -extern const upb_msglayout google_protobuf_FileDescriptorProto_msginit; -UPB_INLINE google_protobuf_FileDescriptorProto* -google_protobuf_FileDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_FileDescriptorProto* -google_protobuf_FileDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_FileDescriptorProto* ret = - google_protobuf_FileDescriptorProto_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_FileDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize( - const google_protobuf_FileDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_FileDescriptorProto_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_FileDescriptorProto_name( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE upb_stringview google_protobuf_FileDescriptorProto_package( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)); -} -UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_dependency( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(40, 80)); -} -UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_message_type( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(44, 88)); -} -UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_enum_type( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(48, 96)); -} -UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_service( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(52, 104)); -} -UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_extension( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(56, 112)); -} -UPB_INLINE const google_protobuf_FileOptions* -google_protobuf_FileDescriptorProto_options( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_FileOptions*, - UPB_SIZE(32, 64)); -} -UPB_INLINE const google_protobuf_SourceCodeInfo* -google_protobuf_FileDescriptorProto_source_code_info( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_SourceCodeInfo*, - UPB_SIZE(36, 72)); -} -UPB_INLINE const upb_array* -google_protobuf_FileDescriptorProto_public_dependency( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(60, 120)); -} -UPB_INLINE const upb_array* google_protobuf_FileDescriptorProto_weak_dependency( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(64, 128)); -} -UPB_INLINE upb_stringview google_protobuf_FileDescriptorProto_syntax( - const google_protobuf_FileDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)); -} - -UPB_INLINE void google_protobuf_FileDescriptorProto_set_name( - google_protobuf_FileDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_package( - google_protobuf_FileDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_dependency( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(40, 80)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_message_type( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(44, 88)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_enum_type( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(48, 96)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_service( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(52, 104)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_extension( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(56, 112)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_options( - google_protobuf_FileDescriptorProto* msg, - google_protobuf_FileOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_FileOptions*, UPB_SIZE(32, 64)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info( - google_protobuf_FileDescriptorProto* msg, - google_protobuf_SourceCodeInfo* value) { - UPB_FIELD_AT(msg, google_protobuf_SourceCodeInfo*, UPB_SIZE(36, 72)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_public_dependency( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(60, 120)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_weak_dependency( - google_protobuf_FileDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(64, 128)) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax( - google_protobuf_FileDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)) = value; -} - -/* google.protobuf.DescriptorProto */ - -extern const upb_msglayout google_protobuf_DescriptorProto_msginit; -UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_DescriptorProto* -google_protobuf_DescriptorProto_parsenew(upb_stringview buf, upb_arena* arena) { - google_protobuf_DescriptorProto* ret = - google_protobuf_DescriptorProto_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_DescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_DescriptorProto_serialize( - const google_protobuf_DescriptorProto* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_DescriptorProto_msginit, arena, len); -} - -UPB_INLINE upb_stringview google_protobuf_DescriptorProto_name( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_field( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 40)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_nested_type( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 48)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_enum_type( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 56)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_extension_range( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(32, 64)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_extension( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(36, 72)); -} -UPB_INLINE const google_protobuf_MessageOptions* -google_protobuf_DescriptorProto_options( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_MessageOptions*, - UPB_SIZE(16, 32)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_oneof_decl( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(40, 80)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_reserved_range( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(44, 88)); -} -UPB_INLINE const upb_array* google_protobuf_DescriptorProto_reserved_name( - const google_protobuf_DescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(48, 96)); -} - -UPB_INLINE void google_protobuf_DescriptorProto_set_name( - google_protobuf_DescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_field( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 40)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_nested_type( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 48)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_enum_type( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 56)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_extension_range( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(32, 64)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_extension( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(36, 72)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_options( - google_protobuf_DescriptorProto* msg, - google_protobuf_MessageOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_MessageOptions*, UPB_SIZE(16, 32)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_oneof_decl( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(40, 80)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_reserved_range( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(44, 88)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_reserved_name( - google_protobuf_DescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(48, 96)) = value; -} - -/* google.protobuf.DescriptorProto.ExtensionRange */ - -extern const upb_msglayout - google_protobuf_DescriptorProto_ExtensionRange_msginit; -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* -google_protobuf_DescriptorProto_ExtensionRange_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, - arena); -} -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* -google_protobuf_DescriptorProto_ExtensionRange_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_DescriptorProto_ExtensionRange* ret = - google_protobuf_DescriptorProto_ExtensionRange_new(arena); - return (ret && - upb_decode(buf, ret, - &google_protobuf_DescriptorProto_ExtensionRange_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize( - const google_protobuf_DescriptorProto_ExtensionRange* msg, upb_arena* arena, - size_t* len) { - return upb_encode( - msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena, len); -} - -UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start( - const google_protobuf_DescriptorProto_ExtensionRange* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); -} -UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end( - const google_protobuf_DescriptorProto_ExtensionRange* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); -} -UPB_INLINE const google_protobuf_ExtensionRangeOptions* -google_protobuf_DescriptorProto_ExtensionRange_options( - const google_protobuf_DescriptorProto_ExtensionRange* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_ExtensionRangeOptions*, - UPB_SIZE(12, 16)); -} - -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start( - google_protobuf_DescriptorProto_ExtensionRange* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end( - google_protobuf_DescriptorProto_ExtensionRange* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options( - google_protobuf_DescriptorProto_ExtensionRange* msg, - google_protobuf_ExtensionRangeOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_ExtensionRangeOptions*, UPB_SIZE(12, 16)) = - value; -} - -/* google.protobuf.DescriptorProto.ReservedRange */ - -extern const upb_msglayout - google_protobuf_DescriptorProto_ReservedRange_msginit; -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* -google_protobuf_DescriptorProto_ReservedRange_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, - arena); -} -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* -google_protobuf_DescriptorProto_ReservedRange_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_DescriptorProto_ReservedRange* ret = - google_protobuf_DescriptorProto_ReservedRange_new(arena); - return (ret && - upb_decode(buf, ret, - &google_protobuf_DescriptorProto_ReservedRange_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize( - const google_protobuf_DescriptorProto_ReservedRange* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, - arena, len); -} - -UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start( - const google_protobuf_DescriptorProto_ReservedRange* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); -} -UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end( - const google_protobuf_DescriptorProto_ReservedRange* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); -} - -UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start( - google_protobuf_DescriptorProto_ReservedRange* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end( - google_protobuf_DescriptorProto_ReservedRange* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; -} - -/* google.protobuf.ExtensionRangeOptions */ - -extern const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit; -UPB_INLINE google_protobuf_ExtensionRangeOptions* -google_protobuf_ExtensionRangeOptions_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); -} -UPB_INLINE google_protobuf_ExtensionRangeOptions* -google_protobuf_ExtensionRangeOptions_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_ExtensionRangeOptions* ret = - google_protobuf_ExtensionRangeOptions_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_ExtensionRangeOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize( - const google_protobuf_ExtensionRangeOptions* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, arena, - len); -} - -UPB_INLINE const upb_array* -google_protobuf_ExtensionRangeOptions_uninterpreted_option( - const google_protobuf_ExtensionRangeOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_ExtensionRangeOptions_set_uninterpreted_option( - google_protobuf_ExtensionRangeOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.FieldDescriptorProto */ - -extern const upb_msglayout google_protobuf_FieldDescriptorProto_msginit; -UPB_INLINE google_protobuf_FieldDescriptorProto* -google_protobuf_FieldDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_FieldDescriptorProto* -google_protobuf_FieldDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_FieldDescriptorProto* ret = - google_protobuf_FieldDescriptorProto_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_FieldDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize( - const google_protobuf_FieldDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_FieldDescriptorProto_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_name( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)); -} -UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_extendee( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)); -} -UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(24, 24)); -} -UPB_INLINE google_protobuf_FieldDescriptorProto_Label -google_protobuf_FieldDescriptorProto_label( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Label, - UPB_SIZE(8, 8)); -} -UPB_INLINE google_protobuf_FieldDescriptorProto_Type -google_protobuf_FieldDescriptorProto_type( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Type, - UPB_SIZE(16, 16)); -} -UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_type_name( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)); -} -UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_default_value( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)); -} -UPB_INLINE const google_protobuf_FieldOptions* -google_protobuf_FieldDescriptorProto_options( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_FieldOptions*, - UPB_SIZE(72, 112)); -} -UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(28, 28)); -} -UPB_INLINE upb_stringview google_protobuf_FieldDescriptorProto_json_name( - const google_protobuf_FieldDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)); -} - -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name( - google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee( - google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number( - google_protobuf_FieldDescriptorProto* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(24, 24)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label( - google_protobuf_FieldDescriptorProto* msg, - google_protobuf_FieldDescriptorProto_Label value) { - UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Label, - UPB_SIZE(8, 8)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type( - google_protobuf_FieldDescriptorProto* msg, - google_protobuf_FieldDescriptorProto_Type value) { - UPB_FIELD_AT(msg, google_protobuf_FieldDescriptorProto_Type, - UPB_SIZE(16, 16)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name( - google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value( - google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options( - google_protobuf_FieldDescriptorProto* msg, - google_protobuf_FieldOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_FieldOptions*, UPB_SIZE(72, 112)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index( - google_protobuf_FieldDescriptorProto* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(28, 28)) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name( - google_protobuf_FieldDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)) = value; -} - -/* google.protobuf.OneofDescriptorProto */ - -extern const upb_msglayout google_protobuf_OneofDescriptorProto_msginit; -UPB_INLINE google_protobuf_OneofDescriptorProto* -google_protobuf_OneofDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_OneofDescriptorProto* -google_protobuf_OneofDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_OneofDescriptorProto* ret = - google_protobuf_OneofDescriptorProto_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_OneofDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize( - const google_protobuf_OneofDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_OneofDescriptorProto_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_OneofDescriptorProto_name( - const google_protobuf_OneofDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE const google_protobuf_OneofOptions* -google_protobuf_OneofDescriptorProto_options( - const google_protobuf_OneofDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_OneofOptions*, - UPB_SIZE(16, 32)); -} - -UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name( - google_protobuf_OneofDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options( - google_protobuf_OneofDescriptorProto* msg, - google_protobuf_OneofOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_OneofOptions*, UPB_SIZE(16, 32)) = value; -} - -/* google.protobuf.EnumDescriptorProto */ - -extern const upb_msglayout google_protobuf_EnumDescriptorProto_msginit; -UPB_INLINE google_protobuf_EnumDescriptorProto* -google_protobuf_EnumDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_EnumDescriptorProto* -google_protobuf_EnumDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_EnumDescriptorProto* ret = - google_protobuf_EnumDescriptorProto_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_EnumDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize( - const google_protobuf_EnumDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_EnumDescriptorProto_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_EnumDescriptorProto_name( - const google_protobuf_EnumDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE const upb_array* google_protobuf_EnumDescriptorProto_value( - const google_protobuf_EnumDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 40)); -} -UPB_INLINE const google_protobuf_EnumOptions* -google_protobuf_EnumDescriptorProto_options( - const google_protobuf_EnumDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_EnumOptions*, - UPB_SIZE(16, 32)); -} -UPB_INLINE const upb_array* google_protobuf_EnumDescriptorProto_reserved_range( - const google_protobuf_EnumDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 48)); -} -UPB_INLINE const upb_array* google_protobuf_EnumDescriptorProto_reserved_name( - const google_protobuf_EnumDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 56)); -} - -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name( - google_protobuf_EnumDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_value( - google_protobuf_EnumDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 40)) = value; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options( - google_protobuf_EnumDescriptorProto* msg, - google_protobuf_EnumOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_EnumOptions*, UPB_SIZE(16, 32)) = value; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_reserved_range( - google_protobuf_EnumDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 48)) = value; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_reserved_name( - google_protobuf_EnumDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 56)) = value; -} - -/* google.protobuf.EnumDescriptorProto.EnumReservedRange */ - -extern const upb_msglayout - google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit; -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* -google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_arena* arena) { - return upb_msg_new( - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); -} -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* -google_protobuf_EnumDescriptorProto_EnumReservedRange_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = - google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); - return (ret && - upb_decode( - buf, ret, - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* -google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize( - const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, - upb_arena* arena, size_t* len) { - return upb_encode( - msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - arena, len); -} - -UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start( - const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); -} -UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end( - const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); -} - -UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start( - google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end( - google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; -} - -/* google.protobuf.EnumValueDescriptorProto */ - -extern const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit; -UPB_INLINE google_protobuf_EnumValueDescriptorProto* -google_protobuf_EnumValueDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_EnumValueDescriptorProto* -google_protobuf_EnumValueDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_EnumValueDescriptorProto* ret = - google_protobuf_EnumValueDescriptorProto_new(arena); - return (ret && upb_decode(buf, ret, - &google_protobuf_EnumValueDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize( - const google_protobuf_EnumValueDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, - arena, len); -} - -UPB_INLINE upb_stringview google_protobuf_EnumValueDescriptorProto_name( - const google_protobuf_EnumValueDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number( - const google_protobuf_EnumValueDescriptorProto* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); -} -UPB_INLINE const google_protobuf_EnumValueOptions* -google_protobuf_EnumValueDescriptorProto_options( - const google_protobuf_EnumValueDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_EnumValueOptions*, - UPB_SIZE(16, 32)); -} - -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name( - google_protobuf_EnumValueDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number( - google_protobuf_EnumValueDescriptorProto* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options( - google_protobuf_EnumValueDescriptorProto* msg, - google_protobuf_EnumValueOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_EnumValueOptions*, UPB_SIZE(16, 32)) = - value; -} - -/* google.protobuf.ServiceDescriptorProto */ - -extern const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit; -UPB_INLINE google_protobuf_ServiceDescriptorProto* -google_protobuf_ServiceDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_ServiceDescriptorProto* -google_protobuf_ServiceDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_ServiceDescriptorProto* ret = - google_protobuf_ServiceDescriptorProto_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_ServiceDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize( - const google_protobuf_ServiceDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_ServiceDescriptorProto_name( - const google_protobuf_ServiceDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE const upb_array* google_protobuf_ServiceDescriptorProto_method( - const google_protobuf_ServiceDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 40)); -} -UPB_INLINE const google_protobuf_ServiceOptions* -google_protobuf_ServiceDescriptorProto_options( - const google_protobuf_ServiceDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_ServiceOptions*, - UPB_SIZE(16, 32)); -} - -UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name( - google_protobuf_ServiceDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_method( - google_protobuf_ServiceDescriptorProto* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 40)) = value; -} -UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options( - google_protobuf_ServiceDescriptorProto* msg, - google_protobuf_ServiceOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_ServiceOptions*, UPB_SIZE(16, 32)) = value; -} - -/* google.protobuf.MethodDescriptorProto */ - -extern const upb_msglayout google_protobuf_MethodDescriptorProto_msginit; -UPB_INLINE google_protobuf_MethodDescriptorProto* -google_protobuf_MethodDescriptorProto_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_MethodDescriptorProto* -google_protobuf_MethodDescriptorProto_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_MethodDescriptorProto* ret = - google_protobuf_MethodDescriptorProto_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_MethodDescriptorProto_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize( - const google_protobuf_MethodDescriptorProto* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_MethodDescriptorProto_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_MethodDescriptorProto_name( - const google_protobuf_MethodDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE upb_stringview google_protobuf_MethodDescriptorProto_input_type( - const google_protobuf_MethodDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)); -} -UPB_INLINE upb_stringview google_protobuf_MethodDescriptorProto_output_type( - const google_protobuf_MethodDescriptorProto* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)); -} -UPB_INLINE const google_protobuf_MethodOptions* -google_protobuf_MethodDescriptorProto_options( - const google_protobuf_MethodDescriptorProto* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_MethodOptions*, - UPB_SIZE(32, 64)); -} -UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming( - const google_protobuf_MethodDescriptorProto* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); -} -UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming( - const google_protobuf_MethodDescriptorProto* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)); -} - -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name( - google_protobuf_MethodDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type( - google_protobuf_MethodDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type( - google_protobuf_MethodDescriptorProto* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(24, 48)) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options( - google_protobuf_MethodDescriptorProto* msg, - google_protobuf_MethodOptions* value) { - UPB_FIELD_AT(msg, google_protobuf_MethodOptions*, UPB_SIZE(32, 64)) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming( - google_protobuf_MethodDescriptorProto* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming( - google_protobuf_MethodDescriptorProto* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)) = value; -} - -/* google.protobuf.FileOptions */ - -extern const upb_msglayout google_protobuf_FileOptions_msginit; -UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_FileOptions_msginit, arena); -} -UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_FileOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_FileOptions_serialize( - const google_protobuf_FileOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_FileOptions_msginit, arena, len); -} - -UPB_INLINE upb_stringview google_protobuf_FileOptions_java_package( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_java_outer_classname( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)); -} -UPB_INLINE google_protobuf_FileOptions_OptimizeMode -google_protobuf_FileOptions_optimize_for( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, google_protobuf_FileOptions_OptimizeMode, - UPB_SIZE(8, 8)); -} -UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)); -} -UPB_INLINE upb_stringview -google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)); -} -UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(17, 17)); -} -UPB_INLINE bool google_protobuf_FileOptions_java_generic_services( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(18, 18)); -} -UPB_INLINE bool google_protobuf_FileOptions_py_generic_services( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(19, 19)); -} -UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(20, 20)); -} -UPB_INLINE bool google_protobuf_FileOptions_deprecated( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(21, 21)); -} -UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(22, 22)); -} -UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(23, 23)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_objc_class_prefix( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_csharp_namespace( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_swift_prefix( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(72, 112)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_php_class_prefix( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(80, 128)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_php_namespace( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(88, 144)); -} -UPB_INLINE bool google_protobuf_FileOptions_php_generic_services( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_php_metadata_namespace( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(96, 160)); -} -UPB_INLINE upb_stringview google_protobuf_FileOptions_ruby_package( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(104, 176)); -} -UPB_INLINE const upb_array* google_protobuf_FileOptions_uninterpreted_option( - const google_protobuf_FileOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(112, 192)); -} - -UPB_INLINE void google_protobuf_FileOptions_set_java_package( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_optimize_for( - google_protobuf_FileOptions* msg, - google_protobuf_FileOptions_OptimizeMode value) { - UPB_FIELD_AT(msg, google_protobuf_FileOptions_OptimizeMode, UPB_SIZE(8, 8)) = - value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_go_package( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(17, 17)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(18, 18)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(19, 19)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(20, 20)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_deprecated( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(21, 21)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(22, 22)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(23, 23)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(56, 80)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(64, 96)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(72, 112)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(80, 128)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_namespace( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(88, 144)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services( - google_protobuf_FileOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(96, 160)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_ruby_package( - google_protobuf_FileOptions* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(104, 176)) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_uninterpreted_option( - google_protobuf_FileOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(112, 192)) = value; -} - -/* google.protobuf.MessageOptions */ - -extern const upb_msglayout google_protobuf_MessageOptions_msginit; -UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); -} -UPB_INLINE google_protobuf_MessageOptions* -google_protobuf_MessageOptions_parsenew(upb_stringview buf, upb_arena* arena) { - google_protobuf_MessageOptions* ret = - google_protobuf_MessageOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_MessageOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_MessageOptions_serialize( - const google_protobuf_MessageOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_MessageOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format( - const google_protobuf_MessageOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); -} -UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor( - const google_protobuf_MessageOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)); -} -UPB_INLINE bool google_protobuf_MessageOptions_deprecated( - const google_protobuf_MessageOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(3, 3)); -} -UPB_INLINE bool google_protobuf_MessageOptions_map_entry( - const google_protobuf_MessageOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(4, 4)); -} -UPB_INLINE const upb_array* google_protobuf_MessageOptions_uninterpreted_option( - const google_protobuf_MessageOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(8, 8)); -} - -UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format( - google_protobuf_MessageOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; -} -UPB_INLINE void -google_protobuf_MessageOptions_set_no_standard_descriptor_accessor( - google_protobuf_MessageOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_deprecated( - google_protobuf_MessageOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(3, 3)) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_map_entry( - google_protobuf_MessageOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(4, 4)) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_uninterpreted_option( - google_protobuf_MessageOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(8, 8)) = value; -} - -/* google.protobuf.FieldOptions */ - -extern const upb_msglayout google_protobuf_FieldOptions_msginit; -UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); -} -UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_FieldOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_FieldOptions_serialize( - const google_protobuf_FieldOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_FieldOptions_msginit, arena, len); -} - -UPB_INLINE google_protobuf_FieldOptions_CType -google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, google_protobuf_FieldOptions_CType, UPB_SIZE(8, 8)); -} -UPB_INLINE bool google_protobuf_FieldOptions_packed( - const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)); -} -UPB_INLINE bool google_protobuf_FieldOptions_deprecated( - const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(25, 25)); -} -UPB_INLINE bool google_protobuf_FieldOptions_lazy( - const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(26, 26)); -} -UPB_INLINE google_protobuf_FieldOptions_JSType -google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, google_protobuf_FieldOptions_JSType, - UPB_SIZE(16, 16)); -} -UPB_INLINE bool google_protobuf_FieldOptions_weak( - const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(27, 27)); -} -UPB_INLINE const upb_array* google_protobuf_FieldOptions_uninterpreted_option( - const google_protobuf_FieldOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 32)); -} - -UPB_INLINE void google_protobuf_FieldOptions_set_ctype( - google_protobuf_FieldOptions* msg, - google_protobuf_FieldOptions_CType value) { - UPB_FIELD_AT(msg, google_protobuf_FieldOptions_CType, UPB_SIZE(8, 8)) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_packed( - google_protobuf_FieldOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(24, 24)) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_deprecated( - google_protobuf_FieldOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(25, 25)) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_lazy( - google_protobuf_FieldOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(26, 26)) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_jstype( - google_protobuf_FieldOptions* msg, - google_protobuf_FieldOptions_JSType value) { - UPB_FIELD_AT(msg, google_protobuf_FieldOptions_JSType, UPB_SIZE(16, 16)) = - value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_weak( - google_protobuf_FieldOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(27, 27)) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_uninterpreted_option( - google_protobuf_FieldOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 32)) = value; -} - -/* google.protobuf.OneofOptions */ - -extern const upb_msglayout google_protobuf_OneofOptions_msginit; -UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); -} -UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_OneofOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_OneofOptions_serialize( - const google_protobuf_OneofOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_OneofOptions_msginit, arena, len); -} - -UPB_INLINE const upb_array* google_protobuf_OneofOptions_uninterpreted_option( - const google_protobuf_OneofOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_OneofOptions_set_uninterpreted_option( - google_protobuf_OneofOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.EnumOptions */ - -extern const upb_msglayout google_protobuf_EnumOptions_msginit; -UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); -} -UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_EnumOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_EnumOptions_serialize( - const google_protobuf_EnumOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_EnumOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumOptions_allow_alias( - const google_protobuf_EnumOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); -} -UPB_INLINE bool google_protobuf_EnumOptions_deprecated( - const google_protobuf_EnumOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)); -} -UPB_INLINE const upb_array* google_protobuf_EnumOptions_uninterpreted_option( - const google_protobuf_EnumOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(4, 8)); -} - -UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias( - google_protobuf_EnumOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; -} -UPB_INLINE void google_protobuf_EnumOptions_set_deprecated( - google_protobuf_EnumOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(2, 2)) = value; -} -UPB_INLINE void google_protobuf_EnumOptions_set_uninterpreted_option( - google_protobuf_EnumOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(4, 8)) = value; -} - -/* google.protobuf.EnumValueOptions */ - -extern const upb_msglayout google_protobuf_EnumValueOptions_msginit; -UPB_INLINE google_protobuf_EnumValueOptions* -google_protobuf_EnumValueOptions_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); -} -UPB_INLINE google_protobuf_EnumValueOptions* -google_protobuf_EnumValueOptions_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_EnumValueOptions* ret = - google_protobuf_EnumValueOptions_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_EnumValueOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_EnumValueOptions_serialize( - const google_protobuf_EnumValueOptions* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_EnumValueOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated( - const google_protobuf_EnumValueOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); -} -UPB_INLINE const upb_array* -google_protobuf_EnumValueOptions_uninterpreted_option( - const google_protobuf_EnumValueOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(4, 8)); -} - -UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated( - google_protobuf_EnumValueOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; -} -UPB_INLINE void google_protobuf_EnumValueOptions_set_uninterpreted_option( - google_protobuf_EnumValueOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(4, 8)) = value; -} - -/* google.protobuf.ServiceOptions */ - -extern const upb_msglayout google_protobuf_ServiceOptions_msginit; -UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); -} -UPB_INLINE google_protobuf_ServiceOptions* -google_protobuf_ServiceOptions_parsenew(upb_stringview buf, upb_arena* arena) { - google_protobuf_ServiceOptions* ret = - google_protobuf_ServiceOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_ServiceOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_ServiceOptions_serialize( - const google_protobuf_ServiceOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_ServiceOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_ServiceOptions_deprecated( - const google_protobuf_ServiceOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); -} -UPB_INLINE const upb_array* google_protobuf_ServiceOptions_uninterpreted_option( - const google_protobuf_ServiceOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(4, 8)); -} - -UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated( - google_protobuf_ServiceOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; -} -UPB_INLINE void google_protobuf_ServiceOptions_set_uninterpreted_option( - google_protobuf_ServiceOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(4, 8)) = value; -} - -/* google.protobuf.MethodOptions */ - -extern const upb_msglayout google_protobuf_MethodOptions_msginit; -UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); -} -UPB_INLINE google_protobuf_MethodOptions* -google_protobuf_MethodOptions_parsenew(upb_stringview buf, upb_arena* arena) { - google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_MethodOptions_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_MethodOptions_serialize( - const google_protobuf_MethodOptions* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_MethodOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_MethodOptions_deprecated( - const google_protobuf_MethodOptions* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)); -} -UPB_INLINE google_protobuf_MethodOptions_IdempotencyLevel -google_protobuf_MethodOptions_idempotency_level( - const google_protobuf_MethodOptions* msg) { - return UPB_FIELD_AT(msg, google_protobuf_MethodOptions_IdempotencyLevel, - UPB_SIZE(8, 8)); -} -UPB_INLINE const upb_array* google_protobuf_MethodOptions_uninterpreted_option( - const google_protobuf_MethodOptions* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(20, 24)); -} - -UPB_INLINE void google_protobuf_MethodOptions_set_deprecated( - google_protobuf_MethodOptions* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(16, 16)) = value; -} -UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level( - google_protobuf_MethodOptions* msg, - google_protobuf_MethodOptions_IdempotencyLevel value) { - UPB_FIELD_AT(msg, google_protobuf_MethodOptions_IdempotencyLevel, - UPB_SIZE(8, 8)) = value; -} -UPB_INLINE void google_protobuf_MethodOptions_set_uninterpreted_option( - google_protobuf_MethodOptions* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(20, 24)) = value; -} - -/* google.protobuf.UninterpretedOption */ - -extern const upb_msglayout google_protobuf_UninterpretedOption_msginit; -UPB_INLINE google_protobuf_UninterpretedOption* -google_protobuf_UninterpretedOption_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); -} -UPB_INLINE google_protobuf_UninterpretedOption* -google_protobuf_UninterpretedOption_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_UninterpretedOption* ret = - google_protobuf_UninterpretedOption_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_UninterpretedOption_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_UninterpretedOption_serialize( - const google_protobuf_UninterpretedOption* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_UninterpretedOption_msginit, arena, - len); -} - -UPB_INLINE const upb_array* google_protobuf_UninterpretedOption_name( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(56, 80)); -} -UPB_INLINE upb_stringview google_protobuf_UninterpretedOption_identifier_value( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)); -} -UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(8, 8)); -} -UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(16, 16)); -} -UPB_INLINE double google_protobuf_UninterpretedOption_double_value( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, double, UPB_SIZE(24, 24)); -} -UPB_INLINE upb_stringview google_protobuf_UninterpretedOption_string_value( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)); -} -UPB_INLINE upb_stringview google_protobuf_UninterpretedOption_aggregate_value( - const google_protobuf_UninterpretedOption* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)); -} - -UPB_INLINE void google_protobuf_UninterpretedOption_set_name( - google_protobuf_UninterpretedOption* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(56, 80)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value( - google_protobuf_UninterpretedOption* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(32, 32)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value( - google_protobuf_UninterpretedOption* msg, uint64_t value) { - UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(8, 8)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value( - google_protobuf_UninterpretedOption* msg, int64_t value) { - UPB_FIELD_AT(msg, int64_t, UPB_SIZE(16, 16)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value( - google_protobuf_UninterpretedOption* msg, double value) { - UPB_FIELD_AT(msg, double, UPB_SIZE(24, 24)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value( - google_protobuf_UninterpretedOption* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(40, 48)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value( - google_protobuf_UninterpretedOption* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(48, 64)) = value; -} - -/* google.protobuf.UninterpretedOption.NamePart */ - -extern const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit; -UPB_INLINE google_protobuf_UninterpretedOption_NamePart* -google_protobuf_UninterpretedOption_NamePart_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, - arena); -} -UPB_INLINE google_protobuf_UninterpretedOption_NamePart* -google_protobuf_UninterpretedOption_NamePart_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_UninterpretedOption_NamePart* ret = - google_protobuf_UninterpretedOption_NamePart_new(arena); - return (ret && - upb_decode(buf, ret, - &google_protobuf_UninterpretedOption_NamePart_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize( - const google_protobuf_UninterpretedOption_NamePart* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, - arena, len); -} - -UPB_INLINE upb_stringview -google_protobuf_UninterpretedOption_NamePart_name_part( - const google_protobuf_UninterpretedOption_NamePart* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension( - const google_protobuf_UninterpretedOption_NamePart* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)); -} - -UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part( - google_protobuf_UninterpretedOption_NamePart* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension( - google_protobuf_UninterpretedOption_NamePart* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(1, 1)) = value; -} - -/* google.protobuf.SourceCodeInfo */ - -extern const upb_msglayout google_protobuf_SourceCodeInfo_msginit; -UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); -} -UPB_INLINE google_protobuf_SourceCodeInfo* -google_protobuf_SourceCodeInfo_parsenew(upb_stringview buf, upb_arena* arena) { - google_protobuf_SourceCodeInfo* ret = - google_protobuf_SourceCodeInfo_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_SourceCodeInfo_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize( - const google_protobuf_SourceCodeInfo* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_SourceCodeInfo_msginit, arena, len); -} - -UPB_INLINE const upb_array* google_protobuf_SourceCodeInfo_location( - const google_protobuf_SourceCodeInfo* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_SourceCodeInfo_set_location( - google_protobuf_SourceCodeInfo* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.SourceCodeInfo.Location */ - -extern const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit; -UPB_INLINE google_protobuf_SourceCodeInfo_Location* -google_protobuf_SourceCodeInfo_Location_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); -} -UPB_INLINE google_protobuf_SourceCodeInfo_Location* -google_protobuf_SourceCodeInfo_Location_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_SourceCodeInfo_Location* ret = - google_protobuf_SourceCodeInfo_Location_new(arena); - return (ret && upb_decode(buf, ret, - &google_protobuf_SourceCodeInfo_Location_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize( - const google_protobuf_SourceCodeInfo_Location* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, - arena, len); -} - -UPB_INLINE const upb_array* google_protobuf_SourceCodeInfo_Location_path( - const google_protobuf_SourceCodeInfo_Location* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 48)); -} -UPB_INLINE const upb_array* google_protobuf_SourceCodeInfo_Location_span( - const google_protobuf_SourceCodeInfo_Location* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(28, 56)); -} -UPB_INLINE upb_stringview -google_protobuf_SourceCodeInfo_Location_leading_comments( - const google_protobuf_SourceCodeInfo_Location* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)); -} -UPB_INLINE upb_stringview -google_protobuf_SourceCodeInfo_Location_trailing_comments( - const google_protobuf_SourceCodeInfo_Location* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)); -} -UPB_INLINE const upb_array* -google_protobuf_SourceCodeInfo_Location_leading_detached_comments( - const google_protobuf_SourceCodeInfo_Location* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(32, 64)); -} - -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_path( - google_protobuf_SourceCodeInfo_Location* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 48)) = value; -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_span( - google_protobuf_SourceCodeInfo_Location* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(28, 56)) = value; -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments( - google_protobuf_SourceCodeInfo_Location* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(8, 16)) = value; -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments( - google_protobuf_SourceCodeInfo_Location* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 32)) = value; -} -UPB_INLINE void -google_protobuf_SourceCodeInfo_Location_set_leading_detached_comments( - google_protobuf_SourceCodeInfo_Location* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(32, 64)) = value; -} - -/* google.protobuf.GeneratedCodeInfo */ - -extern const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit; -UPB_INLINE google_protobuf_GeneratedCodeInfo* -google_protobuf_GeneratedCodeInfo_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_GeneratedCodeInfo_msginit, arena); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo* -google_protobuf_GeneratedCodeInfo_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_GeneratedCodeInfo* ret = - google_protobuf_GeneratedCodeInfo_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_GeneratedCodeInfo_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize( - const google_protobuf_GeneratedCodeInfo* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, arena, - len); -} - -UPB_INLINE const upb_array* google_protobuf_GeneratedCodeInfo_annotation( - const google_protobuf_GeneratedCodeInfo* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_GeneratedCodeInfo_set_annotation( - google_protobuf_GeneratedCodeInfo* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.GeneratedCodeInfo.Annotation */ - -extern const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit; -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* -google_protobuf_GeneratedCodeInfo_Annotation_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, - arena); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* -google_protobuf_GeneratedCodeInfo_Annotation_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_GeneratedCodeInfo_Annotation* ret = - google_protobuf_GeneratedCodeInfo_Annotation_new(arena); - return (ret && - upb_decode(buf, ret, - &google_protobuf_GeneratedCodeInfo_Annotation_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize( - const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, - arena, len); -} - -UPB_INLINE const upb_array* google_protobuf_GeneratedCodeInfo_Annotation_path( - const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(24, 32)); -} -UPB_INLINE upb_stringview -google_protobuf_GeneratedCodeInfo_Annotation_source_file( - const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 16)); -} -UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin( - const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)); -} -UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end( - const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); -} - -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_path( - google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(24, 32)) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file( - google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(16, 16)) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin( - google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(4, 4)) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end( - google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; -} - -UPB_END_EXTERN_C - -#include "upb/port_undef.inc" - -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/duration.upb.c b/src/core/ext/upb-generated/google/protobuf/duration.upb.c deleted file mode 100644 index b057ce5e4aa..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/duration.upb.c +++ /dev/null @@ -1,24 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/duration.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include "google/protobuf/duration.upb.h" -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -static const upb_msglayout_field google_protobuf_Duration__fields[2] = { - {1, UPB_SIZE(0, 0), 0, 0, 3, 1}, - {2, UPB_SIZE(8, 8), 0, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_Duration_msginit = { - NULL, &google_protobuf_Duration__fields[0], UPB_SIZE(16, 16), 2, false, -}; - -#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/duration.upb.h b/src/core/ext/upb-generated/google/protobuf/duration.upb.h deleted file mode 100644 index 1f40b3aed24..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/duration.upb.h +++ /dev/null @@ -1,65 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/duration.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_DURATION_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_DURATION_PROTO_UPB_H_ - -#include "upb/msg.h" - -#include "upb/decode.h" -#include "upb/encode.h" -#include "upb/port_def.inc" -UPB_BEGIN_EXTERN_C - -struct google_protobuf_Duration; -typedef struct google_protobuf_Duration google_protobuf_Duration; - -/* Enums */ - -/* google.protobuf.Duration */ - -extern const upb_msglayout google_protobuf_Duration_msginit; -UPB_INLINE google_protobuf_Duration* google_protobuf_Duration_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_Duration_msginit, arena); -} -UPB_INLINE google_protobuf_Duration* google_protobuf_Duration_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_Duration* ret = google_protobuf_Duration_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Duration_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Duration_serialize( - const google_protobuf_Duration* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Duration_msginit, arena, len); -} - -UPB_INLINE int64_t -google_protobuf_Duration_seconds(const google_protobuf_Duration* msg) { - return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)); -} -UPB_INLINE int32_t -google_protobuf_Duration_nanos(const google_protobuf_Duration* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); -} - -UPB_INLINE void google_protobuf_Duration_set_seconds( - google_protobuf_Duration* msg, int64_t value) { - UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)) = value; -} -UPB_INLINE void google_protobuf_Duration_set_nanos( - google_protobuf_Duration* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; -} - -UPB_END_EXTERN_C - -#include "upb/port_undef.inc" - -#endif /* GOOGLE_PROTOBUF_DURATION_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/struct.upb.c b/src/core/ext/upb-generated/google/protobuf/struct.upb.c deleted file mode 100644 index a0820e722a6..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/struct.upb.c +++ /dev/null @@ -1,88 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/struct.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include "google/protobuf/struct.upb.h" -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -static const upb_msglayout* const google_protobuf_Struct_submsgs[1] = { - &google_protobuf_Struct_FieldsEntry_msginit, -}; - -static const upb_msglayout_field google_protobuf_Struct__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_Struct_msginit = { - &google_protobuf_Struct_submsgs[0], - &google_protobuf_Struct__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -static const upb_msglayout* const - google_protobuf_Struct_FieldsEntry_submsgs[1] = { - &google_protobuf_Value_msginit, -}; - -static const upb_msglayout_field google_protobuf_Struct_FieldsEntry__fields[2] = - { - {1, UPB_SIZE(0, 0), 0, 0, 9, 1}, - {2, UPB_SIZE(8, 16), 0, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_Struct_FieldsEntry_msginit = { - &google_protobuf_Struct_FieldsEntry_submsgs[0], - &google_protobuf_Struct_FieldsEntry__fields[0], - UPB_SIZE(16, 32), - 2, - false, -}; - -static const upb_msglayout* const google_protobuf_Value_submsgs[2] = { - &google_protobuf_ListValue_msginit, - &google_protobuf_Struct_msginit, -}; - -static const upb_msglayout_field google_protobuf_Value__fields[6] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 14, 1}, - {2, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 1, 1}, - {3, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 9, 1}, - {4, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 8, 1}, - {5, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 1, 11, 1}, - {6, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_Value_msginit = { - &google_protobuf_Value_submsgs[0], - &google_protobuf_Value__fields[0], - UPB_SIZE(16, 32), - 6, - false, -}; - -static const upb_msglayout* const google_protobuf_ListValue_submsgs[1] = { - &google_protobuf_Value_msginit, -}; - -static const upb_msglayout_field google_protobuf_ListValue__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_ListValue_msginit = { - &google_protobuf_ListValue_submsgs[0], - &google_protobuf_ListValue__fields[0], - UPB_SIZE(4, 8), - 1, - false, -}; - -#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/struct.upb.h b/src/core/ext/upb-generated/google/protobuf/struct.upb.h deleted file mode 100644 index 5493794f0e6..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/struct.upb.h +++ /dev/null @@ -1,226 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/struct.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_STRUCT_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_STRUCT_PROTO_UPB_H_ - -#include "upb/msg.h" - -#include "upb/decode.h" -#include "upb/encode.h" -#include "upb/port_def.inc" -UPB_BEGIN_EXTERN_C - -struct google_protobuf_Struct; -struct google_protobuf_Struct_FieldsEntry; -struct google_protobuf_Value; -struct google_protobuf_ListValue; -typedef struct google_protobuf_Struct google_protobuf_Struct; -typedef struct google_protobuf_Struct_FieldsEntry - google_protobuf_Struct_FieldsEntry; -typedef struct google_protobuf_Value google_protobuf_Value; -typedef struct google_protobuf_ListValue google_protobuf_ListValue; - -/* Enums */ - -typedef enum { google_protobuf_NULL_VALUE = 0 } google_protobuf_NullValue; - -/* google.protobuf.Struct */ - -extern const upb_msglayout google_protobuf_Struct_msginit; -UPB_INLINE google_protobuf_Struct* google_protobuf_Struct_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_Struct_msginit, arena); -} -UPB_INLINE google_protobuf_Struct* google_protobuf_Struct_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_Struct* ret = google_protobuf_Struct_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Struct_msginit)) ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Struct_serialize( - const google_protobuf_Struct* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Struct_msginit, arena, len); -} - -UPB_INLINE const upb_array* google_protobuf_Struct_fields( - const google_protobuf_Struct* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_Struct_set_fields(google_protobuf_Struct* msg, - upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.Struct.FieldsEntry */ - -extern const upb_msglayout google_protobuf_Struct_FieldsEntry_msginit; -UPB_INLINE google_protobuf_Struct_FieldsEntry* -google_protobuf_Struct_FieldsEntry_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_Struct_FieldsEntry_msginit, arena); -} -UPB_INLINE google_protobuf_Struct_FieldsEntry* -google_protobuf_Struct_FieldsEntry_parsenew(upb_stringview buf, - upb_arena* arena) { - google_protobuf_Struct_FieldsEntry* ret = - google_protobuf_Struct_FieldsEntry_new(arena); - return (ret && - upb_decode(buf, ret, &google_protobuf_Struct_FieldsEntry_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Struct_FieldsEntry_serialize( - const google_protobuf_Struct_FieldsEntry* msg, upb_arena* arena, - size_t* len) { - return upb_encode(msg, &google_protobuf_Struct_FieldsEntry_msginit, arena, - len); -} - -UPB_INLINE upb_stringview google_protobuf_Struct_FieldsEntry_key( - const google_protobuf_Struct_FieldsEntry* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); -} -UPB_INLINE const google_protobuf_Value* -google_protobuf_Struct_FieldsEntry_value( - const google_protobuf_Struct_FieldsEntry* msg) { - return UPB_FIELD_AT(msg, const google_protobuf_Value*, UPB_SIZE(8, 16)); -} - -UPB_INLINE void google_protobuf_Struct_FieldsEntry_set_key( - google_protobuf_Struct_FieldsEntry* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; -} -UPB_INLINE void google_protobuf_Struct_FieldsEntry_set_value( - google_protobuf_Struct_FieldsEntry* msg, google_protobuf_Value* value) { - UPB_FIELD_AT(msg, google_protobuf_Value*, UPB_SIZE(8, 16)) = value; -} - -/* google.protobuf.Value */ - -extern const upb_msglayout google_protobuf_Value_msginit; -UPB_INLINE google_protobuf_Value* google_protobuf_Value_new(upb_arena* arena) { - return upb_msg_new(&google_protobuf_Value_msginit, arena); -} -UPB_INLINE google_protobuf_Value* google_protobuf_Value_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_Value* ret = google_protobuf_Value_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Value_msginit)) ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Value_serialize( - const google_protobuf_Value* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Value_msginit, arena, len); -} - -typedef enum { - google_protobuf_Value_kind_null_value = 1, - google_protobuf_Value_kind_number_value = 2, - google_protobuf_Value_kind_string_value = 3, - google_protobuf_Value_kind_bool_value = 4, - google_protobuf_Value_kind_struct_value = 5, - google_protobuf_Value_kind_list_value = 6, - google_protobuf_Value_kind_NOT_SET = 0, -} google_protobuf_Value_kind_oneofcases; -UPB_INLINE google_protobuf_Value_kind_oneofcases -google_protobuf_Value_kind_case(const google_protobuf_Value* msg) { - return UPB_FIELD_AT(msg, int, UPB_SIZE(8, 16)); -} - -UPB_INLINE google_protobuf_NullValue -google_protobuf_Value_null_value(const google_protobuf_Value* msg) { - return UPB_READ_ONEOF(msg, google_protobuf_NullValue, UPB_SIZE(0, 0), - UPB_SIZE(8, 16), 1, google_protobuf_NULL_VALUE); -} -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 upb_stringview -google_protobuf_Value_string_value(const google_protobuf_Value* msg) { - return UPB_READ_ONEOF(msg, upb_stringview, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 3, - upb_stringview_make("", strlen(""))); -} -UPB_INLINE bool google_protobuf_Value_bool_value( - const google_protobuf_Value* msg) { - return UPB_READ_ONEOF(msg, bool, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 4, false); -} -UPB_INLINE const google_protobuf_Struct* google_protobuf_Value_struct_value( - const google_protobuf_Value* msg) { - return UPB_READ_ONEOF(msg, const google_protobuf_Struct*, UPB_SIZE(0, 0), - UPB_SIZE(8, 16), 5, NULL); -} -UPB_INLINE const google_protobuf_ListValue* google_protobuf_Value_list_value( - const google_protobuf_Value* msg) { - return UPB_READ_ONEOF(msg, const google_protobuf_ListValue*, UPB_SIZE(0, 0), - UPB_SIZE(8, 16), 6, NULL); -} - -UPB_INLINE void google_protobuf_Value_set_null_value( - google_protobuf_Value* msg, google_protobuf_NullValue value) { - UPB_WRITE_ONEOF(msg, google_protobuf_NullValue, UPB_SIZE(0, 0), value, - UPB_SIZE(8, 16), 1); -} -UPB_INLINE void google_protobuf_Value_set_number_value( - google_protobuf_Value* msg, double value) { - UPB_WRITE_ONEOF(msg, double, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 2); -} -UPB_INLINE void google_protobuf_Value_set_string_value( - google_protobuf_Value* msg, upb_stringview value) { - UPB_WRITE_ONEOF(msg, upb_stringview, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), - 3); -} -UPB_INLINE void google_protobuf_Value_set_bool_value(google_protobuf_Value* msg, - bool value) { - UPB_WRITE_ONEOF(msg, bool, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 4); -} -UPB_INLINE void google_protobuf_Value_set_struct_value( - google_protobuf_Value* msg, google_protobuf_Struct* value) { - UPB_WRITE_ONEOF(msg, google_protobuf_Struct*, UPB_SIZE(0, 0), value, - UPB_SIZE(8, 16), 5); -} -UPB_INLINE void google_protobuf_Value_set_list_value( - google_protobuf_Value* msg, google_protobuf_ListValue* value) { - UPB_WRITE_ONEOF(msg, google_protobuf_ListValue*, UPB_SIZE(0, 0), value, - UPB_SIZE(8, 16), 6); -} - -/* google.protobuf.ListValue */ - -extern const upb_msglayout google_protobuf_ListValue_msginit; -UPB_INLINE google_protobuf_ListValue* google_protobuf_ListValue_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_ListValue_msginit, arena); -} -UPB_INLINE google_protobuf_ListValue* google_protobuf_ListValue_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_ListValue* ret = google_protobuf_ListValue_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_ListValue_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_ListValue_serialize( - const google_protobuf_ListValue* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_ListValue_msginit, arena, len); -} - -UPB_INLINE const upb_array* google_protobuf_ListValue_values( - const google_protobuf_ListValue* msg) { - return UPB_FIELD_AT(msg, const upb_array*, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_ListValue_set_values( - google_protobuf_ListValue* msg, upb_array* value) { - UPB_FIELD_AT(msg, upb_array*, UPB_SIZE(0, 0)) = value; -} - -UPB_END_EXTERN_C - -#include "upb/port_undef.inc" - -#endif /* GOOGLE_PROTOBUF_STRUCT_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c b/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c deleted file mode 100644 index 90d0aed7664..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c +++ /dev/null @@ -1,24 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/timestamp.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include "google/protobuf/timestamp.upb.h" -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -static const upb_msglayout_field google_protobuf_Timestamp__fields[2] = { - {1, UPB_SIZE(0, 0), 0, 0, 3, 1}, - {2, UPB_SIZE(8, 8), 0, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_Timestamp_msginit = { - NULL, &google_protobuf_Timestamp__fields[0], UPB_SIZE(16, 16), 2, false, -}; - -#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/timestamp.upb.h b/src/core/ext/upb-generated/google/protobuf/timestamp.upb.h deleted file mode 100644 index a524eb5b6d0..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/timestamp.upb.h +++ /dev/null @@ -1,65 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/timestamp.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_TIMESTAMP_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_TIMESTAMP_PROTO_UPB_H_ - -#include "upb/msg.h" - -#include "upb/decode.h" -#include "upb/encode.h" -#include "upb/port_def.inc" -UPB_BEGIN_EXTERN_C - -struct google_protobuf_Timestamp; -typedef struct google_protobuf_Timestamp google_protobuf_Timestamp; - -/* Enums */ - -/* google.protobuf.Timestamp */ - -extern const upb_msglayout google_protobuf_Timestamp_msginit; -UPB_INLINE google_protobuf_Timestamp* google_protobuf_Timestamp_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_Timestamp_msginit, arena); -} -UPB_INLINE google_protobuf_Timestamp* google_protobuf_Timestamp_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_Timestamp* ret = google_protobuf_Timestamp_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Timestamp_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Timestamp_serialize( - const google_protobuf_Timestamp* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Timestamp_msginit, arena, len); -} - -UPB_INLINE int64_t -google_protobuf_Timestamp_seconds(const google_protobuf_Timestamp* msg) { - return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)); -} -UPB_INLINE int32_t -google_protobuf_Timestamp_nanos(const google_protobuf_Timestamp* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)); -} - -UPB_INLINE void google_protobuf_Timestamp_set_seconds( - google_protobuf_Timestamp* msg, int64_t value) { - UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)) = value; -} -UPB_INLINE void google_protobuf_Timestamp_set_nanos( - google_protobuf_Timestamp* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(8, 8)) = value; -} - -UPB_END_EXTERN_C - -#include "upb/port_undef.inc" - -#endif /* GOOGLE_PROTOBUF_TIMESTAMP_PROTO_UPB_H_ */ diff --git a/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c b/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c deleted file mode 100644 index 3fa3bea1dbc..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c +++ /dev/null @@ -1,87 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/wrappers.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include "google/protobuf/wrappers.upb.h" -#include -#include "upb/msg.h" - -#include "upb/port_def.inc" - -static const upb_msglayout_field google_protobuf_DoubleValue__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 1, 1}, -}; - -const upb_msglayout google_protobuf_DoubleValue_msginit = { - NULL, &google_protobuf_DoubleValue__fields[0], UPB_SIZE(8, 8), 1, false, -}; - -static const upb_msglayout_field google_protobuf_FloatValue__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 2, 1}, -}; - -const upb_msglayout google_protobuf_FloatValue_msginit = { - NULL, &google_protobuf_FloatValue__fields[0], UPB_SIZE(4, 4), 1, false, -}; - -static const upb_msglayout_field google_protobuf_Int64Value__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 3, 1}, -}; - -const upb_msglayout google_protobuf_Int64Value_msginit = { - NULL, &google_protobuf_Int64Value__fields[0], UPB_SIZE(8, 8), 1, false, -}; - -static const upb_msglayout_field google_protobuf_UInt64Value__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 4, 1}, -}; - -const upb_msglayout google_protobuf_UInt64Value_msginit = { - NULL, &google_protobuf_UInt64Value__fields[0], UPB_SIZE(8, 8), 1, false, -}; - -static const upb_msglayout_field google_protobuf_Int32Value__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_Int32Value_msginit = { - NULL, &google_protobuf_Int32Value__fields[0], UPB_SIZE(4, 4), 1, false, -}; - -static const upb_msglayout_field google_protobuf_UInt32Value__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 13, 1}, -}; - -const upb_msglayout google_protobuf_UInt32Value_msginit = { - NULL, &google_protobuf_UInt32Value__fields[0], UPB_SIZE(4, 4), 1, false, -}; - -static const upb_msglayout_field google_protobuf_BoolValue__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 8, 1}, -}; - -const upb_msglayout google_protobuf_BoolValue_msginit = { - NULL, &google_protobuf_BoolValue__fields[0], UPB_SIZE(1, 1), 1, false, -}; - -static const upb_msglayout_field google_protobuf_StringValue__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 9, 1}, -}; - -const upb_msglayout google_protobuf_StringValue_msginit = { - NULL, &google_protobuf_StringValue__fields[0], UPB_SIZE(8, 16), 1, false, -}; - -static const upb_msglayout_field google_protobuf_BytesValue__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 12, 1}, -}; - -const upb_msglayout google_protobuf_BytesValue_msginit = { - NULL, &google_protobuf_BytesValue__fields[0], UPB_SIZE(8, 16), 1, false, -}; - -#include "upb/port_undef.inc" diff --git a/src/core/ext/upb-generated/google/protobuf/wrappers.upb.h b/src/core/ext/upb-generated/google/protobuf/wrappers.upb.h deleted file mode 100644 index 3ae5d3b16e3..00000000000 --- a/src/core/ext/upb-generated/google/protobuf/wrappers.upb.h +++ /dev/null @@ -1,305 +0,0 @@ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/wrappers.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_WRAPPERS_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_WRAPPERS_PROTO_UPB_H_ - -#include "upb/msg.h" - -#include "upb/decode.h" -#include "upb/encode.h" -#include "upb/port_def.inc" -UPB_BEGIN_EXTERN_C - -struct google_protobuf_DoubleValue; -struct google_protobuf_FloatValue; -struct google_protobuf_Int64Value; -struct google_protobuf_UInt64Value; -struct google_protobuf_Int32Value; -struct google_protobuf_UInt32Value; -struct google_protobuf_BoolValue; -struct google_protobuf_StringValue; -struct google_protobuf_BytesValue; -typedef struct google_protobuf_DoubleValue google_protobuf_DoubleValue; -typedef struct google_protobuf_FloatValue google_protobuf_FloatValue; -typedef struct google_protobuf_Int64Value google_protobuf_Int64Value; -typedef struct google_protobuf_UInt64Value google_protobuf_UInt64Value; -typedef struct google_protobuf_Int32Value google_protobuf_Int32Value; -typedef struct google_protobuf_UInt32Value google_protobuf_UInt32Value; -typedef struct google_protobuf_BoolValue google_protobuf_BoolValue; -typedef struct google_protobuf_StringValue google_protobuf_StringValue; -typedef struct google_protobuf_BytesValue google_protobuf_BytesValue; - -/* Enums */ - -/* google.protobuf.DoubleValue */ - -extern const upb_msglayout google_protobuf_DoubleValue_msginit; -UPB_INLINE google_protobuf_DoubleValue* google_protobuf_DoubleValue_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_DoubleValue_msginit, arena); -} -UPB_INLINE google_protobuf_DoubleValue* google_protobuf_DoubleValue_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_DoubleValue* ret = google_protobuf_DoubleValue_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_DoubleValue_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_DoubleValue_serialize( - const google_protobuf_DoubleValue* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_DoubleValue_msginit, arena, len); -} - -UPB_INLINE double google_protobuf_DoubleValue_value( - const google_protobuf_DoubleValue* msg) { - return UPB_FIELD_AT(msg, double, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_DoubleValue_set_value( - google_protobuf_DoubleValue* msg, double value) { - UPB_FIELD_AT(msg, double, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.FloatValue */ - -extern const upb_msglayout google_protobuf_FloatValue_msginit; -UPB_INLINE google_protobuf_FloatValue* google_protobuf_FloatValue_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_FloatValue_msginit, arena); -} -UPB_INLINE google_protobuf_FloatValue* google_protobuf_FloatValue_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_FloatValue* ret = google_protobuf_FloatValue_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_FloatValue_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_FloatValue_serialize( - const google_protobuf_FloatValue* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_FloatValue_msginit, arena, len); -} - -UPB_INLINE float google_protobuf_FloatValue_value( - const google_protobuf_FloatValue* msg) { - return UPB_FIELD_AT(msg, float, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_FloatValue_set_value( - google_protobuf_FloatValue* msg, float value) { - UPB_FIELD_AT(msg, float, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.Int64Value */ - -extern const upb_msglayout google_protobuf_Int64Value_msginit; -UPB_INLINE google_protobuf_Int64Value* google_protobuf_Int64Value_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_Int64Value_msginit, arena); -} -UPB_INLINE google_protobuf_Int64Value* google_protobuf_Int64Value_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_Int64Value* ret = google_protobuf_Int64Value_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Int64Value_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Int64Value_serialize( - const google_protobuf_Int64Value* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Int64Value_msginit, arena, len); -} - -UPB_INLINE int64_t -google_protobuf_Int64Value_value(const google_protobuf_Int64Value* msg) { - return UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_Int64Value_set_value( - google_protobuf_Int64Value* msg, int64_t value) { - UPB_FIELD_AT(msg, int64_t, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.UInt64Value */ - -extern const upb_msglayout google_protobuf_UInt64Value_msginit; -UPB_INLINE google_protobuf_UInt64Value* google_protobuf_UInt64Value_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_UInt64Value_msginit, arena); -} -UPB_INLINE google_protobuf_UInt64Value* google_protobuf_UInt64Value_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_UInt64Value* ret = google_protobuf_UInt64Value_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_UInt64Value_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_UInt64Value_serialize( - const google_protobuf_UInt64Value* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_UInt64Value_msginit, arena, len); -} - -UPB_INLINE uint64_t -google_protobuf_UInt64Value_value(const google_protobuf_UInt64Value* msg) { - return UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_UInt64Value_set_value( - google_protobuf_UInt64Value* msg, uint64_t value) { - UPB_FIELD_AT(msg, uint64_t, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.Int32Value */ - -extern const upb_msglayout google_protobuf_Int32Value_msginit; -UPB_INLINE google_protobuf_Int32Value* google_protobuf_Int32Value_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_Int32Value_msginit, arena); -} -UPB_INLINE google_protobuf_Int32Value* google_protobuf_Int32Value_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_Int32Value* ret = google_protobuf_Int32Value_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_Int32Value_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_Int32Value_serialize( - const google_protobuf_Int32Value* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_Int32Value_msginit, arena, len); -} - -UPB_INLINE int32_t -google_protobuf_Int32Value_value(const google_protobuf_Int32Value* msg) { - return UPB_FIELD_AT(msg, int32_t, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_Int32Value_set_value( - google_protobuf_Int32Value* msg, int32_t value) { - UPB_FIELD_AT(msg, int32_t, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.UInt32Value */ - -extern const upb_msglayout google_protobuf_UInt32Value_msginit; -UPB_INLINE google_protobuf_UInt32Value* google_protobuf_UInt32Value_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_UInt32Value_msginit, arena); -} -UPB_INLINE google_protobuf_UInt32Value* google_protobuf_UInt32Value_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_UInt32Value* ret = google_protobuf_UInt32Value_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_UInt32Value_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_UInt32Value_serialize( - const google_protobuf_UInt32Value* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_UInt32Value_msginit, arena, len); -} - -UPB_INLINE uint32_t -google_protobuf_UInt32Value_value(const google_protobuf_UInt32Value* msg) { - return UPB_FIELD_AT(msg, uint32_t, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_UInt32Value_set_value( - google_protobuf_UInt32Value* msg, uint32_t value) { - UPB_FIELD_AT(msg, uint32_t, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.BoolValue */ - -extern const upb_msglayout google_protobuf_BoolValue_msginit; -UPB_INLINE google_protobuf_BoolValue* google_protobuf_BoolValue_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_BoolValue_msginit, arena); -} -UPB_INLINE google_protobuf_BoolValue* google_protobuf_BoolValue_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_BoolValue* ret = google_protobuf_BoolValue_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_BoolValue_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_BoolValue_serialize( - const google_protobuf_BoolValue* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_BoolValue_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_BoolValue_value( - const google_protobuf_BoolValue* msg) { - return UPB_FIELD_AT(msg, bool, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_BoolValue_set_value( - google_protobuf_BoolValue* msg, bool value) { - UPB_FIELD_AT(msg, bool, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.StringValue */ - -extern const upb_msglayout google_protobuf_StringValue_msginit; -UPB_INLINE google_protobuf_StringValue* google_protobuf_StringValue_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_StringValue_msginit, arena); -} -UPB_INLINE google_protobuf_StringValue* google_protobuf_StringValue_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_StringValue* ret = google_protobuf_StringValue_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_StringValue_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_StringValue_serialize( - const google_protobuf_StringValue* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_StringValue_msginit, arena, len); -} - -UPB_INLINE upb_stringview -google_protobuf_StringValue_value(const google_protobuf_StringValue* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_StringValue_set_value( - google_protobuf_StringValue* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; -} - -/* google.protobuf.BytesValue */ - -extern const upb_msglayout google_protobuf_BytesValue_msginit; -UPB_INLINE google_protobuf_BytesValue* google_protobuf_BytesValue_new( - upb_arena* arena) { - return upb_msg_new(&google_protobuf_BytesValue_msginit, arena); -} -UPB_INLINE google_protobuf_BytesValue* google_protobuf_BytesValue_parsenew( - upb_stringview buf, upb_arena* arena) { - google_protobuf_BytesValue* ret = google_protobuf_BytesValue_new(arena); - return (ret && upb_decode(buf, ret, &google_protobuf_BytesValue_msginit)) - ? ret - : NULL; -} -UPB_INLINE char* google_protobuf_BytesValue_serialize( - const google_protobuf_BytesValue* msg, upb_arena* arena, size_t* len) { - return upb_encode(msg, &google_protobuf_BytesValue_msginit, arena, len); -} - -UPB_INLINE upb_stringview -google_protobuf_BytesValue_value(const google_protobuf_BytesValue* msg) { - return UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)); -} - -UPB_INLINE void google_protobuf_BytesValue_set_value( - google_protobuf_BytesValue* msg, upb_stringview value) { - UPB_FIELD_AT(msg, upb_stringview, UPB_SIZE(0, 0)) = value; -} - -UPB_END_EXTERN_C - -#include "upb/port_undef.inc" - -#endif /* GOOGLE_PROTOBUF_WRAPPERS_PROTO_UPB_H_ */ diff --git a/src/upb/gen_build_yaml.py b/src/upb/gen_build_yaml.py deleted file mode 100755 index 0dd7bfae109..00000000000 --- a/src/upb/gen_build_yaml.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python2.7 - -# 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. - -# TODO: This should ideally be in upb submodule to avoid hardcoding this here. - -import re -import os -import sys -import yaml - -srcs = [ - "third_party/upb/google/protobuf/descriptor.upb.c", - "third_party/upb/upb/decode.c", - "third_party/upb/upb/def.c", - "third_party/upb/upb/encode.c", - "third_party/upb/upb/handlers.c", - "third_party/upb/upb/msg.c", - "third_party/upb/upb/msgfactory.c", - "third_party/upb/upb/refcounted.c", - "third_party/upb/upb/sink.c", - "third_party/upb/upb/table.c", - "third_party/upb/upb/upb.c", -] - -hdrs = [ - "third_party/upb/google/protobuf/descriptor.upb.h", - "third_party/upb/upb/decode.h", - "third_party/upb/upb/def.h", - "third_party/upb/upb/encode.h", - "third_party/upb/upb/handlers.h", - "third_party/upb/upb/msg.h", - "third_party/upb/upb/msgfactory.h", - "third_party/upb/upb/refcounted.h", - "third_party/upb/upb/sink.h", - "third_party/upb/upb/upb.h", -] - -os.chdir(os.path.dirname(sys.argv[0])+'/../..') - -out = {} - -try: - out['libs'] = [{ - 'name': 'upb', - 'defaults': 'upb', - 'build': 'private', - 'language': 'c', - 'secure': 'no', - 'src': srcs, - 'headers': hdrs, - }] -except: - pass - -print yaml.dump(out) - diff --git a/tools/buildgen/generate_build_additions.sh b/tools/buildgen/generate_build_additions.sh index c99ad6ee552..5a1f4a598a7 100755 --- a/tools/buildgen/generate_build_additions.sh +++ b/tools/buildgen/generate_build_additions.sh @@ -19,7 +19,6 @@ gen_build_yaml_dirs=" \ src/boringssl \ src/benchmark \ src/proto \ - src/upb \ src/zlib \ src/c-ares \ test/core/bad_client \ diff --git a/tools/codegen/core/gen_upb_api.sh b/tools/codegen/core/gen_upb_api.sh deleted file mode 100755 index 9457e06f124..00000000000 --- a/tools/codegen/core/gen_upb_api.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# Copyright 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. - -# REQUIRES: Bazel -set -ex -rm -rf src/core/ext/upb-generated -mkdir src/core/ext/upb-generated -cd third_party -cd upb -bazel build :protoc-gen-upb - -cd ../.. - -proto_files=( \ - "google/protobuf/any.proto" \ - "google/protobuf/struct.proto" \ - "google/protobuf/wrappers.proto" \ - "google/protobuf/descriptor.proto" \ - "google/protobuf/duration.proto" \ - "google/protobuf/timestamp.proto" ) - -for i in "${proto_files[@]}" -do - protoc -I=$PWD/third_party/data-plane-api -I=$PWD/third_party/googleapis -I=$PWD/third_party/protobuf -I=$PWD/third_party/protoc-gen-validate $i --upb_out=./src/core/ext/upb-generated --plugin=protoc-gen-upb=third_party/upb/bazel-bin/protoc-gen-upb -done diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py index fd93cf31e05..787bef1778e 100755 --- a/tools/distrib/check_copyright.py +++ b/tools/distrib/check_copyright.py @@ -104,20 +104,6 @@ _EXEMPT = frozenset(( # Designer-generated source 'examples/csharp/HelloworldXamarin/Droid/Resources/Resource.designer.cs', 'examples/csharp/HelloworldXamarin/iOS/ViewController.designer.cs', - - # Upb generated source - 'src/core/ext/upb-generated/google/protobuf/any.upb.h', - 'src/core/ext/upb-generated/google/protobuf/any.upb.c', - 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.h', - 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.c', - 'src/core/ext/upb-generated/google/protobuf/duration.upb.h', - 'src/core/ext/upb-generated/google/protobuf/duration.upb.c', - 'src/core/ext/upb-generated/google/protobuf/struct.upb.h', - 'src/core/ext/upb-generated/google/protobuf/struct.upb.c', - 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.h', - 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c', - 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.h', - 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c', )) RE_YEAR = r'Copyright (?P[0-9]+\-)?(?P[0-9]+) ([Tt]he )?gRPC [Aa]uthors(\.|)' diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py index 15b3478e555..b8d530cce06 100755 --- a/tools/distrib/check_include_guards.py +++ b/tools/distrib/check_include_guards.py @@ -165,20 +165,6 @@ KNOWN_BAD = set([ 'src/core/tsi/alts/handshaker/transport_security_common.pb.h', 'include/grpc++/ext/reflection.grpc.pb.h', 'include/grpc++/ext/reflection.pb.h', - - # Upb generated code - 'src/core/ext/upb-generated/google/protobuf/any.upb.h', - 'src/core/ext/upb-generated/google/protobuf/any.upb.c', - 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.h', - 'src/core/ext/upb-generated/google/protobuf/descriptor.upb.c', - 'src/core/ext/upb-generated/google/protobuf/duration.upb.h', - 'src/core/ext/upb-generated/google/protobuf/duration.upb.c', - 'src/core/ext/upb-generated/google/protobuf/struct.upb.h', - 'src/core/ext/upb-generated/google/protobuf/struct.upb.c', - 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.h', - 'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c', - 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.h', - 'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c', ]) grep_filter = r"grep -E '^(include|src/core)/.*\.h$'" diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 5b0041a250d..2451101f58d 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8831,27 +8831,6 @@ "third_party": false, "type": "lib" }, - { - "deps": [], - "headers": [ - "third_party/upb/google/protobuf/descriptor.upb.h", - "third_party/upb/upb/decode.h", - "third_party/upb/upb/def.h", - "third_party/upb/upb/encode.h", - "third_party/upb/upb/handlers.h", - "third_party/upb/upb/msg.h", - "third_party/upb/upb/msgfactory.h", - "third_party/upb/upb/refcounted.h", - "third_party/upb/upb/sink.h", - "third_party/upb/upb/upb.h" - ], - "is_filegroup": false, - "language": "c", - "name": "upb", - "src": [], - "third_party": false, - "type": "lib" - }, { "deps": [], "headers": [ diff --git a/tools/run_tests/sanity/check_port_platform.py b/tools/run_tests/sanity/check_port_platform.py index 8c412700e45..fff828eaee8 100755 --- a/tools/run_tests/sanity/check_port_platform.py +++ b/tools/run_tests/sanity/check_port_platform.py @@ -35,9 +35,6 @@ def check_port_platform_inclusion(directory_root): continue if filename.endswith('.pb.h') or filename.endswith('.pb.c'): continue - # Skip check for upb generated code - if filename.endswith('.upb.h') or filename.endswith('.upb.c'): - continue with open(path) as f: all_lines_in_file = f.readlines() for index, l in enumerate(all_lines_in_file): From b15758ab371ced8ee541dc62869b63bc247773ea Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Dec 2018 12:25:11 -0800 Subject: [PATCH 77/99] Fix alignment in memory counters. --- test/core/util/memory_counters.cc | 32 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/test/core/util/memory_counters.cc b/test/core/util/memory_counters.cc index 4960fe07572..d0da05d9b4d 100644 --- a/test/core/util/memory_counters.cc +++ b/test/core/util/memory_counters.cc @@ -22,6 +22,7 @@ #include #include +#include "src/core/lib/gpr/alloc.h" #include "test/core/util/memory_counters.h" static struct grpc_memory_counters g_memory_counters; @@ -42,19 +43,18 @@ static void guard_free(void* vptr); #endif static void* guard_malloc(size_t size) { - size_t* ptr; if (!size) return nullptr; NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_absolute, (gpr_atm)size); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, (gpr_atm)size); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_absolute, (gpr_atm)1); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_relative, (gpr_atm)1); - ptr = static_cast(g_old_allocs.malloc_fn(size + sizeof(size))); - *ptr++ = size; - return ptr; + void* ptr = g_old_allocs.malloc_fn( + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(size)) + size); + *static_cast(ptr) = size; + return static_cast(ptr) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(size)); } static void* guard_realloc(void* vptr, size_t size) { - size_t* ptr = static_cast(vptr); if (vptr == nullptr) { return guard_malloc(size); } @@ -62,21 +62,25 @@ static void* guard_realloc(void* vptr, size_t size) { guard_free(vptr); return nullptr; } - --ptr; + void* ptr = + static_cast(vptr) - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(size)); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_absolute, (gpr_atm)size); - NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr); + NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, + -*static_cast(ptr)); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, (gpr_atm)size); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_absolute, (gpr_atm)1); - ptr = static_cast(g_old_allocs.realloc_fn(ptr, size + sizeof(size))); - *ptr++ = size; - return ptr; + ptr = g_old_allocs.realloc_fn( + ptr, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(size)) + size); + *static_cast(ptr) = size; + return static_cast(ptr) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(size)); } static void guard_free(void* vptr) { - size_t* ptr = static_cast(vptr); - if (!vptr) return; - --ptr; - NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr); + if (vptr == nullptr) return; + void* ptr = + static_cast(vptr) - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(size_t)); + NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, + -*static_cast(ptr)); NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_relative, -(gpr_atm)1); g_old_allocs.free_fn(ptr); } From 7dc330f298154571163603a8b568015412767cad Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 12 Oct 2018 11:56:29 -0700 Subject: [PATCH 78/99] Disable SRV and TXT lookups for localhost --- .../resolver/dns/c_ares/dns_resolver_ares.cc | 9 ++++-- .../resolver/dns/c_ares/grpc_ares_wrapper.cc | 29 +++++++++++++++++++ .../dns_resolver_connectivity_test.cc | 5 +++- test/core/end2end/fuzzers/api_fuzzer.cc | 5 +++- test/core/iomgr/resolve_address_posix_test.cc | 13 +++++++-- 5 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index c8425ae3365..fc83fc44889 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -465,11 +465,16 @@ static grpc_error* blocking_resolve_address_ares( static grpc_address_resolver_vtable ares_resolver = { grpc_resolve_address_ares, blocking_resolve_address_ares}; +static bool should_use_ares(const char* resolver_env) { + return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0; +} + void grpc_resolver_dns_ares_init() { char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); /* TODO(zyc): Turn on c-ares based resolver by default after the address sorter and the CNAME support are added. */ - if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) { + if (should_use_ares(resolver_env)) { + gpr_log(GPR_DEBUG, "Using ares dns resolver"); address_sorting_init(); grpc_error* error = grpc_ares_init(); if (error != GRPC_ERROR_NONE) { @@ -489,7 +494,7 @@ void grpc_resolver_dns_ares_init() { void grpc_resolver_dns_ares_shutdown() { char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); - if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) { + if (should_use_ares(resolver_env)) { address_sorting_shutdown(); grpc_ares_cleanup(); } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 1b1c2303da3..68977567694 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -510,6 +510,28 @@ static bool resolve_as_ip_literal_locked( return out; } +static bool target_matches_localhost_inner(const char* name, char** host, + char** port) { + if (!gpr_split_host_port(name, host, port)) { + gpr_log(GPR_INFO, "Unable to split host and port for name: %s", name); + return false; + } + if (gpr_stricmp(*host, "localhost") == 0) { + return true; + } else { + return false; + } +} + +static bool target_matches_localhost(const char* name) { + char* host = nullptr; + char* port = nullptr; + bool out = target_matches_localhost_inner(name, &host, &port); + gpr_free(host); + gpr_free(port); + return out; +} + static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, @@ -536,6 +558,13 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE); return r; } + // Don't query for SRV and TXT records if the target is "localhost", so + // as to cut down on lookups over the network, especially in tests: + // https://github.com/grpc/proposal/pull/79 + if (target_matches_localhost(name)) { + check_grpclb = false; + r->service_config_json_out = nullptr; + } // Look up name using c-ares lib. grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( r, dns_server, name, default_port, interested_parties, check_grpclb, diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc index 1a7a7c9ccc9..0cf549d01da 100644 --- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc @@ -76,7 +76,10 @@ static grpc_ares_request* my_dns_lookup_ares_locked( } else { gpr_mu_unlock(&g_mu); *addresses = grpc_core::MakeUnique(); - (*addresses)->emplace_back(nullptr, 0, nullptr); + grpc_resolved_address dummy_resolved_address; + memset(&dummy_resolved_address, 0, sizeof(dummy_resolved_address)); + dummy_resolved_address.len = 123; + (*addresses)->emplace_back(dummy_resolved_address, nullptr); } GRPC_CLOSURE_SCHED(on_done, error); return nullptr; diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index fe471279841..a0b82904753 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -342,7 +342,10 @@ static void finish_resolve(void* arg, grpc_error* error) { *r->addrs = addrs; } else if (r->addresses != nullptr) { *r->addresses = grpc_core::MakeUnique(); - (*r->addresses)->emplace_back(nullptr, 0, nullptr); + grpc_resolved_address dummy_resolved_address; + memset(&dummy_resolved_address, 0, sizeof(dummy_resolved_address)); + dummy_resolved_address.len = 0; + (*r->addresses)->emplace_back(dummy_resolved_address, nullptr); } GRPC_CLOSURE_SCHED(r->on_done, GRPC_ERROR_NONE); } else { diff --git a/test/core/iomgr/resolve_address_posix_test.cc b/test/core/iomgr/resolve_address_posix_test.cc index ceeb70a1086..5785c73e225 100644 --- a/test/core/iomgr/resolve_address_posix_test.cc +++ b/test/core/iomgr/resolve_address_posix_test.cc @@ -27,6 +27,8 @@ #include #include +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/iomgr/executor.h" @@ -163,8 +165,15 @@ int main(int argc, char** argv) { { grpc_core::ExecCtx exec_ctx; - test_unix_socket(); - test_unix_socket_path_name_too_long(); + char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); + // c-ares resolver doesn't support UDS (ability for native DNS resolver + // to handle this is only expected to be used by servers, which + // unconditionally use the native DNS resolver). + if (resolver_env == nullptr || gpr_stricmp(resolver_env, "native") == 0) { + test_unix_socket(); + test_unix_socket_path_name_too_long(); + } + gpr_free(resolver_env); } grpc_shutdown(); From 1334f8d2009eba9cf9a00bb2469e514a43cd5f22 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Dec 2018 13:27:29 -0800 Subject: [PATCH 79/99] Revert alignment hack in New<> and Delete<>. --- src/core/lib/gprpp/memory.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/core/lib/gprpp/memory.h b/src/core/lib/gprpp/memory.h index e90bedcd9b4..b4b63ae771a 100644 --- a/src/core/lib/gprpp/memory.h +++ b/src/core/lib/gprpp/memory.h @@ -40,15 +40,10 @@ namespace grpc_core { -// The alignment of memory returned by gpr_malloc(). -constexpr size_t kAlignmentForDefaultAllocationInBytes = 8; - // Alternative to new, since we cannot use it (for fear of libstdc++) template inline T* New(Args&&... args) { - void* p = alignof(T) > kAlignmentForDefaultAllocationInBytes - ? gpr_malloc_aligned(sizeof(T), alignof(T)) - : gpr_malloc(sizeof(T)); + void* p = gpr_malloc(sizeof(T)); return new (p) T(std::forward(args)...); } @@ -57,11 +52,7 @@ template inline void Delete(T* p) { if (p == nullptr) return; p->~T(); - if (alignof(T) > kAlignmentForDefaultAllocationInBytes) { - gpr_free_aligned(p); - } else { - gpr_free(p); - } + gpr_free(p); } template From fd74fcf2a07a40cd18b5795614c9f71a0e463e87 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 12 Dec 2018 13:48:39 -0800 Subject: [PATCH 80/99] New abort with grpc.Status API * Add `abort_with_status` method in ServicerContext * Add `Status` interface similar to the design of Details in interceptor * Add 3 unit test cases for abort mechanism --- src/python/grpcio/grpc/__init__.py | 36 +++++ src/python/grpcio/grpc/_server.py | 4 + .../grpc_testing/_server/_servicer_context.py | 3 + src/python/grpcio_tests/tests/tests.json | 1 + .../grpcio_tests/tests/unit/BUILD.bazel | 1 + .../grpcio_tests/tests/unit/_abort_test.py | 124 ++++++++++++++++++ .../grpcio_tests/tests/unit/_api_test.py | 1 + 7 files changed, 170 insertions(+) create mode 100644 src/python/grpcio_tests/tests/unit/_abort_test.py diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py index 6022fc3ef21..441f4ac8132 100644 --- a/src/python/grpcio/grpc/__init__.py +++ b/src/python/grpcio/grpc/__init__.py @@ -266,6 +266,23 @@ class StatusCode(enum.Enum): UNAUTHENTICATED = (_cygrpc.StatusCode.unauthenticated, 'unauthenticated') +############################# gRPC Status ################################ + + +class Status(six.with_metaclass(abc.ABCMeta)): + """Describes the status of an RPC. + + This is an EXPERIMENTAL API. + + Attributes: + code: A StatusCode object to be sent to the client. + It must not be StatusCode.OK. + details: An ASCII-encodable string to be sent to the client upon + termination of the RPC. + trailing_metadata: The trailing :term:`metadata` in the RPC. + """ + + ############################# gRPC Exceptions ################################ @@ -1118,6 +1135,24 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)): """ raise NotImplementedError() + @abc.abstractmethod + def abort_with_status(self, status): + """Raises an exception to terminate the RPC with a non-OK status. + + The status passed as argument will supercede any existing status code, + status message and trailing metadata. + + This is an EXPERIMENTAL API. + + Args: + status: A grpc.Status object. + + Raises: + Exception: An exception is always raised to signal the abortion the + RPC to the gRPC runtime. + """ + raise NotImplementedError() + @abc.abstractmethod def set_code(self, code): """Sets the value to be used as status code upon RPC completion. @@ -1747,6 +1782,7 @@ __all__ = ( 'Future', 'ChannelConnectivity', 'StatusCode', + 'Status', 'RpcError', 'RpcContext', 'Call', diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index e939f615dfd..3bbfa47da53 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -291,6 +291,10 @@ class _Context(grpc.ServicerContext): self._state.abortion = Exception() raise self._state.abortion + def abort_with_status(self, status): + self._state.trailing_metadata = status.trailing_metadata + self.abort(status.code, status.details) + def set_code(self, code): with self._state.condition: self._state.code = code diff --git a/src/python/grpcio_testing/grpc_testing/_server/_servicer_context.py b/src/python/grpcio_testing/grpc_testing/_server/_servicer_context.py index 90eeb130d30..5b1dfeacdf5 100644 --- a/src/python/grpcio_testing/grpc_testing/_server/_servicer_context.py +++ b/src/python/grpcio_testing/grpc_testing/_server/_servicer_context.py @@ -70,6 +70,9 @@ class ServicerContext(grpc.ServicerContext): def abort(self, code, details): raise NotImplementedError() + def abort_with_status(self, status): + raise NotImplementedError() + def set_code(self, code): self._rpc.set_code(code) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index 9cffd3df197..44700e979e9 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -19,6 +19,7 @@ "testing._server_test.FirstServiceServicerTest", "testing._time_test.StrictFakeTimeTest", "testing._time_test.StrictRealTimeTest", + "unit._abort_test.AbortTest", "unit._api_test.AllTest", "unit._api_test.ChannelConnectivityTest", "unit._api_test.ChannelTest", diff --git a/src/python/grpcio_tests/tests/unit/BUILD.bazel b/src/python/grpcio_tests/tests/unit/BUILD.bazel index de33b81e325..4f850220f8f 100644 --- a/src/python/grpcio_tests/tests/unit/BUILD.bazel +++ b/src/python/grpcio_tests/tests/unit/BUILD.bazel @@ -3,6 +3,7 @@ load("@grpc_python_dependencies//:requirements.bzl", "requirement") package(default_visibility = ["//visibility:public"]) GRPCIO_TESTS_UNIT = [ + "_abort_test.py", "_api_test.py", "_auth_context_test.py", "_auth_test.py", diff --git a/src/python/grpcio_tests/tests/unit/_abort_test.py b/src/python/grpcio_tests/tests/unit/_abort_test.py new file mode 100644 index 00000000000..6438f6897a0 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_abort_test.py @@ -0,0 +1,124 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests server context abort mechanism""" + +import unittest +import collections +import logging + +import grpc + +from tests.unit import test_common +from tests.unit.framework.common import test_constants + +_ABORT = '/test/abort' +_ABORT_WITH_STATUS = '/test/AbortWithStatus' +_INVALID_CODE = '/test/InvalidCode' + +_REQUEST = b'\x00\x00\x00' +_RESPONSE = b'\x00\x00\x00' + +_ABORT_DETAILS = 'Abandon ship!' +_ABORT_METADATA = (('a-trailing-metadata', '42'),) + + +class _Status( + collections.namedtuple( + '_Status', ('code', 'details', 'trailing_metadata')), grpc.Status): + pass + + +def abort_unary_unary(request, servicer_context): + servicer_context.abort( + grpc.StatusCode.INTERNAL, + _ABORT_DETAILS, + ) + raise Exception('This line should not be executed!') + + +def abort_with_status_unary_unary(request, servicer_context): + servicer_context.abort_with_status( + _Status( + code=grpc.StatusCode.INTERNAL, + details=_ABORT_DETAILS, + trailing_metadata=_ABORT_METADATA, + )) + raise Exception('This line should not be executed!') + + +def invalid_code_unary_unary(request, servicer_context): + servicer_context.abort( + 42, + _ABORT_DETAILS, + ) + + +class _GenericHandler(grpc.GenericRpcHandler): + + def service(self, handler_call_details): + if handler_call_details.method == _ABORT: + return grpc.unary_unary_rpc_method_handler(abort_unary_unary) + elif handler_call_details.method == _ABORT_WITH_STATUS: + return grpc.unary_unary_rpc_method_handler( + abort_with_status_unary_unary) + elif handler_call_details.method == _INVALID_CODE: + return grpc.stream_stream_rpc_method_handler( + invalid_code_unary_unary) + else: + return None + + +class AbortTest(unittest.TestCase): + + def setUp(self): + self._server = test_common.test_server() + port = self._server.add_insecure_port('[::]:0') + self._server.add_generic_rpc_handlers((_GenericHandler(),)) + self._server.start() + + self._channel = grpc.insecure_channel('localhost:%d' % port) + + def tearDown(self): + self._channel.close() + self._server.stop(0) + + def test_abort(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_ABORT)(_REQUEST) + rpc_error = exception_context.exception + + self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL) + self.assertEqual(rpc_error.details(), _ABORT_DETAILS) + + def test_abort_with_status(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_ABORT_WITH_STATUS)(_REQUEST) + rpc_error = exception_context.exception + + self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL) + self.assertEqual(rpc_error.details(), _ABORT_DETAILS) + self.assertEqual(rpc_error.trailing_metadata(), _ABORT_METADATA) + + def test_invalid_code(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_INVALID_CODE)(_REQUEST) + rpc_error = exception_context.exception + + self.assertEqual(rpc_error.code(), grpc.StatusCode.UNKNOWN) + self.assertEqual(rpc_error.details(), _ABORT_DETAILS) + + +if __name__ == '__main__': + logging.basicConfig() + unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_api_test.py b/src/python/grpcio_tests/tests/unit/_api_test.py index 38072861a49..427894bfe9f 100644 --- a/src/python/grpcio_tests/tests/unit/_api_test.py +++ b/src/python/grpcio_tests/tests/unit/_api_test.py @@ -32,6 +32,7 @@ class AllTest(unittest.TestCase): 'Future', 'ChannelConnectivity', 'StatusCode', + 'Status', 'RpcError', 'RpcContext', 'Call', From 087d48a8bd74f39eabea96b495d132e3332b5927 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 12 Dec 2018 14:31:52 -0800 Subject: [PATCH 81/99] Update the documentation about the status code constraint --- src/python/grpcio/grpc/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py index 441f4ac8132..daf869b1563 100644 --- a/src/python/grpcio/grpc/__init__.py +++ b/src/python/grpcio/grpc/__init__.py @@ -276,7 +276,6 @@ class Status(six.with_metaclass(abc.ABCMeta)): Attributes: code: A StatusCode object to be sent to the client. - It must not be StatusCode.OK. details: An ASCII-encodable string to be sent to the client upon termination of the RPC. trailing_metadata: The trailing :term:`metadata` in the RPC. @@ -1145,7 +1144,8 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)): This is an EXPERIMENTAL API. Args: - status: A grpc.Status object. + status: A grpc.Status object. The status code in it must not be + StatusCode.OK. Raises: Exception: An exception is always raised to signal the abortion the From bd142d6c46ff97ccd17031d8cd272b6d2ea1206e Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Wed, 12 Dec 2018 14:19:05 -0800 Subject: [PATCH 82/99] Actually build CensusContext --- src/python/grpcio/grpc/_channel.py | 40 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index 35fa82d56bd..96118badada 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -499,6 +499,7 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable): self._method = method self._request_serializer = request_serializer self._response_deserializer = response_deserializer + self._context = cygrpc.build_context() def _prepare(self, request, timeout, metadata, wait_for_ready): deadline, serialized_request, rendezvous = _start_unary_request( @@ -528,11 +529,12 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable): raise rendezvous else: call = self._channel.segregated_call( - 0, self._method, None, deadline, metadata, None + cygrpc.PropagationConstants.GRPC_PROPAGATE_DEFAULTS, + self._method, None, deadline, metadata, None if credentials is None else credentials._credentials, (( operations, None, - ),)) + ),), self._context) event = call.next_event() _handle_event(event, state, self._response_deserializer) return state, call, @@ -570,9 +572,10 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable): else: event_handler = _event_handler(state, self._response_deserializer) call = self._managed_call( - 0, self._method, None, deadline, metadata, None + cygrpc.PropagationConstants.GRPC_PROPAGATE_DEFAULTS, + self._method, None, deadline, metadata, None if credentials is None else credentials._credentials, - (operations,), event_handler) + (operations,), event_handler, self._context) return _Rendezvous(state, call, self._response_deserializer, deadline) @@ -587,6 +590,7 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable): self._method = method self._request_serializer = request_serializer self._response_deserializer = response_deserializer + self._context = cygrpc.build_context() def __call__(self, request, @@ -615,9 +619,10 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable): ) event_handler = _event_handler(state, self._response_deserializer) call = self._managed_call( - 0, self._method, None, deadline, metadata, None + cygrpc.PropagationConstants.GRPC_PROPAGATE_DEFAULTS, + self._method, None, deadline, metadata, None if credentials is None else credentials._credentials, - operationses, event_handler) + operationses, event_handler, self._context) return _Rendezvous(state, call, self._response_deserializer, deadline) @@ -632,6 +637,7 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable): self._method = method self._request_serializer = request_serializer self._response_deserializer = response_deserializer + self._context = cygrpc.build_context() def _blocking(self, request_iterator, timeout, metadata, credentials, wait_for_ready): @@ -640,10 +646,11 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable): initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready( wait_for_ready) call = self._channel.segregated_call( - 0, self._method, None, deadline, metadata, None + cygrpc.PropagationConstants.GRPC_PROPAGATE_DEFAULTS, self._method, + None, deadline, metadata, None if credentials is None else credentials._credentials, _stream_unary_invocation_operationses_and_tags( - metadata, initial_metadata_flags)) + metadata, initial_metadata_flags), self._context) _consume_request_iterator(request_iterator, state, call, self._request_serializer, None) while True: @@ -687,10 +694,11 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable): initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready( wait_for_ready) call = self._managed_call( - 0, self._method, None, deadline, metadata, None + cygrpc.PropagationConstants.GRPC_PROPAGATE_DEFAULTS, self._method, + None, deadline, metadata, None if credentials is None else credentials._credentials, _stream_unary_invocation_operationses( - metadata, initial_metadata_flags), event_handler) + metadata, initial_metadata_flags), event_handler, self._context) _consume_request_iterator(request_iterator, state, call, self._request_serializer, event_handler) return _Rendezvous(state, call, self._response_deserializer, deadline) @@ -706,6 +714,7 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable): self._method = method self._request_serializer = request_serializer self._response_deserializer = response_deserializer + self._context = cygrpc.build_context() def __call__(self, request_iterator, @@ -727,9 +736,10 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable): ) event_handler = _event_handler(state, self._response_deserializer) call = self._managed_call( - 0, self._method, None, deadline, metadata, None + cygrpc.PropagationConstants.GRPC_PROPAGATE_DEFAULTS, self._method, + None, deadline, metadata, None if credentials is None else credentials._credentials, operationses, - event_handler) + event_handler, self._context) _consume_request_iterator(request_iterator, state, call, self._request_serializer, event_handler) return _Rendezvous(state, call, self._response_deserializer, deadline) @@ -789,7 +799,7 @@ def _channel_managed_call_management(state): # pylint: disable=too-many-arguments def create(flags, method, host, deadline, metadata, credentials, - operationses, event_handler): + operationses, event_handler, context): """Creates a cygrpc.IntegratedCall. Args: @@ -804,7 +814,7 @@ def _channel_managed_call_management(state): started on the call. event_handler: A behavior to call to handle the events resultant from the operations on the call. - + context: Context object for distributed tracing. Returns: A cygrpc.IntegratedCall with which to conduct an RPC. """ @@ -815,7 +825,7 @@ def _channel_managed_call_management(state): with state.lock: call = state.channel.integrated_call(flags, method, host, deadline, metadata, credentials, - operationses_and_tags) + operationses_and_tags, context) if state.managed_calls == 0: state.managed_calls = 1 _run_channel_spin_thread(state) From 7fd68349e3ac2dbf642cb1c7907901ad51b5d6c6 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 12 Dec 2018 14:50:32 -0800 Subject: [PATCH 83/99] Add gRPC Python Example: Metadata --- examples/python/metadata/README.md | 6 + examples/python/metadata/helloworld_pb2.py | 134 ++++++++++++++++++ .../python/metadata/helloworld_pb2_grpc.py | 46 ++++++ examples/python/metadata/metadata_client.py | 48 +++++++ examples/python/metadata/metadata_server.py | 56 ++++++++ 5 files changed, 290 insertions(+) create mode 100644 examples/python/metadata/README.md create mode 100644 examples/python/metadata/helloworld_pb2.py create mode 100644 examples/python/metadata/helloworld_pb2_grpc.py create mode 100644 examples/python/metadata/metadata_client.py create mode 100644 examples/python/metadata/metadata_server.py diff --git a/examples/python/metadata/README.md b/examples/python/metadata/README.md new file mode 100644 index 00000000000..5aa75d504a8 --- /dev/null +++ b/examples/python/metadata/README.md @@ -0,0 +1,6 @@ +An example showing how to add custom HTTP2 headers (or [metadata](https://grpc.io/grpc/python/glossary.html) in gRPC glossary) + +HTTP2 supports initial headers and trailing headers, which gRPC utilizes both of them ([learn more](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)). + +More complete documentation lives at [grpc.io](https://grpc.io/docs/tutorials/basic/python.html). +For API reference please see [API](https://grpc.io/grpc/python/grpc.html). diff --git a/examples/python/metadata/helloworld_pb2.py b/examples/python/metadata/helloworld_pb2.py new file mode 100644 index 00000000000..e18ab9acc7a --- /dev/null +++ b/examples/python/metadata/helloworld_pb2.py @@ -0,0 +1,134 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: helloworld.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='helloworld.proto', + package='helloworld', + syntax='proto3', + serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3') +) + + + + +_HELLOREQUEST = _descriptor.Descriptor( + name='HelloRequest', + full_name='helloworld.HelloRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='helloworld.HelloRequest.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=32, + serialized_end=60, +) + + +_HELLOREPLY = _descriptor.Descriptor( + name='HelloReply', + full_name='helloworld.HelloReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='helloworld.HelloReply.message', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=62, + serialized_end=91, +) + +DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST +DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict( + DESCRIPTOR = _HELLOREQUEST, + __module__ = 'helloworld_pb2' + # @@protoc_insertion_point(class_scope:helloworld.HelloRequest) + )) +_sym_db.RegisterMessage(HelloRequest) + +HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict( + DESCRIPTOR = _HELLOREPLY, + __module__ = 'helloworld_pb2' + # @@protoc_insertion_point(class_scope:helloworld.HelloReply) + )) +_sym_db.RegisterMessage(HelloReply) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW')) + +_GREETER = _descriptor.ServiceDescriptor( + name='Greeter', + full_name='helloworld.Greeter', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=93, + serialized_end=166, + methods=[ + _descriptor.MethodDescriptor( + name='SayHello', + full_name='helloworld.Greeter.SayHello', + index=0, + containing_service=None, + input_type=_HELLOREQUEST, + output_type=_HELLOREPLY, + options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_GREETER) + +DESCRIPTOR.services_by_name['Greeter'] = _GREETER + +# @@protoc_insertion_point(module_scope) diff --git a/examples/python/metadata/helloworld_pb2_grpc.py b/examples/python/metadata/helloworld_pb2_grpc.py new file mode 100644 index 00000000000..18e07d16797 --- /dev/null +++ b/examples/python/metadata/helloworld_pb2_grpc.py @@ -0,0 +1,46 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import helloworld_pb2 as helloworld__pb2 + + +class GreeterStub(object): + """The greeting service definition. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.SayHello = channel.unary_unary( + '/helloworld.Greeter/SayHello', + request_serializer=helloworld__pb2.HelloRequest.SerializeToString, + response_deserializer=helloworld__pb2.HelloReply.FromString, + ) + + +class GreeterServicer(object): + """The greeting service definition. + """ + + def SayHello(self, request, context): + """Sends a greeting + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_GreeterServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello, + request_deserializer=helloworld__pb2.HelloRequest.FromString, + response_serializer=helloworld__pb2.HelloReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'helloworld.Greeter', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/examples/python/metadata/metadata_client.py b/examples/python/metadata/metadata_client.py new file mode 100644 index 00000000000..f2a8e37cc21 --- /dev/null +++ b/examples/python/metadata/metadata_client.py @@ -0,0 +1,48 @@ +# Copyright 2018 The 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. +"""Example gRPC client that gets/sets metadata (HTTP2 headers)""" + +from __future__ import print_function +import logging + +import grpc + +import helloworld_pb2 +import helloworld_pb2_grpc + + +def run(): + # NOTE(gRPC Python Team): .close() is possible on a channel and should be + # used in circumstances in which the with statement does not fit the needs + # of the code. + with grpc.insecure_channel('localhost:50051') as channel: + stub = helloworld_pb2_grpc.GreeterStub(channel) + response, call = stub.SayHello.with_call( + helloworld_pb2.HelloRequest(name='you'), + metadata=( + ('initial-metadata-1', 'The value should be str'), + ('binary-metadata-bin', + b'With -bin surffix, the value can be bytes'), + ('accesstoken', 'gRPC Python is great'), + )) + + print("Greeter client received: " + response.message) + for key, value in call.trailing_metadata(): + print('Greeter client received trailing metadata: key=%s value=%s' % + (key, value)) + + +if __name__ == '__main__': + logging.basicConfig() + run() diff --git a/examples/python/metadata/metadata_server.py b/examples/python/metadata/metadata_server.py new file mode 100644 index 00000000000..a4329df79aa --- /dev/null +++ b/examples/python/metadata/metadata_server.py @@ -0,0 +1,56 @@ +# Copyright 2018 The 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. +"""Example gRPC server that gets/sets metadata (HTTP2 headers)""" + +from __future__ import print_function +from concurrent import futures +import time +import logging + +import grpc + +import helloworld_pb2 +import helloworld_pb2_grpc + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class Greeter(helloworld_pb2_grpc.GreeterServicer): + + def SayHello(self, request, context): + for key, value in context.invocation_metadata(): + print('Received initial metadata: key=%s value=%s' % (key, value)) + + context.set_trailing_metadata(( + ('checksum-bin', b'I agree'), + ('retry', 'false'), + )) + return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) + + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) + server.add_insecure_port('[::]:50051') + server.start() + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop(0) + + +if __name__ == '__main__': + logging.basicConfig() + serve() From a69fa16dfdb7795f4918c50f607c4306e598d4d9 Mon Sep 17 00:00:00 2001 From: Juanli Shen Date: Wed, 12 Dec 2018 15:06:12 -0800 Subject: [PATCH 84/99] Add compression example --- examples/cpp/compression/Makefile | 110 +++++++++++++++++++++ examples/cpp/compression/README.md | 84 ++++++++++++++++ examples/cpp/compression/greeter_client.cc | 93 +++++++++++++++++ examples/cpp/compression/greeter_server.cc | 76 ++++++++++++++ 4 files changed, 363 insertions(+) create mode 100644 examples/cpp/compression/Makefile create mode 100644 examples/cpp/compression/README.md create mode 100644 examples/cpp/compression/greeter_client.cc create mode 100644 examples/cpp/compression/greeter_server.cc diff --git a/examples/cpp/compression/Makefile b/examples/cpp/compression/Makefile new file mode 100644 index 00000000000..47211886ff6 --- /dev/null +++ b/examples/cpp/compression/Makefile @@ -0,0 +1,110 @@ +# +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +HOST_SYSTEM = $(shell uname | cut -f 1 -d_) +SYSTEM ?= $(HOST_SYSTEM) +CXX = g++ +CPPFLAGS += `pkg-config --cflags protobuf grpc` +CXXFLAGS += -std=c++11 +ifeq ($(SYSTEM),Darwin) +LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ + -lgrpc++_reflection\ + -ldl +else +LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ + -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\ + -ldl +endif +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + +PROTOS_PATH = ../../protos + +vpath %.proto $(PROTOS_PATH) + +all: system-check greeter_client greeter_server + +greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o + $(CXX) $^ $(LDFLAGS) -o $@ + +greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o + $(CXX) $^ $(LDFLAGS) -o $@ + +.PRECIOUS: %.grpc.pb.cc +%.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +.PRECIOUS: %.pb.cc +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +clean: + rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server + + +# The following is to test your system and ensure a smoother experience. +# They are by no means necessary to actually compile a grpc-enabled software. + +PROTOC_CMD = which $(PROTOC) +PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3 +PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN) +HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false) +ifeq ($(HAS_PROTOC),true) +HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +endif +HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false) + +SYSTEM_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_PLUGIN),true) +SYSTEM_OK = true +endif +endif + +system-check: +ifneq ($(HAS_VALID_PROTOC),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have protoc 3.0.0 installed in your path." + @echo "Please install Google protocol buffers 3.0.0 and its compiler." + @echo "You can find it here:" + @echo + @echo " https://github.com/google/protobuf/releases/tag/v3.0.0" + @echo + @echo "Here is what I get when trying to evaluate your version of protoc:" + @echo + -$(PROTOC) --version + @echo + @echo +endif +ifneq ($(HAS_PLUGIN),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have the grpc c++ protobuf plugin installed in your path." + @echo "Please install grpc. You can find it here:" + @echo + @echo " https://github.com/grpc/grpc" + @echo + @echo "Here is what I get when trying to detect if you have the plugin:" + @echo + -which $(GRPC_CPP_PLUGIN) + @echo + @echo +endif +ifneq ($(SYSTEM_OK),true) + @false +endif diff --git a/examples/cpp/compression/README.md b/examples/cpp/compression/README.md new file mode 100644 index 00000000000..13988f2c0c5 --- /dev/null +++ b/examples/cpp/compression/README.md @@ -0,0 +1,84 @@ +# gRPC C++ Message Compression Tutorial + +### Prerequisite +Make sure you have run the [hello world example](../helloworld) or understood the basics of gRPC. We will not dive into the details that have been discussed in the hello world example. + +### Get the tutorial source code + +The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: + + +```sh +$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc +``` + +Change your current directory to examples/cpp/compression + +```sh +$ cd examples/cpp/compression/ +``` + +### Generating gRPC code + +To generate the client and server side interfaces: + +```sh +$ make helloworld.grpc.pb.cc helloworld.pb.cc +``` +Which internally invokes the proto-compiler as: + +```sh +$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto +$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto +``` + +### Writing a client and a server + +The client and the server can be based on the hello world example. + +Additionally, we can configure the compression settings. + +In the client, set the default compression algorithm of the channel via the channel arg. + +```cpp + ChannelArguments args; + // Set the default compression algorithm for the channel. + args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); + GreeterClient greeter(grpc::CreateCustomChannel( + "localhost:50051", grpc::InsecureChannelCredentials(), args)); +``` + +Each call's compression configuration can be overwritten by client context. + +```cpp + // Overwrite the call's compression algorithm to DEFLATE. + context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE); +``` + +In the server, set the default compression algorithm via the server builder. + +```cpp + ServerBuilder builder; + // Set the default compression algorithm for the server. + builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP); +``` + +Each call's compression configuration can be overwritten by server context. + +```cpp + // Overwrite the call's compression algorithm to DEFLATE. + context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE); +``` + +For a working example, refer to [greeter_client.cc](greeter_client.cc) and [greeter_server.cc](greeter_server.cc). + +Build and run the (compressing) client and the server by the following commands. + +```sh +make +./greeter_server +``` + +```sh +./greeter_client +``` diff --git a/examples/cpp/compression/greeter_client.cc b/examples/cpp/compression/greeter_client.cc new file mode 100644 index 00000000000..a8428174644 --- /dev/null +++ b/examples/cpp/compression/greeter_client.cc @@ -0,0 +1,93 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +using grpc::Channel; +using grpc::ChannelArguments; +using grpc::ClientContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +class GreeterClient { + public: + GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + // Assembles the client's payload, sends it and presents the response back + // from the server. + std::string SayHello(const std::string& user) { + // Data we are sending to the server. + HelloRequest request; + request.set_name(user); + + // Container for the data we expect from the server. + HelloReply reply; + + // Context for the client. It could be used to convey extra information to + // the server and/or tweak certain RPC behaviors. + ClientContext context; + + // Overwrite the call's compression algorithm to DEFLATE. + context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE); + + // The actual RPC. + Status status = stub_->SayHello(&context, request, &reply); + + // Act upon its status. + if (status.ok()) { + return reply.message(); + } else { + std::cout << status.error_code() << ": " << status.error_message() + << std::endl; + return "RPC failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + // Instantiate the client. It requires a channel, out of which the actual RPCs + // are created. This channel models a connection to an endpoint (in this case, + // localhost at port 50051). We indicate that the channel isn't authenticated + // (use of InsecureChannelCredentials()). + ChannelArguments args; + // Set the default compression algorithm for the channel. + args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); + GreeterClient greeter(grpc::CreateCustomChannel( + "localhost:50051", grpc::InsecureChannelCredentials(), args)); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + + return 0; +} diff --git a/examples/cpp/compression/greeter_server.cc b/examples/cpp/compression/greeter_server.cc new file mode 100644 index 00000000000..7399017afb7 --- /dev/null +++ b/examples/cpp/compression/greeter_server.cc @@ -0,0 +1,76 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +// Logic and data behind the server's behavior. +class GreeterServiceImpl final : public Greeter::Service { + Status SayHello(ServerContext* context, const HelloRequest* request, + HelloReply* reply) override { + // Overwrite the call's compression algorithm to DEFLATE. + context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE); + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + return Status::OK; + } +}; + +void RunServer() { + std::string server_address("0.0.0.0:50051"); + GreeterServiceImpl service; + + ServerBuilder builder; + // Set the default compression algorithm for the server. + builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP); + // Listen on the given address without any authentication mechanism. + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. + builder.RegisterService(&service); + // Finally assemble the server. + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. + server->Wait(); +} + +int main(int argc, char** argv) { + RunServer(); + + return 0; +} From a050ae8ddc3a64151b344fd1a4d438db9dea2acb Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 13 Dec 2018 00:29:10 +0100 Subject: [PATCH 85/99] Revert "better slice management for win_read" This reverts commit b0139e15425196be518b251dbdfa3b86648b4740. --- src/core/lib/iomgr/tcp_windows.cc | 57 +++++++++---------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index 86ee1010cf7..aaf9fb4ea8a 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -113,10 +113,7 @@ typedef struct grpc_tcp { grpc_closure* read_cb; grpc_closure* write_cb; - - /* garbage after the last read */ - grpc_slice_buffer last_read_buffer; - + grpc_slice read_slice; grpc_slice_buffer* write_slices; grpc_slice_buffer* read_slices; @@ -135,7 +132,6 @@ 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); @@ -184,6 +180,7 @@ static void on_read(void* tcpp, grpc_error* error) { grpc_tcp* tcp = (grpc_tcp*)tcpp; grpc_closure* cb = tcp->read_cb; grpc_winsocket* socket = tcp->socket; + grpc_slice sub; grpc_winsocket_callback_info* info = &socket->read_info; if (grpc_tcp_trace.enabled()) { @@ -197,19 +194,11 @@ static void on_read(void* tcpp, grpc_error* error) { char* utf8_message = gpr_format_message(info->wsa_error); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(utf8_message); gpr_free(utf8_message); - grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); + grpc_slice_unref_internal(tcp->read_slice); } else { if (info->bytes_transfered != 0 && !tcp->shutting_down) { - GPR_ASSERT((size_t)info->bytes_transfered <= tcp->read_slices->length); - if (static_cast(info->bytes_transfered) != - tcp->read_slices->length) { - grpc_slice_buffer_trim_end( - tcp->read_slices, - tcp->read_slices->length - - static_cast(info->bytes_transfered), - &tcp->last_read_buffer); - } - GPR_ASSERT((size_t)info->bytes_transfered == tcp->read_slices->length); + sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); + grpc_slice_buffer_add(tcp->read_slices, sub); if (grpc_tcp_trace.enabled()) { size_t i; @@ -225,7 +214,7 @@ static void on_read(void* tcpp, grpc_error* error) { if (grpc_tcp_trace.enabled()) { gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp); } - grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); + grpc_slice_unref_internal(tcp->read_slice); error = tcp->shutting_down ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "TCP stream shutting down", &tcp->shutdown_error, 1) @@ -239,8 +228,6 @@ static void on_read(void* tcpp, grpc_error* error) { GRPC_CLOSURE_SCHED(cb, error); } -#define DEFAULT_TARGET_READ_SIZE 8192 -#define MAX_WSABUF_COUNT 16 static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, grpc_closure* cb) { grpc_tcp* tcp = (grpc_tcp*)ep; @@ -249,8 +236,7 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, int status; DWORD bytes_read = 0; DWORD flags = 0; - WSABUF buffers[MAX_WSABUF_COUNT]; - size_t i; + WSABUF buffer; if (grpc_tcp_trace.enabled()) { gpr_log(GPR_INFO, "TCP:%p win_read", tcp); @@ -266,27 +252,18 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, tcp->read_cb = cb; tcp->read_slices = read_slices; grpc_slice_buffer_reset_and_unref_internal(read_slices); - grpc_slice_buffer_swap(read_slices, &tcp->last_read_buffer); - if (tcp->read_slices->length < DEFAULT_TARGET_READ_SIZE / 2 && - tcp->read_slices->count < MAX_WSABUF_COUNT) { - // TODO(jtattermusch): slice should be allocated using resource quota - grpc_slice_buffer_add(tcp->read_slices, - GRPC_SLICE_MALLOC(DEFAULT_TARGET_READ_SIZE)); - } + tcp->read_slice = GRPC_SLICE_MALLOC(8192); - GPR_ASSERT(tcp->read_slices->count <= MAX_WSABUF_COUNT); - for (i = 0; i < tcp->read_slices->count; i++) { - buffers[i].len = (ULONG)GRPC_SLICE_LENGTH( - tcp->read_slices->slices[i]); // we know slice size fits in 32bit. - buffers[i].buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[i]); - } + buffer.len = (ULONG)GRPC_SLICE_LENGTH( + tcp->read_slice); // we know slice size fits in 32bit. + buffer.buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slice); TCP_REF(tcp, "read"); /* First let's try a synchronous, non-blocking read. */ - status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count, - &bytes_read, &flags, NULL, NULL); + status = + WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); /* Did we get data immediately ? Yay. */ @@ -298,8 +275,8 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, /* Otherwise, let's retry, by queuing a read. */ memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); - status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count, - &bytes_read, &flags, &info->overlapped, NULL); + status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, + &info->overlapped, NULL); if (status != 0) { int wsa_error = WSAGetLastError(); @@ -353,7 +330,7 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices, unsigned i; DWORD bytes_sent; int status; - WSABUF local_buffers[MAX_WSABUF_COUNT]; + WSABUF local_buffers[16]; WSABUF* allocated = NULL; WSABUF* buffers = local_buffers; size_t len; @@ -472,7 +449,6 @@ static void win_shutdown(grpc_endpoint* ep, grpc_error* why) { static void win_destroy(grpc_endpoint* ep) { grpc_network_status_unregister_endpoint(ep); grpc_tcp* tcp = (grpc_tcp*)ep; - grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer); TCP_UNREF(tcp, "destroy"); } @@ -524,7 +500,6 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket, 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_slice_buffer_init(&tcp->last_read_buffer); tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); /* Tell network status tracking code about the new endpoint */ grpc_network_status_register_endpoint(&tcp->base); From f438d72e6c5e5bd839a255322fb91c416822f629 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 13 Dec 2018 00:29:23 +0100 Subject: [PATCH 86/99] Revert "basic tcp_trace support for windows" This reverts commit 5861f082607344ed42215ac341e97e4b4bbf0abc. --- src/core/lib/iomgr/tcp_windows.cc | 37 ------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index aaf9fb4ea8a..4b5250803d1 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -42,7 +42,6 @@ #include "src/core/lib/iomgr/tcp_windows.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/slice/slice_internal.h" -#include "src/core/lib/slice/slice_string_helpers.h" #if defined(__MSYS__) && defined(GPR_ARCH_64) /* Nasty workaround for nasty bug when using the 64 bits msys compiler @@ -183,10 +182,6 @@ static void on_read(void* tcpp, grpc_error* error) { grpc_slice sub; grpc_winsocket_callback_info* info = &socket->read_info; - if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_INFO, "TCP:%p on_read", tcp); - } - GRPC_ERROR_REF(error); if (error == GRPC_ERROR_NONE) { @@ -199,21 +194,7 @@ static void on_read(void* tcpp, grpc_error* error) { if (info->bytes_transfered != 0 && !tcp->shutting_down) { sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); grpc_slice_buffer_add(tcp->read_slices, sub); - - if (grpc_tcp_trace.enabled()) { - size_t i; - 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_free(dump); - } - } } else { - if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp); - } grpc_slice_unref_internal(tcp->read_slice); error = tcp->shutting_down ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( @@ -238,10 +219,6 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, DWORD flags = 0; WSABUF buffer; - if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_INFO, "TCP:%p win_read", tcp); - } - if (tcp->shutting_down) { GRPC_CLOSURE_SCHED( cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( @@ -298,10 +275,6 @@ static void on_write(void* tcpp, grpc_error* error) { grpc_winsocket_callback_info* info = &handle->write_info; grpc_closure* cb; - if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_INFO, "TCP:%p on_write", tcp); - } - GRPC_ERROR_REF(error); gpr_mu_lock(&tcp->mu); @@ -335,16 +308,6 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices, WSABUF* buffers = local_buffers; size_t len; - if (grpc_tcp_trace.enabled()) { - size_t i; - 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_free(data); - } - } - if (tcp->shutting_down) { GRPC_CLOSURE_SCHED( cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( From e1c78993becfde9006fde8397474da4679367b29 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Tue, 11 Dec 2018 14:41:38 -0800 Subject: [PATCH 87/99] re-enable unit._exit_test.ExitTest --- src/python/grpcio_tests/commands.py | 8 ++++++++ src/python/grpcio_tests/tests/unit/_exit_test.py | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/python/grpcio_tests/commands.py b/src/python/grpcio_tests/commands.py index 65e9a99950e..18413abab02 100644 --- a/src/python/grpcio_tests/commands.py +++ b/src/python/grpcio_tests/commands.py @@ -133,6 +133,14 @@ class TestGevent(setuptools.Command): # TODO(https://github.com/grpc/grpc/issues/15411) unpin gevent version # This test will stuck while running higher version of gevent 'unit._auth_context_test.AuthContextTest.testSessionResumption', + # TODO(https://github.com/grpc/grpc/issues/15411) enable these tests + 'unit._exit_test.ExitTest.test_in_flight_unary_unary_call', + 'unit._exit_test.ExitTest.test_in_flight_unary_stream_call', + 'unit._exit_test.ExitTest.test_in_flight_stream_unary_call', + 'unit._exit_test.ExitTest.test_in_flight_stream_stream_call', + 'unit._exit_test.ExitTest.test_in_flight_partial_unary_stream_call', + 'unit._exit_test.ExitTest.test_in_flight_partial_stream_unary_call', + 'unit._exit_test.ExitTest.test_in_flight_partial_stream_stream_call', # TODO(https://github.com/grpc/grpc/issues/17330) enable these three tests 'channelz._channelz_servicer_test.ChannelzServicerTest.test_many_subchannels', 'channelz._channelz_servicer_test.ChannelzServicerTest.test_many_subchannels_and_sockets', diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py index 52265375799..b429ee089f7 100644 --- a/src/python/grpcio_tests/tests/unit/_exit_test.py +++ b/src/python/grpcio_tests/tests/unit/_exit_test.py @@ -71,7 +71,6 @@ def wait(process): process.wait() -@unittest.skip('https://github.com/grpc/grpc/issues/7311') class ExitTest(unittest.TestCase): def test_unstarted_server(self): @@ -130,6 +129,8 @@ class ExitTest(unittest.TestCase): stderr=sys.stderr) interrupt_and_wait(process) + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_unary_unary_call(self): process = subprocess.Popen( BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_UNARY_UNARY_CALL], @@ -138,6 +139,8 @@ class ExitTest(unittest.TestCase): interrupt_and_wait(process) @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_unary_stream_call(self): process = subprocess.Popen( BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_UNARY_STREAM_CALL], @@ -145,6 +148,8 @@ class ExitTest(unittest.TestCase): stderr=sys.stderr) interrupt_and_wait(process) + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_stream_unary_call(self): process = subprocess.Popen( BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_STREAM_UNARY_CALL], @@ -153,6 +158,8 @@ class ExitTest(unittest.TestCase): interrupt_and_wait(process) @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_stream_stream_call(self): process = subprocess.Popen( BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_STREAM_STREAM_CALL], @@ -161,6 +168,8 @@ class ExitTest(unittest.TestCase): interrupt_and_wait(process) @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_partial_unary_stream_call(self): process = subprocess.Popen( BASE_COMMAND + @@ -169,6 +178,8 @@ class ExitTest(unittest.TestCase): stderr=sys.stderr) interrupt_and_wait(process) + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_partial_stream_unary_call(self): process = subprocess.Popen( BASE_COMMAND + @@ -178,6 +189,8 @@ class ExitTest(unittest.TestCase): interrupt_and_wait(process) @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') + @unittest.skipIf(os.name == 'nt', + 'os.kill does not have required permission on Windows') def test_in_flight_partial_stream_stream_call(self): process = subprocess.Popen( BASE_COMMAND + From 9decf48632e2106a56515e67c4147e1a6506b47d Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Thu, 6 Dec 2018 01:17:51 -0500 Subject: [PATCH 88/99] Move security credentials, connectors, and auth context to C++ This is to use `grpc_core::RefCount` to improve performnace. This commit also replaces explicit C vtables, with C++ vtable with its own compile time assertions and performance benefits. It also makes use of `RefCountedPtr` wherever possible. --- .../lb_policy/grpclb/grpclb_channel_secure.cc | 10 +- .../lb_policy/xds/xds_channel_secure.cc | 10 +- .../client/secure/secure_channel_create.cc | 17 +- .../server/secure/server_secure_chttp2.cc | 19 +- src/core/lib/gprpp/ref_counted_ptr.h | 8 +- .../lib/http/httpcli_security_connector.cc | 195 ++--- src/core/lib/http/parser.h | 10 +- .../lib/security/context/security_context.cc | 183 ++--- .../lib/security/context/security_context.h | 94 ++- .../credentials/alts/alts_credentials.cc | 84 +- .../credentials/alts/alts_credentials.h | 47 +- .../composite/composite_credentials.cc | 297 ++++---- .../composite/composite_credentials.h | 111 ++- .../lib/security/credentials/credentials.cc | 160 +--- .../lib/security/credentials/credentials.h | 214 +++--- .../credentials/fake/fake_credentials.cc | 117 ++- .../credentials/fake/fake_credentials.h | 28 +- .../google_default_credentials.cc | 83 +- .../google_default_credentials.h | 33 +- .../credentials/iam/iam_credentials.cc | 62 +- .../credentials/iam/iam_credentials.h | 22 +- .../credentials/jwt/jwt_credentials.cc | 129 ++-- .../credentials/jwt/jwt_credentials.h | 39 +- .../credentials/local/local_credentials.cc | 51 +- .../credentials/local/local_credentials.h | 43 +- .../credentials/oauth2/oauth2_credentials.cc | 279 ++++--- .../credentials/oauth2/oauth2_credentials.h | 103 ++- .../credentials/plugin/plugin_credentials.cc | 136 ++-- .../credentials/plugin/plugin_credentials.h | 57 +- .../credentials/ssl/ssl_credentials.cc | 149 ++-- .../credentials/ssl/ssl_credentials.h | 73 +- .../alts/alts_security_connector.cc | 329 ++++---- .../alts/alts_security_connector.h | 22 +- .../fake/fake_security_connector.cc | 424 +++++------ .../fake/fake_security_connector.h | 15 +- .../local/local_security_connector.cc | 278 +++---- .../local/local_security_connector.h | 19 +- .../security_connector/security_connector.cc | 165 +--- .../security_connector/security_connector.h | 206 +++-- .../ssl/ssl_security_connector.cc | 718 +++++++++--------- .../ssl/ssl_security_connector.h | 26 +- .../security/security_connector/ssl_utils.cc | 22 +- .../security/security_connector/ssl_utils.h | 4 +- .../security/transport/client_auth_filter.cc | 100 +-- .../security/transport/security_handshaker.cc | 147 ++-- .../security/transport/server_auth_filter.cc | 28 +- src/cpp/client/secure_credentials.cc | 6 +- src/cpp/client/secure_credentials.h | 9 +- src/cpp/common/secure_auth_context.cc | 38 +- src/cpp/common/secure_auth_context.h | 11 +- src/cpp/common/secure_create_auth_context.cc | 5 +- src/cpp/server/secure_server_credentials.cc | 2 +- .../security/alts_security_connector_test.cc | 41 +- test/core/security/auth_context_test.cc | 116 +-- test/core/security/credentials_test.cc | 232 +++--- test/core/security/oauth2_utils.cc | 5 +- .../print_google_default_creds_token.cc | 9 +- test/core/security/security_connector_test.cc | 95 +-- test/core/security/ssl_server_fuzzer.cc | 11 +- .../surface/secure_channel_create_test.cc | 2 +- .../cpp/common/auth_property_iterator_test.cc | 17 +- test/cpp/common/secure_auth_context_test.cc | 14 +- test/cpp/end2end/grpclb_end2end_test.cc | 4 +- 63 files changed, 2940 insertions(+), 3043 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc index 6e8fbdcab77..657ff693126 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc @@ -88,22 +88,18 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args( // bearer token credentials. grpc_channel_credentials* channel_credentials = grpc_channel_credentials_find_in_args(args); - grpc_channel_credentials* creds_sans_call_creds = nullptr; + grpc_core::RefCountedPtr creds_sans_call_creds; if (channel_credentials != nullptr) { creds_sans_call_creds = - grpc_channel_credentials_duplicate_without_call_credentials( - channel_credentials); + channel_credentials->duplicate_without_call_credentials(); GPR_ASSERT(creds_sans_call_creds != nullptr); args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS; args_to_add[num_args_to_add++] = - grpc_channel_credentials_to_arg(creds_sans_call_creds); + grpc_channel_credentials_to_arg(creds_sans_call_creds.get()); } grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove( args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add); // Clean up. grpc_channel_args_destroy(args); - if (creds_sans_call_creds != nullptr) { - grpc_channel_credentials_unref(creds_sans_call_creds); - } return result; } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc index 9a11f8e39fd..55c646e6eed 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc @@ -87,22 +87,18 @@ grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args( // bearer token credentials. grpc_channel_credentials* channel_credentials = grpc_channel_credentials_find_in_args(args); - grpc_channel_credentials* creds_sans_call_creds = nullptr; + grpc_core::RefCountedPtr creds_sans_call_creds; if (channel_credentials != nullptr) { creds_sans_call_creds = - grpc_channel_credentials_duplicate_without_call_credentials( - channel_credentials); + channel_credentials->duplicate_without_call_credentials(); GPR_ASSERT(creds_sans_call_creds != nullptr); args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS; args_to_add[num_args_to_add++] = - grpc_channel_credentials_to_arg(creds_sans_call_creds); + grpc_channel_credentials_to_arg(creds_sans_call_creds.get()); } grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove( args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add); // Clean up. grpc_channel_args_destroy(args); - if (creds_sans_call_creds != nullptr) { - grpc_channel_credentials_unref(creds_sans_call_creds); - } return result; } diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc index e73eee43537..9612698e967 100644 --- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc +++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc @@ -110,14 +110,14 @@ static grpc_subchannel_args* get_secure_naming_subchannel_args( grpc_channel_args* args_with_authority = grpc_channel_args_copy_and_add(args->args, args_to_add, num_args_to_add); grpc_uri_destroy(server_uri); - grpc_channel_security_connector* subchannel_security_connector = nullptr; // Create the security connector using the credentials and target name. grpc_channel_args* new_args_from_connector = nullptr; - const grpc_security_status security_status = - grpc_channel_credentials_create_security_connector( - channel_credentials, authority.get(), args_with_authority, - &subchannel_security_connector, &new_args_from_connector); - if (security_status != GRPC_SECURITY_OK) { + grpc_core::RefCountedPtr + subchannel_security_connector = + channel_credentials->create_security_connector( + /*call_creds=*/nullptr, authority.get(), args_with_authority, + &new_args_from_connector); + if (subchannel_security_connector == nullptr) { gpr_log(GPR_ERROR, "Failed to create secure subchannel for secure name '%s'", authority.get()); @@ -125,15 +125,14 @@ static grpc_subchannel_args* get_secure_naming_subchannel_args( return nullptr; } grpc_arg new_security_connector_arg = - grpc_security_connector_to_arg(&subchannel_security_connector->base); + grpc_security_connector_to_arg(subchannel_security_connector.get()); grpc_channel_args* new_args = grpc_channel_args_copy_and_add( new_args_from_connector != nullptr ? new_args_from_connector : args_with_authority, &new_security_connector_arg, 1); - GRPC_SECURITY_CONNECTOR_UNREF(&subchannel_security_connector->base, - "lb_channel_create"); + subchannel_security_connector.reset(DEBUG_LOCATION, "lb_channel_create"); if (new_args_from_connector != nullptr) { grpc_channel_args_destroy(new_args_from_connector); } 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 6689a17da63..98fdb620704 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 @@ -31,6 +31,7 @@ #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/surface/api_trace.h" @@ -40,9 +41,8 @@ int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr, grpc_server_credentials* creds) { grpc_core::ExecCtx exec_ctx; grpc_error* err = GRPC_ERROR_NONE; - grpc_server_security_connector* sc = nullptr; + grpc_core::RefCountedPtr sc; int port_num = 0; - grpc_security_status status; grpc_channel_args* args = nullptr; GRPC_API_TRACE( "grpc_server_add_secure_http2_port(" @@ -54,30 +54,27 @@ int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr, "No credentials specified for secure server port (creds==NULL)"); goto done; } - status = grpc_server_credentials_create_security_connector(creds, &sc); - if (status != GRPC_SECURITY_OK) { + sc = creds->create_security_connector(); + if (sc == nullptr) { char* msg; gpr_asprintf(&msg, "Unable to create secure server with credentials of type %s.", - creds->type); - err = grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg), - GRPC_ERROR_INT_SECURITY_STATUS, status); + creds->type()); + err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); goto done; } // Create channel args. grpc_arg args_to_add[2]; args_to_add[0] = grpc_server_credentials_to_arg(creds); - args_to_add[1] = grpc_security_connector_to_arg(&sc->base); + args_to_add[1] = grpc_security_connector_to_arg(sc.get()); args = grpc_channel_args_copy_and_add(grpc_server_get_channel_args(server), args_to_add, GPR_ARRAY_SIZE(args_to_add)); // Add server port. err = grpc_chttp2_server_add_port(server, addr, args, &port_num); done: - if (sc != nullptr) { - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server"); - } + sc.reset(DEBUG_LOCATION, "server"); if (err != GRPC_ERROR_NONE) { const char* msg = grpc_error_string(err); diff --git a/src/core/lib/gprpp/ref_counted_ptr.h b/src/core/lib/gprpp/ref_counted_ptr.h index 1ed5d584c70..19f38d7f013 100644 --- a/src/core/lib/gprpp/ref_counted_ptr.h +++ b/src/core/lib/gprpp/ref_counted_ptr.h @@ -50,7 +50,7 @@ class RefCountedPtr { } template RefCountedPtr(RefCountedPtr&& other) { - value_ = other.value_; + value_ = static_cast(other.value_); other.value_ = nullptr; } @@ -77,7 +77,7 @@ class RefCountedPtr { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); if (other.value_ != nullptr) other.value_->IncrementRefCount(); - value_ = other.value_; + value_ = static_cast(other.value_); } // Copy assignment. @@ -118,7 +118,7 @@ class RefCountedPtr { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); if (value_ != nullptr) value_->Unref(); - value_ = value; + value_ = static_cast(value); } template void reset(const DebugLocation& location, const char* reason, @@ -126,7 +126,7 @@ class RefCountedPtr { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); if (value_ != nullptr) value_->Unref(location, reason); - value_ = value; + value_ = static_cast(value); } // TODO(roth): This method exists solely as a transition mechanism to allow diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc index 1c798d368b0..6802851392c 100644 --- a/src/core/lib/http/httpcli_security_connector.cc +++ b/src/core/lib/http/httpcli_security_connector.cc @@ -29,119 +29,125 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/pollset.h" +#include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/security_connector/ssl_utils.h" #include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/ssl_transport_security.h" -typedef struct { - grpc_channel_security_connector base; - tsi_ssl_client_handshaker_factory* handshaker_factory; - char* secure_peer_name; -} grpc_httpcli_ssl_channel_security_connector; - -static void httpcli_ssl_destroy(grpc_security_connector* sc) { - grpc_httpcli_ssl_channel_security_connector* c = - reinterpret_cast(sc); - if (c->handshaker_factory != nullptr) { - tsi_ssl_client_handshaker_factory_unref(c->handshaker_factory); - c->handshaker_factory = nullptr; +class grpc_httpcli_ssl_channel_security_connector final + : public grpc_channel_security_connector { + public: + explicit grpc_httpcli_ssl_channel_security_connector(char* secure_peer_name) + : grpc_channel_security_connector( + /*url_scheme=*/nullptr, + /*channel_creds=*/nullptr, + /*request_metadata_creds=*/nullptr), + secure_peer_name_(secure_peer_name) {} + + ~grpc_httpcli_ssl_channel_security_connector() override { + if (handshaker_factory_ != nullptr) { + tsi_ssl_client_handshaker_factory_unref(handshaker_factory_); + } + if (secure_peer_name_ != nullptr) { + gpr_free(secure_peer_name_); + } + } + + tsi_result InitHandshakerFactory(const char* pem_root_certs, + const tsi_ssl_root_certs_store* root_store) { + tsi_ssl_client_handshaker_options options; + memset(&options, 0, sizeof(options)); + options.pem_root_certs = pem_root_certs; + options.root_store = root_store; + return tsi_create_ssl_client_handshaker_factory_with_options( + &options, &handshaker_factory_); } - if (c->secure_peer_name != nullptr) gpr_free(c->secure_peer_name); - gpr_free(sc); -} -static void httpcli_ssl_add_handshakers(grpc_channel_security_connector* sc, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - grpc_httpcli_ssl_channel_security_connector* c = - reinterpret_cast(sc); - tsi_handshaker* handshaker = nullptr; - if (c->handshaker_factory != nullptr) { - tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( - c->handshaker_factory, c->secure_peer_name, &handshaker); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", - tsi_result_to_string(result)); + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) override { + tsi_handshaker* handshaker = nullptr; + if (handshaker_factory_ != nullptr) { + tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( + handshaker_factory_, secure_peer_name_, &handshaker); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", + tsi_result_to_string(result)); + } } + grpc_handshake_manager_add( + handshake_mgr, grpc_security_handshaker_create(handshaker, this)); } - grpc_handshake_manager_add( - handshake_mgr, grpc_security_handshaker_create(handshaker, &sc->base)); -} -static void httpcli_ssl_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - grpc_httpcli_ssl_channel_security_connector* c = - reinterpret_cast(sc); - grpc_error* error = GRPC_ERROR_NONE; - - /* Check the peer name. */ - if (c->secure_peer_name != nullptr && - !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) { - char* msg; - gpr_asprintf(&msg, "Peer name %s is not in peer certificate", - c->secure_peer_name); - error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); - gpr_free(msg); + tsi_ssl_client_handshaker_factory* handshaker_factory() const { + return handshaker_factory_; } - GRPC_CLOSURE_SCHED(on_peer_checked, error); - tsi_peer_destruct(&peer); -} -static int httpcli_ssl_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_httpcli_ssl_channel_security_connector* c1 = - reinterpret_cast(sc1); - grpc_httpcli_ssl_channel_security_connector* c2 = - reinterpret_cast(sc2); - return strcmp(c1->secure_peer_name, c2->secure_peer_name); -} + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* /*auth_context*/, + grpc_closure* on_peer_checked) override { + grpc_error* error = GRPC_ERROR_NONE; + + /* Check the peer name. */ + if (secure_peer_name_ != nullptr && + !tsi_ssl_peer_matches_name(&peer, secure_peer_name_)) { + char* msg; + gpr_asprintf(&msg, "Peer name %s is not in peer certificate", + secure_peer_name_); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + gpr_free(msg); + } + GRPC_CLOSURE_SCHED(on_peer_checked, error); + tsi_peer_destruct(&peer); + } -static grpc_security_connector_vtable httpcli_ssl_vtable = { - httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp}; + int cmp(const grpc_security_connector* other_sc) const override { + auto* other = + reinterpret_cast( + other_sc); + return strcmp(secure_peer_name_, other->secure_peer_name_); + } -static grpc_security_status httpcli_ssl_channel_security_connector_create( - const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store, - const char* secure_peer_name, grpc_channel_security_connector** sc) { - tsi_result result = TSI_OK; - grpc_httpcli_ssl_channel_security_connector* c; + bool check_call_host(const char* host, grpc_auth_context* auth_context, + grpc_closure* on_call_host_checked, + grpc_error** error) override { + *error = GRPC_ERROR_NONE; + return true; + } - if (secure_peer_name != nullptr && pem_root_certs == nullptr) { - gpr_log(GPR_ERROR, - "Cannot assert a secure peer name without a trust root."); - return GRPC_SECURITY_ERROR; + void cancel_check_call_host(grpc_closure* on_call_host_checked, + grpc_error* error) override { + GRPC_ERROR_UNREF(error); } - c = static_cast( - gpr_zalloc(sizeof(grpc_httpcli_ssl_channel_security_connector))); + const char* secure_peer_name() const { return secure_peer_name_; } - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &httpcli_ssl_vtable; - if (secure_peer_name != nullptr) { - c->secure_peer_name = gpr_strdup(secure_peer_name); + private: + tsi_ssl_client_handshaker_factory* handshaker_factory_ = nullptr; + char* secure_peer_name_; +}; + +static grpc_core::RefCountedPtr +httpcli_ssl_channel_security_connector_create( + const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store, + const char* secure_peer_name) { + if (secure_peer_name != nullptr && pem_root_certs == nullptr) { + gpr_log(GPR_ERROR, + "Cannot assert a secure peer name without a trust root."); + return nullptr; } - tsi_ssl_client_handshaker_options options; - memset(&options, 0, sizeof(options)); - options.pem_root_certs = pem_root_certs; - options.root_store = root_store; - result = tsi_create_ssl_client_handshaker_factory_with_options( - &options, &c->handshaker_factory); + grpc_core::RefCountedPtr c = + grpc_core::MakeRefCounted( + secure_peer_name == nullptr ? nullptr : gpr_strdup(secure_peer_name)); + tsi_result result = c->InitHandshakerFactory(pem_root_certs, root_store); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); - httpcli_ssl_destroy(&c->base.base); - *sc = nullptr; - return GRPC_SECURITY_ERROR; + return nullptr; } - // We don't actually need a channel credentials object in this case, - // but we set it to a non-nullptr address so that we don't trigger - // assertions in grpc_channel_security_connector_cmp(). - c->base.channel_creds = (grpc_channel_credentials*)1; - c->base.add_handshakers = httpcli_ssl_add_handshakers; - *sc = &c->base; - return GRPC_SECURITY_OK; + return c; } /* handshaker */ @@ -186,10 +192,11 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host, } c->func = on_done; c->arg = arg; - grpc_channel_security_connector* sc = nullptr; - GPR_ASSERT(httpcli_ssl_channel_security_connector_create( - pem_root_certs, root_store, host, &sc) == GRPC_SECURITY_OK); - grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base); + grpc_core::RefCountedPtr sc = + httpcli_ssl_channel_security_connector_create(pem_root_certs, root_store, + host); + GPR_ASSERT(sc != nullptr); + grpc_arg channel_arg = grpc_security_connector_to_arg(sc.get()); grpc_channel_args args = {1, &channel_arg}; c->handshake_mgr = grpc_handshake_manager_create(); grpc_handshakers_add(HANDSHAKER_CLIENT, &args, @@ -197,7 +204,7 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host, grpc_handshake_manager_do_handshake( c->handshake_mgr, tcp, nullptr /* channel_args */, deadline, nullptr /* acceptor */, on_handshake_done, c /* user_data */); - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); + sc.reset(DEBUG_LOCATION, "httpcli"); } const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h index 1d2e13e8317..a8f47c96c85 100644 --- a/src/core/lib/http/parser.h +++ b/src/core/lib/http/parser.h @@ -70,13 +70,13 @@ typedef struct grpc_http_request { /* A response */ typedef struct grpc_http_response { /* HTTP status code */ - int status; + int status = 0; /* Headers: count and key/values */ - size_t hdr_count; - grpc_http_header* hdrs; + size_t hdr_count = 0; + grpc_http_header* hdrs = nullptr; /* Body: length and contents; contents are NOT null-terminated */ - size_t body_length; - char* body; + size_t body_length = 0; + char* body = nullptr; } grpc_http_response; typedef struct { diff --git a/src/core/lib/security/context/security_context.cc b/src/core/lib/security/context/security_context.cc index 16f40b4f55d..8443ee0695a 100644 --- a/src/core/lib/security/context/security_context.cc +++ b/src/core/lib/security/context/security_context.cc @@ -23,6 +23,8 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/arena.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" @@ -50,13 +52,11 @@ grpc_call_error grpc_call_set_credentials(grpc_call* call, ctx = static_cast( grpc_call_context_get(call, GRPC_CONTEXT_SECURITY)); if (ctx == nullptr) { - ctx = grpc_client_security_context_create(grpc_call_get_arena(call)); - ctx->creds = grpc_call_credentials_ref(creds); + ctx = grpc_client_security_context_create(grpc_call_get_arena(call), creds); grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, grpc_client_security_context_destroy); } else { - grpc_call_credentials_unref(ctx->creds); - ctx->creds = grpc_call_credentials_ref(creds); + ctx->creds = creds != nullptr ? creds->Ref() : nullptr; } return GRPC_CALL_OK; @@ -66,33 +66,45 @@ grpc_auth_context* grpc_call_auth_context(grpc_call* call) { void* sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY); GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call)); if (sec_ctx == nullptr) return nullptr; - return grpc_call_is_client(call) - ? GRPC_AUTH_CONTEXT_REF( - ((grpc_client_security_context*)sec_ctx)->auth_context, - "grpc_call_auth_context client") - : GRPC_AUTH_CONTEXT_REF( - ((grpc_server_security_context*)sec_ctx)->auth_context, - "grpc_call_auth_context server"); + if (grpc_call_is_client(call)) { + auto* sc = static_cast(sec_ctx); + if (sc->auth_context == nullptr) { + return nullptr; + } else { + return sc->auth_context + ->Ref(DEBUG_LOCATION, "grpc_call_auth_context client") + .release(); + } + } else { + auto* sc = static_cast(sec_ctx); + if (sc->auth_context == nullptr) { + return nullptr; + } else { + return sc->auth_context + ->Ref(DEBUG_LOCATION, "grpc_call_auth_context server") + .release(); + } + } } void grpc_auth_context_release(grpc_auth_context* context) { GRPC_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context)); - GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref"); + if (context == nullptr) return; + context->Unref(DEBUG_LOCATION, "grpc_auth_context_unref"); } /* --- grpc_client_security_context --- */ grpc_client_security_context::~grpc_client_security_context() { - grpc_call_credentials_unref(creds); - GRPC_AUTH_CONTEXT_UNREF(auth_context, "client_security_context"); + auth_context.reset(DEBUG_LOCATION, "client_security_context"); if (extension.instance != nullptr && extension.destroy != nullptr) { extension.destroy(extension.instance); } } grpc_client_security_context* grpc_client_security_context_create( - gpr_arena* arena) { + gpr_arena* arena, grpc_call_credentials* creds) { return new (gpr_arena_alloc(arena, sizeof(grpc_client_security_context))) - grpc_client_security_context(); + grpc_client_security_context(creds != nullptr ? creds->Ref() : nullptr); } void grpc_client_security_context_destroy(void* ctx) { @@ -104,7 +116,7 @@ void grpc_client_security_context_destroy(void* ctx) { /* --- grpc_server_security_context --- */ grpc_server_security_context::~grpc_server_security_context() { - GRPC_AUTH_CONTEXT_UNREF(auth_context, "server_security_context"); + auth_context.reset(DEBUG_LOCATION, "server_security_context"); if (extension.instance != nullptr && extension.destroy != nullptr) { extension.destroy(extension.instance); } @@ -126,69 +138,11 @@ void grpc_server_security_context_destroy(void* ctx) { static grpc_auth_property_iterator empty_iterator = {nullptr, 0, nullptr}; -grpc_auth_context* grpc_auth_context_create(grpc_auth_context* chained) { - grpc_auth_context* ctx = - static_cast(gpr_zalloc(sizeof(grpc_auth_context))); - gpr_ref_init(&ctx->refcount, 1); - if (chained != nullptr) { - ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); - ctx->peer_identity_property_name = - ctx->chained->peer_identity_property_name; - } - return ctx; -} - -#ifndef NDEBUG -grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* ctx, - const char* file, int line, - const char* reason) { - if (ctx == nullptr) return nullptr; - if (grpc_trace_auth_context_refcount.enabled()) { - gpr_atm val = gpr_atm_no_barrier_load(&ctx->refcount.count); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "AUTH_CONTEXT:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", ctx, val, - val + 1, reason); - } -#else -grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* ctx) { - if (ctx == nullptr) return nullptr; -#endif - gpr_ref(&ctx->refcount); - return ctx; -} - -#ifndef NDEBUG -void grpc_auth_context_unref(grpc_auth_context* ctx, const char* file, int line, - const char* reason) { - if (ctx == nullptr) return; - if (grpc_trace_auth_context_refcount.enabled()) { - gpr_atm val = gpr_atm_no_barrier_load(&ctx->refcount.count); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "AUTH_CONTEXT:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", ctx, val, - val - 1, reason); - } -#else -void grpc_auth_context_unref(grpc_auth_context* ctx) { - if (ctx == nullptr) return; -#endif - if (gpr_unref(&ctx->refcount)) { - size_t i; - GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); - if (ctx->properties.array != nullptr) { - for (i = 0; i < ctx->properties.count; i++) { - grpc_auth_property_reset(&ctx->properties.array[i]); - } - gpr_free(ctx->properties.array); - } - gpr_free(ctx); - } -} - const char* grpc_auth_context_peer_identity_property_name( const grpc_auth_context* ctx) { GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1, (ctx)); - return ctx->peer_identity_property_name; + return ctx->peer_identity_property_name(); } int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context* ctx, @@ -204,13 +158,13 @@ int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context* ctx, name != nullptr ? name : "NULL"); return 0; } - ctx->peer_identity_property_name = prop->name; + ctx->set_peer_identity_property_name(prop->name); return 1; } int grpc_auth_context_peer_is_authenticated(const grpc_auth_context* ctx) { GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx)); - return ctx->peer_identity_property_name == nullptr ? 0 : 1; + return ctx->is_authenticated(); } grpc_auth_property_iterator grpc_auth_context_property_iterator( @@ -226,16 +180,17 @@ const grpc_auth_property* grpc_auth_property_iterator_next( grpc_auth_property_iterator* it) { GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it)); if (it == nullptr || it->ctx == nullptr) return nullptr; - while (it->index == it->ctx->properties.count) { - if (it->ctx->chained == nullptr) return nullptr; - it->ctx = it->ctx->chained; + while (it->index == it->ctx->properties().count) { + if (it->ctx->chained() == nullptr) return nullptr; + it->ctx = it->ctx->chained(); it->index = 0; } if (it->name == nullptr) { - return &it->ctx->properties.array[it->index++]; + return &it->ctx->properties().array[it->index++]; } else { - while (it->index < it->ctx->properties.count) { - const grpc_auth_property* prop = &it->ctx->properties.array[it->index++]; + while (it->index < it->ctx->properties().count) { + const grpc_auth_property* prop = + &it->ctx->properties().array[it->index++]; GPR_ASSERT(prop->name != nullptr); if (strcmp(it->name, prop->name) == 0) { return prop; @@ -262,49 +217,56 @@ grpc_auth_property_iterator grpc_auth_context_peer_identity( GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx)); if (ctx == nullptr) return empty_iterator; return grpc_auth_context_find_properties_by_name( - ctx, ctx->peer_identity_property_name); + ctx, ctx->peer_identity_property_name()); } -static void ensure_auth_context_capacity(grpc_auth_context* ctx) { - if (ctx->properties.count == ctx->properties.capacity) { - ctx->properties.capacity = - GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2); - ctx->properties.array = static_cast( - gpr_realloc(ctx->properties.array, - ctx->properties.capacity * sizeof(grpc_auth_property))); +void grpc_auth_context::ensure_capacity() { + if (properties_.count == properties_.capacity) { + properties_.capacity = + GPR_MAX(properties_.capacity + 8, properties_.capacity * 2); + properties_.array = static_cast(gpr_realloc( + properties_.array, properties_.capacity * sizeof(grpc_auth_property))); } } +void grpc_auth_context::add_property(const char* name, const char* value, + size_t value_length) { + ensure_capacity(); + grpc_auth_property* prop = &properties_.array[properties_.count++]; + prop->name = gpr_strdup(name); + prop->value = static_cast(gpr_malloc(value_length + 1)); + memcpy(prop->value, value, value_length); + prop->value[value_length] = '\0'; + prop->value_length = value_length; +} + void grpc_auth_context_add_property(grpc_auth_context* ctx, const char* name, const char* value, size_t value_length) { - grpc_auth_property* prop; GRPC_API_TRACE( "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, " "value_length=%lu)", 6, (ctx, name, (int)value_length, (int)value_length, value, (unsigned long)value_length)); - ensure_auth_context_capacity(ctx); - prop = &ctx->properties.array[ctx->properties.count++]; + ctx->add_property(name, value, value_length); +} + +void grpc_auth_context::add_cstring_property(const char* name, + const char* value) { + ensure_capacity(); + grpc_auth_property* prop = &properties_.array[properties_.count++]; prop->name = gpr_strdup(name); - prop->value = static_cast(gpr_malloc(value_length + 1)); - memcpy(prop->value, value, value_length); - prop->value[value_length] = '\0'; - prop->value_length = value_length; + prop->value = gpr_strdup(value); + prop->value_length = strlen(value); } void grpc_auth_context_add_cstring_property(grpc_auth_context* ctx, const char* name, const char* value) { - grpc_auth_property* prop; GRPC_API_TRACE( "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3, (ctx, name, value)); - ensure_auth_context_capacity(ctx); - prop = &ctx->properties.array[ctx->properties.count++]; - prop->name = gpr_strdup(name); - prop->value = gpr_strdup(value); - prop->value_length = strlen(value); + ctx->add_cstring_property(name, value); } void grpc_auth_property_reset(grpc_auth_property* property) { @@ -314,12 +276,17 @@ void grpc_auth_property_reset(grpc_auth_property* property) { } static void auth_context_pointer_arg_destroy(void* p) { - GRPC_AUTH_CONTEXT_UNREF((grpc_auth_context*)p, "auth_context_pointer_arg"); + if (p != nullptr) { + static_cast(p)->Unref(DEBUG_LOCATION, + "auth_context_pointer_arg"); + } } static void* auth_context_pointer_arg_copy(void* p) { - return GRPC_AUTH_CONTEXT_REF((grpc_auth_context*)p, - "auth_context_pointer_arg"); + auto* ctx = static_cast(p); + return ctx == nullptr + ? nullptr + : ctx->Ref(DEBUG_LOCATION, "auth_context_pointer_arg").release(); } static int auth_context_pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); } diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h index e45415f63b8..b43ee5e62d5 100644 --- a/src/core/lib/security/context/security_context.h +++ b/src/core/lib/security/context/security_context.h @@ -21,6 +21,8 @@ #include +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/security/credentials/credentials.h" @@ -40,39 +42,59 @@ struct grpc_auth_property_array { size_t capacity = 0; }; -struct grpc_auth_context { - grpc_auth_context() { gpr_ref_init(&refcount, 0); } +void grpc_auth_property_reset(grpc_auth_property* property); - struct grpc_auth_context* chained = nullptr; - grpc_auth_property_array properties; - gpr_refcount refcount; - const char* peer_identity_property_name = nullptr; - grpc_pollset* pollset = nullptr; +// This type is forward declared as a C struct and we cannot define it as a +// class. Otherwise, compiler will complain about type mismatch due to +// -Wmismatched-tags. +struct grpc_auth_context + : public grpc_core::RefCounted { + public: + explicit grpc_auth_context( + grpc_core::RefCountedPtr chained) + : grpc_core::RefCounted( + &grpc_trace_auth_context_refcount), + chained_(std::move(chained)) { + if (chained_ != nullptr) { + peer_identity_property_name_ = chained_->peer_identity_property_name_; + } + } + + ~grpc_auth_context() { + chained_.reset(DEBUG_LOCATION, "chained"); + if (properties_.array != nullptr) { + for (size_t i = 0; i < properties_.count; i++) { + grpc_auth_property_reset(&properties_.array[i]); + } + gpr_free(properties_.array); + } + } + + const grpc_auth_context* chained() const { return chained_.get(); } + const grpc_auth_property_array& properties() const { return properties_; } + + bool is_authenticated() const { + return peer_identity_property_name_ != nullptr; + } + const char* peer_identity_property_name() const { + return peer_identity_property_name_; + } + void set_peer_identity_property_name(const char* name) { + peer_identity_property_name_ = name; + } + + void ensure_capacity(); + void add_property(const char* name, const char* value, size_t value_length); + void add_cstring_property(const char* name, const char* value); + + private: + grpc_core::RefCountedPtr chained_; + grpc_auth_property_array properties_; + const char* peer_identity_property_name_ = nullptr; }; -/* Creation. */ -grpc_auth_context* grpc_auth_context_create(grpc_auth_context* chained); - -/* Refcounting. */ -#ifndef NDEBUG -#define GRPC_AUTH_CONTEXT_REF(p, r) \ - grpc_auth_context_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_AUTH_CONTEXT_UNREF(p, r) \ - grpc_auth_context_unref((p), __FILE__, __LINE__, (r)) -grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* policy, - const char* file, int line, - const char* reason); -void grpc_auth_context_unref(grpc_auth_context* policy, const char* file, - int line, const char* reason); -#else -#define GRPC_AUTH_CONTEXT_REF(p, r) grpc_auth_context_ref((p)) -#define GRPC_AUTH_CONTEXT_UNREF(p, r) grpc_auth_context_unref((p)) -grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* policy); -void grpc_auth_context_unref(grpc_auth_context* policy); -#endif - -void grpc_auth_property_reset(grpc_auth_property* property); - /* --- grpc_security_context_extension --- Extension to the security context that may be set in a filter and accessed @@ -88,16 +110,18 @@ struct grpc_security_context_extension { Internal client-side security context. */ struct grpc_client_security_context { - grpc_client_security_context() = default; + explicit grpc_client_security_context( + grpc_core::RefCountedPtr creds) + : creds(std::move(creds)) {} ~grpc_client_security_context(); - grpc_call_credentials* creds = nullptr; - grpc_auth_context* auth_context = nullptr; + grpc_core::RefCountedPtr creds; + grpc_core::RefCountedPtr auth_context; grpc_security_context_extension extension; }; grpc_client_security_context* grpc_client_security_context_create( - gpr_arena* arena); + gpr_arena* arena, grpc_call_credentials* creds); void grpc_client_security_context_destroy(void* ctx); /* --- grpc_server_security_context --- @@ -108,7 +132,7 @@ struct grpc_server_security_context { grpc_server_security_context() = default; ~grpc_server_security_context(); - grpc_auth_context* auth_context = nullptr; + grpc_core::RefCountedPtr auth_context; grpc_security_context_extension extension; }; diff --git a/src/core/lib/security/credentials/alts/alts_credentials.cc b/src/core/lib/security/credentials/alts/alts_credentials.cc index 1fbef4ae0c7..06546492bc7 100644 --- a/src/core/lib/security/credentials/alts/alts_credentials.cc +++ b/src/core/lib/security/credentials/alts/alts_credentials.cc @@ -33,40 +33,47 @@ #define GRPC_CREDENTIALS_TYPE_ALTS "Alts" #define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080" -static void alts_credentials_destruct(grpc_channel_credentials* creds) { - grpc_alts_credentials* alts_creds = - reinterpret_cast(creds); - grpc_alts_credentials_options_destroy(alts_creds->options); - gpr_free(alts_creds->handshaker_service_url); -} - -static void alts_server_credentials_destruct(grpc_server_credentials* creds) { - grpc_alts_server_credentials* alts_creds = - reinterpret_cast(creds); - grpc_alts_credentials_options_destroy(alts_creds->options); - gpr_free(alts_creds->handshaker_service_url); +grpc_alts_credentials::grpc_alts_credentials( + const grpc_alts_credentials_options* options, + const char* handshaker_service_url) + : grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_ALTS), + options_(grpc_alts_credentials_options_copy(options)), + handshaker_service_url_(handshaker_service_url == nullptr + ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL) + : gpr_strdup(handshaker_service_url)) {} + +grpc_alts_credentials::~grpc_alts_credentials() { + grpc_alts_credentials_options_destroy(options_); + gpr_free(handshaker_service_url_); } -static grpc_security_status alts_create_security_connector( - grpc_channel_credentials* creds, - grpc_call_credentials* request_metadata_creds, const char* target_name, - const grpc_channel_args* args, grpc_channel_security_connector** sc, +grpc_core::RefCountedPtr +grpc_alts_credentials::create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target_name, const grpc_channel_args* args, grpc_channel_args** new_args) { return grpc_alts_channel_security_connector_create( - creds, request_metadata_creds, target_name, sc); + this->Ref(), std::move(call_creds), target_name); } -static grpc_security_status alts_server_create_security_connector( - grpc_server_credentials* creds, grpc_server_security_connector** sc) { - return grpc_alts_server_security_connector_create(creds, sc); +grpc_alts_server_credentials::grpc_alts_server_credentials( + const grpc_alts_credentials_options* options, + const char* handshaker_service_url) + : grpc_server_credentials(GRPC_CREDENTIALS_TYPE_ALTS), + options_(grpc_alts_credentials_options_copy(options)), + handshaker_service_url_(handshaker_service_url == nullptr + ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL) + : gpr_strdup(handshaker_service_url)) {} + +grpc_core::RefCountedPtr +grpc_alts_server_credentials::create_security_connector() { + return grpc_alts_server_security_connector_create(this->Ref()); } -static const grpc_channel_credentials_vtable alts_credentials_vtable = { - alts_credentials_destruct, alts_create_security_connector, - /*duplicate_without_call_credentials=*/nullptr}; - -static const grpc_server_credentials_vtable alts_server_credentials_vtable = { - alts_server_credentials_destruct, alts_server_create_security_connector}; +grpc_alts_server_credentials::~grpc_alts_server_credentials() { + grpc_alts_credentials_options_destroy(options_); + gpr_free(handshaker_service_url_); +} grpc_channel_credentials* grpc_alts_credentials_create_customized( const grpc_alts_credentials_options* options, @@ -74,17 +81,7 @@ grpc_channel_credentials* grpc_alts_credentials_create_customized( if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) { return nullptr; } - auto creds = static_cast( - gpr_zalloc(sizeof(grpc_alts_credentials))); - creds->options = grpc_alts_credentials_options_copy(options); - creds->handshaker_service_url = - handshaker_service_url == nullptr - ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL) - : gpr_strdup(handshaker_service_url); - creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS; - creds->base.vtable = &alts_credentials_vtable; - gpr_ref_init(&creds->base.refcount, 1); - return &creds->base; + return grpc_core::New(options, handshaker_service_url); } grpc_server_credentials* grpc_alts_server_credentials_create_customized( @@ -93,17 +90,8 @@ grpc_server_credentials* grpc_alts_server_credentials_create_customized( if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) { return nullptr; } - auto creds = static_cast( - gpr_zalloc(sizeof(grpc_alts_server_credentials))); - creds->options = grpc_alts_credentials_options_copy(options); - creds->handshaker_service_url = - handshaker_service_url == nullptr - ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL) - : gpr_strdup(handshaker_service_url); - creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS; - creds->base.vtable = &alts_server_credentials_vtable; - gpr_ref_init(&creds->base.refcount, 1); - return &creds->base; + return grpc_core::New(options, + handshaker_service_url); } grpc_channel_credentials* grpc_alts_credentials_create( diff --git a/src/core/lib/security/credentials/alts/alts_credentials.h b/src/core/lib/security/credentials/alts/alts_credentials.h index 810117f2bea..cc6d5222b16 100644 --- a/src/core/lib/security/credentials/alts/alts_credentials.h +++ b/src/core/lib/security/credentials/alts/alts_credentials.h @@ -27,18 +27,45 @@ #include "src/core/lib/security/credentials/credentials.h" /* Main struct for grpc ALTS channel credential. */ -typedef struct grpc_alts_credentials { - grpc_channel_credentials base; - grpc_alts_credentials_options* options; - char* handshaker_service_url; -} grpc_alts_credentials; +class grpc_alts_credentials final : public grpc_channel_credentials { + public: + grpc_alts_credentials(const grpc_alts_credentials_options* options, + const char* handshaker_service_url); + ~grpc_alts_credentials() override; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target_name, const grpc_channel_args* args, + grpc_channel_args** new_args) override; + + const grpc_alts_credentials_options* options() const { return options_; } + grpc_alts_credentials_options* mutable_options() { return options_; } + const char* handshaker_service_url() const { return handshaker_service_url_; } + + private: + grpc_alts_credentials_options* options_; + char* handshaker_service_url_; +}; /* Main struct for grpc ALTS server credential. */ -typedef struct grpc_alts_server_credentials { - grpc_server_credentials base; - grpc_alts_credentials_options* options; - char* handshaker_service_url; -} grpc_alts_server_credentials; +class grpc_alts_server_credentials final : public grpc_server_credentials { + public: + grpc_alts_server_credentials(const grpc_alts_credentials_options* options, + const char* handshaker_service_url); + ~grpc_alts_server_credentials() override; + + grpc_core::RefCountedPtr + create_security_connector() override; + + const grpc_alts_credentials_options* options() const { return options_; } + grpc_alts_credentials_options* mutable_options() { return options_; } + const char* handshaker_service_url() const { return handshaker_service_url_; } + + private: + grpc_alts_credentials_options* options_; + char* handshaker_service_url_; +}; /** * This method creates an ALTS channel credential object with customized diff --git a/src/core/lib/security/credentials/composite/composite_credentials.cc b/src/core/lib/security/credentials/composite/composite_credentials.cc index b8f409260f0..85dcd4693bc 100644 --- a/src/core/lib/security/credentials/composite/composite_credentials.cc +++ b/src/core/lib/security/credentials/composite/composite_credentials.cc @@ -20,8 +20,10 @@ #include "src/core/lib/security/credentials/composite/composite_credentials.h" -#include +#include +#include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/surface/api_trace.h" @@ -31,36 +33,83 @@ /* -- Composite call credentials. -- */ -typedef struct { +static void composite_call_metadata_cb(void* arg, grpc_error* error); + +grpc_call_credentials_array::~grpc_call_credentials_array() { + for (size_t i = 0; i < num_creds_; ++i) { + creds_array_[i].~RefCountedPtr(); + } + if (creds_array_ != nullptr) { + gpr_free(creds_array_); + } +} + +grpc_call_credentials_array::grpc_call_credentials_array( + const grpc_call_credentials_array& that) + : num_creds_(that.num_creds_) { + reserve(that.capacity_); + for (size_t i = 0; i < num_creds_; ++i) { + new (&creds_array_[i]) + grpc_core::RefCountedPtr(that.creds_array_[i]); + } +} + +void grpc_call_credentials_array::reserve(size_t capacity) { + if (capacity_ >= capacity) { + return; + } + grpc_core::RefCountedPtr* new_arr = + static_cast*>(gpr_malloc( + sizeof(grpc_core::RefCountedPtr) * capacity)); + if (creds_array_ != nullptr) { + for (size_t i = 0; i < num_creds_; ++i) { + new (&new_arr[i]) grpc_core::RefCountedPtr( + std::move(creds_array_[i])); + creds_array_[i].~RefCountedPtr(); + } + gpr_free(creds_array_); + } + creds_array_ = new_arr; + capacity_ = capacity; +} + +namespace { +struct grpc_composite_call_credentials_metadata_context { + grpc_composite_call_credentials_metadata_context( + grpc_composite_call_credentials* composite_creds, + grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata) + : composite_creds(composite_creds), + pollent(pollent), + auth_md_context(auth_md_context), + md_array(md_array), + on_request_metadata(on_request_metadata) { + GRPC_CLOSURE_INIT(&internal_on_request_metadata, composite_call_metadata_cb, + this, grpc_schedule_on_exec_ctx); + } + grpc_composite_call_credentials* composite_creds; - size_t creds_index; + size_t creds_index = 0; grpc_polling_entity* pollent; grpc_auth_metadata_context auth_md_context; grpc_credentials_mdelem_array* md_array; grpc_closure* on_request_metadata; grpc_closure internal_on_request_metadata; -} grpc_composite_call_credentials_metadata_context; - -static void composite_call_destruct(grpc_call_credentials* creds) { - grpc_composite_call_credentials* c = - reinterpret_cast(creds); - for (size_t i = 0; i < c->inner.num_creds; i++) { - grpc_call_credentials_unref(c->inner.creds_array[i]); - } - gpr_free(c->inner.creds_array); -} +}; +} // namespace static void composite_call_metadata_cb(void* arg, grpc_error* error) { grpc_composite_call_credentials_metadata_context* ctx = static_cast(arg); if (error == GRPC_ERROR_NONE) { + const grpc_call_credentials_array& inner = ctx->composite_creds->inner(); /* See if we need to get some more metadata. */ - if (ctx->creds_index < ctx->composite_creds->inner.num_creds) { - grpc_call_credentials* inner_creds = - ctx->composite_creds->inner.creds_array[ctx->creds_index++]; - if (grpc_call_credentials_get_request_metadata( - inner_creds, ctx->pollent, ctx->auth_md_context, ctx->md_array, - &ctx->internal_on_request_metadata, &error)) { + if (ctx->creds_index < inner.size()) { + if (inner.get(ctx->creds_index++) + ->get_request_metadata( + ctx->pollent, ctx->auth_md_context, ctx->md_array, + &ctx->internal_on_request_metadata, &error)) { // Synchronous response, so call ourselves recursively. composite_call_metadata_cb(arg, error); GRPC_ERROR_UNREF(error); @@ -73,76 +122,86 @@ static void composite_call_metadata_cb(void* arg, grpc_error* error) { gpr_free(ctx); } -static bool composite_call_get_request_metadata( - grpc_call_credentials* creds, grpc_polling_entity* pollent, - grpc_auth_metadata_context auth_md_context, +bool grpc_composite_call_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context, grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, grpc_error** error) { - grpc_composite_call_credentials* c = - reinterpret_cast(creds); grpc_composite_call_credentials_metadata_context* ctx; - ctx = static_cast( - gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context))); - ctx->composite_creds = c; - ctx->pollent = pollent; - ctx->auth_md_context = auth_md_context; - ctx->md_array = md_array; - ctx->on_request_metadata = on_request_metadata; - GRPC_CLOSURE_INIT(&ctx->internal_on_request_metadata, - composite_call_metadata_cb, ctx, grpc_schedule_on_exec_ctx); + ctx = grpc_core::New( + this, pollent, auth_md_context, md_array, on_request_metadata); bool synchronous = true; - while (ctx->creds_index < ctx->composite_creds->inner.num_creds) { - grpc_call_credentials* inner_creds = - ctx->composite_creds->inner.creds_array[ctx->creds_index++]; - if (grpc_call_credentials_get_request_metadata( - inner_creds, ctx->pollent, ctx->auth_md_context, ctx->md_array, - &ctx->internal_on_request_metadata, error)) { + const grpc_call_credentials_array& inner = ctx->composite_creds->inner(); + while (ctx->creds_index < inner.size()) { + if (inner.get(ctx->creds_index++) + ->get_request_metadata(ctx->pollent, ctx->auth_md_context, + ctx->md_array, + &ctx->internal_on_request_metadata, error)) { if (*error != GRPC_ERROR_NONE) break; } else { synchronous = false; // Async return. break; } } - if (synchronous) gpr_free(ctx); + if (synchronous) grpc_core::Delete(ctx); return synchronous; } -static void composite_call_cancel_get_request_metadata( - grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { - grpc_composite_call_credentials* c = - reinterpret_cast(creds); - for (size_t i = 0; i < c->inner.num_creds; ++i) { - grpc_call_credentials_cancel_get_request_metadata( - c->inner.creds_array[i], md_array, GRPC_ERROR_REF(error)); +void grpc_composite_call_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { + for (size_t i = 0; i < inner_.size(); ++i) { + inner_.get(i)->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable composite_call_credentials_vtable = { - composite_call_destruct, composite_call_get_request_metadata, - composite_call_cancel_get_request_metadata}; +static size_t get_creds_array_size(const grpc_call_credentials* creds, + bool is_composite) { + return is_composite + ? static_cast(creds) + ->inner() + .size() + : 1; +} -static grpc_call_credentials_array get_creds_array( - grpc_call_credentials** creds_addr) { - grpc_call_credentials_array result; - grpc_call_credentials* creds = *creds_addr; - result.creds_array = creds_addr; - result.num_creds = 1; - if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { - result = *grpc_composite_call_credentials_get_credentials(creds); +void grpc_composite_call_credentials::push_to_inner( + grpc_core::RefCountedPtr creds, bool is_composite) { + if (!is_composite) { + inner_.push_back(std::move(creds)); + return; } - return result; + auto composite_creds = + static_cast(creds.get()); + for (size_t i = 0; i < composite_creds->inner().size(); ++i) { + inner_.push_back(std::move(composite_creds->inner_.get_mutable(i))); + } +} + +grpc_composite_call_credentials::grpc_composite_call_credentials( + grpc_core::RefCountedPtr creds1, + grpc_core::RefCountedPtr creds2) + : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) { + const bool creds1_is_composite = + strcmp(creds1->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0; + const bool creds2_is_composite = + strcmp(creds2->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0; + const size_t size = get_creds_array_size(creds1.get(), creds1_is_composite) + + get_creds_array_size(creds2.get(), creds2_is_composite); + inner_.reserve(size); + push_to_inner(std::move(creds1), creds1_is_composite); + push_to_inner(std::move(creds2), creds2_is_composite); +} + +static grpc_core::RefCountedPtr +composite_call_credentials_create( + grpc_core::RefCountedPtr creds1, + grpc_core::RefCountedPtr creds2) { + return grpc_core::MakeRefCounted( + std::move(creds1), std::move(creds2)); } grpc_call_credentials* grpc_composite_call_credentials_create( grpc_call_credentials* creds1, grpc_call_credentials* creds2, void* reserved) { - size_t i; - size_t creds_array_byte_size; - grpc_call_credentials_array creds1_array; - grpc_call_credentials_array creds2_array; - grpc_composite_call_credentials* c; GRPC_API_TRACE( "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, " "reserved=%p)", @@ -150,120 +209,40 @@ grpc_call_credentials* grpc_composite_call_credentials_create( GPR_ASSERT(reserved == nullptr); GPR_ASSERT(creds1 != nullptr); GPR_ASSERT(creds2 != nullptr); - c = static_cast( - gpr_zalloc(sizeof(grpc_composite_call_credentials))); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE; - c->base.vtable = &composite_call_credentials_vtable; - gpr_ref_init(&c->base.refcount, 1); - creds1_array = get_creds_array(&creds1); - creds2_array = get_creds_array(&creds2); - c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; - creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials*); - c->inner.creds_array = - static_cast(gpr_zalloc(creds_array_byte_size)); - for (i = 0; i < creds1_array.num_creds; i++) { - grpc_call_credentials* cur_creds = creds1_array.creds_array[i]; - c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds); - } - for (i = 0; i < creds2_array.num_creds; i++) { - grpc_call_credentials* cur_creds = creds2_array.creds_array[i]; - c->inner.creds_array[i + creds1_array.num_creds] = - grpc_call_credentials_ref(cur_creds); - } - return &c->base; -} -const grpc_call_credentials_array* -grpc_composite_call_credentials_get_credentials(grpc_call_credentials* creds) { - const grpc_composite_call_credentials* c = - reinterpret_cast(creds); - GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); - return &c->inner; -} - -grpc_call_credentials* grpc_credentials_contains_type( - grpc_call_credentials* creds, const char* type, - grpc_call_credentials** composite_creds) { - size_t i; - if (strcmp(creds->type, type) == 0) { - if (composite_creds != nullptr) *composite_creds = nullptr; - return creds; - } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { - const grpc_call_credentials_array* inner_creds_array = - grpc_composite_call_credentials_get_credentials(creds); - for (i = 0; i < inner_creds_array->num_creds; i++) { - if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) { - if (composite_creds != nullptr) *composite_creds = creds; - return inner_creds_array->creds_array[i]; - } - } - } - return nullptr; + return composite_call_credentials_create(creds1->Ref(), creds2->Ref()) + .release(); } /* -- Composite channel credentials. -- */ -static void composite_channel_destruct(grpc_channel_credentials* creds) { - grpc_composite_channel_credentials* c = - reinterpret_cast(creds); - grpc_channel_credentials_unref(c->inner_creds); - grpc_call_credentials_unref(c->call_creds); -} - -static grpc_security_status composite_channel_create_security_connector( - grpc_channel_credentials* creds, grpc_call_credentials* call_creds, +grpc_core::RefCountedPtr +grpc_composite_channel_credentials::create_security_connector( + grpc_core::RefCountedPtr call_creds, const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args) { - grpc_composite_channel_credentials* c = - reinterpret_cast(creds); - grpc_security_status status = GRPC_SECURITY_ERROR; - - GPR_ASSERT(c->inner_creds != nullptr && c->call_creds != nullptr && - c->inner_creds->vtable != nullptr && - c->inner_creds->vtable->create_security_connector != nullptr); + grpc_channel_args** new_args) { + GPR_ASSERT(inner_creds_ != nullptr && call_creds_ != nullptr); /* If we are passed a call_creds, create a call composite to pass it downstream. */ if (call_creds != nullptr) { - grpc_call_credentials* composite_call_creds = - grpc_composite_call_credentials_create(c->call_creds, call_creds, - nullptr); - status = c->inner_creds->vtable->create_security_connector( - c->inner_creds, composite_call_creds, target, args, sc, new_args); - grpc_call_credentials_unref(composite_call_creds); + return inner_creds_->create_security_connector( + composite_call_credentials_create(call_creds_, std::move(call_creds)), + target, args, new_args); } else { - status = c->inner_creds->vtable->create_security_connector( - c->inner_creds, c->call_creds, target, args, sc, new_args); + return inner_creds_->create_security_connector(call_creds_, target, args, + new_args); } - return status; -} - -static grpc_channel_credentials* -composite_channel_duplicate_without_call_credentials( - grpc_channel_credentials* creds) { - grpc_composite_channel_credentials* c = - reinterpret_cast(creds); - return grpc_channel_credentials_ref(c->inner_creds); } -static grpc_channel_credentials_vtable composite_channel_credentials_vtable = { - composite_channel_destruct, composite_channel_create_security_connector, - composite_channel_duplicate_without_call_credentials}; - grpc_channel_credentials* grpc_composite_channel_credentials_create( grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds, void* reserved) { - grpc_composite_channel_credentials* c = - static_cast(gpr_zalloc(sizeof(*c))); GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr && reserved == nullptr); GRPC_API_TRACE( "grpc_composite_channel_credentials_create(channel_creds=%p, " "call_creds=%p, reserved=%p)", 3, (channel_creds, call_creds, reserved)); - c->base.type = channel_creds->type; - c->base.vtable = &composite_channel_credentials_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->inner_creds = grpc_channel_credentials_ref(channel_creds); - c->call_creds = grpc_call_credentials_ref(call_creds); - return &c->base; + return grpc_core::New( + channel_creds->Ref(), call_creds->Ref()); } diff --git a/src/core/lib/security/credentials/composite/composite_credentials.h b/src/core/lib/security/credentials/composite/composite_credentials.h index a952ad57f1e..6b7fca13708 100644 --- a/src/core/lib/security/credentials/composite/composite_credentials.h +++ b/src/core/lib/security/credentials/composite/composite_credentials.h @@ -21,39 +21,104 @@ #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/credentials/credentials.h" -typedef struct { - grpc_call_credentials** creds_array; - size_t num_creds; -} grpc_call_credentials_array; +// TODO(soheil): Replace this with InlinedVector once #16032 is resolved. +class grpc_call_credentials_array { + public: + grpc_call_credentials_array() = default; + grpc_call_credentials_array(const grpc_call_credentials_array& that); -const grpc_call_credentials_array* -grpc_composite_call_credentials_get_credentials( - grpc_call_credentials* composite_creds); + ~grpc_call_credentials_array(); -/* Returns creds if creds is of the specified type or the inner creds of the - specified type (if found), if the creds is of type COMPOSITE. - If composite_creds is not NULL, *composite_creds will point to creds if of - type COMPOSITE in case of success. */ -grpc_call_credentials* grpc_credentials_contains_type( - grpc_call_credentials* creds, const char* type, - grpc_call_credentials** composite_creds); + void reserve(size_t capacity); + + // Must reserve before pushing any data. + void push_back(grpc_core::RefCountedPtr cred) { + GPR_DEBUG_ASSERT(capacity_ > num_creds_); + new (&creds_array_[num_creds_++]) + grpc_core::RefCountedPtr(std::move(cred)); + } + + const grpc_core::RefCountedPtr& get(size_t i) const { + GPR_DEBUG_ASSERT(i < num_creds_); + return creds_array_[i]; + } + grpc_core::RefCountedPtr& get_mutable(size_t i) { + GPR_DEBUG_ASSERT(i < num_creds_); + return creds_array_[i]; + } + + size_t size() const { return num_creds_; } + + private: + grpc_core::RefCountedPtr* creds_array_ = nullptr; + size_t num_creds_ = 0; + size_t capacity_ = 0; +}; /* -- Composite channel credentials. -- */ -typedef struct { - grpc_channel_credentials base; - grpc_channel_credentials* inner_creds; - grpc_call_credentials* call_creds; -} grpc_composite_channel_credentials; +class grpc_composite_channel_credentials : public grpc_channel_credentials { + public: + grpc_composite_channel_credentials( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr call_creds) + : grpc_channel_credentials(channel_creds->type()), + inner_creds_(std::move(channel_creds)), + call_creds_(std::move(call_creds)) {} + + ~grpc_composite_channel_credentials() override = default; + + grpc_core::RefCountedPtr + duplicate_without_call_credentials() override { + return inner_creds_; + } + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target, const grpc_channel_args* args, + grpc_channel_args** new_args) override; + + const grpc_channel_credentials* inner_creds() const { + return inner_creds_.get(); + } + const grpc_call_credentials* call_creds() const { return call_creds_.get(); } + grpc_call_credentials* mutable_call_creds() { return call_creds_.get(); } + + private: + grpc_core::RefCountedPtr inner_creds_; + grpc_core::RefCountedPtr call_creds_; +}; /* -- Composite call credentials. -- */ -typedef struct { - grpc_call_credentials base; - grpc_call_credentials_array inner; -} grpc_composite_call_credentials; +class grpc_composite_call_credentials : public grpc_call_credentials { + public: + grpc_composite_call_credentials( + grpc_core::RefCountedPtr creds1, + grpc_core::RefCountedPtr creds2); + ~grpc_composite_call_credentials() override = default; + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + const grpc_call_credentials_array& inner() const { return inner_; } + + private: + void push_to_inner(grpc_core::RefCountedPtr creds, + bool is_composite); + + grpc_call_credentials_array inner_; +}; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_COMPOSITE_COMPOSITE_CREDENTIALS_H \ */ diff --git a/src/core/lib/security/credentials/credentials.cc b/src/core/lib/security/credentials/credentials.cc index c43cb440ebf..90452d68d61 100644 --- a/src/core/lib/security/credentials/credentials.cc +++ b/src/core/lib/security/credentials/credentials.cc @@ -39,120 +39,24 @@ /* -- Common. -- */ -grpc_credentials_metadata_request* grpc_credentials_metadata_request_create( - grpc_call_credentials* creds) { - grpc_credentials_metadata_request* r = - static_cast( - gpr_zalloc(sizeof(grpc_credentials_metadata_request))); - r->creds = grpc_call_credentials_ref(creds); - return r; -} - -void grpc_credentials_metadata_request_destroy( - grpc_credentials_metadata_request* r) { - grpc_call_credentials_unref(r->creds); - grpc_http_response_destroy(&r->response); - gpr_free(r); -} - -grpc_channel_credentials* grpc_channel_credentials_ref( - grpc_channel_credentials* creds) { - if (creds == nullptr) return nullptr; - gpr_ref(&creds->refcount); - return creds; -} - -void grpc_channel_credentials_unref(grpc_channel_credentials* creds) { - if (creds == nullptr) return; - if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != nullptr) { - creds->vtable->destruct(creds); - } - gpr_free(creds); - } -} - void grpc_channel_credentials_release(grpc_channel_credentials* creds) { GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds)); grpc_core::ExecCtx exec_ctx; - grpc_channel_credentials_unref(creds); -} - -grpc_call_credentials* grpc_call_credentials_ref(grpc_call_credentials* creds) { - if (creds == nullptr) return nullptr; - gpr_ref(&creds->refcount); - return creds; -} - -void grpc_call_credentials_unref(grpc_call_credentials* creds) { - if (creds == nullptr) return; - if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != nullptr) { - creds->vtable->destruct(creds); - } - gpr_free(creds); - } + if (creds) creds->Unref(); } void grpc_call_credentials_release(grpc_call_credentials* creds) { GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds)); grpc_core::ExecCtx exec_ctx; - grpc_call_credentials_unref(creds); -} - -bool grpc_call_credentials_get_request_metadata( - grpc_call_credentials* creds, grpc_polling_entity* pollent, - grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, grpc_error** error) { - if (creds == nullptr || creds->vtable->get_request_metadata == nullptr) { - return true; - } - return creds->vtable->get_request_metadata(creds, pollent, context, md_array, - on_request_metadata, error); -} - -void grpc_call_credentials_cancel_get_request_metadata( - grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { - if (creds == nullptr || - creds->vtable->cancel_get_request_metadata == nullptr) { - return; - } - creds->vtable->cancel_get_request_metadata(creds, md_array, error); -} - -grpc_security_status grpc_channel_credentials_create_security_connector( - grpc_channel_credentials* channel_creds, const char* target, - const grpc_channel_args* args, grpc_channel_security_connector** sc, - grpc_channel_args** new_args) { - *new_args = nullptr; - if (channel_creds == nullptr) { - return GRPC_SECURITY_ERROR; - } - GPR_ASSERT(channel_creds->vtable->create_security_connector != nullptr); - return channel_creds->vtable->create_security_connector( - channel_creds, nullptr, target, args, sc, new_args); -} - -grpc_channel_credentials* -grpc_channel_credentials_duplicate_without_call_credentials( - grpc_channel_credentials* channel_creds) { - if (channel_creds != nullptr && channel_creds->vtable != nullptr && - channel_creds->vtable->duplicate_without_call_credentials != nullptr) { - return channel_creds->vtable->duplicate_without_call_credentials( - channel_creds); - } else { - return grpc_channel_credentials_ref(channel_creds); - } + if (creds) creds->Unref(); } static void credentials_pointer_arg_destroy(void* p) { - grpc_channel_credentials_unref(static_cast(p)); + static_cast(p)->Unref(); } static void* credentials_pointer_arg_copy(void* p) { - return grpc_channel_credentials_ref( - static_cast(p)); + return static_cast(p)->Ref().release(); } static int credentials_pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); } @@ -191,63 +95,35 @@ grpc_channel_credentials* grpc_channel_credentials_find_in_args( return nullptr; } -grpc_server_credentials* grpc_server_credentials_ref( - grpc_server_credentials* creds) { - if (creds == nullptr) return nullptr; - gpr_ref(&creds->refcount); - return creds; -} - -void grpc_server_credentials_unref(grpc_server_credentials* creds) { - if (creds == nullptr) return; - if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != nullptr) { - creds->vtable->destruct(creds); - } - if (creds->processor.destroy != nullptr && - creds->processor.state != nullptr) { - creds->processor.destroy(creds->processor.state); - } - gpr_free(creds); - } -} - void grpc_server_credentials_release(grpc_server_credentials* creds) { GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds)); grpc_core::ExecCtx exec_ctx; - grpc_server_credentials_unref(creds); + if (creds) creds->Unref(); } -grpc_security_status grpc_server_credentials_create_security_connector( - grpc_server_credentials* creds, grpc_server_security_connector** sc) { - if (creds == nullptr || creds->vtable->create_security_connector == nullptr) { - gpr_log(GPR_ERROR, "Server credentials cannot create security context."); - return GRPC_SECURITY_ERROR; - } - return creds->vtable->create_security_connector(creds, sc); -} - -void grpc_server_credentials_set_auth_metadata_processor( - grpc_server_credentials* creds, grpc_auth_metadata_processor processor) { +void grpc_server_credentials::set_auth_metadata_processor( + const grpc_auth_metadata_processor& processor) { GRPC_API_TRACE( "grpc_server_credentials_set_auth_metadata_processor(" "creds=%p, " "processor=grpc_auth_metadata_processor { process: %p, state: %p })", - 3, (creds, (void*)(intptr_t)processor.process, processor.state)); - if (creds == nullptr) return; - if (creds->processor.destroy != nullptr && - creds->processor.state != nullptr) { - creds->processor.destroy(creds->processor.state); - } - creds->processor = processor; + 3, (this, (void*)(intptr_t)processor.process, processor.state)); + DestroyProcessor(); + processor_ = processor; +} + +void grpc_server_credentials_set_auth_metadata_processor( + grpc_server_credentials* creds, grpc_auth_metadata_processor processor) { + GPR_DEBUG_ASSERT(creds != nullptr); + creds->set_auth_metadata_processor(processor); } static void server_credentials_pointer_arg_destroy(void* p) { - grpc_server_credentials_unref(static_cast(p)); + static_cast(p)->Unref(); } static void* server_credentials_pointer_arg_copy(void* p) { - return grpc_server_credentials_ref(static_cast(p)); + return static_cast(p)->Ref().release(); } static int server_credentials_pointer_cmp(void* a, void* b) { diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h index 3878958b38b..4091ef3dfb5 100644 --- a/src/core/lib/security/credentials/credentials.h +++ b/src/core/lib/security/credentials/credentials.h @@ -26,6 +26,7 @@ #include #include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/http/httpcli.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/polling_entity.h" @@ -90,44 +91,46 @@ void grpc_override_well_known_credentials_path_getter( #define GRPC_ARG_CHANNEL_CREDENTIALS "grpc.channel_credentials" -typedef struct { - void (*destruct)(grpc_channel_credentials* c); - - grpc_security_status (*create_security_connector)( - grpc_channel_credentials* c, grpc_call_credentials* call_creds, +// This type is forward declared as a C struct and we cannot define it as a +// class. Otherwise, compiler will complain about type mismatch due to +// -Wmismatched-tags. +struct grpc_channel_credentials + : grpc_core::RefCounted { + public: + explicit grpc_channel_credentials(const char* type) : type_(type) {} + virtual ~grpc_channel_credentials() = default; + + // Creates a security connector for the channel. May also create new channel + // args for the channel to be used in place of the passed in const args if + // returned non NULL. In that case the caller is responsible for destroying + // new_args after channel creation. + virtual grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args); - - grpc_channel_credentials* (*duplicate_without_call_credentials)( - grpc_channel_credentials* c); -} grpc_channel_credentials_vtable; - -struct grpc_channel_credentials { - const grpc_channel_credentials_vtable* vtable; - const char* type; - gpr_refcount refcount; + grpc_channel_args** new_args) { + // Tell clang-tidy that call_creds cannot be passed as const-ref. + call_creds.reset(); + GRPC_ABSTRACT; + } + + // Creates a version of the channel credentials without any attached call + // credentials. This can be used in order to open a channel to a non-trusted + // gRPC load balancer. + virtual grpc_core::RefCountedPtr + duplicate_without_call_credentials() { + // By default we just increment the refcount. + return Ref(); + } + + const char* type() const { return type_; } + + GRPC_ABSTRACT_BASE_CLASS + + private: + const char* type_; }; -grpc_channel_credentials* grpc_channel_credentials_ref( - grpc_channel_credentials* creds); -void grpc_channel_credentials_unref(grpc_channel_credentials* creds); - -/* Creates a security connector for the channel. May also create new channel - args for the channel to be used in place of the passed in const args if - returned non NULL. In that case the caller is responsible for destroying - new_args after channel creation. */ -grpc_security_status grpc_channel_credentials_create_security_connector( - grpc_channel_credentials* creds, const char* target, - const grpc_channel_args* args, grpc_channel_security_connector** sc, - grpc_channel_args** new_args); - -/* Creates a version of the channel credentials without any attached call - credentials. This can be used in order to open a channel to a non-trusted - gRPC load balancer. */ -grpc_channel_credentials* -grpc_channel_credentials_duplicate_without_call_credentials( - grpc_channel_credentials* creds); - /* Util to encapsulate the channel credentials in a channel arg. */ grpc_arg grpc_channel_credentials_to_arg(grpc_channel_credentials* credentials); @@ -158,44 +161,39 @@ void grpc_credentials_mdelem_array_destroy(grpc_credentials_mdelem_array* list); /* --- grpc_call_credentials. --- */ -typedef struct { - void (*destruct)(grpc_call_credentials* c); - bool (*get_request_metadata)(grpc_call_credentials* c, - grpc_polling_entity* pollent, - grpc_auth_metadata_context context, - grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, - grpc_error** error); - void (*cancel_get_request_metadata)(grpc_call_credentials* c, - grpc_credentials_mdelem_array* md_array, - grpc_error* error); -} grpc_call_credentials_vtable; - -struct grpc_call_credentials { - const grpc_call_credentials_vtable* vtable; - const char* type; - gpr_refcount refcount; +// This type is forward declared as a C struct and we cannot define it as a +// class. Otherwise, compiler will complain about type mismatch due to +// -Wmismatched-tags. +struct grpc_call_credentials + : public grpc_core::RefCounted { + public: + explicit grpc_call_credentials(const char* type) : type_(type) {} + virtual ~grpc_call_credentials() = default; + + // Returns true if completed synchronously, in which case \a error will + // be set to indicate the result. Otherwise, \a on_request_metadata will + // be invoked asynchronously when complete. \a md_array will be populated + // with the resulting metadata once complete. + virtual bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) GRPC_ABSTRACT; + + // Cancels a pending asynchronous operation started by + // grpc_call_credentials_get_request_metadata() with the corresponding + // value of \a md_array. + virtual void cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) GRPC_ABSTRACT; + + const char* type() const { return type_; } + + GRPC_ABSTRACT_BASE_CLASS + + private: + const char* type_; }; -grpc_call_credentials* grpc_call_credentials_ref(grpc_call_credentials* creds); -void grpc_call_credentials_unref(grpc_call_credentials* creds); - -/// Returns true if completed synchronously, in which case \a error will -/// be set to indicate the result. Otherwise, \a on_request_metadata will -/// be invoked asynchronously when complete. \a md_array will be populated -/// with the resulting metadata once complete. -bool grpc_call_credentials_get_request_metadata( - grpc_call_credentials* creds, grpc_polling_entity* pollent, - grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, grpc_error** error); - -/// Cancels a pending asynchronous operation started by -/// grpc_call_credentials_get_request_metadata() with the corresponding -/// value of \a md_array. -void grpc_call_credentials_cancel_get_request_metadata( - grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array, - grpc_error* error); - /* Metadata-only credentials with the specified key and value where asynchronicity can be simulated for testing. */ grpc_call_credentials* grpc_md_only_test_credentials_create( @@ -203,26 +201,40 @@ grpc_call_credentials* grpc_md_only_test_credentials_create( /* --- grpc_server_credentials. --- */ -typedef struct { - void (*destruct)(grpc_server_credentials* c); - grpc_security_status (*create_security_connector)( - grpc_server_credentials* c, grpc_server_security_connector** sc); -} grpc_server_credentials_vtable; - -struct grpc_server_credentials { - const grpc_server_credentials_vtable* vtable; - const char* type; - gpr_refcount refcount; - grpc_auth_metadata_processor processor; -}; +// This type is forward declared as a C struct and we cannot define it as a +// class. Otherwise, compiler will complain about type mismatch due to +// -Wmismatched-tags. +struct grpc_server_credentials + : public grpc_core::RefCounted { + public: + explicit grpc_server_credentials(const char* type) : type_(type) {} -grpc_security_status grpc_server_credentials_create_security_connector( - grpc_server_credentials* creds, grpc_server_security_connector** sc); + virtual ~grpc_server_credentials() { DestroyProcessor(); } -grpc_server_credentials* grpc_server_credentials_ref( - grpc_server_credentials* creds); + virtual grpc_core::RefCountedPtr + create_security_connector() GRPC_ABSTRACT; -void grpc_server_credentials_unref(grpc_server_credentials* creds); + const char* type() const { return type_; } + + const grpc_auth_metadata_processor& auth_metadata_processor() const { + return processor_; + } + void set_auth_metadata_processor( + const grpc_auth_metadata_processor& processor); + + GRPC_ABSTRACT_BASE_CLASS + + private: + void DestroyProcessor() { + if (processor_.destroy != nullptr && processor_.state != nullptr) { + processor_.destroy(processor_.state); + } + } + + const char* type_; + grpc_auth_metadata_processor processor_ = + grpc_auth_metadata_processor(); // Zero-initialize the C struct. +}; #define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials" @@ -233,15 +245,27 @@ grpc_server_credentials* grpc_find_server_credentials_in_args( /* -- Credentials Metadata Request. -- */ -typedef struct { - grpc_call_credentials* creds; +struct grpc_credentials_metadata_request { + explicit grpc_credentials_metadata_request( + grpc_core::RefCountedPtr creds) + : creds(std::move(creds)) {} + ~grpc_credentials_metadata_request() { + grpc_http_response_destroy(&response); + } + + grpc_core::RefCountedPtr creds; grpc_http_response response; -} grpc_credentials_metadata_request; +}; -grpc_credentials_metadata_request* grpc_credentials_metadata_request_create( - grpc_call_credentials* creds); +inline grpc_credentials_metadata_request* +grpc_credentials_metadata_request_create( + grpc_core::RefCountedPtr creds) { + return grpc_core::New(std::move(creds)); +} -void grpc_credentials_metadata_request_destroy( - grpc_credentials_metadata_request* r); +inline void grpc_credentials_metadata_request_destroy( + grpc_credentials_metadata_request* r) { + grpc_core::Delete(r); +} #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/fake/fake_credentials.cc b/src/core/lib/security/credentials/fake/fake_credentials.cc index d3e0e8c8168..337dd7679fd 100644 --- a/src/core/lib/security/credentials/fake/fake_credentials.cc +++ b/src/core/lib/security/credentials/fake/fake_credentials.cc @@ -33,49 +33,45 @@ /* -- Fake transport security credentials. -- */ -static grpc_security_status fake_transport_security_create_security_connector( - grpc_channel_credentials* c, grpc_call_credentials* call_creds, - const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args) { - *sc = - grpc_fake_channel_security_connector_create(c, call_creds, target, args); - return GRPC_SECURITY_OK; -} - -static grpc_security_status -fake_transport_security_server_create_security_connector( - grpc_server_credentials* c, grpc_server_security_connector** sc) { - *sc = grpc_fake_server_security_connector_create(c); - return GRPC_SECURITY_OK; -} +namespace { +class grpc_fake_channel_credentials final : public grpc_channel_credentials { + public: + grpc_fake_channel_credentials() + : grpc_channel_credentials( + GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) {} + ~grpc_fake_channel_credentials() override = default; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target, const grpc_channel_args* args, + grpc_channel_args** new_args) override { + return grpc_fake_channel_security_connector_create( + this->Ref(), std::move(call_creds), target, args); + } +}; + +class grpc_fake_server_credentials final : public grpc_server_credentials { + public: + grpc_fake_server_credentials() + : grpc_server_credentials( + GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) {} + ~grpc_fake_server_credentials() override = default; + + grpc_core::RefCountedPtr + create_security_connector() override { + return grpc_fake_server_security_connector_create(this->Ref()); + } +}; +} // namespace -static grpc_channel_credentials_vtable - fake_transport_security_credentials_vtable = { - nullptr, fake_transport_security_create_security_connector, nullptr}; - -static grpc_server_credentials_vtable - fake_transport_security_server_credentials_vtable = { - nullptr, fake_transport_security_server_create_security_connector}; - -grpc_channel_credentials* grpc_fake_transport_security_credentials_create( - void) { - grpc_channel_credentials* c = static_cast( - gpr_zalloc(sizeof(grpc_channel_credentials))); - c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; - c->vtable = &fake_transport_security_credentials_vtable; - gpr_ref_init(&c->refcount, 1); - return c; +grpc_channel_credentials* grpc_fake_transport_security_credentials_create() { + return grpc_core::New(); } -grpc_server_credentials* grpc_fake_transport_security_server_credentials_create( - void) { - grpc_server_credentials* c = static_cast( - gpr_malloc(sizeof(grpc_server_credentials))); - memset(c, 0, sizeof(grpc_server_credentials)); - c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; - gpr_ref_init(&c->refcount, 1); - c->vtable = &fake_transport_security_server_credentials_vtable; - return c; +grpc_server_credentials* +grpc_fake_transport_security_server_credentials_create() { + return grpc_core::New(); } grpc_arg grpc_fake_transport_expected_targets_arg(char* expected_targets) { @@ -92,46 +88,25 @@ const char* grpc_fake_transport_get_expected_targets( /* -- Metadata-only test credentials. -- */ -static void md_only_test_destruct(grpc_call_credentials* creds) { - grpc_md_only_test_credentials* c = - reinterpret_cast(creds); - GRPC_MDELEM_UNREF(c->md); -} - -static bool md_only_test_get_request_metadata( - grpc_call_credentials* creds, grpc_polling_entity* pollent, - grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, grpc_error** error) { - grpc_md_only_test_credentials* c = - reinterpret_cast(creds); - grpc_credentials_mdelem_array_add(md_array, c->md); - if (c->is_async) { +bool grpc_md_only_test_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, + grpc_error** error) { + grpc_credentials_mdelem_array_add(md_array, md_); + if (is_async_) { GRPC_CLOSURE_SCHED(on_request_metadata, GRPC_ERROR_NONE); return false; } return true; } -static void md_only_test_cancel_get_request_metadata( - grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { +void grpc_md_only_test_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable md_only_test_vtable = { - md_only_test_destruct, md_only_test_get_request_metadata, - md_only_test_cancel_get_request_metadata}; - grpc_call_credentials* grpc_md_only_test_credentials_create( const char* md_key, const char* md_value, bool is_async) { - grpc_md_only_test_credentials* c = - static_cast( - gpr_zalloc(sizeof(grpc_md_only_test_credentials))); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; - c->base.vtable = &md_only_test_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->md = grpc_mdelem_from_slices(grpc_slice_from_copied_string(md_key), - grpc_slice_from_copied_string(md_value)); - c->is_async = is_async; - return &c->base; + return grpc_core::New(md_key, md_value, + is_async); } diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h index e89e6e24cca..b7f6a1909fc 100644 --- a/src/core/lib/security/credentials/fake/fake_credentials.h +++ b/src/core/lib/security/credentials/fake/fake_credentials.h @@ -55,10 +55,28 @@ const char* grpc_fake_transport_get_expected_targets( /* -- Metadata-only Test credentials. -- */ -typedef struct { - grpc_call_credentials base; - grpc_mdelem md; - bool is_async; -} grpc_md_only_test_credentials; +class grpc_md_only_test_credentials : public grpc_call_credentials { + public: + grpc_md_only_test_credentials(const char* md_key, const char* md_value, + bool is_async) + : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2), + md_(grpc_mdelem_from_slices(grpc_slice_from_copied_string(md_key), + grpc_slice_from_copied_string(md_value))), + is_async_(is_async) {} + ~grpc_md_only_test_credentials() override { GRPC_MDELEM_UNREF(md_); } + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + private: + grpc_mdelem md_; + bool is_async_; +}; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc index 0674540d01c..a86a17d5864 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -30,6 +30,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/http/httpcli.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/load_file.h" @@ -72,20 +73,11 @@ typedef struct { grpc_http_response response; } metadata_server_detector; -static void google_default_credentials_destruct( - grpc_channel_credentials* creds) { - grpc_google_default_channel_credentials* c = - reinterpret_cast(creds); - grpc_channel_credentials_unref(c->alts_creds); - grpc_channel_credentials_unref(c->ssl_creds); -} - -static grpc_security_status google_default_create_security_connector( - grpc_channel_credentials* creds, grpc_call_credentials* call_creds, +grpc_core::RefCountedPtr +grpc_google_default_channel_credentials::create_security_connector( + grpc_core::RefCountedPtr call_creds, const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args) { - grpc_google_default_channel_credentials* c = - reinterpret_cast(creds); + grpc_channel_args** new_args) { bool is_grpclb_load_balancer = grpc_channel_arg_get_bool( grpc_channel_args_find(args, GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), false); @@ -95,22 +87,22 @@ static grpc_security_status google_default_create_security_connector( false); bool use_alts = is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer; - grpc_security_status status = GRPC_SECURITY_ERROR; /* Return failure if ALTS is selected but not running on GCE. */ if (use_alts && !g_is_on_gce) { gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE."); - goto end; + return nullptr; } - status = use_alts ? c->alts_creds->vtable->create_security_connector( - c->alts_creds, call_creds, target, args, sc, new_args) - : c->ssl_creds->vtable->create_security_connector( - c->ssl_creds, call_creds, target, args, sc, new_args); -/* grpclb-specific channel args are removed from the channel args set - * to ensure backends and fallback adresses will have the same set of channel - * args. By doing that, it guarantees the connections to backends will not be - * torn down and re-connected when switching in and out of fallback mode. - */ -end: + + grpc_core::RefCountedPtr sc = + use_alts ? alts_creds_->create_security_connector(call_creds, target, + args, new_args) + : ssl_creds_->create_security_connector(call_creds, target, args, + new_args); + /* grpclb-specific channel args are removed from the channel args set + * to ensure backends and fallback adresses will have the same set of channel + * args. By doing that, it guarantees the connections to backends will not be + * torn down and re-connected when switching in and out of fallback mode. + */ if (use_alts) { static const char* args_to_remove[] = { GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER, @@ -119,13 +111,9 @@ end: *new_args = grpc_channel_args_copy_and_add_and_remove( args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), nullptr, 0); } - return status; + return sc; } -static grpc_channel_credentials_vtable google_default_credentials_vtable = { - google_default_credentials_destruct, - google_default_create_security_connector, nullptr}; - static void on_metadata_server_detection_http_response(void* user_data, grpc_error* error) { metadata_server_detector* detector = @@ -215,11 +203,11 @@ static int is_metadata_server_reachable() { /* Takes ownership of creds_path if not NULL. */ static grpc_error* create_default_creds_from_path( - char* creds_path, grpc_call_credentials** creds) { + char* creds_path, grpc_core::RefCountedPtr* creds) { grpc_json* json = nullptr; grpc_auth_json_key key; grpc_auth_refresh_token token; - grpc_call_credentials* result = nullptr; + grpc_core::RefCountedPtr result; grpc_slice creds_data = grpc_empty_slice(); grpc_error* error = GRPC_ERROR_NONE; if (creds_path == nullptr) { @@ -276,9 +264,9 @@ end: return error; } -grpc_channel_credentials* grpc_google_default_credentials_create(void) { +grpc_channel_credentials* grpc_google_default_credentials_create() { grpc_channel_credentials* result = nullptr; - grpc_call_credentials* call_creds = nullptr; + grpc_core::RefCountedPtr call_creds; grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Failed to create Google credentials"); grpc_error* err; @@ -316,7 +304,8 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) { gpr_mu_unlock(&g_state_mu); if (g_metadata_server_available) { - call_creds = grpc_google_compute_engine_credentials_create(nullptr); + call_creds = grpc_core::RefCountedPtr( + grpc_google_compute_engine_credentials_create(nullptr)); if (call_creds == nullptr) { error = grpc_error_add_child( error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( @@ -327,23 +316,23 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) { end: if (call_creds != nullptr) { /* Create google default credentials. */ - auto creds = static_cast( - gpr_zalloc(sizeof(grpc_google_default_channel_credentials))); - creds->base.vtable = &google_default_credentials_vtable; - creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT; - gpr_ref_init(&creds->base.refcount, 1); - creds->ssl_creds = + grpc_channel_credentials* ssl_creds = grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr); - GPR_ASSERT(creds->ssl_creds != nullptr); + GPR_ASSERT(ssl_creds != nullptr); grpc_alts_credentials_options* options = grpc_alts_credentials_client_options_create(); - creds->alts_creds = grpc_alts_credentials_create(options); + grpc_channel_credentials* alts_creds = + grpc_alts_credentials_create(options); grpc_alts_credentials_options_destroy(options); - result = grpc_composite_channel_credentials_create(&creds->base, call_creds, - nullptr); + auto creds = + grpc_core::MakeRefCounted( + alts_creds != nullptr ? alts_creds->Ref() : nullptr, + ssl_creds != nullptr ? ssl_creds->Ref() : nullptr); + if (ssl_creds) ssl_creds->Unref(); + if (alts_creds) alts_creds->Unref(); + result = grpc_composite_channel_credentials_create( + creds.get(), call_creds.get(), nullptr); GPR_ASSERT(result != nullptr); - grpc_channel_credentials_unref(&creds->base); - grpc_call_credentials_unref(call_creds); } else { gpr_log(GPR_ERROR, "Could not create google default credentials: %s", grpc_error_string(error)); diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.h b/src/core/lib/security/credentials/google_default/google_default_credentials.h index b9e2efb04fa..bf00f7285ad 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.h +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.h @@ -21,6 +21,7 @@ #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/credentials/credentials.h" #define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud" @@ -39,11 +40,33 @@ "/" GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE #endif -typedef struct { - grpc_channel_credentials base; - grpc_channel_credentials* alts_creds; - grpc_channel_credentials* ssl_creds; -} grpc_google_default_channel_credentials; +class grpc_google_default_channel_credentials + : public grpc_channel_credentials { + public: + grpc_google_default_channel_credentials( + grpc_core::RefCountedPtr alts_creds, + grpc_core::RefCountedPtr ssl_creds) + : grpc_channel_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT), + alts_creds_(std::move(alts_creds)), + ssl_creds_(std::move(ssl_creds)) {} + + ~grpc_google_default_channel_credentials() override = default; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target, const grpc_channel_args* args, + grpc_channel_args** new_args) override; + + const grpc_channel_credentials* alts_creds() const { + return alts_creds_.get(); + } + const grpc_channel_credentials* ssl_creds() const { return ssl_creds_.get(); } + + private: + grpc_core::RefCountedPtr alts_creds_; + grpc_core::RefCountedPtr ssl_creds_; +}; namespace grpc_core { namespace internal { diff --git a/src/core/lib/security/credentials/iam/iam_credentials.cc b/src/core/lib/security/credentials/iam/iam_credentials.cc index 5d92fa88c45..5cd561f676a 100644 --- a/src/core/lib/security/credentials/iam/iam_credentials.cc +++ b/src/core/lib/security/credentials/iam/iam_credentials.cc @@ -22,6 +22,7 @@ #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/surface/api_trace.h" #include @@ -29,32 +30,37 @@ #include #include -static void iam_destruct(grpc_call_credentials* creds) { - grpc_google_iam_credentials* c = - reinterpret_cast(creds); - grpc_credentials_mdelem_array_destroy(&c->md_array); +grpc_google_iam_credentials::~grpc_google_iam_credentials() { + grpc_credentials_mdelem_array_destroy(&md_array_); } -static bool iam_get_request_metadata(grpc_call_credentials* creds, - grpc_polling_entity* pollent, - grpc_auth_metadata_context context, - grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, - grpc_error** error) { - grpc_google_iam_credentials* c = - reinterpret_cast(creds); - grpc_credentials_mdelem_array_append(md_array, &c->md_array); +bool grpc_google_iam_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, + grpc_error** error) { + grpc_credentials_mdelem_array_append(md_array, &md_array_); return true; } -static void iam_cancel_get_request_metadata( - grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { +void grpc_google_iam_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable iam_vtable = { - iam_destruct, iam_get_request_metadata, iam_cancel_get_request_metadata}; +grpc_google_iam_credentials::grpc_google_iam_credentials( + const char* token, const char* authority_selector) + : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_IAM) { + grpc_mdelem md = grpc_mdelem_from_slices( + grpc_slice_from_static_string(GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY), + grpc_slice_from_copied_string(token)); + grpc_credentials_mdelem_array_add(&md_array_, md); + GRPC_MDELEM_UNREF(md); + md = grpc_mdelem_from_slices( + grpc_slice_from_static_string(GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY), + grpc_slice_from_copied_string(authority_selector)); + grpc_credentials_mdelem_array_add(&md_array_, md); + GRPC_MDELEM_UNREF(md); +} grpc_call_credentials* grpc_google_iam_credentials_create( const char* token, const char* authority_selector, void* reserved) { @@ -66,21 +72,7 @@ grpc_call_credentials* grpc_google_iam_credentials_create( GPR_ASSERT(reserved == nullptr); GPR_ASSERT(token != nullptr); GPR_ASSERT(authority_selector != nullptr); - grpc_google_iam_credentials* c = - static_cast(gpr_zalloc(sizeof(*c))); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM; - c->base.vtable = &iam_vtable; - gpr_ref_init(&c->base.refcount, 1); - grpc_mdelem md = grpc_mdelem_from_slices( - grpc_slice_from_static_string(GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY), - grpc_slice_from_copied_string(token)); - grpc_credentials_mdelem_array_add(&c->md_array, md); - GRPC_MDELEM_UNREF(md); - md = grpc_mdelem_from_slices( - grpc_slice_from_static_string(GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY), - grpc_slice_from_copied_string(authority_selector)); - grpc_credentials_mdelem_array_add(&c->md_array, md); - GRPC_MDELEM_UNREF(md); - - return &c->base; + return grpc_core::MakeRefCounted( + token, authority_selector) + .release(); } diff --git a/src/core/lib/security/credentials/iam/iam_credentials.h b/src/core/lib/security/credentials/iam/iam_credentials.h index a45710fe0f8..36f5ee89307 100644 --- a/src/core/lib/security/credentials/iam/iam_credentials.h +++ b/src/core/lib/security/credentials/iam/iam_credentials.h @@ -23,9 +23,23 @@ #include "src/core/lib/security/credentials/credentials.h" -typedef struct { - grpc_call_credentials base; - grpc_credentials_mdelem_array md_array; -} grpc_google_iam_credentials; +class grpc_google_iam_credentials : public grpc_call_credentials { + public: + grpc_google_iam_credentials(const char* token, + const char* authority_selector); + ~grpc_google_iam_credentials() override; + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + private: + grpc_credentials_mdelem_array md_array_; +}; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_IAM_IAM_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/src/core/lib/security/credentials/jwt/jwt_credentials.cc index 05c08a68b01..f2591a1ea5e 100644 --- a/src/core/lib/security/credentials/jwt/jwt_credentials.cc +++ b/src/core/lib/security/credentials/jwt/jwt_credentials.cc @@ -23,6 +23,8 @@ #include #include +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/surface/api_trace.h" #include @@ -30,71 +32,66 @@ #include #include -static void jwt_reset_cache(grpc_service_account_jwt_access_credentials* c) { - GRPC_MDELEM_UNREF(c->cached.jwt_md); - c->cached.jwt_md = GRPC_MDNULL; - if (c->cached.service_url != nullptr) { - gpr_free(c->cached.service_url); - c->cached.service_url = nullptr; +void grpc_service_account_jwt_access_credentials::reset_cache() { + GRPC_MDELEM_UNREF(cached_.jwt_md); + cached_.jwt_md = GRPC_MDNULL; + if (cached_.service_url != nullptr) { + gpr_free(cached_.service_url); + cached_.service_url = nullptr; } - c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); + cached_.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); } -static void jwt_destruct(grpc_call_credentials* creds) { - grpc_service_account_jwt_access_credentials* c = - reinterpret_cast(creds); - grpc_auth_json_key_destruct(&c->key); - jwt_reset_cache(c); - gpr_mu_destroy(&c->cache_mu); +grpc_service_account_jwt_access_credentials:: + ~grpc_service_account_jwt_access_credentials() { + grpc_auth_json_key_destruct(&key_); + reset_cache(); + gpr_mu_destroy(&cache_mu_); } -static bool jwt_get_request_metadata(grpc_call_credentials* creds, - grpc_polling_entity* pollent, - grpc_auth_metadata_context context, - grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, - grpc_error** error) { - grpc_service_account_jwt_access_credentials* c = - reinterpret_cast(creds); +bool grpc_service_account_jwt_access_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, + grpc_error** error) { gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); /* See if we can return a cached jwt. */ grpc_mdelem jwt_md = GRPC_MDNULL; { - gpr_mu_lock(&c->cache_mu); - if (c->cached.service_url != nullptr && - strcmp(c->cached.service_url, context.service_url) == 0 && - !GRPC_MDISNULL(c->cached.jwt_md) && - (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, - gpr_now(GPR_CLOCK_REALTIME)), - refresh_threshold) > 0)) { - jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md); + gpr_mu_lock(&cache_mu_); + if (cached_.service_url != nullptr && + strcmp(cached_.service_url, context.service_url) == 0 && + !GRPC_MDISNULL(cached_.jwt_md) && + (gpr_time_cmp( + gpr_time_sub(cached_.jwt_expiration, gpr_now(GPR_CLOCK_REALTIME)), + refresh_threshold) > 0)) { + jwt_md = GRPC_MDELEM_REF(cached_.jwt_md); } - gpr_mu_unlock(&c->cache_mu); + gpr_mu_unlock(&cache_mu_); } if (GRPC_MDISNULL(jwt_md)) { char* jwt = nullptr; /* Generate a new jwt. */ - gpr_mu_lock(&c->cache_mu); - jwt_reset_cache(c); - jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url, - c->jwt_lifetime, nullptr); + gpr_mu_lock(&cache_mu_); + reset_cache(); + jwt = grpc_jwt_encode_and_sign(&key_, context.service_url, jwt_lifetime_, + nullptr); if (jwt != nullptr) { char* md_value; gpr_asprintf(&md_value, "Bearer %s", jwt); gpr_free(jwt); - c->cached.jwt_expiration = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime); - c->cached.service_url = gpr_strdup(context.service_url); - c->cached.jwt_md = grpc_mdelem_from_slices( + cached_.jwt_expiration = + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), jwt_lifetime_); + cached_.service_url = gpr_strdup(context.service_url); + cached_.jwt_md = grpc_mdelem_from_slices( grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), grpc_slice_from_copied_string(md_value)); gpr_free(md_value); - jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md); + jwt_md = GRPC_MDELEM_REF(cached_.jwt_md); } - gpr_mu_unlock(&c->cache_mu); + gpr_mu_unlock(&cache_mu_); } if (!GRPC_MDISNULL(jwt_md)) { @@ -106,29 +103,15 @@ static bool jwt_get_request_metadata(grpc_call_credentials* creds, return true; } -static void jwt_cancel_get_request_metadata( - grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { +void grpc_service_account_jwt_access_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable jwt_vtable = { - jwt_destruct, jwt_get_request_metadata, jwt_cancel_get_request_metadata}; - -grpc_call_credentials* -grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key key, gpr_timespec token_lifetime) { - grpc_service_account_jwt_access_credentials* c; - if (!grpc_auth_json_key_is_valid(&key)) { - gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); - return nullptr; - } - c = static_cast( - gpr_zalloc(sizeof(grpc_service_account_jwt_access_credentials))); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT; - gpr_ref_init(&c->base.refcount, 1); - c->base.vtable = &jwt_vtable; - c->key = key; +grpc_service_account_jwt_access_credentials:: + grpc_service_account_jwt_access_credentials(grpc_auth_json_key key, + gpr_timespec token_lifetime) + : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_JWT), key_(key) { gpr_timespec max_token_lifetime = grpc_max_auth_token_lifetime(); if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) { gpr_log(GPR_INFO, @@ -136,10 +119,20 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key( static_cast(max_token_lifetime.tv_sec)); token_lifetime = grpc_max_auth_token_lifetime(); } - c->jwt_lifetime = token_lifetime; - gpr_mu_init(&c->cache_mu); - jwt_reset_cache(c); - return &c->base; + jwt_lifetime_ = token_lifetime; + gpr_mu_init(&cache_mu_); + reset_cache(); +} + +grpc_core::RefCountedPtr +grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + grpc_auth_json_key key, gpr_timespec token_lifetime) { + if (!grpc_auth_json_key_is_valid(&key)) { + gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); + return nullptr; + } + return grpc_core::MakeRefCounted( + key, token_lifetime); } static char* redact_private_key(const char* json_key) { @@ -182,9 +175,7 @@ grpc_call_credentials* grpc_service_account_jwt_access_credentials_create( } GPR_ASSERT(reserved == nullptr); grpc_core::ExecCtx exec_ctx; - grpc_call_credentials* creds = - grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key_create_from_string(json_key), token_lifetime); - - return creds; + return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + grpc_auth_json_key_create_from_string(json_key), token_lifetime) + .release(); } diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.h b/src/core/lib/security/credentials/jwt/jwt_credentials.h index 5c3d34aa566..5af909f44df 100644 --- a/src/core/lib/security/credentials/jwt/jwt_credentials.h +++ b/src/core/lib/security/credentials/jwt/jwt_credentials.h @@ -24,25 +24,44 @@ #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/jwt/json_token.h" -typedef struct { - grpc_call_credentials base; +class grpc_service_account_jwt_access_credentials + : public grpc_call_credentials { + public: + grpc_service_account_jwt_access_credentials(grpc_auth_json_key key, + gpr_timespec token_lifetime); + ~grpc_service_account_jwt_access_credentials() override; + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + const gpr_timespec& jwt_lifetime() const { return jwt_lifetime_; } + const grpc_auth_json_key& key() const { return key_; } + + private: + void reset_cache(); // Have a simple cache for now with just 1 entry. We could have a map based on // the service_url for a more sophisticated one. - gpr_mu cache_mu; + gpr_mu cache_mu_; struct { - grpc_mdelem jwt_md; - char* service_url; + grpc_mdelem jwt_md = GRPC_MDNULL; + char* service_url = nullptr; gpr_timespec jwt_expiration; - } cached; + } cached_; - grpc_auth_json_key key; - gpr_timespec jwt_lifetime; -} grpc_service_account_jwt_access_credentials; + grpc_auth_json_key key_; + gpr_timespec jwt_lifetime_; +}; // Private constructor for jwt credentials from an already parsed json key. // Takes ownership of the key. -grpc_call_credentials* +grpc_core::RefCountedPtr grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime); diff --git a/src/core/lib/security/credentials/local/local_credentials.cc b/src/core/lib/security/credentials/local/local_credentials.cc index 3ccfa2b9086..6f6f95a34a7 100644 --- a/src/core/lib/security/credentials/local/local_credentials.cc +++ b/src/core/lib/security/credentials/local/local_credentials.cc @@ -29,49 +29,36 @@ #define GRPC_CREDENTIALS_TYPE_LOCAL "Local" -static void local_credentials_destruct(grpc_channel_credentials* creds) {} - -static void local_server_credentials_destruct(grpc_server_credentials* creds) {} - -static grpc_security_status local_create_security_connector( - grpc_channel_credentials* creds, - grpc_call_credentials* request_metadata_creds, const char* target_name, - const grpc_channel_args* args, grpc_channel_security_connector** sc, +grpc_core::RefCountedPtr +grpc_local_credentials::create_security_connector( + grpc_core::RefCountedPtr request_metadata_creds, + const char* target_name, const grpc_channel_args* args, grpc_channel_args** new_args) { return grpc_local_channel_security_connector_create( - creds, request_metadata_creds, args, target_name, sc); + this->Ref(), std::move(request_metadata_creds), args, target_name); } -static grpc_security_status local_server_create_security_connector( - grpc_server_credentials* creds, grpc_server_security_connector** sc) { - return grpc_local_server_security_connector_create(creds, sc); +grpc_core::RefCountedPtr +grpc_local_server_credentials::create_security_connector() { + return grpc_local_server_security_connector_create(this->Ref()); } -static const grpc_channel_credentials_vtable local_credentials_vtable = { - local_credentials_destruct, local_create_security_connector, - /*duplicate_without_call_credentials=*/nullptr}; - -static const grpc_server_credentials_vtable local_server_credentials_vtable = { - local_server_credentials_destruct, local_server_create_security_connector}; +grpc_local_credentials::grpc_local_credentials( + grpc_local_connect_type connect_type) + : grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_LOCAL), + connect_type_(connect_type) {} grpc_channel_credentials* grpc_local_credentials_create( grpc_local_connect_type connect_type) { - auto creds = static_cast( - gpr_zalloc(sizeof(grpc_local_credentials))); - creds->connect_type = connect_type; - creds->base.type = GRPC_CREDENTIALS_TYPE_LOCAL; - creds->base.vtable = &local_credentials_vtable; - gpr_ref_init(&creds->base.refcount, 1); - return &creds->base; + return grpc_core::New(connect_type); } +grpc_local_server_credentials::grpc_local_server_credentials( + grpc_local_connect_type connect_type) + : grpc_server_credentials(GRPC_CREDENTIALS_TYPE_LOCAL), + connect_type_(connect_type) {} + grpc_server_credentials* grpc_local_server_credentials_create( grpc_local_connect_type connect_type) { - auto creds = static_cast( - gpr_zalloc(sizeof(grpc_local_server_credentials))); - creds->connect_type = connect_type; - creds->base.type = GRPC_CREDENTIALS_TYPE_LOCAL; - creds->base.vtable = &local_server_credentials_vtable; - gpr_ref_init(&creds->base.refcount, 1); - return &creds->base; + return grpc_core::New(connect_type); } diff --git a/src/core/lib/security/credentials/local/local_credentials.h b/src/core/lib/security/credentials/local/local_credentials.h index 47358b04bc1..60a8a4f64ca 100644 --- a/src/core/lib/security/credentials/local/local_credentials.h +++ b/src/core/lib/security/credentials/local/local_credentials.h @@ -25,16 +25,37 @@ #include "src/core/lib/security/credentials/credentials.h" -/* Main struct for grpc local channel credential. */ -typedef struct grpc_local_credentials { - grpc_channel_credentials base; - grpc_local_connect_type connect_type; -} grpc_local_credentials; - -/* Main struct for grpc local server credential. */ -typedef struct grpc_local_server_credentials { - grpc_server_credentials base; - grpc_local_connect_type connect_type; -} grpc_local_server_credentials; +/* Main class for grpc local channel credential. */ +class grpc_local_credentials final : public grpc_channel_credentials { + public: + explicit grpc_local_credentials(grpc_local_connect_type connect_type); + ~grpc_local_credentials() override = default; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr request_metadata_creds, + const char* target_name, const grpc_channel_args* args, + grpc_channel_args** new_args) override; + + grpc_local_connect_type connect_type() const { return connect_type_; } + + private: + grpc_local_connect_type connect_type_; +}; + +/* Main class for grpc local server credential. */ +class grpc_local_server_credentials final : public grpc_server_credentials { + public: + explicit grpc_local_server_credentials(grpc_local_connect_type connect_type); + ~grpc_local_server_credentials() override = default; + + grpc_core::RefCountedPtr + create_security_connector() override; + + grpc_local_connect_type connect_type() const { return connect_type_; } + + private: + grpc_local_connect_type connect_type_; +}; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_LOCAL_LOCAL_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index 44b093557f3..ad63b01e754 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -22,6 +22,7 @@ #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/util/json_util.h" #include "src/core/lib/surface/api_trace.h" @@ -105,13 +106,12 @@ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token* refresh_token) { // Oauth2 Token Fetcher credentials. // -static void oauth2_token_fetcher_destruct(grpc_call_credentials* creds) { - grpc_oauth2_token_fetcher_credentials* c = - reinterpret_cast(creds); - GRPC_MDELEM_UNREF(c->access_token_md); - gpr_mu_destroy(&c->mu); - grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&c->pollent)); - grpc_httpcli_context_destroy(&c->httpcli_context); +grpc_oauth2_token_fetcher_credentials:: + ~grpc_oauth2_token_fetcher_credentials() { + GRPC_MDELEM_UNREF(access_token_md_); + gpr_mu_destroy(&mu_); + grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&pollent_)); + grpc_httpcli_context_destroy(&httpcli_context_); } grpc_credentials_status @@ -209,25 +209,29 @@ static void on_oauth2_token_fetcher_http_response(void* user_data, grpc_credentials_metadata_request* r = static_cast(user_data); grpc_oauth2_token_fetcher_credentials* c = - reinterpret_cast(r->creds); + reinterpret_cast(r->creds.get()); + c->on_http_response(r, error); +} + +void grpc_oauth2_token_fetcher_credentials::on_http_response( + grpc_credentials_metadata_request* r, grpc_error* error) { grpc_mdelem access_token_md = GRPC_MDNULL; grpc_millis token_lifetime; grpc_credentials_status status = grpc_oauth2_token_fetcher_credentials_parse_server_response( &r->response, &access_token_md, &token_lifetime); // Update cache and grab list of pending requests. - gpr_mu_lock(&c->mu); - c->token_fetch_pending = false; - c->access_token_md = GRPC_MDELEM_REF(access_token_md); - c->token_expiration = + gpr_mu_lock(&mu_); + token_fetch_pending_ = false; + access_token_md_ = GRPC_MDELEM_REF(access_token_md); + token_expiration_ = status == GRPC_CREDENTIALS_OK ? gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(token_lifetime, GPR_TIMESPAN)) : gpr_inf_past(GPR_CLOCK_MONOTONIC); - grpc_oauth2_pending_get_request_metadata* pending_request = - c->pending_requests; - c->pending_requests = nullptr; - gpr_mu_unlock(&c->mu); + grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_; + pending_requests_ = nullptr; + gpr_mu_unlock(&mu_); // Invoke callbacks for all pending requests. while (pending_request != nullptr) { if (status == GRPC_CREDENTIALS_OK) { @@ -239,42 +243,40 @@ static void on_oauth2_token_fetcher_http_response(void* user_data, } GRPC_CLOSURE_SCHED(pending_request->on_request_metadata, error); grpc_polling_entity_del_from_pollset_set( - pending_request->pollent, grpc_polling_entity_pollset_set(&c->pollent)); + pending_request->pollent, grpc_polling_entity_pollset_set(&pollent_)); grpc_oauth2_pending_get_request_metadata* prev = pending_request; pending_request = pending_request->next; gpr_free(prev); } GRPC_MDELEM_UNREF(access_token_md); - grpc_call_credentials_unref(r->creds); + Unref(); grpc_credentials_metadata_request_destroy(r); } -static bool oauth2_token_fetcher_get_request_metadata( - grpc_call_credentials* creds, grpc_polling_entity* pollent, - grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, grpc_error** error) { - grpc_oauth2_token_fetcher_credentials* c = - reinterpret_cast(creds); +bool grpc_oauth2_token_fetcher_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, + grpc_error** error) { // Check if we can use the cached token. grpc_millis refresh_threshold = GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS * GPR_MS_PER_SEC; grpc_mdelem cached_access_token_md = GRPC_MDNULL; - gpr_mu_lock(&c->mu); - if (!GRPC_MDISNULL(c->access_token_md) && + gpr_mu_lock(&mu_); + if (!GRPC_MDISNULL(access_token_md_) && gpr_time_cmp( - gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_MONOTONIC)), + gpr_time_sub(token_expiration_, gpr_now(GPR_CLOCK_MONOTONIC)), gpr_time_from_seconds(GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN)) > 0) { - cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md); + cached_access_token_md = GRPC_MDELEM_REF(access_token_md_); } if (!GRPC_MDISNULL(cached_access_token_md)) { - gpr_mu_unlock(&c->mu); + gpr_mu_unlock(&mu_); grpc_credentials_mdelem_array_add(md_array, cached_access_token_md); GRPC_MDELEM_UNREF(cached_access_token_md); return true; } // Couldn't get the token from the cache. - // Add request to c->pending_requests and start a new fetch if needed. + // Add request to pending_requests_ and start a new fetch if needed. grpc_oauth2_pending_get_request_metadata* pending_request = static_cast( gpr_malloc(sizeof(*pending_request))); @@ -282,41 +284,37 @@ static bool oauth2_token_fetcher_get_request_metadata( pending_request->on_request_metadata = on_request_metadata; pending_request->pollent = pollent; grpc_polling_entity_add_to_pollset_set( - pollent, grpc_polling_entity_pollset_set(&c->pollent)); - pending_request->next = c->pending_requests; - c->pending_requests = pending_request; + pollent, grpc_polling_entity_pollset_set(&pollent_)); + pending_request->next = pending_requests_; + pending_requests_ = pending_request; bool start_fetch = false; - if (!c->token_fetch_pending) { - c->token_fetch_pending = true; + if (!token_fetch_pending_) { + token_fetch_pending_ = true; start_fetch = true; } - gpr_mu_unlock(&c->mu); + gpr_mu_unlock(&mu_); if (start_fetch) { - grpc_call_credentials_ref(creds); - c->fetch_func(grpc_credentials_metadata_request_create(creds), - &c->httpcli_context, &c->pollent, - on_oauth2_token_fetcher_http_response, - grpc_core::ExecCtx::Get()->Now() + refresh_threshold); + Ref().release(); + fetch_oauth2(grpc_credentials_metadata_request_create(this->Ref()), + &httpcli_context_, &pollent_, + on_oauth2_token_fetcher_http_response, + grpc_core::ExecCtx::Get()->Now() + refresh_threshold); } return false; } -static void oauth2_token_fetcher_cancel_get_request_metadata( - grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { - grpc_oauth2_token_fetcher_credentials* c = - reinterpret_cast(creds); - gpr_mu_lock(&c->mu); +void grpc_oauth2_token_fetcher_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { + gpr_mu_lock(&mu_); grpc_oauth2_pending_get_request_metadata* prev = nullptr; - grpc_oauth2_pending_get_request_metadata* pending_request = - c->pending_requests; + grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_; while (pending_request != nullptr) { if (pending_request->md_array == md_array) { // Remove matching pending request from the list. if (prev != nullptr) { prev->next = pending_request->next; } else { - c->pending_requests = pending_request->next; + pending_requests_ = pending_request->next; } // Invoke the callback immediately with an error. GRPC_CLOSURE_SCHED(pending_request->on_request_metadata, @@ -327,96 +325,89 @@ static void oauth2_token_fetcher_cancel_get_request_metadata( prev = pending_request; pending_request = pending_request->next; } - gpr_mu_unlock(&c->mu); + gpr_mu_unlock(&mu_); GRPC_ERROR_UNREF(error); } -static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials* c, - grpc_fetch_oauth2_func fetch_func) { - memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; - gpr_ref_init(&c->base.refcount, 1); - gpr_mu_init(&c->mu); - c->token_expiration = gpr_inf_past(GPR_CLOCK_MONOTONIC); - c->fetch_func = fetch_func; - c->pollent = - grpc_polling_entity_create_from_pollset_set(grpc_pollset_set_create()); - grpc_httpcli_context_init(&c->httpcli_context); +grpc_oauth2_token_fetcher_credentials::grpc_oauth2_token_fetcher_credentials() + : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2), + token_expiration_(gpr_inf_past(GPR_CLOCK_MONOTONIC)), + pollent_(grpc_polling_entity_create_from_pollset_set( + grpc_pollset_set_create())) { + gpr_mu_init(&mu_); + grpc_httpcli_context_init(&httpcli_context_); } // // Google Compute Engine credentials. // -static grpc_call_credentials_vtable compute_engine_vtable = { - oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata, - oauth2_token_fetcher_cancel_get_request_metadata}; +namespace { + +class grpc_compute_engine_token_fetcher_credentials + : public grpc_oauth2_token_fetcher_credentials { + public: + grpc_compute_engine_token_fetcher_credentials() = default; + ~grpc_compute_engine_token_fetcher_credentials() override = default; + + protected: + void fetch_oauth2(grpc_credentials_metadata_request* metadata_req, + grpc_httpcli_context* http_context, + grpc_polling_entity* pollent, + grpc_iomgr_cb_func response_cb, + grpc_millis deadline) override { + grpc_http_header header = {(char*)"Metadata-Flavor", (char*)"Google"}; + grpc_httpcli_request request; + memset(&request, 0, sizeof(grpc_httpcli_request)); + request.host = (char*)GRPC_COMPUTE_ENGINE_METADATA_HOST; + request.http.path = (char*)GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; + request.http.hdr_count = 1; + request.http.hdrs = &header; + /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host + channel. This would allow us to cancel an authentication query when under + extreme memory pressure. */ + grpc_resource_quota* resource_quota = + grpc_resource_quota_create("oauth2_credentials"); + grpc_httpcli_get(http_context, pollent, resource_quota, &request, deadline, + GRPC_CLOSURE_CREATE(response_cb, metadata_req, + grpc_schedule_on_exec_ctx), + &metadata_req->response); + grpc_resource_quota_unref_internal(resource_quota); + } +}; -static void compute_engine_fetch_oauth2( - grpc_credentials_metadata_request* metadata_req, - grpc_httpcli_context* httpcli_context, grpc_polling_entity* pollent, - grpc_iomgr_cb_func response_cb, grpc_millis deadline) { - grpc_http_header header = {(char*)"Metadata-Flavor", (char*)"Google"}; - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = (char*)GRPC_COMPUTE_ENGINE_METADATA_HOST; - request.http.path = (char*)GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; - request.http.hdr_count = 1; - request.http.hdrs = &header; - /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host - channel. This would allow us to cancel an authentication query when under - extreme memory pressure. */ - grpc_resource_quota* resource_quota = - grpc_resource_quota_create("oauth2_credentials"); - grpc_httpcli_get( - httpcli_context, pollent, resource_quota, &request, deadline, - GRPC_CLOSURE_CREATE(response_cb, metadata_req, grpc_schedule_on_exec_ctx), - &metadata_req->response); - grpc_resource_quota_unref_internal(resource_quota); -} +} // namespace grpc_call_credentials* grpc_google_compute_engine_credentials_create( void* reserved) { - grpc_oauth2_token_fetcher_credentials* c = - static_cast( - gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials))); GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1, (reserved)); GPR_ASSERT(reserved == nullptr); - init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2); - c->base.vtable = &compute_engine_vtable; - return &c->base; + return grpc_core::MakeRefCounted< + grpc_compute_engine_token_fetcher_credentials>() + .release(); } // // Google Refresh Token credentials. // -static void refresh_token_destruct(grpc_call_credentials* creds) { - grpc_google_refresh_token_credentials* c = - reinterpret_cast(creds); - grpc_auth_refresh_token_destruct(&c->refresh_token); - oauth2_token_fetcher_destruct(&c->base.base); +grpc_google_refresh_token_credentials:: + ~grpc_google_refresh_token_credentials() { + grpc_auth_refresh_token_destruct(&refresh_token_); } -static grpc_call_credentials_vtable refresh_token_vtable = { - refresh_token_destruct, oauth2_token_fetcher_get_request_metadata, - oauth2_token_fetcher_cancel_get_request_metadata}; - -static void refresh_token_fetch_oauth2( +void grpc_google_refresh_token_credentials::fetch_oauth2( grpc_credentials_metadata_request* metadata_req, grpc_httpcli_context* httpcli_context, grpc_polling_entity* pollent, grpc_iomgr_cb_func response_cb, grpc_millis deadline) { - grpc_google_refresh_token_credentials* c = - reinterpret_cast( - metadata_req->creds); grpc_http_header header = {(char*)"Content-Type", (char*)"application/x-www-form-urlencoded"}; grpc_httpcli_request request; char* body = nullptr; gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, - c->refresh_token.client_id, c->refresh_token.client_secret, - c->refresh_token.refresh_token); + refresh_token_.client_id, refresh_token_.client_secret, + refresh_token_.refresh_token); memset(&request, 0, sizeof(grpc_httpcli_request)); request.host = (char*)GRPC_GOOGLE_OAUTH2_SERVICE_HOST; request.http.path = (char*)GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; @@ -437,20 +428,19 @@ static void refresh_token_fetch_oauth2( gpr_free(body); } -grpc_call_credentials* +grpc_google_refresh_token_credentials::grpc_google_refresh_token_credentials( + grpc_auth_refresh_token refresh_token) + : refresh_token_(refresh_token) {} + +grpc_core::RefCountedPtr grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token refresh_token) { - grpc_google_refresh_token_credentials* c; if (!grpc_auth_refresh_token_is_valid(&refresh_token)) { gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation"); return nullptr; } - c = static_cast( - gpr_zalloc(sizeof(grpc_google_refresh_token_credentials))); - init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2); - c->base.base.vtable = &refresh_token_vtable; - c->refresh_token = refresh_token; - return &c->base.base; + return grpc_core::MakeRefCounted( + refresh_token); } static char* create_loggable_refresh_token(grpc_auth_refresh_token* token) { @@ -478,59 +468,50 @@ grpc_call_credentials* grpc_google_refresh_token_credentials_create( gpr_free(loggable_token); } GPR_ASSERT(reserved == nullptr); - return grpc_refresh_token_credentials_create_from_auth_refresh_token(token); + return grpc_refresh_token_credentials_create_from_auth_refresh_token(token) + .release(); } // // Oauth2 Access Token credentials. // -static void access_token_destruct(grpc_call_credentials* creds) { - grpc_access_token_credentials* c = - reinterpret_cast(creds); - GRPC_MDELEM_UNREF(c->access_token_md); +grpc_access_token_credentials::~grpc_access_token_credentials() { + GRPC_MDELEM_UNREF(access_token_md_); } -static bool access_token_get_request_metadata( - grpc_call_credentials* creds, grpc_polling_entity* pollent, - grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, grpc_error** error) { - grpc_access_token_credentials* c = - reinterpret_cast(creds); - grpc_credentials_mdelem_array_add(md_array, c->access_token_md); +bool grpc_access_token_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, + grpc_error** error) { + grpc_credentials_mdelem_array_add(md_array, access_token_md_); return true; } -static void access_token_cancel_get_request_metadata( - grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { +void grpc_access_token_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable access_token_vtable = { - access_token_destruct, access_token_get_request_metadata, - access_token_cancel_get_request_metadata}; +grpc_access_token_credentials::grpc_access_token_credentials( + const char* access_token) + : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) { + char* token_md_value; + gpr_asprintf(&token_md_value, "Bearer %s", access_token); + grpc_core::ExecCtx exec_ctx; + access_token_md_ = grpc_mdelem_from_slices( + grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(token_md_value)); + gpr_free(token_md_value); +} grpc_call_credentials* grpc_access_token_credentials_create( const char* access_token, void* reserved) { - grpc_access_token_credentials* c = - static_cast( - gpr_zalloc(sizeof(grpc_access_token_credentials))); GRPC_API_TRACE( "grpc_access_token_credentials_create(access_token=, " "reserved=%p)", 1, (reserved)); GPR_ASSERT(reserved == nullptr); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; - c->base.vtable = &access_token_vtable; - gpr_ref_init(&c->base.refcount, 1); - char* token_md_value; - gpr_asprintf(&token_md_value, "Bearer %s", access_token); - grpc_core::ExecCtx exec_ctx; - c->access_token_md = grpc_mdelem_from_slices( - grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), - grpc_slice_from_copied_string(token_md_value)); - - gpr_free(token_md_value); - return &c->base; + return grpc_core::MakeRefCounted(access_token) + .release(); } diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h index 12a1d4484fe..510a78b484a 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h @@ -54,46 +54,91 @@ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token* refresh_token); // This object is a base for credentials that need to acquire an oauth2 token // from an http service. -typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request* req, - grpc_httpcli_context* http_context, - grpc_polling_entity* pollent, - grpc_iomgr_cb_func cb, - grpc_millis deadline); - -typedef struct grpc_oauth2_pending_get_request_metadata { +struct grpc_oauth2_pending_get_request_metadata { grpc_credentials_mdelem_array* md_array; grpc_closure* on_request_metadata; grpc_polling_entity* pollent; struct grpc_oauth2_pending_get_request_metadata* next; -} grpc_oauth2_pending_get_request_metadata; - -typedef struct { - grpc_call_credentials base; - gpr_mu mu; - grpc_mdelem access_token_md; - gpr_timespec token_expiration; - bool token_fetch_pending; - grpc_oauth2_pending_get_request_metadata* pending_requests; - grpc_httpcli_context httpcli_context; - grpc_fetch_oauth2_func fetch_func; - grpc_polling_entity pollent; -} grpc_oauth2_token_fetcher_credentials; +}; + +class grpc_oauth2_token_fetcher_credentials : public grpc_call_credentials { + public: + grpc_oauth2_token_fetcher_credentials(); + ~grpc_oauth2_token_fetcher_credentials() override; + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + void on_http_response(grpc_credentials_metadata_request* r, + grpc_error* error); + + GRPC_ABSTRACT_BASE_CLASS + + protected: + virtual void fetch_oauth2(grpc_credentials_metadata_request* req, + grpc_httpcli_context* httpcli_context, + grpc_polling_entity* pollent, grpc_iomgr_cb_func cb, + grpc_millis deadline) GRPC_ABSTRACT; + + private: + gpr_mu mu_; + grpc_mdelem access_token_md_ = GRPC_MDNULL; + gpr_timespec token_expiration_; + bool token_fetch_pending_ = false; + grpc_oauth2_pending_get_request_metadata* pending_requests_ = nullptr; + grpc_httpcli_context httpcli_context_; + grpc_polling_entity pollent_; +}; // Google refresh token credentials. -typedef struct { - grpc_oauth2_token_fetcher_credentials base; - grpc_auth_refresh_token refresh_token; -} grpc_google_refresh_token_credentials; +class grpc_google_refresh_token_credentials final + : public grpc_oauth2_token_fetcher_credentials { + public: + grpc_google_refresh_token_credentials(grpc_auth_refresh_token refresh_token); + ~grpc_google_refresh_token_credentials() override; + + const grpc_auth_refresh_token& refresh_token() const { + return refresh_token_; + } + + protected: + void fetch_oauth2(grpc_credentials_metadata_request* req, + grpc_httpcli_context* httpcli_context, + grpc_polling_entity* pollent, grpc_iomgr_cb_func cb, + grpc_millis deadline) override; + + private: + grpc_auth_refresh_token refresh_token_; +}; // Access token credentials. -typedef struct { - grpc_call_credentials base; - grpc_mdelem access_token_md; -} grpc_access_token_credentials; +class grpc_access_token_credentials final : public grpc_call_credentials { + public: + grpc_access_token_credentials(const char* access_token); + ~grpc_access_token_credentials() override; + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + private: + grpc_mdelem access_token_md_; +}; // Private constructor for refresh token credentials from an already parsed // refresh token. Takes ownership of the refresh token. -grpc_call_credentials* +grpc_core::RefCountedPtr grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token token); diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc index 4015124298b..52982fdb8f1 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc @@ -35,20 +35,17 @@ grpc_core::TraceFlag grpc_plugin_credentials_trace(false, "plugin_credentials"); -static void plugin_destruct(grpc_call_credentials* creds) { - grpc_plugin_credentials* c = - reinterpret_cast(creds); - gpr_mu_destroy(&c->mu); - if (c->plugin.state != nullptr && c->plugin.destroy != nullptr) { - c->plugin.destroy(c->plugin.state); +grpc_plugin_credentials::~grpc_plugin_credentials() { + gpr_mu_destroy(&mu_); + if (plugin_.state != nullptr && plugin_.destroy != nullptr) { + plugin_.destroy(plugin_.state); } } -static void pending_request_remove_locked( - grpc_plugin_credentials* c, - grpc_plugin_credentials_pending_request* pending_request) { +void grpc_plugin_credentials::pending_request_remove_locked( + pending_request* pending_request) { if (pending_request->prev == nullptr) { - c->pending_requests = pending_request->next; + pending_requests_ = pending_request->next; } else { pending_request->prev->next = pending_request->next; } @@ -62,17 +59,17 @@ static void pending_request_remove_locked( // cancelled out from under us. // When this returns, r->cancelled indicates whether the request was // cancelled before completion. -static void pending_request_complete( - grpc_plugin_credentials_pending_request* r) { - gpr_mu_lock(&r->creds->mu); - if (!r->cancelled) pending_request_remove_locked(r->creds, r); - gpr_mu_unlock(&r->creds->mu); +void grpc_plugin_credentials::pending_request_complete(pending_request* r) { + GPR_DEBUG_ASSERT(r->creds == this); + gpr_mu_lock(&mu_); + if (!r->cancelled) pending_request_remove_locked(r); + gpr_mu_unlock(&mu_); // Ref to credentials not needed anymore. - grpc_call_credentials_unref(&r->creds->base); + Unref(); } static grpc_error* process_plugin_result( - grpc_plugin_credentials_pending_request* r, const grpc_metadata* md, + grpc_plugin_credentials::pending_request* r, const grpc_metadata* md, size_t num_md, grpc_status_code status, const char* error_details) { grpc_error* error = GRPC_ERROR_NONE; if (status != GRPC_STATUS_OK) { @@ -119,8 +116,8 @@ static void plugin_md_request_metadata_ready(void* request, /* called from application code */ grpc_core::ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_FINISHED | GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP); - grpc_plugin_credentials_pending_request* r = - static_cast(request); + grpc_plugin_credentials::pending_request* r = + static_cast(request); if (grpc_plugin_credentials_trace.enabled()) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin returned " @@ -128,7 +125,7 @@ static void plugin_md_request_metadata_ready(void* request, r->creds, r); } // Remove request from pending list if not previously cancelled. - pending_request_complete(r); + r->creds->pending_request_complete(r); // If it has not been cancelled, process it. if (!r->cancelled) { grpc_error* error = @@ -143,65 +140,59 @@ static void plugin_md_request_metadata_ready(void* request, gpr_free(r); } -static bool plugin_get_request_metadata(grpc_call_credentials* creds, - grpc_polling_entity* pollent, - grpc_auth_metadata_context context, - grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, - grpc_error** error) { - grpc_plugin_credentials* c = - reinterpret_cast(creds); +bool grpc_plugin_credentials::get_request_metadata( + grpc_polling_entity* pollent, grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata, + grpc_error** error) { bool retval = true; // Synchronous return. - if (c->plugin.get_metadata != nullptr) { + if (plugin_.get_metadata != nullptr) { // Create pending_request object. - grpc_plugin_credentials_pending_request* pending_request = - static_cast( - gpr_zalloc(sizeof(*pending_request))); - pending_request->creds = c; - pending_request->md_array = md_array; - pending_request->on_request_metadata = on_request_metadata; + pending_request* request = + static_cast(gpr_zalloc(sizeof(*request))); + request->creds = this; + request->md_array = md_array; + request->on_request_metadata = on_request_metadata; // Add it to the pending list. - gpr_mu_lock(&c->mu); - if (c->pending_requests != nullptr) { - c->pending_requests->prev = pending_request; + gpr_mu_lock(&mu_); + if (pending_requests_ != nullptr) { + pending_requests_->prev = request; } - pending_request->next = c->pending_requests; - c->pending_requests = pending_request; - gpr_mu_unlock(&c->mu); + request->next = pending_requests_; + pending_requests_ = request; + gpr_mu_unlock(&mu_); // Invoke the plugin. The callback holds a ref to us. if (grpc_plugin_credentials_trace.enabled()) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin", - c, pending_request); + this, request); } - grpc_call_credentials_ref(creds); + Ref().release(); grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX]; size_t num_creds_md = 0; grpc_status_code status = GRPC_STATUS_OK; const char* error_details = nullptr; - if (!c->plugin.get_metadata(c->plugin.state, context, - plugin_md_request_metadata_ready, - pending_request, creds_md, &num_creds_md, - &status, &error_details)) { + if (!plugin_.get_metadata( + plugin_.state, context, plugin_md_request_metadata_ready, request, + creds_md, &num_creds_md, &status, &error_details)) { if (grpc_plugin_credentials_trace.enabled()) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin will return " "asynchronously", - c, pending_request); + this, request); } return false; // Asynchronous return. } // Returned synchronously. // Remove request from pending list if not previously cancelled. - pending_request_complete(pending_request); + request->creds->pending_request_complete(request); // If the request was cancelled, the error will have been returned // asynchronously by plugin_cancel_get_request_metadata(), so return // false. Otherwise, process the result. - if (pending_request->cancelled) { + if (request->cancelled) { if (grpc_plugin_credentials_trace.enabled()) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p was cancelled, error " "will be returned asynchronously", - c, pending_request); + this, request); } retval = false; } else { @@ -209,10 +200,10 @@ static bool plugin_get_request_metadata(grpc_call_credentials* creds, gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin returned " "synchronously", - c, pending_request); + this, request); } - *error = process_plugin_result(pending_request, creds_md, num_creds_md, - status, error_details); + *error = process_plugin_result(request, creds_md, num_creds_md, status, + error_details); } // Clean up. for (size_t i = 0; i < num_creds_md; ++i) { @@ -220,51 +211,42 @@ static bool plugin_get_request_metadata(grpc_call_credentials* creds, grpc_slice_unref_internal(creds_md[i].value); } gpr_free((void*)error_details); - gpr_free(pending_request); + gpr_free(request); } return retval; } -static void plugin_cancel_get_request_metadata( - grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array, - grpc_error* error) { - grpc_plugin_credentials* c = - reinterpret_cast(creds); - gpr_mu_lock(&c->mu); - for (grpc_plugin_credentials_pending_request* pending_request = - c->pending_requests; +void grpc_plugin_credentials::cancel_get_request_metadata( + grpc_credentials_mdelem_array* md_array, grpc_error* error) { + gpr_mu_lock(&mu_); + for (pending_request* pending_request = pending_requests_; pending_request != nullptr; pending_request = pending_request->next) { if (pending_request->md_array == md_array) { if (grpc_plugin_credentials_trace.enabled()) { - gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", c, + gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", this, pending_request); } pending_request->cancelled = true; GRPC_CLOSURE_SCHED(pending_request->on_request_metadata, GRPC_ERROR_REF(error)); - pending_request_remove_locked(c, pending_request); + pending_request_remove_locked(pending_request); break; } } - gpr_mu_unlock(&c->mu); + gpr_mu_unlock(&mu_); GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable plugin_vtable = { - plugin_destruct, plugin_get_request_metadata, - plugin_cancel_get_request_metadata}; +grpc_plugin_credentials::grpc_plugin_credentials( + grpc_metadata_credentials_plugin plugin) + : grpc_call_credentials(plugin.type), plugin_(plugin) { + gpr_mu_init(&mu_); +} grpc_call_credentials* grpc_metadata_credentials_create_from_plugin( grpc_metadata_credentials_plugin plugin, void* reserved) { - grpc_plugin_credentials* c = - static_cast(gpr_zalloc(sizeof(*c))); GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1, (reserved)); GPR_ASSERT(reserved == nullptr); - c->base.type = plugin.type; - c->base.vtable = &plugin_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->plugin = plugin; - gpr_mu_init(&c->mu); - return &c->base; + return grpc_core::New(plugin); } diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.h b/src/core/lib/security/credentials/plugin/plugin_credentials.h index caf990efa15..77a957e5137 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.h +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.h @@ -25,22 +25,45 @@ extern grpc_core::TraceFlag grpc_plugin_credentials_trace; -struct grpc_plugin_credentials; - -typedef struct grpc_plugin_credentials_pending_request { - bool cancelled; - struct grpc_plugin_credentials* creds; - grpc_credentials_mdelem_array* md_array; - grpc_closure* on_request_metadata; - struct grpc_plugin_credentials_pending_request* prev; - struct grpc_plugin_credentials_pending_request* next; -} grpc_plugin_credentials_pending_request; - -typedef struct grpc_plugin_credentials { - grpc_call_credentials base; - grpc_metadata_credentials_plugin plugin; - gpr_mu mu; - grpc_plugin_credentials_pending_request* pending_requests; -} grpc_plugin_credentials; +// This type is forward declared as a C struct and we cannot define it as a +// class. Otherwise, compiler will complain about type mismatch due to +// -Wmismatched-tags. +struct grpc_plugin_credentials final : public grpc_call_credentials { + public: + struct pending_request { + bool cancelled; + struct grpc_plugin_credentials* creds; + grpc_credentials_mdelem_array* md_array; + grpc_closure* on_request_metadata; + struct pending_request* prev; + struct pending_request* next; + }; + + explicit grpc_plugin_credentials(grpc_metadata_credentials_plugin plugin); + ~grpc_plugin_credentials() override; + + bool get_request_metadata(grpc_polling_entity* pollent, + grpc_auth_metadata_context context, + grpc_credentials_mdelem_array* md_array, + grpc_closure* on_request_metadata, + grpc_error** error) override; + + void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, + grpc_error* error) override; + + // Checks if the request has been cancelled. + // If not, removes it from the pending list, so that it cannot be + // cancelled out from under us. + // When this returns, r->cancelled indicates whether the request was + // cancelled before completion. + void pending_request_complete(pending_request* r); + + private: + void pending_request_remove_locked(pending_request* pending_request); + + grpc_metadata_credentials_plugin plugin_; + gpr_mu mu_; + pending_request* pending_requests_ = nullptr; +}; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/src/core/lib/security/credentials/ssl/ssl_credentials.cc index 3d6f2f200a3..83db86f1eac 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.cc +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.cc @@ -44,22 +44,27 @@ void grpc_tsi_ssl_pem_key_cert_pairs_destroy(tsi_ssl_pem_key_cert_pair* kp, gpr_free(kp); } -static void ssl_destruct(grpc_channel_credentials* creds) { - grpc_ssl_credentials* c = reinterpret_cast(creds); - gpr_free(c->config.pem_root_certs); - grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pair, 1); - if (c->config.verify_options.verify_peer_destruct != nullptr) { - c->config.verify_options.verify_peer_destruct( - c->config.verify_options.verify_peer_callback_userdata); +grpc_ssl_credentials::grpc_ssl_credentials( + const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, + const verify_peer_options* verify_options) + : grpc_channel_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_SSL) { + build_config(pem_root_certs, pem_key_cert_pair, verify_options); +} + +grpc_ssl_credentials::~grpc_ssl_credentials() { + gpr_free(config_.pem_root_certs); + grpc_tsi_ssl_pem_key_cert_pairs_destroy(config_.pem_key_cert_pair, 1); + if (config_.verify_options.verify_peer_destruct != nullptr) { + config_.verify_options.verify_peer_destruct( + config_.verify_options.verify_peer_callback_userdata); } } -static grpc_security_status ssl_create_security_connector( - grpc_channel_credentials* creds, grpc_call_credentials* call_creds, +grpc_core::RefCountedPtr +grpc_ssl_credentials::create_security_connector( + grpc_core::RefCountedPtr call_creds, const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args) { - grpc_ssl_credentials* c = reinterpret_cast(creds); - grpc_security_status status = GRPC_SECURITY_OK; + grpc_channel_args** new_args) { const char* overridden_target_name = nullptr; tsi_ssl_session_cache* ssl_session_cache = nullptr; for (size_t i = 0; args && i < args->num_args; i++) { @@ -74,52 +79,47 @@ static grpc_security_status ssl_create_security_connector( static_cast(arg->value.pointer.p); } } - status = grpc_ssl_channel_security_connector_create( - creds, call_creds, &c->config, target, overridden_target_name, - ssl_session_cache, sc); - if (status != GRPC_SECURITY_OK) { - return status; + grpc_core::RefCountedPtr sc = + grpc_ssl_channel_security_connector_create( + this->Ref(), std::move(call_creds), &config_, target, + overridden_target_name, ssl_session_cache); + if (sc == nullptr) { + return sc; } grpc_arg new_arg = grpc_channel_arg_string_create( (char*)GRPC_ARG_HTTP2_SCHEME, (char*)"https"); *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1); - return status; + return sc; } -static grpc_channel_credentials_vtable ssl_vtable = { - ssl_destruct, ssl_create_security_connector, nullptr}; - -static void ssl_build_config(const char* pem_root_certs, - grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, - const verify_peer_options* verify_options, - grpc_ssl_config* config) { - if (pem_root_certs != nullptr) { - config->pem_root_certs = gpr_strdup(pem_root_certs); - } +void grpc_ssl_credentials::build_config( + const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, + const verify_peer_options* verify_options) { + config_.pem_root_certs = gpr_strdup(pem_root_certs); if (pem_key_cert_pair != nullptr) { GPR_ASSERT(pem_key_cert_pair->private_key != nullptr); GPR_ASSERT(pem_key_cert_pair->cert_chain != nullptr); - config->pem_key_cert_pair = static_cast( + config_.pem_key_cert_pair = static_cast( gpr_zalloc(sizeof(tsi_ssl_pem_key_cert_pair))); - config->pem_key_cert_pair->cert_chain = + config_.pem_key_cert_pair->cert_chain = gpr_strdup(pem_key_cert_pair->cert_chain); - config->pem_key_cert_pair->private_key = + config_.pem_key_cert_pair->private_key = gpr_strdup(pem_key_cert_pair->private_key); + } else { + config_.pem_key_cert_pair = nullptr; } if (verify_options != nullptr) { - memcpy(&config->verify_options, verify_options, + memcpy(&config_.verify_options, verify_options, sizeof(verify_peer_options)); } else { // Otherwise set all options to default values - memset(&config->verify_options, 0, sizeof(verify_peer_options)); + memset(&config_.verify_options, 0, sizeof(verify_peer_options)); } } grpc_channel_credentials* grpc_ssl_credentials_create( const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, const verify_peer_options* verify_options, void* reserved) { - grpc_ssl_credentials* c = static_cast( - gpr_zalloc(sizeof(grpc_ssl_credentials))); GRPC_API_TRACE( "grpc_ssl_credentials_create(pem_root_certs=%s, " "pem_key_cert_pair=%p, " @@ -127,12 +127,9 @@ grpc_channel_credentials* grpc_ssl_credentials_create( "reserved=%p)", 4, (pem_root_certs, pem_key_cert_pair, verify_options, reserved)); GPR_ASSERT(reserved == nullptr); - c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; - c->base.vtable = &ssl_vtable; - gpr_ref_init(&c->base.refcount, 1); - ssl_build_config(pem_root_certs, pem_key_cert_pair, verify_options, - &c->config); - return &c->base; + + return grpc_core::New(pem_root_certs, pem_key_cert_pair, + verify_options); } // @@ -145,21 +142,29 @@ struct grpc_ssl_server_credentials_options { grpc_ssl_server_certificate_config_fetcher* certificate_config_fetcher; }; -static void ssl_server_destruct(grpc_server_credentials* creds) { - grpc_ssl_server_credentials* c = - reinterpret_cast(creds); - grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pairs, - c->config.num_key_cert_pairs); - gpr_free(c->config.pem_root_certs); +grpc_ssl_server_credentials::grpc_ssl_server_credentials( + const grpc_ssl_server_credentials_options& options) + : grpc_server_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_SSL) { + if (options.certificate_config_fetcher != nullptr) { + config_.client_certificate_request = options.client_certificate_request; + certificate_config_fetcher_ = *options.certificate_config_fetcher; + } else { + build_config(options.certificate_config->pem_root_certs, + options.certificate_config->pem_key_cert_pairs, + options.certificate_config->num_key_cert_pairs, + options.client_certificate_request); + } } -static grpc_security_status ssl_server_create_security_connector( - grpc_server_credentials* creds, grpc_server_security_connector** sc) { - return grpc_ssl_server_security_connector_create(creds, sc); +grpc_ssl_server_credentials::~grpc_ssl_server_credentials() { + grpc_tsi_ssl_pem_key_cert_pairs_destroy(config_.pem_key_cert_pairs, + config_.num_key_cert_pairs); + gpr_free(config_.pem_root_certs); +} +grpc_core::RefCountedPtr +grpc_ssl_server_credentials::create_security_connector() { + return grpc_ssl_server_security_connector_create(this->Ref()); } - -static grpc_server_credentials_vtable ssl_server_vtable = { - ssl_server_destruct, ssl_server_create_security_connector}; tsi_ssl_pem_key_cert_pair* grpc_convert_grpc_to_tsi_cert_pairs( const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, @@ -179,18 +184,15 @@ tsi_ssl_pem_key_cert_pair* grpc_convert_grpc_to_tsi_cert_pairs( return tsi_pairs; } -static void ssl_build_server_config( +void grpc_ssl_server_credentials::build_config( const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, size_t num_key_cert_pairs, - grpc_ssl_client_certificate_request_type client_certificate_request, - grpc_ssl_server_config* config) { - config->client_certificate_request = client_certificate_request; - if (pem_root_certs != nullptr) { - config->pem_root_certs = gpr_strdup(pem_root_certs); - } - config->pem_key_cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( + grpc_ssl_client_certificate_request_type client_certificate_request) { + config_.client_certificate_request = client_certificate_request; + config_.pem_root_certs = gpr_strdup(pem_root_certs); + config_.pem_key_cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( pem_key_cert_pairs, num_key_cert_pairs); - config->num_key_cert_pairs = num_key_cert_pairs; + config_.num_key_cert_pairs = num_key_cert_pairs; } grpc_ssl_server_certificate_config* grpc_ssl_server_certificate_config_create( @@ -200,9 +202,7 @@ grpc_ssl_server_certificate_config* grpc_ssl_server_certificate_config_create( grpc_ssl_server_certificate_config* config = static_cast( gpr_zalloc(sizeof(grpc_ssl_server_certificate_config))); - if (pem_root_certs != nullptr) { - config->pem_root_certs = gpr_strdup(pem_root_certs); - } + config->pem_root_certs = gpr_strdup(pem_root_certs); if (num_key_cert_pairs > 0) { GPR_ASSERT(pem_key_cert_pairs != nullptr); config->pem_key_cert_pairs = static_cast( @@ -311,7 +311,6 @@ grpc_server_credentials* grpc_ssl_server_credentials_create_ex( grpc_server_credentials* grpc_ssl_server_credentials_create_with_options( grpc_ssl_server_credentials_options* options) { grpc_server_credentials* retval = nullptr; - grpc_ssl_server_credentials* c = nullptr; if (options == nullptr) { gpr_log(GPR_ERROR, @@ -331,23 +330,7 @@ grpc_server_credentials* grpc_ssl_server_credentials_create_with_options( goto done; } - c = static_cast( - gpr_zalloc(sizeof(grpc_ssl_server_credentials))); - c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; - gpr_ref_init(&c->base.refcount, 1); - c->base.vtable = &ssl_server_vtable; - - if (options->certificate_config_fetcher != nullptr) { - c->config.client_certificate_request = options->client_certificate_request; - c->certificate_config_fetcher = *options->certificate_config_fetcher; - } else { - ssl_build_server_config(options->certificate_config->pem_root_certs, - options->certificate_config->pem_key_cert_pairs, - options->certificate_config->num_key_cert_pairs, - options->client_certificate_request, &c->config); - } - - retval = &c->base; + retval = grpc_core::New(*options); done: grpc_ssl_server_credentials_options_destroy(options); diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.h b/src/core/lib/security/credentials/ssl/ssl_credentials.h index 0fba413876e..e1174327b30 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.h +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.h @@ -24,27 +24,70 @@ #include "src/core/lib/security/security_connector/ssl/ssl_security_connector.h" -typedef struct { - grpc_channel_credentials base; - grpc_ssl_config config; -} grpc_ssl_credentials; +class grpc_ssl_credentials : public grpc_channel_credentials { + public: + grpc_ssl_credentials(const char* pem_root_certs, + grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, + const verify_peer_options* verify_options); + + ~grpc_ssl_credentials() override; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target, const grpc_channel_args* args, + grpc_channel_args** new_args) override; + + private: + void build_config(const char* pem_root_certs, + grpc_ssl_pem_key_cert_pair* pem_key_cert_pair, + const verify_peer_options* verify_options); + + grpc_ssl_config config_; +}; struct grpc_ssl_server_certificate_config { - grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs; - size_t num_key_cert_pairs; - char* pem_root_certs; + grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr; + size_t num_key_cert_pairs = 0; + char* pem_root_certs = nullptr; }; -typedef struct { - grpc_ssl_server_certificate_config_callback cb; +struct grpc_ssl_server_certificate_config_fetcher { + grpc_ssl_server_certificate_config_callback cb = nullptr; void* user_data; -} grpc_ssl_server_certificate_config_fetcher; +}; + +class grpc_ssl_server_credentials final : public grpc_server_credentials { + public: + grpc_ssl_server_credentials( + const grpc_ssl_server_credentials_options& options); + ~grpc_ssl_server_credentials() override; -typedef struct { - grpc_server_credentials base; - grpc_ssl_server_config config; - grpc_ssl_server_certificate_config_fetcher certificate_config_fetcher; -} grpc_ssl_server_credentials; + grpc_core::RefCountedPtr + create_security_connector() override; + + bool has_cert_config_fetcher() const { + return certificate_config_fetcher_.cb != nullptr; + } + + grpc_ssl_certificate_config_reload_status FetchCertConfig( + grpc_ssl_server_certificate_config** config) { + GPR_DEBUG_ASSERT(has_cert_config_fetcher()); + return certificate_config_fetcher_.cb(certificate_config_fetcher_.user_data, + config); + } + + const grpc_ssl_server_config& config() const { return config_; } + + private: + void build_config( + const char* pem_root_certs, + grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, size_t num_key_cert_pairs, + grpc_ssl_client_certificate_request_type client_certificate_request); + + grpc_ssl_server_config config_; + grpc_ssl_server_certificate_config_fetcher certificate_config_fetcher_; +}; tsi_ssl_pem_key_cert_pair* grpc_convert_grpc_to_tsi_cert_pairs( const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, diff --git a/src/core/lib/security/security_connector/alts/alts_security_connector.cc b/src/core/lib/security/security_connector/alts/alts_security_connector.cc index dd71c8bc606..6db70ef1720 100644 --- a/src/core/lib/security/security_connector/alts/alts_security_connector.cc +++ b/src/core/lib/security/security_connector/alts/alts_security_connector.cc @@ -28,6 +28,7 @@ #include #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/credentials/alts/alts_credentials.h" #include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/lib/slice/slice_internal.h" @@ -35,64 +36,9 @@ #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" #include "src/core/tsi/transport_security.h" -typedef struct { - grpc_channel_security_connector base; - char* target_name; -} grpc_alts_channel_security_connector; +namespace { -typedef struct { - grpc_server_security_connector base; -} grpc_alts_server_security_connector; - -static void alts_channel_destroy(grpc_security_connector* sc) { - if (sc == nullptr) { - return; - } - auto c = reinterpret_cast(sc); - grpc_call_credentials_unref(c->base.request_metadata_creds); - grpc_channel_credentials_unref(c->base.channel_creds); - gpr_free(c->target_name); - gpr_free(sc); -} - -static void alts_server_destroy(grpc_security_connector* sc) { - if (sc == nullptr) { - return; - } - auto c = reinterpret_cast(sc); - grpc_server_credentials_unref(c->base.server_creds); - gpr_free(sc); -} - -static void alts_channel_add_handshakers( - grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_manager) { - tsi_handshaker* handshaker = nullptr; - auto c = reinterpret_cast(sc); - grpc_alts_credentials* creds = - reinterpret_cast(c->base.channel_creds); - GPR_ASSERT(alts_tsi_handshaker_create( - creds->options, c->target_name, creds->handshaker_service_url, - true, interested_parties, &handshaker) == TSI_OK); - grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( - handshaker, &sc->base)); -} - -static void alts_server_add_handshakers( - grpc_server_security_connector* sc, grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_manager) { - tsi_handshaker* handshaker = nullptr; - auto c = reinterpret_cast(sc); - grpc_alts_server_credentials* creds = - reinterpret_cast(c->base.server_creds); - GPR_ASSERT(alts_tsi_handshaker_create( - creds->options, nullptr, creds->handshaker_service_url, false, - interested_parties, &handshaker) == TSI_OK); - grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( - handshaker, &sc->base)); -} - -static void alts_set_rpc_protocol_versions( +void alts_set_rpc_protocol_versions( grpc_gcp_rpc_protocol_versions* rpc_versions) { grpc_gcp_rpc_protocol_versions_set_max(rpc_versions, GRPC_PROTOCOL_VERSION_MAX_MAJOR, @@ -102,17 +48,131 @@ static void alts_set_rpc_protocol_versions( GRPC_PROTOCOL_VERSION_MIN_MINOR); } +void atls_check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) { + *auth_context = + grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer); + tsi_peer_destruct(&peer); + grpc_error* error = + *auth_context != nullptr + ? GRPC_ERROR_NONE + : GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Could not get ALTS auth context from TSI peer"); + GRPC_CLOSURE_SCHED(on_peer_checked, error); +} + +class grpc_alts_channel_security_connector final + : public grpc_channel_security_connector { + public: + grpc_alts_channel_security_connector( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target_name) + : grpc_channel_security_connector(/*url_scheme=*/nullptr, + std::move(channel_creds), + std::move(request_metadata_creds)), + target_name_(gpr_strdup(target_name)) { + grpc_alts_credentials* creds = + static_cast(mutable_channel_creds()); + alts_set_rpc_protocol_versions(&creds->mutable_options()->rpc_versions); + } + + ~grpc_alts_channel_security_connector() override { gpr_free(target_name_); } + + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_manager) override { + tsi_handshaker* handshaker = nullptr; + const grpc_alts_credentials* creds = + static_cast(channel_creds()); + GPR_ASSERT(alts_tsi_handshaker_create(creds->options(), target_name_, + creds->handshaker_service_url(), true, + interested_parties, + &handshaker) == TSI_OK); + grpc_handshake_manager_add( + handshake_manager, grpc_security_handshaker_create(handshaker, this)); + } + + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + atls_check_peer(peer, auth_context, on_peer_checked); + } + + int cmp(const grpc_security_connector* other_sc) const override { + auto* other = + reinterpret_cast(other_sc); + int c = channel_security_connector_cmp(other); + if (c != 0) return c; + return strcmp(target_name_, other->target_name_); + } + + bool check_call_host(const char* host, grpc_auth_context* auth_context, + grpc_closure* on_call_host_checked, + grpc_error** error) override { + if (host == nullptr || strcmp(host, target_name_) != 0) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "ALTS call host does not match target name"); + } + return true; + } + + void cancel_check_call_host(grpc_closure* on_call_host_checked, + grpc_error* error) override { + GRPC_ERROR_UNREF(error); + } + + private: + char* target_name_; +}; + +class grpc_alts_server_security_connector final + : public grpc_server_security_connector { + public: + grpc_alts_server_security_connector( + grpc_core::RefCountedPtr server_creds) + : grpc_server_security_connector(/*url_scheme=*/nullptr, + std::move(server_creds)) { + grpc_alts_server_credentials* creds = + reinterpret_cast(mutable_server_creds()); + alts_set_rpc_protocol_versions(&creds->mutable_options()->rpc_versions); + } + ~grpc_alts_server_security_connector() override = default; + + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_manager) override { + tsi_handshaker* handshaker = nullptr; + const grpc_alts_server_credentials* creds = + static_cast(server_creds()); + GPR_ASSERT(alts_tsi_handshaker_create( + creds->options(), nullptr, creds->handshaker_service_url(), + false, interested_parties, &handshaker) == TSI_OK); + grpc_handshake_manager_add( + handshake_manager, grpc_security_handshaker_create(handshaker, this)); + } + + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + atls_check_peer(peer, auth_context, on_peer_checked); + } + + int cmp(const grpc_security_connector* other) const override { + return server_security_connector_cmp( + static_cast(other)); + } +}; +} // namespace + namespace grpc_core { namespace internal { - -grpc_security_status grpc_alts_auth_context_from_tsi_peer( - const tsi_peer* peer, grpc_auth_context** ctx) { - if (peer == nullptr || ctx == nullptr) { +grpc_core::RefCountedPtr +grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) { + if (peer == nullptr) { gpr_log(GPR_ERROR, "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()"); - return GRPC_SECURITY_ERROR; + return nullptr; } - *ctx = nullptr; /* Validate certificate type. */ const tsi_peer_property* cert_type_prop = tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); @@ -120,14 +180,14 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer( strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE, cert_type_prop->value.length) != 0) { gpr_log(GPR_ERROR, "Invalid or missing certificate type property."); - return GRPC_SECURITY_ERROR; + return nullptr; } /* Validate RPC protocol versions. */ const tsi_peer_property* rpc_versions_prop = tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS); if (rpc_versions_prop == nullptr) { gpr_log(GPR_ERROR, "Missing rpc protocol versions property."); - return GRPC_SECURITY_ERROR; + return nullptr; } grpc_gcp_rpc_protocol_versions local_versions, peer_versions; alts_set_rpc_protocol_versions(&local_versions); @@ -138,19 +198,19 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer( grpc_slice_unref_internal(slice); if (!decode_result) { gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions."); - return GRPC_SECURITY_ERROR; + return nullptr; } /* TODO: Pass highest common rpc protocol version to grpc caller. */ bool check_result = grpc_gcp_rpc_protocol_versions_check( &local_versions, &peer_versions, nullptr); if (!check_result) { gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions."); - return GRPC_SECURITY_ERROR; + return nullptr; } /* Create auth context. */ - *ctx = grpc_auth_context_create(nullptr); + auto ctx = grpc_core::MakeRefCounted(nullptr); grpc_auth_context_add_cstring_property( - *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_ALTS_TRANSPORT_SECURITY_TYPE); size_t i = 0; for (i = 0; i < peer->property_count; i++) { @@ -158,132 +218,47 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer( /* Add service account to auth context. */ if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) { grpc_auth_context_add_property( - *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, tsi_prop->value.data, - tsi_prop->value.length); + ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, + tsi_prop->value.data, tsi_prop->value.length); GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1); + ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1); } } - if (!grpc_auth_context_peer_is_authenticated(*ctx)) { + if (!grpc_auth_context_peer_is_authenticated(ctx.get())) { gpr_log(GPR_ERROR, "Invalid unauthenticated peer."); - GRPC_AUTH_CONTEXT_UNREF(*ctx, "test"); - *ctx = nullptr; - return GRPC_SECURITY_ERROR; + ctx.reset(DEBUG_LOCATION, "test"); + return nullptr; } - return GRPC_SECURITY_OK; + return ctx; } } // namespace internal } // namespace grpc_core -static void alts_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - grpc_security_status status; - status = grpc_core::internal::grpc_alts_auth_context_from_tsi_peer( - &peer, auth_context); - tsi_peer_destruct(&peer); - grpc_error* error = - status == GRPC_SECURITY_OK - ? GRPC_ERROR_NONE - : GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Could not get ALTS auth context from TSI peer"); - GRPC_CLOSURE_SCHED(on_peer_checked, error); -} - -static int alts_channel_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_alts_channel_security_connector* c1 = - reinterpret_cast(sc1); - grpc_alts_channel_security_connector* c2 = - reinterpret_cast(sc2); - int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); - if (c != 0) return c; - return strcmp(c1->target_name, c2->target_name); -} - -static int alts_server_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_alts_server_security_connector* c1 = - reinterpret_cast(sc1); - grpc_alts_server_security_connector* c2 = - reinterpret_cast(sc2); - return grpc_server_security_connector_cmp(&c1->base, &c2->base); -} - -static grpc_security_connector_vtable alts_channel_vtable = { - alts_channel_destroy, alts_check_peer, alts_channel_cmp}; - -static grpc_security_connector_vtable alts_server_vtable = { - alts_server_destroy, alts_check_peer, alts_server_cmp}; - -static bool alts_check_call_host(grpc_channel_security_connector* sc, - const char* host, - grpc_auth_context* auth_context, - grpc_closure* on_call_host_checked, - grpc_error** error) { - grpc_alts_channel_security_connector* alts_sc = - reinterpret_cast(sc); - if (host == nullptr || alts_sc == nullptr || - strcmp(host, alts_sc->target_name) != 0) { - *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "ALTS call host does not match target name"); - } - return true; -} - -static void alts_cancel_check_call_host(grpc_channel_security_connector* sc, - grpc_closure* on_call_host_checked, - grpc_error* error) { - GRPC_ERROR_UNREF(error); -} - -grpc_security_status grpc_alts_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, const char* target_name, - grpc_channel_security_connector** sc) { - if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) { +grpc_core::RefCountedPtr +grpc_alts_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target_name) { + if (channel_creds == nullptr || target_name == nullptr) { gpr_log( GPR_ERROR, "Invalid arguments to grpc_alts_channel_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } - auto c = static_cast( - gpr_zalloc(sizeof(grpc_alts_channel_security_connector))); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &alts_channel_vtable; - c->base.add_handshakers = alts_channel_add_handshakers; - c->base.channel_creds = grpc_channel_credentials_ref(channel_creds); - c->base.request_metadata_creds = - grpc_call_credentials_ref(request_metadata_creds); - c->base.check_call_host = alts_check_call_host; - c->base.cancel_check_call_host = alts_cancel_check_call_host; - grpc_alts_credentials* creds = - reinterpret_cast(c->base.channel_creds); - alts_set_rpc_protocol_versions(&creds->options->rpc_versions); - c->target_name = gpr_strdup(target_name); - *sc = &c->base; - return GRPC_SECURITY_OK; + return grpc_core::MakeRefCounted( + std::move(channel_creds), std::move(request_metadata_creds), target_name); } -grpc_security_status grpc_alts_server_security_connector_create( - grpc_server_credentials* server_creds, - grpc_server_security_connector** sc) { - if (server_creds == nullptr || sc == nullptr) { +grpc_core::RefCountedPtr +grpc_alts_server_security_connector_create( + grpc_core::RefCountedPtr server_creds) { + if (server_creds == nullptr) { gpr_log( GPR_ERROR, "Invalid arguments to grpc_alts_server_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } - auto c = static_cast( - gpr_zalloc(sizeof(grpc_alts_server_security_connector))); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &alts_server_vtable; - c->base.server_creds = grpc_server_credentials_ref(server_creds); - c->base.add_handshakers = alts_server_add_handshakers; - grpc_alts_server_credentials* creds = - reinterpret_cast(c->base.server_creds); - alts_set_rpc_protocol_versions(&creds->options->rpc_versions); - *sc = &c->base; - return GRPC_SECURITY_OK; + return grpc_core::MakeRefCounted( + std::move(server_creds)); } diff --git a/src/core/lib/security/security_connector/alts/alts_security_connector.h b/src/core/lib/security/security_connector/alts/alts_security_connector.h index d2e057a76aa..b96dc36b302 100644 --- a/src/core/lib/security/security_connector/alts/alts_security_connector.h +++ b/src/core/lib/security/security_connector/alts/alts_security_connector.h @@ -36,12 +36,13 @@ * - sc: address of ALTS channel security connector instance to be returned from * the method. * - * It returns GRPC_SECURITY_OK on success, and an error stauts code on failure. + * It returns nullptr on failure. */ -grpc_security_status grpc_alts_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, const char* target_name, - grpc_channel_security_connector** sc); +grpc_core::RefCountedPtr +grpc_alts_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target_name); /** * This method creates an ALTS server security connector. @@ -50,17 +51,18 @@ grpc_security_status grpc_alts_channel_security_connector_create( * - sc: address of ALTS server security connector instance to be returned from * the method. * - * It returns GRPC_SECURITY_OK on success, and an error status code on failure. + * It returns nullptr on failure. */ -grpc_security_status grpc_alts_server_security_connector_create( - grpc_server_credentials* server_creds, grpc_server_security_connector** sc); +grpc_core::RefCountedPtr +grpc_alts_server_security_connector_create( + grpc_core::RefCountedPtr server_creds); namespace grpc_core { namespace internal { /* Exposed only for testing. */ -grpc_security_status grpc_alts_auth_context_from_tsi_peer( - const tsi_peer* peer, grpc_auth_context** ctx); +grpc_core::RefCountedPtr +grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer); } // namespace internal } // namespace grpc_core diff --git a/src/core/lib/security/security_connector/fake/fake_security_connector.cc b/src/core/lib/security/security_connector/fake/fake_security_connector.cc index 5c0c89b88f2..d2cdaaac77c 100644 --- a/src/core/lib/security/security_connector/fake/fake_security_connector.cc +++ b/src/core/lib/security/security_connector/fake/fake_security_connector.cc @@ -31,6 +31,7 @@ #include "src/core/lib/channel/handshaker.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/fake/fake_credentials.h" @@ -38,91 +39,183 @@ #include "src/core/lib/security/transport/target_authority_table.h" #include "src/core/tsi/fake_transport_security.h" -typedef struct { - grpc_channel_security_connector base; - char* target; - char* expected_targets; - bool is_lb_channel; - char* target_name_override; -} grpc_fake_channel_security_connector; +namespace { +class grpc_fake_channel_security_connector final + : public grpc_channel_security_connector { + public: + grpc_fake_channel_security_connector( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target, const grpc_channel_args* args) + : grpc_channel_security_connector(GRPC_FAKE_SECURITY_URL_SCHEME, + std::move(channel_creds), + std::move(request_metadata_creds)), + target_(gpr_strdup(target)), + expected_targets_( + gpr_strdup(grpc_fake_transport_get_expected_targets(args))), + is_lb_channel_(grpc_core::FindTargetAuthorityTableInArgs(args) != + nullptr) { + const grpc_arg* target_name_override_arg = + grpc_channel_args_find(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + if (target_name_override_arg != nullptr) { + target_name_override_ = + gpr_strdup(grpc_channel_arg_get_string(target_name_override_arg)); + } else { + target_name_override_ = nullptr; + } + } -static void fake_channel_destroy(grpc_security_connector* sc) { - grpc_fake_channel_security_connector* c = - reinterpret_cast(sc); - grpc_call_credentials_unref(c->base.request_metadata_creds); - gpr_free(c->target); - gpr_free(c->expected_targets); - gpr_free(c->target_name_override); - gpr_free(c); -} + ~grpc_fake_channel_security_connector() override { + gpr_free(target_); + gpr_free(expected_targets_); + if (target_name_override_ != nullptr) gpr_free(target_name_override_); + } -static void fake_server_destroy(grpc_security_connector* sc) { gpr_free(sc); } + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override; -static bool fake_check_target(const char* target_type, const char* target, - const char* set_str) { - GPR_ASSERT(target_type != nullptr); - GPR_ASSERT(target != nullptr); - char** set = nullptr; - size_t set_size = 0; - gpr_string_split(set_str, ",", &set, &set_size); - bool found = false; - for (size_t i = 0; i < set_size; ++i) { - if (set[i] != nullptr && strcmp(target, set[i]) == 0) found = true; + int cmp(const grpc_security_connector* other_sc) const override { + auto* other = + reinterpret_cast(other_sc); + int c = channel_security_connector_cmp(other); + if (c != 0) return c; + c = strcmp(target_, other->target_); + if (c != 0) return c; + if (expected_targets_ == nullptr || other->expected_targets_ == nullptr) { + c = GPR_ICMP(expected_targets_, other->expected_targets_); + } else { + c = strcmp(expected_targets_, other->expected_targets_); + } + if (c != 0) return c; + return GPR_ICMP(is_lb_channel_, other->is_lb_channel_); } - for (size_t i = 0; i < set_size; ++i) { - gpr_free(set[i]); + + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) override { + grpc_handshake_manager_add( + handshake_mgr, + grpc_security_handshaker_create( + tsi_create_fake_handshaker(/*is_client=*/true), this)); } - gpr_free(set); - return found; -} -static void fake_secure_name_check(const char* target, - const char* expected_targets, - bool is_lb_channel) { - if (expected_targets == nullptr) return; - char** lbs_and_backends = nullptr; - size_t lbs_and_backends_size = 0; - bool success = false; - gpr_string_split(expected_targets, ";", &lbs_and_backends, - &lbs_and_backends_size); - if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) { - gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'", - expected_targets); - goto done; + bool check_call_host(const char* host, grpc_auth_context* auth_context, + grpc_closure* on_call_host_checked, + grpc_error** error) override { + char* authority_hostname = nullptr; + char* authority_ignored_port = nullptr; + char* target_hostname = nullptr; + char* target_ignored_port = nullptr; + gpr_split_host_port(host, &authority_hostname, &authority_ignored_port); + gpr_split_host_port(target_, &target_hostname, &target_ignored_port); + if (target_name_override_ != nullptr) { + char* fake_security_target_name_override_hostname = nullptr; + char* fake_security_target_name_override_ignored_port = nullptr; + gpr_split_host_port(target_name_override_, + &fake_security_target_name_override_hostname, + &fake_security_target_name_override_ignored_port); + if (strcmp(authority_hostname, + fake_security_target_name_override_hostname) != 0) { + gpr_log(GPR_ERROR, + "Authority (host) '%s' != Fake Security Target override '%s'", + host, fake_security_target_name_override_hostname); + abort(); + } + gpr_free(fake_security_target_name_override_hostname); + gpr_free(fake_security_target_name_override_ignored_port); + } else if (strcmp(authority_hostname, target_hostname) != 0) { + gpr_log(GPR_ERROR, "Authority (host) '%s' != Target '%s'", + authority_hostname, target_hostname); + abort(); + } + gpr_free(authority_hostname); + gpr_free(authority_ignored_port); + gpr_free(target_hostname); + gpr_free(target_ignored_port); + return true; } - if (is_lb_channel) { - if (lbs_and_backends_size != 2) { - gpr_log(GPR_ERROR, - "Invalid expected targets arg value: '%s'. Expectations for LB " - "channels must be of the form 'be1,be2,be3,...;lb1,lb2,...", - expected_targets); - goto done; + + void cancel_check_call_host(grpc_closure* on_call_host_checked, + grpc_error* error) override { + GRPC_ERROR_UNREF(error); + } + + char* target() const { return target_; } + char* expected_targets() const { return expected_targets_; } + bool is_lb_channel() const { return is_lb_channel_; } + char* target_name_override() const { return target_name_override_; } + + private: + bool fake_check_target(const char* target_type, const char* target, + const char* set_str) const { + GPR_ASSERT(target_type != nullptr); + GPR_ASSERT(target != nullptr); + char** set = nullptr; + size_t set_size = 0; + gpr_string_split(set_str, ",", &set, &set_size); + bool found = false; + for (size_t i = 0; i < set_size; ++i) { + if (set[i] != nullptr && strcmp(target, set[i]) == 0) found = true; } - if (!fake_check_target("LB", target, lbs_and_backends[1])) { - gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'", - target, lbs_and_backends[1]); - goto done; + for (size_t i = 0; i < set_size; ++i) { + gpr_free(set[i]); } - success = true; - } else { - if (!fake_check_target("Backend", target, lbs_and_backends[0])) { - gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'", - target, lbs_and_backends[0]); + gpr_free(set); + return found; + } + + void fake_secure_name_check() const { + if (expected_targets_ == nullptr) return; + char** lbs_and_backends = nullptr; + size_t lbs_and_backends_size = 0; + bool success = false; + gpr_string_split(expected_targets_, ";", &lbs_and_backends, + &lbs_and_backends_size); + if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) { + gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'", + expected_targets_); goto done; } - success = true; - } -done: - for (size_t i = 0; i < lbs_and_backends_size; ++i) { - gpr_free(lbs_and_backends[i]); + if (is_lb_channel_) { + if (lbs_and_backends_size != 2) { + gpr_log(GPR_ERROR, + "Invalid expected targets arg value: '%s'. Expectations for LB " + "channels must be of the form 'be1,be2,be3,...;lb1,lb2,...", + expected_targets_); + goto done; + } + if (!fake_check_target("LB", target_, lbs_and_backends[1])) { + gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'", + target_, lbs_and_backends[1]); + goto done; + } + success = true; + } else { + if (!fake_check_target("Backend", target_, lbs_and_backends[0])) { + gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'", + target_, lbs_and_backends[0]); + goto done; + } + success = true; + } + done: + for (size_t i = 0; i < lbs_and_backends_size; ++i) { + gpr_free(lbs_and_backends[i]); + } + gpr_free(lbs_and_backends); + if (!success) abort(); } - gpr_free(lbs_and_backends); - if (!success) abort(); -} -static void fake_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { + char* target_; + char* expected_targets_; + bool is_lb_channel_; + char* target_name_override_; +}; + +static void fake_check_peer( + grpc_security_connector* sc, tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) { const char* prop_name; grpc_error* error = GRPC_ERROR_NONE; *auth_context = nullptr; @@ -147,164 +240,65 @@ static void fake_check_peer(grpc_security_connector* sc, tsi_peer peer, "Invalid value for cert type property."); goto end; } - *auth_context = grpc_auth_context_create(nullptr); + *auth_context = grpc_core::MakeRefCounted(nullptr); grpc_auth_context_add_cstring_property( - *auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + auth_context->get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_FAKE_TRANSPORT_SECURITY_TYPE); end: GRPC_CLOSURE_SCHED(on_peer_checked, error); tsi_peer_destruct(&peer); } -static void fake_channel_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - fake_check_peer(sc, peer, auth_context, on_peer_checked); - grpc_fake_channel_security_connector* c = - reinterpret_cast(sc); - fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel); +void grpc_fake_channel_security_connector::check_peer( + tsi_peer peer, grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) { + fake_check_peer(this, peer, auth_context, on_peer_checked); + fake_secure_name_check(); } -static void fake_server_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - fake_check_peer(sc, peer, auth_context, on_peer_checked); -} +class grpc_fake_server_security_connector + : public grpc_server_security_connector { + public: + grpc_fake_server_security_connector( + grpc_core::RefCountedPtr server_creds) + : grpc_server_security_connector(GRPC_FAKE_SECURITY_URL_SCHEME, + std::move(server_creds)) {} + ~grpc_fake_server_security_connector() override = default; -static int fake_channel_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_fake_channel_security_connector* c1 = - reinterpret_cast(sc1); - grpc_fake_channel_security_connector* c2 = - reinterpret_cast(sc2); - int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); - if (c != 0) return c; - c = strcmp(c1->target, c2->target); - if (c != 0) return c; - if (c1->expected_targets == nullptr || c2->expected_targets == nullptr) { - c = GPR_ICMP(c1->expected_targets, c2->expected_targets); - } else { - c = strcmp(c1->expected_targets, c2->expected_targets); + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + fake_check_peer(this, peer, auth_context, on_peer_checked); } - if (c != 0) return c; - return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel); -} -static int fake_server_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - return grpc_server_security_connector_cmp( - reinterpret_cast(sc1), - reinterpret_cast(sc2)); -} - -static bool fake_channel_check_call_host(grpc_channel_security_connector* sc, - const char* host, - grpc_auth_context* auth_context, - grpc_closure* on_call_host_checked, - grpc_error** error) { - grpc_fake_channel_security_connector* c = - reinterpret_cast(sc); - char* authority_hostname = nullptr; - char* authority_ignored_port = nullptr; - char* target_hostname = nullptr; - char* target_ignored_port = nullptr; - gpr_split_host_port(host, &authority_hostname, &authority_ignored_port); - gpr_split_host_port(c->target, &target_hostname, &target_ignored_port); - if (c->target_name_override != nullptr) { - char* fake_security_target_name_override_hostname = nullptr; - char* fake_security_target_name_override_ignored_port = nullptr; - gpr_split_host_port(c->target_name_override, - &fake_security_target_name_override_hostname, - &fake_security_target_name_override_ignored_port); - if (strcmp(authority_hostname, - fake_security_target_name_override_hostname) != 0) { - gpr_log(GPR_ERROR, - "Authority (host) '%s' != Fake Security Target override '%s'", - host, fake_security_target_name_override_hostname); - abort(); - } - gpr_free(fake_security_target_name_override_hostname); - gpr_free(fake_security_target_name_override_ignored_port); - } else if (strcmp(authority_hostname, target_hostname) != 0) { - gpr_log(GPR_ERROR, "Authority (host) '%s' != Target '%s'", - authority_hostname, target_hostname); - abort(); + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) override { + grpc_handshake_manager_add( + handshake_mgr, + grpc_security_handshaker_create( + tsi_create_fake_handshaker(/*=is_client*/ false), this)); } - gpr_free(authority_hostname); - gpr_free(authority_ignored_port); - gpr_free(target_hostname); - gpr_free(target_ignored_port); - return true; -} -static void fake_channel_cancel_check_call_host( - grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked, - grpc_error* error) { - GRPC_ERROR_UNREF(error); -} - -static void fake_channel_add_handshakers( - grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - grpc_handshake_manager_add( - handshake_mgr, - grpc_security_handshaker_create( - tsi_create_fake_handshaker(true /* is_client */), &sc->base)); -} - -static void fake_server_add_handshakers(grpc_server_security_connector* sc, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - grpc_handshake_manager_add( - handshake_mgr, - grpc_security_handshaker_create( - tsi_create_fake_handshaker(false /* is_client */), &sc->base)); -} - -static grpc_security_connector_vtable fake_channel_vtable = { - fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp}; - -static grpc_security_connector_vtable fake_server_vtable = { - fake_server_destroy, fake_server_check_peer, fake_server_cmp}; - -grpc_channel_security_connector* grpc_fake_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, const char* target, - const grpc_channel_args* args) { - grpc_fake_channel_security_connector* c = - static_cast( - gpr_zalloc(sizeof(*c))); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; - c->base.base.vtable = &fake_channel_vtable; - c->base.channel_creds = channel_creds; - c->base.request_metadata_creds = - grpc_call_credentials_ref(request_metadata_creds); - c->base.check_call_host = fake_channel_check_call_host; - c->base.cancel_check_call_host = fake_channel_cancel_check_call_host; - c->base.add_handshakers = fake_channel_add_handshakers; - c->target = gpr_strdup(target); - const char* expected_targets = grpc_fake_transport_get_expected_targets(args); - c->expected_targets = gpr_strdup(expected_targets); - c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr; - const grpc_arg* target_name_override_arg = - grpc_channel_args_find(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); - if (target_name_override_arg != nullptr) { - c->target_name_override = - gpr_strdup(grpc_channel_arg_get_string(target_name_override_arg)); + int cmp(const grpc_security_connector* other) const override { + return server_security_connector_cmp( + static_cast(other)); } - return &c->base; +}; +} // namespace + +grpc_core::RefCountedPtr +grpc_fake_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target, const grpc_channel_args* args) { + return grpc_core::MakeRefCounted( + std::move(channel_creds), std::move(request_metadata_creds), target, + args); } -grpc_server_security_connector* grpc_fake_server_security_connector_create( - grpc_server_credentials* server_creds) { - grpc_server_security_connector* c = - static_cast( - gpr_zalloc(sizeof(grpc_server_security_connector))); - gpr_ref_init(&c->base.refcount, 1); - c->base.vtable = &fake_server_vtable; - c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; - c->server_creds = server_creds; - c->add_handshakers = fake_server_add_handshakers; - return c; +grpc_core::RefCountedPtr +grpc_fake_server_security_connector_create( + grpc_core::RefCountedPtr server_creds) { + return grpc_core::MakeRefCounted( + std::move(server_creds)); } diff --git a/src/core/lib/security/security_connector/fake/fake_security_connector.h b/src/core/lib/security/security_connector/fake/fake_security_connector.h index fdfe048c6e7..344a2349a49 100644 --- a/src/core/lib/security/security_connector/fake/fake_security_connector.h +++ b/src/core/lib/security/security_connector/fake/fake_security_connector.h @@ -24,19 +24,22 @@ #include #include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/security_connector/security_connector.h" #define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" /* Creates a fake connector that emulates real channel security. */ -grpc_channel_security_connector* grpc_fake_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, const char* target, - const grpc_channel_args* args); +grpc_core::RefCountedPtr +grpc_fake_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target, const grpc_channel_args* args); /* Creates a fake connector that emulates real server security. */ -grpc_server_security_connector* grpc_fake_server_security_connector_create( - grpc_server_credentials* server_creds); +grpc_core::RefCountedPtr +grpc_fake_server_security_connector_create( + grpc_core::RefCountedPtr server_creds); #endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_FAKE_FAKE_SECURITY_CONNECTOR_H \ */ diff --git a/src/core/lib/security/security_connector/local/local_security_connector.cc b/src/core/lib/security/security_connector/local/local_security_connector.cc index 008a98df281..7a59e54e9a7 100644 --- a/src/core/lib/security/security_connector/local/local_security_connector.cc +++ b/src/core/lib/security/security_connector/local/local_security_connector.cc @@ -30,6 +30,7 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/security/credentials/local/local_credentials.h" #include "src/core/lib/security/transport/security_handshaker.h" @@ -39,153 +40,145 @@ #define GRPC_UDS_URL_SCHEME "unix" #define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local" -typedef struct { - grpc_channel_security_connector base; - char* target_name; -} grpc_local_channel_security_connector; +namespace { -typedef struct { - grpc_server_security_connector base; -} grpc_local_server_security_connector; - -static void local_channel_destroy(grpc_security_connector* sc) { - if (sc == nullptr) { - return; - } - auto c = reinterpret_cast(sc); - grpc_call_credentials_unref(c->base.request_metadata_creds); - grpc_channel_credentials_unref(c->base.channel_creds); - gpr_free(c->target_name); - gpr_free(sc); -} - -static void local_server_destroy(grpc_security_connector* sc) { - if (sc == nullptr) { - return; - } - auto c = reinterpret_cast(sc); - grpc_server_credentials_unref(c->base.server_creds); - gpr_free(sc); -} - -static void local_channel_add_handshakers( - grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_manager) { - tsi_handshaker* handshaker = nullptr; - GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) == - TSI_OK); - grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( - handshaker, &sc->base)); -} - -static void local_server_add_handshakers( - grpc_server_security_connector* sc, grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_manager) { - tsi_handshaker* handshaker = nullptr; - GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */, &handshaker) == - TSI_OK); - grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create( - handshaker, &sc->base)); -} - -static int local_channel_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_local_channel_security_connector* c1 = - reinterpret_cast(sc1); - grpc_local_channel_security_connector* c2 = - reinterpret_cast(sc2); - int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); - if (c != 0) return c; - return strcmp(c1->target_name, c2->target_name); -} - -static int local_server_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_local_server_security_connector* c1 = - reinterpret_cast(sc1); - grpc_local_server_security_connector* c2 = - reinterpret_cast(sc2); - return grpc_server_security_connector_cmp(&c1->base, &c2->base); -} - -static grpc_security_status local_auth_context_create(grpc_auth_context** ctx) { - if (ctx == nullptr) { - gpr_log(GPR_ERROR, "Invalid arguments to local_auth_context_create()"); - return GRPC_SECURITY_ERROR; - } +grpc_core::RefCountedPtr local_auth_context_create() { /* Create auth context. */ - *ctx = grpc_auth_context_create(nullptr); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(nullptr); grpc_auth_context_add_cstring_property( - *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_LOCAL_TRANSPORT_SECURITY_TYPE); GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1); - return GRPC_SECURITY_OK; + ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1); + return ctx; } -static void local_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - grpc_security_status status; +void local_check_peer(grpc_security_connector* sc, tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) { /* Create an auth context which is necessary to pass the santiy check in - * {client, server}_auth_filter that verifies if the peer's auth context is + * {client, server}_auth_filter that verifies if the pepp's auth context is * obtained during handshakes. The auth context is only checked for its * existence and not actually used. */ - status = local_auth_context_create(auth_context); - grpc_error* error = status == GRPC_SECURITY_OK + *auth_context = local_auth_context_create(); + grpc_error* error = *auth_context != nullptr ? GRPC_ERROR_NONE : GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Could not create local auth context"); GRPC_CLOSURE_SCHED(on_peer_checked, error); } -static grpc_security_connector_vtable local_channel_vtable = { - local_channel_destroy, local_check_peer, local_channel_cmp}; - -static grpc_security_connector_vtable local_server_vtable = { - local_server_destroy, local_check_peer, local_server_cmp}; - -static bool local_check_call_host(grpc_channel_security_connector* sc, - const char* host, - grpc_auth_context* auth_context, - grpc_closure* on_call_host_checked, - grpc_error** error) { - grpc_local_channel_security_connector* local_sc = - reinterpret_cast(sc); - if (host == nullptr || local_sc == nullptr || - strcmp(host, local_sc->target_name) != 0) { - *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "local call host does not match target name"); +class grpc_local_channel_security_connector final + : public grpc_channel_security_connector { + public: + grpc_local_channel_security_connector( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const char* target_name) + : grpc_channel_security_connector(GRPC_UDS_URL_SCHEME, + std::move(channel_creds), + std::move(request_metadata_creds)), + target_name_(gpr_strdup(target_name)) {} + + ~grpc_local_channel_security_connector() override { gpr_free(target_name_); } + + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_manager) override { + tsi_handshaker* handshaker = nullptr; + GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) == + TSI_OK); + grpc_handshake_manager_add( + handshake_manager, grpc_security_handshaker_create(handshaker, this)); } - return true; -} -static void local_cancel_check_call_host(grpc_channel_security_connector* sc, - grpc_closure* on_call_host_checked, - grpc_error* error) { - GRPC_ERROR_UNREF(error); -} + int cmp(const grpc_security_connector* other_sc) const override { + auto* other = + reinterpret_cast( + other_sc); + int c = channel_security_connector_cmp(other); + if (c != 0) return c; + return strcmp(target_name_, other->target_name_); + } + + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + local_check_peer(this, peer, auth_context, on_peer_checked); + } + + bool check_call_host(const char* host, grpc_auth_context* auth_context, + grpc_closure* on_call_host_checked, + grpc_error** error) override { + if (host == nullptr || strcmp(host, target_name_) != 0) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "local call host does not match target name"); + } + return true; + } -grpc_security_status grpc_local_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, - const grpc_channel_args* args, const char* target_name, - grpc_channel_security_connector** sc) { - if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) { + void cancel_check_call_host(grpc_closure* on_call_host_checked, + grpc_error* error) override { + GRPC_ERROR_UNREF(error); + } + + const char* target_name() const { return target_name_; } + + private: + char* target_name_; +}; + +class grpc_local_server_security_connector final + : public grpc_server_security_connector { + public: + grpc_local_server_security_connector( + grpc_core::RefCountedPtr server_creds) + : grpc_server_security_connector(GRPC_UDS_URL_SCHEME, + std::move(server_creds)) {} + ~grpc_local_server_security_connector() override = default; + + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_manager) override { + tsi_handshaker* handshaker = nullptr; + GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */, + &handshaker) == TSI_OK); + grpc_handshake_manager_add( + handshake_manager, grpc_security_handshaker_create(handshaker, this)); + } + + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + local_check_peer(this, peer, auth_context, on_peer_checked); + } + + int cmp(const grpc_security_connector* other) const override { + return server_security_connector_cmp( + static_cast(other)); + } +}; +} // namespace + +grpc_core::RefCountedPtr +grpc_local_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const grpc_channel_args* args, const char* target_name) { + if (channel_creds == nullptr || target_name == nullptr) { gpr_log( GPR_ERROR, "Invalid arguments to grpc_local_channel_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } // Check if local_connect_type is UDS. Only UDS is supported for now. grpc_local_credentials* creds = - reinterpret_cast(channel_creds); - if (creds->connect_type != UDS) { + static_cast(channel_creds.get()); + if (creds->connect_type() != UDS) { gpr_log(GPR_ERROR, "Invalid local channel type to " "grpc_local_channel_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } // Check if target_name is a valid UDS address. const grpc_arg* server_uri_arg = @@ -196,51 +189,30 @@ grpc_security_status grpc_local_channel_security_connector_create( gpr_log(GPR_ERROR, "Invalid target_name to " "grpc_local_channel_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } - auto c = static_cast( - gpr_zalloc(sizeof(grpc_local_channel_security_connector))); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &local_channel_vtable; - c->base.add_handshakers = local_channel_add_handshakers; - c->base.channel_creds = grpc_channel_credentials_ref(channel_creds); - c->base.request_metadata_creds = - grpc_call_credentials_ref(request_metadata_creds); - c->base.check_call_host = local_check_call_host; - c->base.cancel_check_call_host = local_cancel_check_call_host; - c->base.base.url_scheme = - creds->connect_type == UDS ? GRPC_UDS_URL_SCHEME : nullptr; - c->target_name = gpr_strdup(target_name); - *sc = &c->base; - return GRPC_SECURITY_OK; + return grpc_core::MakeRefCounted( + channel_creds, request_metadata_creds, target_name); } -grpc_security_status grpc_local_server_security_connector_create( - grpc_server_credentials* server_creds, - grpc_server_security_connector** sc) { - if (server_creds == nullptr || sc == nullptr) { +grpc_core::RefCountedPtr +grpc_local_server_security_connector_create( + grpc_core::RefCountedPtr server_creds) { + if (server_creds == nullptr) { gpr_log( GPR_ERROR, "Invalid arguments to grpc_local_server_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } // Check if local_connect_type is UDS. Only UDS is supported for now. - grpc_local_server_credentials* creds = - reinterpret_cast(server_creds); - if (creds->connect_type != UDS) { + const grpc_local_server_credentials* creds = + static_cast(server_creds.get()); + if (creds->connect_type() != UDS) { gpr_log(GPR_ERROR, "Invalid local server type to " "grpc_local_server_security_connector_create()"); - return GRPC_SECURITY_ERROR; + return nullptr; } - auto c = static_cast( - gpr_zalloc(sizeof(grpc_local_server_security_connector))); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &local_server_vtable; - c->base.server_creds = grpc_server_credentials_ref(server_creds); - c->base.base.url_scheme = - creds->connect_type == UDS ? GRPC_UDS_URL_SCHEME : nullptr; - c->base.add_handshakers = local_server_add_handshakers; - *sc = &c->base; - return GRPC_SECURITY_OK; + return grpc_core::MakeRefCounted( + std::move(server_creds)); } diff --git a/src/core/lib/security/security_connector/local/local_security_connector.h b/src/core/lib/security/security_connector/local/local_security_connector.h index 5369a2127aa..6eee0ca9a6c 100644 --- a/src/core/lib/security/security_connector/local/local_security_connector.h +++ b/src/core/lib/security/security_connector/local/local_security_connector.h @@ -34,13 +34,13 @@ * - sc: address of local channel security connector instance to be returned * from the method. * - * It returns GRPC_SECURITY_OK on success, and an error stauts code on failure. + * It returns nullptr on failure. */ -grpc_security_status grpc_local_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, - const grpc_channel_args* args, const char* target_name, - grpc_channel_security_connector** sc); +grpc_core::RefCountedPtr +grpc_local_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const grpc_channel_args* args, const char* target_name); /** * This method creates a local server security connector. @@ -49,10 +49,11 @@ grpc_security_status grpc_local_channel_security_connector_create( * - sc: address of local server security connector instance to be returned from * the method. * - * It returns GRPC_SECURITY_OK on success, and an error status code on failure. + * It returns nullptr on failure. */ -grpc_security_status grpc_local_server_security_connector_create( - grpc_server_credentials* server_creds, grpc_server_security_connector** sc); +grpc_core::RefCountedPtr +grpc_local_server_security_connector_create( + grpc_core::RefCountedPtr server_creds); #endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_LOCAL_SECURITY_CONNECTOR_H \ */ diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc index 02cecb0eb1e..96a19605466 100644 --- a/src/core/lib/security/security_connector/security_connector.cc +++ b/src/core/lib/security/security_connector/security_connector.cc @@ -35,150 +35,67 @@ #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/security_connector/load_system_roots.h" +#include "src/core/lib/security/security_connector/security_connector.h" #include "src/core/lib/security/transport/security_handshaker.h" grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount( false, "security_connector_refcount"); -void grpc_channel_security_connector_add_handshakers( - grpc_channel_security_connector* connector, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - if (connector != nullptr) { - connector->add_handshakers(connector, interested_parties, handshake_mgr); - } -} - -void grpc_server_security_connector_add_handshakers( - grpc_server_security_connector* connector, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - if (connector != nullptr) { - connector->add_handshakers(connector, interested_parties, handshake_mgr); - } -} - -void grpc_security_connector_check_peer(grpc_security_connector* sc, - tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - if (sc == nullptr) { - GRPC_CLOSURE_SCHED(on_peer_checked, - GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "cannot check peer -- no security connector")); - tsi_peer_destruct(&peer); - } else { - sc->vtable->check_peer(sc, peer, auth_context, on_peer_checked); - } -} - -int grpc_security_connector_cmp(grpc_security_connector* sc, - grpc_security_connector* other) { +grpc_server_security_connector::grpc_server_security_connector( + const char* url_scheme, + grpc_core::RefCountedPtr server_creds) + : grpc_security_connector(url_scheme), + server_creds_(std::move(server_creds)) {} + +grpc_channel_security_connector::grpc_channel_security_connector( + const char* url_scheme, + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds) + : grpc_security_connector(url_scheme), + channel_creds_(std::move(channel_creds)), + request_metadata_creds_(std::move(request_metadata_creds)) {} +grpc_channel_security_connector::~grpc_channel_security_connector() {} + +int grpc_security_connector_cmp(const grpc_security_connector* sc, + const grpc_security_connector* other) { if (sc == nullptr || other == nullptr) return GPR_ICMP(sc, other); - int c = GPR_ICMP(sc->vtable, other->vtable); - if (c != 0) return c; - return sc->vtable->cmp(sc, other); + return sc->cmp(other); } -int grpc_channel_security_connector_cmp(grpc_channel_security_connector* sc1, - grpc_channel_security_connector* sc2) { - GPR_ASSERT(sc1->channel_creds != nullptr); - GPR_ASSERT(sc2->channel_creds != nullptr); - int c = GPR_ICMP(sc1->channel_creds, sc2->channel_creds); - if (c != 0) return c; - c = GPR_ICMP(sc1->request_metadata_creds, sc2->request_metadata_creds); - if (c != 0) return c; - c = GPR_ICMP((void*)sc1->check_call_host, (void*)sc2->check_call_host); - if (c != 0) return c; - c = GPR_ICMP((void*)sc1->cancel_check_call_host, - (void*)sc2->cancel_check_call_host); +int grpc_channel_security_connector::channel_security_connector_cmp( + const grpc_channel_security_connector* other) const { + const grpc_channel_security_connector* other_sc = + static_cast(other); + GPR_ASSERT(channel_creds() != nullptr); + GPR_ASSERT(other_sc->channel_creds() != nullptr); + int c = GPR_ICMP(channel_creds(), other_sc->channel_creds()); if (c != 0) return c; - return GPR_ICMP((void*)sc1->add_handshakers, (void*)sc2->add_handshakers); + return GPR_ICMP(request_metadata_creds(), other_sc->request_metadata_creds()); } -int grpc_server_security_connector_cmp(grpc_server_security_connector* sc1, - grpc_server_security_connector* sc2) { - GPR_ASSERT(sc1->server_creds != nullptr); - GPR_ASSERT(sc2->server_creds != nullptr); - int c = GPR_ICMP(sc1->server_creds, sc2->server_creds); - if (c != 0) return c; - return GPR_ICMP((void*)sc1->add_handshakers, (void*)sc2->add_handshakers); -} - -bool grpc_channel_security_connector_check_call_host( - grpc_channel_security_connector* sc, const char* host, - grpc_auth_context* auth_context, grpc_closure* on_call_host_checked, - grpc_error** error) { - if (sc == nullptr || sc->check_call_host == nullptr) { - *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "cannot check call host -- no security connector"); - return true; - } - return sc->check_call_host(sc, host, auth_context, on_call_host_checked, - error); -} - -void grpc_channel_security_connector_cancel_check_call_host( - grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked, - grpc_error* error) { - if (sc == nullptr || sc->cancel_check_call_host == nullptr) { - GRPC_ERROR_UNREF(error); - return; - } - sc->cancel_check_call_host(sc, on_call_host_checked, error); -} - -#ifndef NDEBUG -grpc_security_connector* grpc_security_connector_ref( - grpc_security_connector* sc, const char* file, int line, - const char* reason) { - if (sc == nullptr) return nullptr; - if (grpc_trace_security_connector_refcount.enabled()) { - gpr_atm val = gpr_atm_no_barrier_load(&sc->refcount.count); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SECURITY_CONNECTOR:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", sc, - val, val + 1, reason); - } -#else -grpc_security_connector* grpc_security_connector_ref( - grpc_security_connector* sc) { - if (sc == nullptr) return nullptr; -#endif - gpr_ref(&sc->refcount); - return sc; -} - -#ifndef NDEBUG -void grpc_security_connector_unref(grpc_security_connector* sc, - const char* file, int line, - const char* reason) { - if (sc == nullptr) return; - if (grpc_trace_security_connector_refcount.enabled()) { - gpr_atm val = gpr_atm_no_barrier_load(&sc->refcount.count); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SECURITY_CONNECTOR:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", sc, - val, val - 1, reason); - } -#else -void grpc_security_connector_unref(grpc_security_connector* sc) { - if (sc == nullptr) return; -#endif - if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); +int grpc_server_security_connector::server_security_connector_cmp( + const grpc_server_security_connector* other) const { + const grpc_server_security_connector* other_sc = + static_cast(other); + GPR_ASSERT(server_creds() != nullptr); + GPR_ASSERT(other_sc->server_creds() != nullptr); + return GPR_ICMP(server_creds(), other_sc->server_creds()); } static void connector_arg_destroy(void* p) { - GRPC_SECURITY_CONNECTOR_UNREF((grpc_security_connector*)p, - "connector_arg_destroy"); + static_cast(p)->Unref(DEBUG_LOCATION, + "connector_arg_destroy"); } static void* connector_arg_copy(void* p) { - return GRPC_SECURITY_CONNECTOR_REF((grpc_security_connector*)p, - "connector_arg_copy"); + return static_cast(p) + ->Ref(DEBUG_LOCATION, "connector_arg_copy") + .release(); } static int connector_cmp(void* a, void* b) { - return grpc_security_connector_cmp(static_cast(a), - static_cast(b)); + return static_cast(a)->cmp( + static_cast(b)); } static const grpc_arg_pointer_vtable connector_arg_vtable = { diff --git a/src/core/lib/security/security_connector/security_connector.h b/src/core/lib/security/security_connector/security_connector.h index 4c921a87931..d90aa8c4dab 100644 --- a/src/core/lib/security/security_connector/security_connector.h +++ b/src/core/lib/security/security_connector/security_connector.h @@ -26,6 +26,7 @@ #include #include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/tcp_server.h" @@ -34,8 +35,6 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount; -/* --- status enum. --- */ - typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status; /* --- security_connector object. --- @@ -43,54 +42,33 @@ typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status; A security connector object represents away to configure the underlying transport security mechanism and check the resulting trusted peer. */ -typedef struct grpc_security_connector grpc_security_connector; - #define GRPC_ARG_SECURITY_CONNECTOR "grpc.security_connector" -typedef struct { - void (*destroy)(grpc_security_connector* sc); - void (*check_peer)(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked); - int (*cmp)(grpc_security_connector* sc, grpc_security_connector* other); -} grpc_security_connector_vtable; - -struct grpc_security_connector { - const grpc_security_connector_vtable* vtable; - gpr_refcount refcount; - const char* url_scheme; -}; +class grpc_security_connector + : public grpc_core::RefCounted { + public: + explicit grpc_security_connector(const char* url_scheme) + : grpc_core::RefCounted( + &grpc_trace_security_connector_refcount), + url_scheme_(url_scheme) {} + virtual ~grpc_security_connector() = default; + + /* Check the peer. Callee takes ownership of the peer object. + When done, sets *auth_context and invokes on_peer_checked. */ + virtual void check_peer( + tsi_peer peer, grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) GRPC_ABSTRACT; + + /* Compares two security connectors. */ + virtual int cmp(const grpc_security_connector* other) const GRPC_ABSTRACT; + + const char* url_scheme() const { return url_scheme_; } -/* Refcounting. */ -#ifndef NDEBUG -#define GRPC_SECURITY_CONNECTOR_REF(p, r) \ - grpc_security_connector_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \ - grpc_security_connector_unref((p), __FILE__, __LINE__, (r)) -grpc_security_connector* grpc_security_connector_ref( - grpc_security_connector* policy, const char* file, int line, - const char* reason); -void grpc_security_connector_unref(grpc_security_connector* policy, - const char* file, int line, - const char* reason); -#else -#define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p)) -#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p)) -grpc_security_connector* grpc_security_connector_ref( - grpc_security_connector* policy); -void grpc_security_connector_unref(grpc_security_connector* policy); -#endif - -/* Check the peer. Callee takes ownership of the peer object. - When done, sets *auth_context and invokes on_peer_checked. */ -void grpc_security_connector_check_peer(grpc_security_connector* sc, - tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked); - -/* Compares two security connectors. */ -int grpc_security_connector_cmp(grpc_security_connector* sc, - grpc_security_connector* other); + GRPC_ABSTRACT_BASE_CLASS + + private: + const char* url_scheme_; +}; /* Util to encapsulate the connector in a channel arg. */ grpc_arg grpc_security_connector_to_arg(grpc_security_connector* sc); @@ -107,71 +85,89 @@ grpc_security_connector* grpc_security_connector_find_in_args( A channel security connector object represents a way to configure the underlying transport security mechanism on the client side. */ -typedef struct grpc_channel_security_connector grpc_channel_security_connector; - -struct grpc_channel_security_connector { - grpc_security_connector base; - grpc_channel_credentials* channel_creds; - grpc_call_credentials* request_metadata_creds; - bool (*check_call_host)(grpc_channel_security_connector* sc, const char* host, - grpc_auth_context* auth_context, - grpc_closure* on_call_host_checked, - grpc_error** error); - void (*cancel_check_call_host)(grpc_channel_security_connector* sc, - grpc_closure* on_call_host_checked, - grpc_error* error); - void (*add_handshakers)(grpc_channel_security_connector* sc, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr); +class grpc_channel_security_connector : public grpc_security_connector { + public: + grpc_channel_security_connector( + const char* url_scheme, + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds); + ~grpc_channel_security_connector() override; + + /// Checks that the host that will be set for a call is acceptable. + /// Returns true if completed synchronously, in which case \a error will + /// be set to indicate the result. Otherwise, \a on_call_host_checked + /// will be invoked when complete. + virtual bool check_call_host(const char* host, + grpc_auth_context* auth_context, + grpc_closure* on_call_host_checked, + grpc_error** error) GRPC_ABSTRACT; + /// Cancels a pending asychronous call to + /// grpc_channel_security_connector_check_call_host() with + /// \a on_call_host_checked as its callback. + virtual void cancel_check_call_host(grpc_closure* on_call_host_checked, + grpc_error* error) GRPC_ABSTRACT; + /// Registers handshakers with \a handshake_mgr. + virtual void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) + GRPC_ABSTRACT; + + const grpc_channel_credentials* channel_creds() const { + return channel_creds_.get(); + } + grpc_channel_credentials* mutable_channel_creds() { + return channel_creds_.get(); + } + const grpc_call_credentials* request_metadata_creds() const { + return request_metadata_creds_.get(); + } + grpc_call_credentials* mutable_request_metadata_creds() { + return request_metadata_creds_.get(); + } + + GRPC_ABSTRACT_BASE_CLASS + + protected: + // Helper methods to be used in subclasses. + int channel_security_connector_cmp( + const grpc_channel_security_connector* other) const; + + private: + grpc_core::RefCountedPtr channel_creds_; + grpc_core::RefCountedPtr request_metadata_creds_; }; -/// A helper function for use in grpc_security_connector_cmp() implementations. -int grpc_channel_security_connector_cmp(grpc_channel_security_connector* sc1, - grpc_channel_security_connector* sc2); - -/// Checks that the host that will be set for a call is acceptable. -/// Returns true if completed synchronously, in which case \a error will -/// be set to indicate the result. Otherwise, \a on_call_host_checked -/// will be invoked when complete. -bool grpc_channel_security_connector_check_call_host( - grpc_channel_security_connector* sc, const char* host, - grpc_auth_context* auth_context, grpc_closure* on_call_host_checked, - grpc_error** error); - -/// Cancels a pending asychronous call to -/// grpc_channel_security_connector_check_call_host() with -/// \a on_call_host_checked as its callback. -void grpc_channel_security_connector_cancel_check_call_host( - grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked, - grpc_error* error); - -/* Registers handshakers with \a handshake_mgr. */ -void grpc_channel_security_connector_add_handshakers( - grpc_channel_security_connector* connector, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr); - /* --- server_security_connector object. --- A server security connector object represents a way to configure the underlying transport security mechanism on the server side. */ -typedef struct grpc_server_security_connector grpc_server_security_connector; - -struct grpc_server_security_connector { - grpc_security_connector base; - grpc_server_credentials* server_creds; - void (*add_handshakers)(grpc_server_security_connector* sc, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr); +class grpc_server_security_connector : public grpc_security_connector { + public: + grpc_server_security_connector( + const char* url_scheme, + grpc_core::RefCountedPtr server_creds); + ~grpc_server_security_connector() override = default; + + virtual void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) + GRPC_ABSTRACT; + + const grpc_server_credentials* server_creds() const { + return server_creds_.get(); + } + grpc_server_credentials* mutable_server_creds() { + return server_creds_.get(); + } + + GRPC_ABSTRACT_BASE_CLASS + + protected: + // Helper methods to be used in subclasses. + int server_security_connector_cmp( + const grpc_server_security_connector* other) const; + + private: + grpc_core::RefCountedPtr server_creds_; }; -/// A helper function for use in grpc_security_connector_cmp() implementations. -int grpc_server_security_connector_cmp(grpc_server_security_connector* sc1, - grpc_server_security_connector* sc2); - -void grpc_server_security_connector_add_handshakers( - grpc_server_security_connector* sc, grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr); - #endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H */ diff --git a/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc b/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc index 20a9533dd13..14b2c4030f2 100644 --- a/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc +++ b/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc @@ -30,6 +30,7 @@ #include "src/core/lib/channel/handshaker.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/ssl/ssl_credentials.h" @@ -39,172 +40,10 @@ #include "src/core/tsi/ssl_transport_security.h" #include "src/core/tsi/transport_security.h" -typedef struct { - grpc_channel_security_connector base; - tsi_ssl_client_handshaker_factory* client_handshaker_factory; - char* target_name; - char* overridden_target_name; - const verify_peer_options* verify_options; -} grpc_ssl_channel_security_connector; - -typedef struct { - grpc_server_security_connector base; - tsi_ssl_server_handshaker_factory* server_handshaker_factory; -} grpc_ssl_server_security_connector; - -static bool server_connector_has_cert_config_fetcher( - grpc_ssl_server_security_connector* c) { - GPR_ASSERT(c != nullptr); - grpc_ssl_server_credentials* server_creds = - reinterpret_cast(c->base.server_creds); - GPR_ASSERT(server_creds != nullptr); - return server_creds->certificate_config_fetcher.cb != nullptr; -} - -static void ssl_channel_destroy(grpc_security_connector* sc) { - grpc_ssl_channel_security_connector* c = - reinterpret_cast(sc); - grpc_channel_credentials_unref(c->base.channel_creds); - grpc_call_credentials_unref(c->base.request_metadata_creds); - tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory); - c->client_handshaker_factory = nullptr; - if (c->target_name != nullptr) gpr_free(c->target_name); - if (c->overridden_target_name != nullptr) gpr_free(c->overridden_target_name); - gpr_free(sc); -} - -static void ssl_server_destroy(grpc_security_connector* sc) { - grpc_ssl_server_security_connector* c = - reinterpret_cast(sc); - grpc_server_credentials_unref(c->base.server_creds); - tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory); - c->server_handshaker_factory = nullptr; - gpr_free(sc); -} - -static void ssl_channel_add_handshakers(grpc_channel_security_connector* sc, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - grpc_ssl_channel_security_connector* c = - reinterpret_cast(sc); - // Instantiate TSI handshaker. - tsi_handshaker* tsi_hs = nullptr; - tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( - c->client_handshaker_factory, - c->overridden_target_name != nullptr ? c->overridden_target_name - : c->target_name, - &tsi_hs); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", - tsi_result_to_string(result)); - return; - } - // Create handshakers. - grpc_handshake_manager_add( - handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base)); -} - -/* Attempts to replace the server_handshaker_factory with a new factory using - * the provided grpc_ssl_server_certificate_config. Should new factory creation - * fail, the existing factory will not be replaced. Returns true on success (new - * factory created). */ -static bool try_replace_server_handshaker_factory( - grpc_ssl_server_security_connector* sc, - const grpc_ssl_server_certificate_config* config) { - if (config == nullptr) { - gpr_log(GPR_ERROR, - "Server certificate config callback returned invalid (NULL) " - "config."); - return false; - } - gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config); - - size_t num_alpn_protocols = 0; - const char** alpn_protocol_strings = - grpc_fill_alpn_protocol_strings(&num_alpn_protocols); - tsi_ssl_pem_key_cert_pair* cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( - config->pem_key_cert_pairs, config->num_key_cert_pairs); - tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr; - grpc_ssl_server_credentials* server_creds = - reinterpret_cast(sc->base.server_creds); - tsi_result result = tsi_create_ssl_server_handshaker_factory_ex( - cert_pairs, config->num_key_cert_pairs, config->pem_root_certs, - grpc_get_tsi_client_certificate_request_type( - server_creds->config.client_certificate_request), - grpc_get_ssl_cipher_suites(), alpn_protocol_strings, - static_cast(num_alpn_protocols), &new_handshaker_factory); - gpr_free(cert_pairs); - gpr_free((void*)alpn_protocol_strings); - - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - return false; - } - tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory); - sc->server_handshaker_factory = new_handshaker_factory; - return true; -} - -/* Attempts to fetch the server certificate config if a callback is available. - * Current certificate config will continue to be used if the callback returns - * an error. Returns true if new credentials were sucessfully loaded. */ -static bool try_fetch_ssl_server_credentials( - grpc_ssl_server_security_connector* sc) { - grpc_ssl_server_certificate_config* certificate_config = nullptr; - bool status; - - GPR_ASSERT(sc != nullptr); - if (!server_connector_has_cert_config_fetcher(sc)) return false; - - grpc_ssl_server_credentials* server_creds = - reinterpret_cast(sc->base.server_creds); - grpc_ssl_certificate_config_reload_status cb_result = - server_creds->certificate_config_fetcher.cb( - server_creds->certificate_config_fetcher.user_data, - &certificate_config); - if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { - gpr_log(GPR_DEBUG, "No change in SSL server credentials."); - status = false; - } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { - status = try_replace_server_handshaker_factory(sc, certificate_config); - } else { - // Log error, continue using previously-loaded credentials. - gpr_log(GPR_ERROR, - "Failed fetching new server credentials, continuing to " - "use previously-loaded credentials."); - status = false; - } - - if (certificate_config != nullptr) { - grpc_ssl_server_certificate_config_destroy(certificate_config); - } - return status; -} - -static void ssl_server_add_handshakers(grpc_server_security_connector* sc, - grpc_pollset_set* interested_parties, - grpc_handshake_manager* handshake_mgr) { - grpc_ssl_server_security_connector* c = - reinterpret_cast(sc); - // Instantiate TSI handshaker. - try_fetch_ssl_server_credentials(c); - tsi_handshaker* tsi_hs = nullptr; - tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( - c->server_handshaker_factory, &tsi_hs); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", - tsi_result_to_string(result)); - return; - } - // Create handshakers. - grpc_handshake_manager_add( - handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base)); -} - -static grpc_error* ssl_check_peer(grpc_security_connector* sc, - const char* peer_name, const tsi_peer* peer, - grpc_auth_context** auth_context) { +namespace { +grpc_error* ssl_check_peer( + const char* peer_name, const tsi_peer* peer, + grpc_core::RefCountedPtr* auth_context) { #if TSI_OPENSSL_ALPN_SUPPORT /* Check the ALPN if ALPN is supported. */ const tsi_peer_property* p = @@ -230,245 +69,384 @@ static grpc_error* ssl_check_peer(grpc_security_connector* sc, return GRPC_ERROR_NONE; } -static void ssl_channel_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - grpc_ssl_channel_security_connector* c = - reinterpret_cast(sc); - const char* target_name = c->overridden_target_name != nullptr - ? c->overridden_target_name - : c->target_name; - grpc_error* error = ssl_check_peer(sc, target_name, &peer, auth_context); - if (error == GRPC_ERROR_NONE && - c->verify_options->verify_peer_callback != nullptr) { - const tsi_peer_property* p = - tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY); - if (p == nullptr) { - error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Cannot check peer: missing pem cert property."); - } else { - char* peer_pem = static_cast(gpr_malloc(p->value.length + 1)); - memcpy(peer_pem, p->value.data, p->value.length); - peer_pem[p->value.length] = '\0'; - int callback_status = c->verify_options->verify_peer_callback( - target_name, peer_pem, - c->verify_options->verify_peer_callback_userdata); - gpr_free(peer_pem); - if (callback_status) { - char* msg; - gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)", - callback_status); - error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); - gpr_free(msg); - } - } +class grpc_ssl_channel_security_connector final + : public grpc_channel_security_connector { + public: + grpc_ssl_channel_security_connector( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const grpc_ssl_config* config, const char* target_name, + const char* overridden_target_name) + : grpc_channel_security_connector(GRPC_SSL_URL_SCHEME, + std::move(channel_creds), + std::move(request_metadata_creds)), + overridden_target_name_(overridden_target_name == nullptr + ? nullptr + : gpr_strdup(overridden_target_name)), + verify_options_(&config->verify_options) { + char* port; + gpr_split_host_port(target_name, &target_name_, &port); + gpr_free(port); } - GRPC_CLOSURE_SCHED(on_peer_checked, error); - tsi_peer_destruct(&peer); -} -static void ssl_server_check_peer(grpc_security_connector* sc, tsi_peer peer, - grpc_auth_context** auth_context, - grpc_closure* on_peer_checked) { - grpc_error* error = ssl_check_peer(sc, nullptr, &peer, auth_context); - tsi_peer_destruct(&peer); - GRPC_CLOSURE_SCHED(on_peer_checked, error); -} + ~grpc_ssl_channel_security_connector() override { + tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_); + if (target_name_ != nullptr) gpr_free(target_name_); + if (overridden_target_name_ != nullptr) gpr_free(overridden_target_name_); + } -static int ssl_channel_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - grpc_ssl_channel_security_connector* c1 = - reinterpret_cast(sc1); - grpc_ssl_channel_security_connector* c2 = - reinterpret_cast(sc2); - int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); - if (c != 0) return c; - c = strcmp(c1->target_name, c2->target_name); - if (c != 0) return c; - return (c1->overridden_target_name == nullptr || - c2->overridden_target_name == nullptr) - ? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name) - : strcmp(c1->overridden_target_name, c2->overridden_target_name); -} + grpc_security_status InitializeHandshakerFactory( + const grpc_ssl_config* config, const char* pem_root_certs, + const tsi_ssl_root_certs_store* root_store, + tsi_ssl_session_cache* ssl_session_cache) { + bool has_key_cert_pair = + config->pem_key_cert_pair != nullptr && + config->pem_key_cert_pair->private_key != nullptr && + config->pem_key_cert_pair->cert_chain != nullptr; + tsi_ssl_client_handshaker_options options; + memset(&options, 0, sizeof(options)); + GPR_DEBUG_ASSERT(pem_root_certs != nullptr); + options.pem_root_certs = pem_root_certs; + options.root_store = root_store; + options.alpn_protocols = + grpc_fill_alpn_protocol_strings(&options.num_alpn_protocols); + if (has_key_cert_pair) { + options.pem_key_cert_pair = config->pem_key_cert_pair; + } + options.cipher_suites = grpc_get_ssl_cipher_suites(); + options.session_cache = ssl_session_cache; + const tsi_result result = + tsi_create_ssl_client_handshaker_factory_with_options( + &options, &client_handshaker_factory_); + gpr_free((void*)options.alpn_protocols); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + return GRPC_SECURITY_ERROR; + } + return GRPC_SECURITY_OK; + } -static int ssl_server_cmp(grpc_security_connector* sc1, - grpc_security_connector* sc2) { - return grpc_server_security_connector_cmp( - reinterpret_cast(sc1), - reinterpret_cast(sc2)); -} + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) override { + // Instantiate TSI handshaker. + tsi_handshaker* tsi_hs = nullptr; + tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( + client_handshaker_factory_, + overridden_target_name_ != nullptr ? overridden_target_name_ + : target_name_, + &tsi_hs); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", + tsi_result_to_string(result)); + return; + } + // Create handshakers. + grpc_handshake_manager_add(handshake_mgr, + grpc_security_handshaker_create(tsi_hs, this)); + } -static bool ssl_channel_check_call_host(grpc_channel_security_connector* sc, - const char* host, - grpc_auth_context* auth_context, - grpc_closure* on_call_host_checked, - grpc_error** error) { - grpc_ssl_channel_security_connector* c = - reinterpret_cast(sc); - grpc_security_status status = GRPC_SECURITY_ERROR; - tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context); - if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK; - /* If the target name was overridden, then the original target_name was - 'checked' transitively during the previous peer check at the end of the - handshake. */ - if (c->overridden_target_name != nullptr && - strcmp(host, c->target_name) == 0) { - status = GRPC_SECURITY_OK; + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + const char* target_name = overridden_target_name_ != nullptr + ? overridden_target_name_ + : target_name_; + grpc_error* error = ssl_check_peer(target_name, &peer, auth_context); + if (error == GRPC_ERROR_NONE && + verify_options_->verify_peer_callback != nullptr) { + const tsi_peer_property* p = + tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY); + if (p == nullptr) { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Cannot check peer: missing pem cert property."); + } else { + char* peer_pem = static_cast(gpr_malloc(p->value.length + 1)); + memcpy(peer_pem, p->value.data, p->value.length); + peer_pem[p->value.length] = '\0'; + int callback_status = verify_options_->verify_peer_callback( + target_name, peer_pem, + verify_options_->verify_peer_callback_userdata); + gpr_free(peer_pem); + if (callback_status) { + char* msg; + gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)", + callback_status); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + gpr_free(msg); + } + } + } + GRPC_CLOSURE_SCHED(on_peer_checked, error); + tsi_peer_destruct(&peer); } - if (status != GRPC_SECURITY_OK) { - *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "call host does not match SSL server name"); + + int cmp(const grpc_security_connector* other_sc) const override { + auto* other = + reinterpret_cast(other_sc); + int c = channel_security_connector_cmp(other); + if (c != 0) return c; + c = strcmp(target_name_, other->target_name_); + if (c != 0) return c; + return (overridden_target_name_ == nullptr || + other->overridden_target_name_ == nullptr) + ? GPR_ICMP(overridden_target_name_, + other->overridden_target_name_) + : strcmp(overridden_target_name_, + other->overridden_target_name_); } - grpc_shallow_peer_destruct(&peer); - return true; -} -static void ssl_channel_cancel_check_call_host( - grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked, - grpc_error* error) { - GRPC_ERROR_UNREF(error); -} + bool check_call_host(const char* host, grpc_auth_context* auth_context, + grpc_closure* on_call_host_checked, + grpc_error** error) override { + grpc_security_status status = GRPC_SECURITY_ERROR; + tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context); + if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK; + /* If the target name was overridden, then the original target_name was + 'checked' transitively during the previous peer check at the end of the + handshake. */ + if (overridden_target_name_ != nullptr && strcmp(host, target_name_) == 0) { + status = GRPC_SECURITY_OK; + } + if (status != GRPC_SECURITY_OK) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "call host does not match SSL server name"); + } + grpc_shallow_peer_destruct(&peer); + return true; + } -static grpc_security_connector_vtable ssl_channel_vtable = { - ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp}; + void cancel_check_call_host(grpc_closure* on_call_host_checked, + grpc_error* error) override { + GRPC_ERROR_UNREF(error); + } -static grpc_security_connector_vtable ssl_server_vtable = { - ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp}; + private: + tsi_ssl_client_handshaker_factory* client_handshaker_factory_; + char* target_name_; + char* overridden_target_name_; + const verify_peer_options* verify_options_; +}; + +class grpc_ssl_server_security_connector + : public grpc_server_security_connector { + public: + grpc_ssl_server_security_connector( + grpc_core::RefCountedPtr server_creds) + : grpc_server_security_connector(GRPC_SSL_URL_SCHEME, + std::move(server_creds)) {} + + ~grpc_ssl_server_security_connector() override { + tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_); + } -grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, - const grpc_ssl_config* config, const char* target_name, - const char* overridden_target_name, - tsi_ssl_session_cache* ssl_session_cache, - grpc_channel_security_connector** sc) { - tsi_result result = TSI_OK; - grpc_ssl_channel_security_connector* c; - char* port; - bool has_key_cert_pair; - tsi_ssl_client_handshaker_options options; - memset(&options, 0, sizeof(options)); - options.alpn_protocols = - grpc_fill_alpn_protocol_strings(&options.num_alpn_protocols); + bool has_cert_config_fetcher() const { + return static_cast(server_creds()) + ->has_cert_config_fetcher(); + } - if (config == nullptr || target_name == nullptr) { - gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); - goto error; + const tsi_ssl_server_handshaker_factory* server_handshaker_factory() const { + return server_handshaker_factory_; } - if (config->pem_root_certs == nullptr) { - // Use default root certificates. - options.pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts(); - options.root_store = grpc_core::DefaultSslRootStore::GetRootStore(); - if (options.pem_root_certs == nullptr) { - gpr_log(GPR_ERROR, "Could not get default pem root certs."); - goto error; + + grpc_security_status InitializeHandshakerFactory() { + if (has_cert_config_fetcher()) { + // Load initial credentials from certificate_config_fetcher: + if (!try_fetch_ssl_server_credentials()) { + gpr_log(GPR_ERROR, + "Failed loading SSL server credentials from fetcher."); + return GRPC_SECURITY_ERROR; + } + } else { + auto* server_credentials = + static_cast(server_creds()); + size_t num_alpn_protocols = 0; + const char** alpn_protocol_strings = + grpc_fill_alpn_protocol_strings(&num_alpn_protocols); + const tsi_result result = tsi_create_ssl_server_handshaker_factory_ex( + server_credentials->config().pem_key_cert_pairs, + server_credentials->config().num_key_cert_pairs, + server_credentials->config().pem_root_certs, + grpc_get_tsi_client_certificate_request_type( + server_credentials->config().client_certificate_request), + grpc_get_ssl_cipher_suites(), alpn_protocol_strings, + static_cast(num_alpn_protocols), + &server_handshaker_factory_); + gpr_free((void*)alpn_protocol_strings); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + return GRPC_SECURITY_ERROR; + } } - } else { - options.pem_root_certs = config->pem_root_certs; - } - c = static_cast( - gpr_zalloc(sizeof(grpc_ssl_channel_security_connector))); - - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &ssl_channel_vtable; - c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.channel_creds = grpc_channel_credentials_ref(channel_creds); - c->base.request_metadata_creds = - grpc_call_credentials_ref(request_metadata_creds); - c->base.check_call_host = ssl_channel_check_call_host; - c->base.cancel_check_call_host = ssl_channel_cancel_check_call_host; - c->base.add_handshakers = ssl_channel_add_handshakers; - gpr_split_host_port(target_name, &c->target_name, &port); - gpr_free(port); - if (overridden_target_name != nullptr) { - c->overridden_target_name = gpr_strdup(overridden_target_name); + return GRPC_SECURITY_OK; } - c->verify_options = &config->verify_options; - has_key_cert_pair = config->pem_key_cert_pair != nullptr && - config->pem_key_cert_pair->private_key != nullptr && - config->pem_key_cert_pair->cert_chain != nullptr; - if (has_key_cert_pair) { - options.pem_key_cert_pair = config->pem_key_cert_pair; + void add_handshakers(grpc_pollset_set* interested_parties, + grpc_handshake_manager* handshake_mgr) override { + // Instantiate TSI handshaker. + try_fetch_ssl_server_credentials(); + tsi_handshaker* tsi_hs = nullptr; + tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( + server_handshaker_factory_, &tsi_hs); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", + tsi_result_to_string(result)); + return; + } + // Create handshakers. + grpc_handshake_manager_add(handshake_mgr, + grpc_security_handshaker_create(tsi_hs, this)); } - options.cipher_suites = grpc_get_ssl_cipher_suites(); - options.session_cache = ssl_session_cache; - result = tsi_create_ssl_client_handshaker_factory_with_options( - &options, &c->client_handshaker_factory); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - ssl_channel_destroy(&c->base.base); - *sc = nullptr; - goto error; + + void check_peer(tsi_peer peer, + grpc_core::RefCountedPtr* auth_context, + grpc_closure* on_peer_checked) override { + grpc_error* error = ssl_check_peer(nullptr, &peer, auth_context); + tsi_peer_destruct(&peer); + GRPC_CLOSURE_SCHED(on_peer_checked, error); } - *sc = &c->base; - gpr_free((void*)options.alpn_protocols); - return GRPC_SECURITY_OK; -error: - gpr_free((void*)options.alpn_protocols); - return GRPC_SECURITY_ERROR; -} + int cmp(const grpc_security_connector* other) const override { + return server_security_connector_cmp( + static_cast(other)); + } -static grpc_ssl_server_security_connector* -grpc_ssl_server_security_connector_initialize( - grpc_server_credentials* server_creds) { - grpc_ssl_server_security_connector* c = - static_cast( - gpr_zalloc(sizeof(grpc_ssl_server_security_connector))); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.base.vtable = &ssl_server_vtable; - c->base.add_handshakers = ssl_server_add_handshakers; - c->base.server_creds = grpc_server_credentials_ref(server_creds); - return c; -} + private: + /* Attempts to fetch the server certificate config if a callback is available. + * Current certificate config will continue to be used if the callback returns + * an error. Returns true if new credentials were sucessfully loaded. */ + bool try_fetch_ssl_server_credentials() { + grpc_ssl_server_certificate_config* certificate_config = nullptr; + bool status; + + if (!has_cert_config_fetcher()) return false; + + grpc_ssl_server_credentials* server_creds = + static_cast(this->mutable_server_creds()); + grpc_ssl_certificate_config_reload_status cb_result = + server_creds->FetchCertConfig(&certificate_config); + if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { + gpr_log(GPR_DEBUG, "No change in SSL server credentials."); + status = false; + } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { + status = try_replace_server_handshaker_factory(certificate_config); + } else { + // Log error, continue using previously-loaded credentials. + gpr_log(GPR_ERROR, + "Failed fetching new server credentials, continuing to " + "use previously-loaded credentials."); + status = false; + } -grpc_security_status grpc_ssl_server_security_connector_create( - grpc_server_credentials* gsc, grpc_server_security_connector** sc) { - tsi_result result = TSI_OK; - grpc_ssl_server_credentials* server_credentials = - reinterpret_cast(gsc); - grpc_security_status retval = GRPC_SECURITY_OK; + if (certificate_config != nullptr) { + grpc_ssl_server_certificate_config_destroy(certificate_config); + } + return status; + } - GPR_ASSERT(server_credentials != nullptr); - GPR_ASSERT(sc != nullptr); - - grpc_ssl_server_security_connector* c = - grpc_ssl_server_security_connector_initialize(gsc); - if (server_connector_has_cert_config_fetcher(c)) { - // Load initial credentials from certificate_config_fetcher: - if (!try_fetch_ssl_server_credentials(c)) { - gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher."); - retval = GRPC_SECURITY_ERROR; + /* Attempts to replace the server_handshaker_factory with a new factory using + * the provided grpc_ssl_server_certificate_config. Should new factory + * creation fail, the existing factory will not be replaced. Returns true on + * success (new factory created). */ + bool try_replace_server_handshaker_factory( + const grpc_ssl_server_certificate_config* config) { + if (config == nullptr) { + gpr_log(GPR_ERROR, + "Server certificate config callback returned invalid (NULL) " + "config."); + return false; } - } else { + gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config); + size_t num_alpn_protocols = 0; const char** alpn_protocol_strings = grpc_fill_alpn_protocol_strings(&num_alpn_protocols); - result = tsi_create_ssl_server_handshaker_factory_ex( - server_credentials->config.pem_key_cert_pairs, - server_credentials->config.num_key_cert_pairs, - server_credentials->config.pem_root_certs, + tsi_ssl_pem_key_cert_pair* cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( + config->pem_key_cert_pairs, config->num_key_cert_pairs); + tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr; + const grpc_ssl_server_credentials* server_creds = + static_cast(this->server_creds()); + GPR_DEBUG_ASSERT(config->pem_root_certs != nullptr); + tsi_result result = tsi_create_ssl_server_handshaker_factory_ex( + cert_pairs, config->num_key_cert_pairs, config->pem_root_certs, grpc_get_tsi_client_certificate_request_type( - server_credentials->config.client_certificate_request), + server_creds->config().client_certificate_request), grpc_get_ssl_cipher_suites(), alpn_protocol_strings, - static_cast(num_alpn_protocols), - &c->server_handshaker_factory); + static_cast(num_alpn_protocols), &new_handshaker_factory); + gpr_free(cert_pairs); gpr_free((void*)alpn_protocol_strings); + if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); - retval = GRPC_SECURITY_ERROR; + return false; } + set_server_handshaker_factory(new_handshaker_factory); + return true; + } + + void set_server_handshaker_factory( + tsi_ssl_server_handshaker_factory* new_factory) { + if (server_handshaker_factory_) { + tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_); + } + server_handshaker_factory_ = new_factory; + } + + tsi_ssl_server_handshaker_factory* server_handshaker_factory_ = nullptr; +}; +} // namespace + +grpc_core::RefCountedPtr +grpc_ssl_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, + const grpc_ssl_config* config, const char* target_name, + const char* overridden_target_name, + tsi_ssl_session_cache* ssl_session_cache) { + if (config == nullptr || target_name == nullptr) { + gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); + return nullptr; } - if (retval == GRPC_SECURITY_OK) { - *sc = &c->base; + const char* pem_root_certs; + const tsi_ssl_root_certs_store* root_store; + if (config->pem_root_certs == nullptr) { + // Use default root certificates. + pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts(); + if (pem_root_certs == nullptr) { + gpr_log(GPR_ERROR, "Could not get default pem root certs."); + return nullptr; + } + root_store = grpc_core::DefaultSslRootStore::GetRootStore(); } else { - if (c != nullptr) ssl_server_destroy(&c->base.base); - if (sc != nullptr) *sc = nullptr; + pem_root_certs = config->pem_root_certs; + root_store = nullptr; + } + + grpc_core::RefCountedPtr c = + grpc_core::MakeRefCounted( + std::move(channel_creds), std::move(request_metadata_creds), config, + target_name, overridden_target_name); + const grpc_security_status result = c->InitializeHandshakerFactory( + config, pem_root_certs, root_store, ssl_session_cache); + if (result != GRPC_SECURITY_OK) { + return nullptr; } - return retval; + return c; +} + +grpc_core::RefCountedPtr +grpc_ssl_server_security_connector_create( + grpc_core::RefCountedPtr server_credentials) { + GPR_ASSERT(server_credentials != nullptr); + grpc_core::RefCountedPtr c = + grpc_core::MakeRefCounted( + std::move(server_credentials)); + const grpc_security_status retval = c->InitializeHandshakerFactory(); + if (retval != GRPC_SECURITY_OK) { + return nullptr; + } + return c; } diff --git a/src/core/lib/security/security_connector/ssl/ssl_security_connector.h b/src/core/lib/security/security_connector/ssl/ssl_security_connector.h index 9b805906061..70e26e338aa 100644 --- a/src/core/lib/security/security_connector/ssl/ssl_security_connector.h +++ b/src/core/lib/security/security_connector/ssl/ssl_security_connector.h @@ -25,6 +25,7 @@ #include "src/core/lib/security/security_connector/security_connector.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/tsi/ssl_transport_security.h" #include "src/core/tsi/transport_security_interface.h" @@ -47,20 +48,21 @@ typedef struct { This function returns GRPC_SECURITY_OK in case of success or a specific error code otherwise. */ -grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_channel_credentials* channel_creds, - grpc_call_credentials* request_metadata_creds, +grpc_core::RefCountedPtr +grpc_ssl_channel_security_connector_create( + grpc_core::RefCountedPtr channel_creds, + grpc_core::RefCountedPtr request_metadata_creds, const grpc_ssl_config* config, const char* target_name, const char* overridden_target_name, - tsi_ssl_session_cache* ssl_session_cache, - grpc_channel_security_connector** sc); + tsi_ssl_session_cache* ssl_session_cache); /* Config for ssl servers. */ typedef struct { - tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs; - size_t num_key_cert_pairs; - char* pem_root_certs; - grpc_ssl_client_certificate_request_type client_certificate_request; + tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr; + size_t num_key_cert_pairs = 0; + char* pem_root_certs = nullptr; + grpc_ssl_client_certificate_request_type client_certificate_request = + GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE; } grpc_ssl_server_config; /* Creates an SSL server_security_connector. @@ -69,9 +71,9 @@ typedef struct { This function returns GRPC_SECURITY_OK in case of success or a specific error code otherwise. */ -grpc_security_status grpc_ssl_server_security_connector_create( - grpc_server_credentials* server_credentials, - grpc_server_security_connector** sc); +grpc_core::RefCountedPtr +grpc_ssl_server_security_connector_create( + grpc_core::RefCountedPtr server_credentials); #endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SSL_SSL_SECURITY_CONNECTOR_H \ */ diff --git a/src/core/lib/security/security_connector/ssl_utils.cc b/src/core/lib/security/security_connector/ssl_utils.cc index fbf41cfbc7c..29030f07ad6 100644 --- a/src/core/lib/security/security_connector/ssl_utils.cc +++ b/src/core/lib/security/security_connector/ssl_utils.cc @@ -30,6 +30,7 @@ #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/load_file.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/security_connector/load_system_roots.h" @@ -141,16 +142,17 @@ int grpc_ssl_host_matches_name(const tsi_peer* peer, const char* peer_name) { return r; } -grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) { +grpc_core::RefCountedPtr grpc_ssl_peer_to_auth_context( + const tsi_peer* peer) { size_t i; - grpc_auth_context* ctx = nullptr; const char* peer_identity_property_name = nullptr; /* The caller has checked the certificate type property. */ GPR_ASSERT(peer->property_count >= 1); - ctx = grpc_auth_context_create(nullptr); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(nullptr); grpc_auth_context_add_cstring_property( - ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_SSL_TRANSPORT_SECURITY_TYPE); for (i = 0; i < peer->property_count; i++) { const tsi_peer_property* prop = &peer->properties[i]; @@ -160,24 +162,26 @@ grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) { if (peer_identity_property_name == nullptr) { peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; } - grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME, + grpc_auth_context_add_property(ctx.get(), GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length); } else if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; - grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, + grpc_auth_context_add_property(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length); } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) { - grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME, + grpc_auth_context_add_property(ctx.get(), + GRPC_X509_PEM_CERT_PROPERTY_NAME, prop->value.data, prop->value.length); } else if (strcmp(prop->name, TSI_SSL_SESSION_REUSED_PEER_PROPERTY) == 0) { - grpc_auth_context_add_property(ctx, GRPC_SSL_SESSION_REUSED_PROPERTY, + grpc_auth_context_add_property(ctx.get(), + GRPC_SSL_SESSION_REUSED_PROPERTY, prop->value.data, prop->value.length); } } if (peer_identity_property_name != nullptr) { GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - ctx, peer_identity_property_name) == 1); + ctx.get(), peer_identity_property_name) == 1); } return ctx; } diff --git a/src/core/lib/security/security_connector/ssl_utils.h b/src/core/lib/security/security_connector/ssl_utils.h index 6f6d473311b..c9cd1a1d9c5 100644 --- a/src/core/lib/security/security_connector/ssl_utils.h +++ b/src/core/lib/security/security_connector/ssl_utils.h @@ -26,6 +26,7 @@ #include #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/tsi/ssl_transport_security.h" #include "src/core/tsi/transport_security_interface.h" @@ -47,7 +48,8 @@ grpc_get_tsi_client_certificate_request_type( const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols); /* Exposed for testing only. */ -grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer); +grpc_core::RefCountedPtr grpc_ssl_peer_to_auth_context( + const tsi_peer* peer); tsi_peer grpc_shallow_peer_from_ssl_auth_context( const grpc_auth_context* auth_context); void grpc_shallow_peer_destruct(tsi_peer* peer); diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc index 6955e8698e2..66f86b8bc52 100644 --- a/src/core/lib/security/transport/client_auth_filter.cc +++ b/src/core/lib/security/transport/client_auth_filter.cc @@ -55,7 +55,7 @@ struct call_data { // that the memory is not initialized. void destroy() { grpc_credentials_mdelem_array_destroy(&md_array); - grpc_call_credentials_unref(creds); + creds.reset(); grpc_slice_unref_internal(host); grpc_slice_unref_internal(method); grpc_auth_metadata_context_reset(&auth_md_context); @@ -64,7 +64,7 @@ struct call_data { gpr_arena* arena; grpc_call_stack* owning_call; grpc_call_combiner* call_combiner; - grpc_call_credentials* creds = nullptr; + grpc_core::RefCountedPtr creds; grpc_slice host = grpc_empty_slice(); grpc_slice method = grpc_empty_slice(); /* pollset{_set} bound to this call; if we need to make external @@ -83,8 +83,18 @@ struct call_data { /* We can have a per-channel credentials. */ struct channel_data { - grpc_channel_security_connector* security_connector; - grpc_auth_context* auth_context; + channel_data(grpc_channel_security_connector* security_connector, + grpc_auth_context* auth_context) + : security_connector( + security_connector->Ref(DEBUG_LOCATION, "client_auth_filter")), + auth_context(auth_context->Ref(DEBUG_LOCATION, "client_auth_filter")) {} + ~channel_data() { + security_connector.reset(DEBUG_LOCATION, "client_auth_filter"); + auth_context.reset(DEBUG_LOCATION, "client_auth_filter"); + } + + grpc_core::RefCountedPtr security_connector; + grpc_core::RefCountedPtr auth_context; }; } // namespace @@ -98,10 +108,11 @@ void grpc_auth_metadata_context_reset( gpr_free(const_cast(auth_md_context->method_name)); auth_md_context->method_name = nullptr; } - GRPC_AUTH_CONTEXT_UNREF( - (grpc_auth_context*)auth_md_context->channel_auth_context, - "grpc_auth_metadata_context"); - auth_md_context->channel_auth_context = nullptr; + if (auth_md_context->channel_auth_context != nullptr) { + const_cast(auth_md_context->channel_auth_context) + ->Unref(DEBUG_LOCATION, "grpc_auth_metadata_context"); + auth_md_context->channel_auth_context = nullptr; + } } static void add_error(grpc_error** combined, grpc_error* error) { @@ -175,7 +186,10 @@ void grpc_auth_metadata_context_build( auth_md_context->service_url = service_url; auth_md_context->method_name = method_name; auth_md_context->channel_auth_context = - GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context"); + auth_context == nullptr + ? nullptr + : auth_context->Ref(DEBUG_LOCATION, "grpc_auth_metadata_context") + .release(); gpr_free(service); gpr_free(host_and_port); } @@ -184,8 +198,8 @@ static void cancel_get_request_metadata(void* arg, grpc_error* error) { grpc_call_element* elem = static_cast(arg); call_data* calld = static_cast(elem->call_data); if (error != GRPC_ERROR_NONE) { - grpc_call_credentials_cancel_get_request_metadata( - calld->creds, &calld->md_array, GRPC_ERROR_REF(error)); + calld->creds->cancel_get_request_metadata(&calld->md_array, + GRPC_ERROR_REF(error)); } } @@ -197,7 +211,7 @@ static void send_security_metadata(grpc_call_element* elem, static_cast( batch->payload->context[GRPC_CONTEXT_SECURITY].value); grpc_call_credentials* channel_call_creds = - chand->security_connector->request_metadata_creds; + chand->security_connector->mutable_request_metadata_creds(); int call_creds_has_md = (ctx != nullptr) && (ctx->creds != nullptr); if (channel_call_creds == nullptr && !call_creds_has_md) { @@ -207,8 +221,9 @@ static void send_security_metadata(grpc_call_element* elem, } if (channel_call_creds != nullptr && call_creds_has_md) { - calld->creds = grpc_composite_call_credentials_create(channel_call_creds, - ctx->creds, nullptr); + calld->creds = grpc_core::RefCountedPtr( + grpc_composite_call_credentials_create(channel_call_creds, + ctx->creds.get(), nullptr)); if (calld->creds == nullptr) { grpc_transport_stream_op_batch_finish_with_failure( batch, @@ -220,22 +235,22 @@ static void send_security_metadata(grpc_call_element* elem, return; } } else { - calld->creds = grpc_call_credentials_ref( - call_creds_has_md ? ctx->creds : channel_call_creds); + calld->creds = + call_creds_has_md ? ctx->creds->Ref() : channel_call_creds->Ref(); } grpc_auth_metadata_context_build( - chand->security_connector->base.url_scheme, calld->host, calld->method, - chand->auth_context, &calld->auth_md_context); + chand->security_connector->url_scheme(), calld->host, calld->method, + chand->auth_context.get(), &calld->auth_md_context); GPR_ASSERT(calld->pollent != nullptr); GRPC_CALL_STACK_REF(calld->owning_call, "get_request_metadata"); GRPC_CLOSURE_INIT(&calld->async_result_closure, on_credentials_metadata, batch, grpc_schedule_on_exec_ctx); grpc_error* error = GRPC_ERROR_NONE; - if (grpc_call_credentials_get_request_metadata( - calld->creds, calld->pollent, calld->auth_md_context, - &calld->md_array, &calld->async_result_closure, &error)) { + if (calld->creds->get_request_metadata( + calld->pollent, calld->auth_md_context, &calld->md_array, + &calld->async_result_closure, &error)) { // Synchronous return; invoke on_credentials_metadata() directly. on_credentials_metadata(batch, error); GRPC_ERROR_UNREF(error); @@ -279,9 +294,8 @@ static void cancel_check_call_host(void* arg, grpc_error* error) { call_data* calld = static_cast(elem->call_data); channel_data* chand = static_cast(elem->channel_data); if (error != GRPC_ERROR_NONE) { - grpc_channel_security_connector_cancel_check_call_host( - chand->security_connector, &calld->async_result_closure, - GRPC_ERROR_REF(error)); + chand->security_connector->cancel_check_call_host( + &calld->async_result_closure, GRPC_ERROR_REF(error)); } } @@ -299,16 +313,16 @@ static void auth_start_transport_stream_op_batch( GPR_ASSERT(batch->payload->context != nullptr); if (batch->payload->context[GRPC_CONTEXT_SECURITY].value == nullptr) { batch->payload->context[GRPC_CONTEXT_SECURITY].value = - grpc_client_security_context_create(calld->arena); + grpc_client_security_context_create(calld->arena, /*creds=*/nullptr); batch->payload->context[GRPC_CONTEXT_SECURITY].destroy = grpc_client_security_context_destroy; } grpc_client_security_context* sec_ctx = static_cast( batch->payload->context[GRPC_CONTEXT_SECURITY].value); - GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); + sec_ctx->auth_context.reset(DEBUG_LOCATION, "client_auth_filter"); sec_ctx->auth_context = - GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter"); + chand->auth_context->Ref(DEBUG_LOCATION, "client_auth_filter"); } if (batch->send_initial_metadata) { @@ -327,8 +341,8 @@ static void auth_start_transport_stream_op_batch( grpc_schedule_on_exec_ctx); char* call_host = grpc_slice_to_c_string(calld->host); grpc_error* error = GRPC_ERROR_NONE; - if (grpc_channel_security_connector_check_call_host( - chand->security_connector, call_host, chand->auth_context, + if (chand->security_connector->check_call_host( + call_host, chand->auth_context.get(), &calld->async_result_closure, &error)) { // Synchronous return; invoke on_host_checked() directly. on_host_checked(batch, error); @@ -374,6 +388,10 @@ static void destroy_call_elem(grpc_call_element* elem, /* Constructor for channel_data */ static grpc_error* init_channel_elem(grpc_channel_element* elem, grpc_channel_element_args* args) { + /* The first and the last filters tend to be implemented differently to + handle the case that there's no 'next' filter to call on the up or down + path */ + GPR_ASSERT(!args->is_last); grpc_security_connector* sc = grpc_security_connector_find_in_args(args->channel_args); if (sc == nullptr) { @@ -386,33 +404,15 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem, return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Auth context missing from client auth filter args"); } - - /* grab pointers to our data from the channel element */ - channel_data* chand = static_cast(elem->channel_data); - - /* The first and the last filters tend to be implemented differently to - handle the case that there's no 'next' filter to call on the up or down - path */ - GPR_ASSERT(!args->is_last); - - /* initialize members */ - chand->security_connector = - reinterpret_cast( - GRPC_SECURITY_CONNECTOR_REF(sc, "client_auth_filter")); - chand->auth_context = - GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter"); + new (elem->channel_data) channel_data( + static_cast(sc), auth_context); return GRPC_ERROR_NONE; } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element* elem) { - /* grab pointers to our data from the channel element */ channel_data* chand = static_cast(elem->channel_data); - grpc_channel_security_connector* sc = chand->security_connector; - if (sc != nullptr) { - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter"); - } - GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter"); + chand->~channel_data(); } const grpc_channel_filter grpc_client_auth_filter = { diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc index 854a1c4af97..48d6901e883 100644 --- a/src/core/lib/security/transport/security_handshaker.cc +++ b/src/core/lib/security/transport/security_handshaker.cc @@ -30,6 +30,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker.h" #include "src/core/lib/channel/handshaker_registry.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/tsi_error.h" @@ -38,34 +39,62 @@ #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 -typedef struct { +namespace { +struct security_handshaker { + security_handshaker(tsi_handshaker* handshaker, + grpc_security_connector* connector); + ~security_handshaker() { + gpr_mu_destroy(&mu); + tsi_handshaker_destroy(handshaker); + tsi_handshaker_result_destroy(handshaker_result); + if (endpoint_to_destroy != nullptr) { + grpc_endpoint_destroy(endpoint_to_destroy); + } + if (read_buffer_to_destroy != nullptr) { + grpc_slice_buffer_destroy_internal(read_buffer_to_destroy); + gpr_free(read_buffer_to_destroy); + } + gpr_free(handshake_buffer); + grpc_slice_buffer_destroy_internal(&outgoing); + auth_context.reset(DEBUG_LOCATION, "handshake"); + connector.reset(DEBUG_LOCATION, "handshake"); + } + + void Ref() { refs.Ref(); } + void Unref() { + if (refs.Unref()) { + grpc_core::Delete(this); + } + } + grpc_handshaker base; // State set at creation time. tsi_handshaker* handshaker; - grpc_security_connector* connector; + grpc_core::RefCountedPtr connector; gpr_mu mu; - gpr_refcount refs; + grpc_core::RefCount refs; - bool shutdown; + bool shutdown = false; // Endpoint and read buffer to destroy after a shutdown. - grpc_endpoint* endpoint_to_destroy; - grpc_slice_buffer* read_buffer_to_destroy; + grpc_endpoint* endpoint_to_destroy = nullptr; + grpc_slice_buffer* read_buffer_to_destroy = nullptr; // State saved while performing the handshake. - grpc_handshaker_args* args; - grpc_closure* on_handshake_done; + grpc_handshaker_args* args = nullptr; + grpc_closure* on_handshake_done = nullptr; - unsigned char* handshake_buffer; size_t handshake_buffer_size; + unsigned char* handshake_buffer; grpc_slice_buffer outgoing; grpc_closure on_handshake_data_sent_to_peer; grpc_closure on_handshake_data_received_from_peer; grpc_closure on_peer_checked; - grpc_auth_context* auth_context; - tsi_handshaker_result* handshaker_result; -} security_handshaker; + grpc_core::RefCountedPtr auth_context; + tsi_handshaker_result* handshaker_result = nullptr; +}; +} // namespace static size_t move_read_buffer_into_handshake_buffer(security_handshaker* h) { size_t bytes_in_read_buffer = h->args->read_buffer->length; @@ -85,26 +114,6 @@ static size_t move_read_buffer_into_handshake_buffer(security_handshaker* h) { return bytes_in_read_buffer; } -static void security_handshaker_unref(security_handshaker* h) { - if (gpr_unref(&h->refs)) { - gpr_mu_destroy(&h->mu); - tsi_handshaker_destroy(h->handshaker); - tsi_handshaker_result_destroy(h->handshaker_result); - if (h->endpoint_to_destroy != nullptr) { - grpc_endpoint_destroy(h->endpoint_to_destroy); - } - if (h->read_buffer_to_destroy != nullptr) { - grpc_slice_buffer_destroy_internal(h->read_buffer_to_destroy); - gpr_free(h->read_buffer_to_destroy); - } - gpr_free(h->handshake_buffer); - grpc_slice_buffer_destroy_internal(&h->outgoing); - GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); - GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); - gpr_free(h); - } -} - // Set args fields to NULL, saving the endpoint and read buffer for // later destruction. static void cleanup_args_for_failure_locked(security_handshaker* h) { @@ -194,7 +203,7 @@ static void on_peer_checked_inner(security_handshaker* h, grpc_error* error) { tsi_handshaker_result_destroy(h->handshaker_result); h->handshaker_result = nullptr; // Add auth context to channel args. - grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context); + grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context.get()); grpc_channel_args* tmp_args = h->args->args; h->args->args = grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1); @@ -211,7 +220,7 @@ static void on_peer_checked(void* arg, grpc_error* error) { gpr_mu_lock(&h->mu); on_peer_checked_inner(h, error); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); } static grpc_error* check_peer_locked(security_handshaker* h) { @@ -222,8 +231,7 @@ static grpc_error* check_peer_locked(security_handshaker* h) { return grpc_set_tsi_error_result( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), result); } - grpc_security_connector_check_peer(h->connector, peer, &h->auth_context, - &h->on_peer_checked); + h->connector->check_peer(peer, &h->auth_context, &h->on_peer_checked); return GRPC_ERROR_NONE; } @@ -281,7 +289,7 @@ static void on_handshake_next_done_grpc_wrapper( if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(h, error); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); } else { gpr_mu_unlock(&h->mu); } @@ -317,7 +325,7 @@ static void on_handshake_data_received_from_peer(void* arg, grpc_error* error) { h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Handshake read failed", &error, 1)); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); return; } // Copy all slices received. @@ -329,7 +337,7 @@ static void on_handshake_data_received_from_peer(void* arg, grpc_error* error) { if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(h, error); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); } else { gpr_mu_unlock(&h->mu); } @@ -343,7 +351,7 @@ static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) { h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Handshake write failed", &error, 1)); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); return; } // We may be done. @@ -355,7 +363,7 @@ static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) { if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(h, error); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); return; } } @@ -368,7 +376,7 @@ static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) { static void security_handshaker_destroy(grpc_handshaker* handshaker) { security_handshaker* h = reinterpret_cast(handshaker); - security_handshaker_unref(h); + h->Unref(); } static void security_handshaker_shutdown(grpc_handshaker* handshaker, @@ -393,14 +401,14 @@ static void security_handshaker_do_handshake(grpc_handshaker* handshaker, gpr_mu_lock(&h->mu); h->args = args; h->on_handshake_done = on_handshake_done; - gpr_ref(&h->refs); + h->Ref(); size_t bytes_received_size = move_read_buffer_into_handshake_buffer(h); grpc_error* error = do_handshaker_next_locked(h, h->handshake_buffer, bytes_received_size); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(h, error); gpr_mu_unlock(&h->mu); - security_handshaker_unref(h); + h->Unref(); return; } gpr_mu_unlock(&h->mu); @@ -410,27 +418,32 @@ static const grpc_handshaker_vtable security_handshaker_vtable = { security_handshaker_destroy, security_handshaker_shutdown, security_handshaker_do_handshake, "security"}; -static grpc_handshaker* security_handshaker_create( - tsi_handshaker* handshaker, grpc_security_connector* connector) { - security_handshaker* h = static_cast( - gpr_zalloc(sizeof(security_handshaker))); - grpc_handshaker_init(&security_handshaker_vtable, &h->base); - h->handshaker = handshaker; - h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); - gpr_mu_init(&h->mu); - gpr_ref_init(&h->refs, 1); - h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; - h->handshake_buffer = - static_cast(gpr_malloc(h->handshake_buffer_size)); - GRPC_CLOSURE_INIT(&h->on_handshake_data_sent_to_peer, - on_handshake_data_sent_to_peer, h, +namespace { +security_handshaker::security_handshaker(tsi_handshaker* handshaker, + grpc_security_connector* connector) + : handshaker(handshaker), + connector(connector->Ref(DEBUG_LOCATION, "handshake")), + handshake_buffer_size(GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE), + handshake_buffer( + static_cast(gpr_malloc(handshake_buffer_size))) { + grpc_handshaker_init(&security_handshaker_vtable, &base); + gpr_mu_init(&mu); + grpc_slice_buffer_init(&outgoing); + GRPC_CLOSURE_INIT(&on_handshake_data_sent_to_peer, + ::on_handshake_data_sent_to_peer, this, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&h->on_handshake_data_received_from_peer, - on_handshake_data_received_from_peer, h, + GRPC_CLOSURE_INIT(&on_handshake_data_received_from_peer, + ::on_handshake_data_received_from_peer, this, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&h->on_peer_checked, on_peer_checked, h, + GRPC_CLOSURE_INIT(&on_peer_checked, ::on_peer_checked, this, grpc_schedule_on_exec_ctx); - grpc_slice_buffer_init(&h->outgoing); +} +} // namespace + +static grpc_handshaker* security_handshaker_create( + tsi_handshaker* handshaker, grpc_security_connector* connector) { + security_handshaker* h = + grpc_core::New(handshaker, connector); return &h->base; } @@ -477,8 +490,9 @@ static void client_handshaker_factory_add_handshakers( grpc_channel_security_connector* security_connector = reinterpret_cast( grpc_security_connector_find_in_args(args)); - grpc_channel_security_connector_add_handshakers( - security_connector, interested_parties, handshake_mgr); + if (security_connector) { + security_connector->add_handshakers(interested_parties, handshake_mgr); + } } static void server_handshaker_factory_add_handshakers( @@ -488,8 +502,9 @@ static void server_handshaker_factory_add_handshakers( grpc_server_security_connector* security_connector = reinterpret_cast( grpc_security_connector_find_in_args(args)); - grpc_server_security_connector_add_handshakers( - security_connector, interested_parties, handshake_mgr); + if (security_connector) { + security_connector->add_handshakers(interested_parties, handshake_mgr); + } } static void handshaker_factory_destroy( diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc index 362f49a5843..f93eb4275e3 100644 --- a/src/core/lib/security/transport/server_auth_filter.cc +++ b/src/core/lib/security/transport/server_auth_filter.cc @@ -39,8 +39,12 @@ enum async_state { }; struct channel_data { - grpc_auth_context* auth_context; - grpc_server_credentials* creds; + channel_data(grpc_auth_context* auth_context, grpc_server_credentials* creds) + : auth_context(auth_context->Ref()), creds(creds->Ref()) {} + ~channel_data() { auth_context.reset(DEBUG_LOCATION, "server_auth_filter"); } + + grpc_core::RefCountedPtr auth_context; + grpc_core::RefCountedPtr creds; }; struct call_data { @@ -58,7 +62,7 @@ struct call_data { grpc_server_security_context_create(args.arena); channel_data* chand = static_cast(elem->channel_data); server_ctx->auth_context = - GRPC_AUTH_CONTEXT_REF(chand->auth_context, "server_auth_filter"); + chand->auth_context->Ref(DEBUG_LOCATION, "server_auth_filter"); if (args.context[GRPC_CONTEXT_SECURITY].value != nullptr) { args.context[GRPC_CONTEXT_SECURITY].destroy( args.context[GRPC_CONTEXT_SECURITY].value); @@ -208,7 +212,8 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { call_data* calld = static_cast(elem->call_data); grpc_transport_stream_op_batch* batch = calld->recv_initial_metadata_batch; if (error == GRPC_ERROR_NONE) { - if (chand->creds != nullptr && chand->creds->processor.process != nullptr) { + if (chand->creds != nullptr && + chand->creds->auth_metadata_processor().process != nullptr) { // We're calling out to the application, so we need to make sure // to drop the call combiner early if we get cancelled. GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem, @@ -218,9 +223,10 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { GRPC_CALL_STACK_REF(calld->owning_call, "server_auth_metadata"); calld->md = metadata_batch_to_md_array( batch->payload->recv_initial_metadata.recv_initial_metadata); - chand->creds->processor.process( - chand->creds->processor.state, chand->auth_context, - calld->md.metadata, calld->md.count, on_md_processing_done, elem); + chand->creds->auth_metadata_processor().process( + chand->creds->auth_metadata_processor().state, + chand->auth_context.get(), calld->md.metadata, calld->md.count, + on_md_processing_done, elem); return; } } @@ -290,23 +296,19 @@ static void destroy_call_elem(grpc_call_element* elem, static grpc_error* init_channel_elem(grpc_channel_element* elem, grpc_channel_element_args* args) { GPR_ASSERT(!args->is_last); - channel_data* chand = static_cast(elem->channel_data); grpc_auth_context* auth_context = grpc_find_auth_context_in_args(args->channel_args); GPR_ASSERT(auth_context != nullptr); - chand->auth_context = - GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter"); grpc_server_credentials* creds = grpc_find_server_credentials_in_args(args->channel_args); - chand->creds = grpc_server_credentials_ref(creds); + new (elem->channel_data) channel_data(auth_context, creds); return GRPC_ERROR_NONE; } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element* elem) { channel_data* chand = static_cast(elem->channel_data); - GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter"); - grpc_server_credentials_unref(chand->creds); + chand->~channel_data(); } const grpc_channel_filter grpc_server_auth_filter = { diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index d0abe441a6a..4d0ed355aba 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -261,10 +261,10 @@ void MetadataCredentialsPluginWrapper::InvokePlugin( grpc_status_code* status_code, const char** error_details) { std::multimap metadata; - // const_cast is safe since the SecureAuthContext does not take owndership and - // the object is passed as a const ref to plugin_->GetMetadata. + // const_cast is safe since the SecureAuthContext only inc/dec the refcount + // and the object is passed as a const ref to plugin_->GetMetadata. SecureAuthContext cpp_channel_auth_context( - const_cast(context.channel_auth_context), false); + const_cast(context.channel_auth_context)); Status status = plugin_->GetMetadata(context.service_url, context.method_name, cpp_channel_auth_context, &metadata); diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index 613f1d6dc2c..4918bd5a4d7 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -24,6 +24,7 @@ #include #include +#include "src/core/lib/security/credentials/credentials.h" #include "src/cpp/server/thread_pool_interface.h" namespace grpc { @@ -31,7 +32,9 @@ namespace grpc { class SecureChannelCredentials final : public ChannelCredentials { public: explicit SecureChannelCredentials(grpc_channel_credentials* c_creds); - ~SecureChannelCredentials() { grpc_channel_credentials_release(c_creds_); } + ~SecureChannelCredentials() { + if (c_creds_ != nullptr) c_creds_->Unref(); + } grpc_channel_credentials* GetRawCreds() { return c_creds_; } std::shared_ptr CreateChannel( @@ -51,7 +54,9 @@ class SecureChannelCredentials final : public ChannelCredentials { class SecureCallCredentials final : public CallCredentials { public: explicit SecureCallCredentials(grpc_call_credentials* c_creds); - ~SecureCallCredentials() { grpc_call_credentials_release(c_creds_); } + ~SecureCallCredentials() { + if (c_creds_ != nullptr) c_creds_->Unref(); + } grpc_call_credentials* GetRawCreds() { return c_creds_; } bool ApplyToCall(grpc_call* call) override; diff --git a/src/cpp/common/secure_auth_context.cc b/src/cpp/common/secure_auth_context.cc index 1d66dd3d1f1..7a2b5afed69 100644 --- a/src/cpp/common/secure_auth_context.cc +++ b/src/cpp/common/secure_auth_context.cc @@ -22,19 +22,12 @@ namespace grpc { -SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx, - bool take_ownership) - : ctx_(ctx), take_ownership_(take_ownership) {} - -SecureAuthContext::~SecureAuthContext() { - if (take_ownership_) grpc_auth_context_release(ctx_); -} - std::vector SecureAuthContext::GetPeerIdentity() const { - if (!ctx_) { + if (ctx_ == nullptr) { return std::vector(); } - grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_); + grpc_auth_property_iterator iter = + grpc_auth_context_peer_identity(ctx_.get()); std::vector identity; const grpc_auth_property* property = nullptr; while ((property = grpc_auth_property_iterator_next(&iter))) { @@ -45,20 +38,20 @@ std::vector SecureAuthContext::GetPeerIdentity() const { } grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const { - if (!ctx_) { + if (ctx_ == nullptr) { return ""; } - const char* name = grpc_auth_context_peer_identity_property_name(ctx_); + const char* name = grpc_auth_context_peer_identity_property_name(ctx_.get()); return name == nullptr ? "" : name; } std::vector SecureAuthContext::FindPropertyValues( const grpc::string& name) const { - if (!ctx_) { + if (ctx_ == nullptr) { return std::vector(); } grpc_auth_property_iterator iter = - grpc_auth_context_find_properties_by_name(ctx_, name.c_str()); + grpc_auth_context_find_properties_by_name(ctx_.get(), name.c_str()); const grpc_auth_property* property = nullptr; std::vector values; while ((property = grpc_auth_property_iterator_next(&iter))) { @@ -68,9 +61,9 @@ std::vector SecureAuthContext::FindPropertyValues( } AuthPropertyIterator SecureAuthContext::begin() const { - if (ctx_) { + if (ctx_ != nullptr) { grpc_auth_property_iterator iter = - grpc_auth_context_property_iterator(ctx_); + grpc_auth_context_property_iterator(ctx_.get()); const grpc_auth_property* property = grpc_auth_property_iterator_next(&iter); return AuthPropertyIterator(property, &iter); @@ -85,19 +78,20 @@ AuthPropertyIterator SecureAuthContext::end() const { void SecureAuthContext::AddProperty(const grpc::string& key, const grpc::string_ref& value) { - if (!ctx_) return; - grpc_auth_context_add_property(ctx_, key.c_str(), value.data(), value.size()); + if (ctx_ == nullptr) return; + grpc_auth_context_add_property(ctx_.get(), key.c_str(), value.data(), + value.size()); } bool SecureAuthContext::SetPeerIdentityPropertyName(const grpc::string& name) { - if (!ctx_) return false; - return grpc_auth_context_set_peer_identity_property_name(ctx_, + if (ctx_ == nullptr) return false; + return grpc_auth_context_set_peer_identity_property_name(ctx_.get(), name.c_str()) != 0; } bool SecureAuthContext::IsPeerAuthenticated() const { - if (!ctx_) return false; - return grpc_auth_context_peer_is_authenticated(ctx_) != 0; + if (ctx_ == nullptr) return false; + return grpc_auth_context_peer_is_authenticated(ctx_.get()) != 0; } } // namespace grpc diff --git a/src/cpp/common/secure_auth_context.h b/src/cpp/common/secure_auth_context.h index 142617959cb..2e8f7937211 100644 --- a/src/cpp/common/secure_auth_context.h +++ b/src/cpp/common/secure_auth_context.h @@ -21,15 +21,17 @@ #include -struct grpc_auth_context; +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/security/context/security_context.h" namespace grpc { class SecureAuthContext final : public AuthContext { public: - SecureAuthContext(grpc_auth_context* ctx, bool take_ownership); + explicit SecureAuthContext(grpc_auth_context* ctx) + : ctx_(ctx != nullptr ? ctx->Ref() : nullptr) {} - ~SecureAuthContext() override; + ~SecureAuthContext() override = default; bool IsPeerAuthenticated() const override; @@ -50,8 +52,7 @@ class SecureAuthContext final : public AuthContext { virtual bool SetPeerIdentityPropertyName(const grpc::string& name) override; private: - grpc_auth_context* ctx_; - bool take_ownership_; + grpc_core::RefCountedPtr ctx_; }; } // namespace grpc diff --git a/src/cpp/common/secure_create_auth_context.cc b/src/cpp/common/secure_create_auth_context.cc index bc1387c8d75..908c46629e6 100644 --- a/src/cpp/common/secure_create_auth_context.cc +++ b/src/cpp/common/secure_create_auth_context.cc @@ -20,6 +20,7 @@ #include #include #include +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/cpp/common/secure_auth_context.h" namespace grpc { @@ -28,8 +29,8 @@ std::shared_ptr CreateAuthContext(grpc_call* call) { if (call == nullptr) { return std::shared_ptr(); } - return std::shared_ptr( - new SecureAuthContext(grpc_call_auth_context(call), true)); + grpc_core::RefCountedPtr ctx(grpc_call_auth_context(call)); + return std::make_shared(ctx.get()); } } // namespace grpc diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index ebb17def32b..453e76eb25d 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -61,7 +61,7 @@ void AuthMetadataProcessorAyncWrapper::InvokeProcessor( metadata.insert(std::make_pair(StringRefFromSlice(&md[i].key), StringRefFromSlice(&md[i].value))); } - SecureAuthContext context(ctx, false); + SecureAuthContext context(ctx); AuthMetadataProcessor::OutputMetadata consumed_metadata; AuthMetadataProcessor::OutputMetadata response_metadata; diff --git a/test/core/security/alts_security_connector_test.cc b/test/core/security/alts_security_connector_test.cc index 9378236338d..bcba3408216 100644 --- a/test/core/security/alts_security_connector_test.cc +++ b/test/core/security/alts_security_connector_test.cc @@ -33,40 +33,34 @@ using grpc_core::internal::grpc_alts_auth_context_from_tsi_peer; /* This file contains unit tests of grpc_alts_auth_context_from_tsi_peer(). */ static void test_invalid_input_failure() { - tsi_peer peer; - grpc_auth_context* ctx; - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(nullptr, &ctx) == - GRPC_SECURITY_ERROR); - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, nullptr) == - GRPC_SECURITY_ERROR); + grpc_core::RefCountedPtr ctx = + grpc_alts_auth_context_from_tsi_peer(nullptr); + GPR_ASSERT(ctx == nullptr); } static void test_empty_certificate_type_failure() { tsi_peer peer; - grpc_auth_context* ctx = nullptr; GPR_ASSERT(tsi_construct_peer(0, &peer) == TSI_OK); - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) == - GRPC_SECURITY_ERROR); + grpc_core::RefCountedPtr ctx = + grpc_alts_auth_context_from_tsi_peer(&peer); GPR_ASSERT(ctx == nullptr); tsi_peer_destruct(&peer); } static void test_empty_peer_property_failure() { tsi_peer peer; - grpc_auth_context* ctx; GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE, &peer.properties[0]) == TSI_OK); - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) == - GRPC_SECURITY_ERROR); + grpc_core::RefCountedPtr ctx = + grpc_alts_auth_context_from_tsi_peer(&peer); GPR_ASSERT(ctx == nullptr); tsi_peer_destruct(&peer); } static void test_missing_rpc_protocol_versions_property_failure() { tsi_peer peer; - grpc_auth_context* ctx; GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE, @@ -74,23 +68,22 @@ static void test_missing_rpc_protocol_versions_property_failure() { GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, "alice", &peer.properties[1]) == TSI_OK); - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) == - GRPC_SECURITY_ERROR); + grpc_core::RefCountedPtr ctx = + grpc_alts_auth_context_from_tsi_peer(&peer); GPR_ASSERT(ctx == nullptr); tsi_peer_destruct(&peer); } static void test_unknown_peer_property_failure() { tsi_peer peer; - grpc_auth_context* ctx; GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE, &peer.properties[0]) == TSI_OK); GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( "unknown", "alice", &peer.properties[1]) == TSI_OK); - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) == - GRPC_SECURITY_ERROR); + grpc_core::RefCountedPtr ctx = + grpc_alts_auth_context_from_tsi_peer(&peer); GPR_ASSERT(ctx == nullptr); tsi_peer_destruct(&peer); } @@ -119,7 +112,6 @@ static bool test_identity(const grpc_auth_context* ctx, static void test_alts_peer_to_auth_context_success() { tsi_peer peer; - grpc_auth_context* ctx; GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE, @@ -144,11 +136,12 @@ static void test_alts_peer_to_auth_context_success() { GRPC_SLICE_START_PTR(serialized_peer_versions)), GRPC_SLICE_LENGTH(serialized_peer_versions), &peer.properties[2]) == TSI_OK); - GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) == - GRPC_SECURITY_OK); - GPR_ASSERT( - test_identity(ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, "alice")); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + grpc_core::RefCountedPtr ctx = + grpc_alts_auth_context_from_tsi_peer(&peer); + GPR_ASSERT(ctx != nullptr); + GPR_ASSERT(test_identity(ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, + "alice")); + ctx.reset(DEBUG_LOCATION, "test"); grpc_slice_unref(serialized_peer_versions); tsi_peer_destruct(&peer); } diff --git a/test/core/security/auth_context_test.cc b/test/core/security/auth_context_test.cc index 9a39afb8006..e7e0cb2ed94 100644 --- a/test/core/security/auth_context_test.cc +++ b/test/core/security/auth_context_test.cc @@ -19,114 +19,122 @@ #include #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "test/core/util/test_config.h" #include static void test_empty_context(void) { - grpc_auth_context* ctx = grpc_auth_context_create(nullptr); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(nullptr); grpc_auth_property_iterator it; gpr_log(GPR_INFO, "test_empty_context"); GPR_ASSERT(ctx != nullptr); - GPR_ASSERT(grpc_auth_context_peer_identity_property_name(ctx) == nullptr); - it = grpc_auth_context_peer_identity(ctx); + GPR_ASSERT(grpc_auth_context_peer_identity_property_name(ctx.get()) == + nullptr); + it = grpc_auth_context_peer_identity(ctx.get()); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - it = grpc_auth_context_property_iterator(ctx); + it = grpc_auth_context_property_iterator(ctx.get()); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - it = grpc_auth_context_find_properties_by_name(ctx, "foo"); + it = grpc_auth_context_find_properties_by_name(ctx.get(), "foo"); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx, "bar") == - 0); - GPR_ASSERT(grpc_auth_context_peer_identity_property_name(ctx) == nullptr); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + GPR_ASSERT( + grpc_auth_context_set_peer_identity_property_name(ctx.get(), "bar") == 0); + GPR_ASSERT(grpc_auth_context_peer_identity_property_name(ctx.get()) == + nullptr); + ctx.reset(DEBUG_LOCATION, "test"); } static void test_simple_context(void) { - grpc_auth_context* ctx = grpc_auth_context_create(nullptr); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(nullptr); grpc_auth_property_iterator it; size_t i; gpr_log(GPR_INFO, "test_simple_context"); GPR_ASSERT(ctx != nullptr); - grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); - grpc_auth_context_add_cstring_property(ctx, "name", "chapo"); - grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); - GPR_ASSERT(ctx->properties.count == 3); - GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx, "name") == - 1); - - GPR_ASSERT( - strcmp(grpc_auth_context_peer_identity_property_name(ctx), "name") == 0); - it = grpc_auth_context_property_iterator(ctx); - for (i = 0; i < ctx->properties.count; i++) { + grpc_auth_context_add_cstring_property(ctx.get(), "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx.get(), "name", "chapo"); + grpc_auth_context_add_cstring_property(ctx.get(), "foo", "bar"); + GPR_ASSERT(ctx->properties().count == 3); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx.get(), + "name") == 1); + + GPR_ASSERT(strcmp(grpc_auth_context_peer_identity_property_name(ctx.get()), + "name") == 0); + it = grpc_auth_context_property_iterator(ctx.get()); + for (i = 0; i < ctx->properties().count; i++) { const grpc_auth_property* p = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(p == &ctx->properties.array[i]); + GPR_ASSERT(p == &ctx->properties().array[i]); } GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - it = grpc_auth_context_find_properties_by_name(ctx, "foo"); + it = grpc_auth_context_find_properties_by_name(ctx.get(), "foo"); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &ctx->properties.array[2]); + &ctx->properties().array[2]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - it = grpc_auth_context_peer_identity(ctx); + it = grpc_auth_context_peer_identity(ctx.get()); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &ctx->properties.array[0]); + &ctx->properties().array[0]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &ctx->properties.array[1]); + &ctx->properties().array[1]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } static void test_chained_context(void) { - grpc_auth_context* chained = grpc_auth_context_create(nullptr); - grpc_auth_context* ctx = grpc_auth_context_create(chained); + grpc_core::RefCountedPtr chained = + grpc_core::MakeRefCounted(nullptr); + grpc_auth_context* chained_ptr = chained.get(); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(std::move(chained)); + grpc_auth_property_iterator it; size_t i; gpr_log(GPR_INFO, "test_chained_context"); - GRPC_AUTH_CONTEXT_UNREF(chained, "chained"); - grpc_auth_context_add_cstring_property(chained, "name", "padapo"); - grpc_auth_context_add_cstring_property(chained, "foo", "baz"); - grpc_auth_context_add_cstring_property(ctx, "name", "chapi"); - grpc_auth_context_add_cstring_property(ctx, "name", "chap0"); - grpc_auth_context_add_cstring_property(ctx, "foo", "bar"); - GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx, "name") == - 1); - - GPR_ASSERT( - strcmp(grpc_auth_context_peer_identity_property_name(ctx), "name") == 0); - it = grpc_auth_context_property_iterator(ctx); - for (i = 0; i < ctx->properties.count; i++) { + grpc_auth_context_add_cstring_property(chained_ptr, "name", "padapo"); + grpc_auth_context_add_cstring_property(chained_ptr, "foo", "baz"); + grpc_auth_context_add_cstring_property(ctx.get(), "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx.get(), "name", "chap0"); + grpc_auth_context_add_cstring_property(ctx.get(), "foo", "bar"); + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(ctx.get(), + "name") == 1); + + GPR_ASSERT(strcmp(grpc_auth_context_peer_identity_property_name(ctx.get()), + "name") == 0); + it = grpc_auth_context_property_iterator(ctx.get()); + for (i = 0; i < ctx->properties().count; i++) { const grpc_auth_property* p = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(p == &ctx->properties.array[i]); + GPR_ASSERT(p == &ctx->properties().array[i]); } - for (i = 0; i < chained->properties.count; i++) { + for (i = 0; i < chained_ptr->properties().count; i++) { const grpc_auth_property* p = grpc_auth_property_iterator_next(&it); - GPR_ASSERT(p == &chained->properties.array[i]); + GPR_ASSERT(p == &chained_ptr->properties().array[i]); } GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - it = grpc_auth_context_find_properties_by_name(ctx, "foo"); + it = grpc_auth_context_find_properties_by_name(ctx.get(), "foo"); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &ctx->properties.array[2]); + &ctx->properties().array[2]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &chained->properties.array[1]); + &chained_ptr->properties().array[1]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - it = grpc_auth_context_peer_identity(ctx); + it = grpc_auth_context_peer_identity(ctx.get()); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &ctx->properties.array[0]); + &ctx->properties().array[0]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &ctx->properties.array[1]); + &ctx->properties().array[1]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == - &chained->properties.array[0]); + &chained_ptr->properties().array[0]); GPR_ASSERT(grpc_auth_property_iterator_next(&it) == nullptr); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } int main(int argc, char** argv) { diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc index a7a6050ec0a..b3a81617865 100644 --- a/test/core/security/credentials_test.cc +++ b/test/core/security/credentials_test.cc @@ -46,19 +46,6 @@ using grpc_core::internal::grpc_flush_cached_google_default_credentials; using grpc_core::internal::set_gce_tenancy_checker_for_testing; -/* -- Mock channel credentials. -- */ - -static grpc_channel_credentials* grpc_mock_channel_credentials_create( - const grpc_channel_credentials_vtable* vtable) { - grpc_channel_credentials* c = - static_cast(gpr_malloc(sizeof(*c))); - memset(c, 0, sizeof(*c)); - c->type = "mock"; - c->vtable = vtable; - gpr_ref_init(&c->refcount, 1); - return c; -} - /* -- Constants. -- */ static const char test_google_iam_authorization_token[] = "blahblahblhahb"; @@ -377,9 +364,9 @@ static void run_request_metadata_test(grpc_call_credentials* creds, grpc_auth_metadata_context auth_md_ctx, request_metadata_state* state) { grpc_error* error = GRPC_ERROR_NONE; - if (grpc_call_credentials_get_request_metadata( - creds, &state->pollent, auth_md_ctx, &state->md_array, - &state->on_request_metadata, &error)) { + if (creds->get_request_metadata(&state->pollent, auth_md_ctx, + &state->md_array, &state->on_request_metadata, + &error)) { // Synchronous result. Invoke the callback directly. check_request_metadata(state, error); GRPC_ERROR_UNREF(error); @@ -400,7 +387,7 @@ static void test_google_iam_creds(void) { grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; run_request_metadata_test(creds, auth_md_ctx, state); - grpc_call_credentials_unref(creds); + creds->Unref(); } static void test_access_token_creds(void) { @@ -412,28 +399,36 @@ static void test_access_token_creds(void) { grpc_access_token_credentials_create("blah", nullptr); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); + GPR_ASSERT(strcmp(creds->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); run_request_metadata_test(creds, auth_md_ctx, state); - grpc_call_credentials_unref(creds); + creds->Unref(); } -static grpc_security_status check_channel_oauth2_create_security_connector( - grpc_channel_credentials* c, grpc_call_credentials* call_creds, - const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args) { - GPR_ASSERT(strcmp(c->type, "mock") == 0); - GPR_ASSERT(call_creds != nullptr); - GPR_ASSERT(strcmp(call_creds->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); - return GRPC_SECURITY_OK; -} +namespace { +class check_channel_oauth2 final : public grpc_channel_credentials { + public: + check_channel_oauth2() : grpc_channel_credentials("mock") {} + ~check_channel_oauth2() override = default; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target, const grpc_channel_args* args, + grpc_channel_args** new_args) override { + GPR_ASSERT(strcmp(type(), "mock") == 0); + GPR_ASSERT(call_creds != nullptr); + GPR_ASSERT(strcmp(call_creds->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == + 0); + return nullptr; + } +}; +} // namespace static void test_channel_oauth2_composite_creds(void) { grpc_core::ExecCtx exec_ctx; grpc_channel_args* new_args; - grpc_channel_credentials_vtable vtable = { - nullptr, check_channel_oauth2_create_security_connector, nullptr}; grpc_channel_credentials* channel_creds = - grpc_mock_channel_credentials_create(&vtable); + grpc_core::New(); grpc_call_credentials* oauth2_creds = grpc_access_token_credentials_create("blah", nullptr); grpc_channel_credentials* channel_oauth2_creds = @@ -441,9 +436,8 @@ static void test_channel_oauth2_composite_creds(void) { nullptr); grpc_channel_credentials_release(channel_creds); grpc_call_credentials_release(oauth2_creds); - GPR_ASSERT(grpc_channel_credentials_create_security_connector( - channel_oauth2_creds, nullptr, nullptr, nullptr, &new_args) == - GRPC_SECURITY_OK); + channel_oauth2_creds->create_security_connector(nullptr, nullptr, nullptr, + &new_args); grpc_channel_credentials_release(channel_oauth2_creds); } @@ -467,47 +461,54 @@ static void test_oauth2_google_iam_composite_creds(void) { grpc_call_credentials* composite_creds = grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds, nullptr); - grpc_call_credentials_unref(oauth2_creds); - grpc_call_credentials_unref(google_iam_creds); - GPR_ASSERT( - strcmp(composite_creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); - const grpc_call_credentials_array* creds_array = - grpc_composite_call_credentials_get_credentials(composite_creds); - GPR_ASSERT(creds_array->num_creds == 2); - GPR_ASSERT(strcmp(creds_array->creds_array[0]->type, + oauth2_creds->Unref(); + google_iam_creds->Unref(); + GPR_ASSERT(strcmp(composite_creds->type(), + GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); + const grpc_call_credentials_array& creds_array = + static_cast(composite_creds) + ->inner(); + GPR_ASSERT(creds_array.size() == 2); + GPR_ASSERT(strcmp(creds_array.get(0)->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); - GPR_ASSERT(strcmp(creds_array->creds_array[1]->type, - GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0); + GPR_ASSERT( + strcmp(creds_array.get(1)->type(), GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0); run_request_metadata_test(composite_creds, auth_md_ctx, state); - grpc_call_credentials_unref(composite_creds); + composite_creds->Unref(); } -static grpc_security_status -check_channel_oauth2_google_iam_create_security_connector( - grpc_channel_credentials* c, grpc_call_credentials* call_creds, - const char* target, const grpc_channel_args* args, - grpc_channel_security_connector** sc, grpc_channel_args** new_args) { - const grpc_call_credentials_array* creds_array; - GPR_ASSERT(strcmp(c->type, "mock") == 0); - GPR_ASSERT(call_creds != nullptr); - GPR_ASSERT(strcmp(call_creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == - 0); - creds_array = grpc_composite_call_credentials_get_credentials(call_creds); - GPR_ASSERT(strcmp(creds_array->creds_array[0]->type, - GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); - GPR_ASSERT(strcmp(creds_array->creds_array[1]->type, - GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0); - return GRPC_SECURITY_OK; -} +namespace { +class check_channel_oauth2_google_iam final : public grpc_channel_credentials { + public: + check_channel_oauth2_google_iam() : grpc_channel_credentials("mock") {} + ~check_channel_oauth2_google_iam() override = default; + + grpc_core::RefCountedPtr + create_security_connector( + grpc_core::RefCountedPtr call_creds, + const char* target, const grpc_channel_args* args, + grpc_channel_args** new_args) override { + GPR_ASSERT(strcmp(type(), "mock") == 0); + GPR_ASSERT(call_creds != nullptr); + GPR_ASSERT( + strcmp(call_creds->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); + const grpc_call_credentials_array& creds_array = + static_cast(call_creds.get()) + ->inner(); + GPR_ASSERT(strcmp(creds_array.get(0)->type(), + GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); + GPR_ASSERT(strcmp(creds_array.get(1)->type(), + GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0); + return nullptr; + } +}; +} // namespace static void test_channel_oauth2_google_iam_composite_creds(void) { grpc_core::ExecCtx exec_ctx; grpc_channel_args* new_args; - grpc_channel_credentials_vtable vtable = { - nullptr, check_channel_oauth2_google_iam_create_security_connector, - nullptr}; grpc_channel_credentials* channel_creds = - grpc_mock_channel_credentials_create(&vtable); + grpc_core::New(); grpc_call_credentials* oauth2_creds = grpc_access_token_credentials_create("blah", nullptr); grpc_channel_credentials* channel_oauth2_creds = @@ -524,9 +525,8 @@ static void test_channel_oauth2_google_iam_composite_creds(void) { grpc_channel_credentials_release(channel_oauth2_creds); grpc_call_credentials_release(google_iam_creds); - GPR_ASSERT(grpc_channel_credentials_create_security_connector( - channel_oauth2_iam_creds, nullptr, nullptr, nullptr, - &new_args) == GRPC_SECURITY_OK); + channel_oauth2_iam_creds->create_security_connector(nullptr, nullptr, nullptr, + &new_args); grpc_channel_credentials_release(channel_oauth2_iam_creds); } @@ -578,7 +578,7 @@ static int httpcli_get_should_not_be_called(const grpc_httpcli_request* request, return 1; } -static void test_compute_engine_creds_success(void) { +static void test_compute_engine_creds_success() { grpc_core::ExecCtx exec_ctx; expected_md emd[] = { {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}}; @@ -603,7 +603,7 @@ static void test_compute_engine_creds_success(void) { run_request_metadata_test(creds, auth_md_ctx, state); grpc_core::ExecCtx::Get()->Flush(); - grpc_call_credentials_unref(creds); + creds->Unref(); grpc_httpcli_set_override(nullptr, nullptr); } @@ -620,7 +620,7 @@ static void test_compute_engine_creds_failure(void) { grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override, httpcli_post_should_not_be_called); run_request_metadata_test(creds, auth_md_ctx, state); - grpc_call_credentials_unref(creds); + creds->Unref(); grpc_httpcli_set_override(nullptr, nullptr); } @@ -692,7 +692,7 @@ static void test_refresh_token_creds_success(void) { run_request_metadata_test(creds, auth_md_ctx, state); grpc_core::ExecCtx::Get()->Flush(); - grpc_call_credentials_unref(creds); + creds->Unref(); grpc_httpcli_set_override(nullptr, nullptr); } @@ -709,7 +709,7 @@ static void test_refresh_token_creds_failure(void) { grpc_httpcli_set_override(httpcli_get_should_not_be_called, refresh_token_httpcli_post_failure); run_request_metadata_test(creds, auth_md_ctx, state); - grpc_call_credentials_unref(creds); + creds->Unref(); grpc_httpcli_set_override(nullptr, nullptr); } @@ -762,7 +762,7 @@ static char* encode_and_sign_jwt_should_not_be_called( static grpc_service_account_jwt_access_credentials* creds_as_jwt( grpc_call_credentials* creds) { GPR_ASSERT(creds != nullptr); - GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_JWT) == 0); + GPR_ASSERT(strcmp(creds->type(), GRPC_CALL_CREDENTIALS_TYPE_JWT) == 0); return reinterpret_cast(creds); } @@ -773,7 +773,7 @@ static void test_jwt_creds_lifetime(void) { grpc_call_credentials* jwt_creds = grpc_service_account_jwt_access_credentials_create( json_key_string, grpc_max_auth_token_lifetime(), nullptr); - GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime, + GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(), grpc_max_auth_token_lifetime()) == 0); grpc_call_credentials_release(jwt_creds); @@ -782,8 +782,8 @@ static void test_jwt_creds_lifetime(void) { GPR_ASSERT(gpr_time_cmp(grpc_max_auth_token_lifetime(), token_lifetime) > 0); jwt_creds = grpc_service_account_jwt_access_credentials_create( json_key_string, token_lifetime, nullptr); - GPR_ASSERT( - gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime, token_lifetime) == 0); + GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(), + token_lifetime) == 0); grpc_call_credentials_release(jwt_creds); // Cropped lifetime. @@ -791,7 +791,7 @@ static void test_jwt_creds_lifetime(void) { token_lifetime = gpr_time_add(grpc_max_auth_token_lifetime(), add_to_max); jwt_creds = grpc_service_account_jwt_access_credentials_create( json_key_string, token_lifetime, nullptr); - GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime, + GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(), grpc_max_auth_token_lifetime()) == 0); grpc_call_credentials_release(jwt_creds); @@ -834,7 +834,7 @@ static void test_jwt_creds_success(void) { run_request_metadata_test(creds, auth_md_ctx, state); grpc_core::ExecCtx::Get()->Flush(); - grpc_call_credentials_unref(creds); + creds->Unref(); gpr_free(json_key_string); gpr_free(expected_md_value); grpc_jwt_encode_and_sign_set_override(nullptr); @@ -856,7 +856,7 @@ static void test_jwt_creds_signing_failure(void) { run_request_metadata_test(creds, auth_md_ctx, state); gpr_free(json_key_string); - grpc_call_credentials_unref(creds); + creds->Unref(); grpc_jwt_encode_and_sign_set_override(nullptr); } @@ -875,8 +875,6 @@ static void set_google_default_creds_env_var_with_file_contents( static void test_google_default_creds_auth_key(void) { grpc_core::ExecCtx exec_ctx; - grpc_service_account_jwt_access_credentials* jwt; - grpc_google_default_channel_credentials* default_creds; grpc_composite_channel_credentials* creds; char* json_key = test_json_key_str(); grpc_flush_cached_google_default_credentials(); @@ -885,37 +883,39 @@ static void test_google_default_creds_auth_key(void) { gpr_free(json_key); creds = reinterpret_cast( grpc_google_default_credentials_create()); - default_creds = reinterpret_cast( - creds->inner_creds); - GPR_ASSERT(default_creds->ssl_creds != nullptr); - jwt = reinterpret_cast( - creds->call_creds); + auto* default_creds = + reinterpret_cast( + creds->inner_creds()); + GPR_ASSERT(default_creds->ssl_creds() != nullptr); + auto* jwt = + reinterpret_cast( + creds->call_creds()); GPR_ASSERT( - strcmp(jwt->key.client_id, + strcmp(jwt->key().client_id, "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") == 0); - grpc_channel_credentials_unref(&creds->base); + creds->Unref(); gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ } static void test_google_default_creds_refresh_token(void) { grpc_core::ExecCtx exec_ctx; - grpc_google_refresh_token_credentials* refresh; - grpc_google_default_channel_credentials* default_creds; grpc_composite_channel_credentials* creds; grpc_flush_cached_google_default_credentials(); set_google_default_creds_env_var_with_file_contents( "refresh_token_google_default_creds", test_refresh_token_str); creds = reinterpret_cast( grpc_google_default_credentials_create()); - default_creds = reinterpret_cast( - creds->inner_creds); - GPR_ASSERT(default_creds->ssl_creds != nullptr); - refresh = reinterpret_cast( - creds->call_creds); - GPR_ASSERT(strcmp(refresh->refresh_token.client_id, + auto* default_creds = + reinterpret_cast( + creds->inner_creds()); + GPR_ASSERT(default_creds->ssl_creds() != nullptr); + auto* refresh = + reinterpret_cast( + creds->call_creds()); + GPR_ASSERT(strcmp(refresh->refresh_token().client_id, "32555999999.apps.googleusercontent.com") == 0); - grpc_channel_credentials_unref(&creds->base); + creds->Unref(); gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ } @@ -965,16 +965,16 @@ static void test_google_default_creds_gce(void) { /* Verify that the default creds actually embeds a GCE creds. */ GPR_ASSERT(creds != nullptr); - GPR_ASSERT(creds->call_creds != nullptr); + GPR_ASSERT(creds->call_creds() != nullptr); grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, httpcli_post_should_not_be_called); - run_request_metadata_test(creds->call_creds, auth_md_ctx, state); + run_request_metadata_test(creds->mutable_call_creds(), auth_md_ctx, state); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT(g_test_gce_tenancy_checker_called == true); /* Cleanup. */ - grpc_channel_credentials_unref(&creds->base); + creds->Unref(); grpc_httpcli_set_override(nullptr, nullptr); grpc_override_well_known_credentials_path_getter(nullptr); } @@ -1003,14 +1003,14 @@ static void test_google_default_creds_non_gce(void) { grpc_google_default_credentials_create()); /* Verify that the default creds actually embeds a GCE creds. */ GPR_ASSERT(creds != nullptr); - GPR_ASSERT(creds->call_creds != nullptr); + GPR_ASSERT(creds->call_creds() != nullptr); grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, httpcli_post_should_not_be_called); - run_request_metadata_test(creds->call_creds, auth_md_ctx, state); + run_request_metadata_test(creds->mutable_call_creds(), auth_md_ctx, state); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT(g_test_gce_tenancy_checker_called == true); /* Cleanup. */ - grpc_channel_credentials_unref(&creds->base); + creds->Unref(); grpc_httpcli_set_override(nullptr, nullptr); grpc_override_well_known_credentials_path_getter(nullptr); } @@ -1121,7 +1121,7 @@ static void test_metadata_plugin_success(void) { GPR_ASSERT(state == PLUGIN_INITIAL_STATE); run_request_metadata_test(creds, auth_md_ctx, md_state); GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE); - grpc_call_credentials_unref(creds); + creds->Unref(); GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE); } @@ -1149,7 +1149,7 @@ static void test_metadata_plugin_failure(void) { GPR_ASSERT(state == PLUGIN_INITIAL_STATE); run_request_metadata_test(creds, auth_md_ctx, md_state); GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE); - grpc_call_credentials_unref(creds); + creds->Unref(); GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE); } @@ -1176,25 +1176,23 @@ static void test_channel_creds_duplicate_without_call_creds(void) { grpc_channel_credentials* channel_creds = grpc_fake_transport_security_credentials_create(); - grpc_channel_credentials* dup = - grpc_channel_credentials_duplicate_without_call_credentials( - channel_creds); + grpc_core::RefCountedPtr dup = + channel_creds->duplicate_without_call_credentials(); GPR_ASSERT(dup == channel_creds); - grpc_channel_credentials_unref(dup); + dup.reset(); grpc_call_credentials* call_creds = grpc_access_token_credentials_create("blah", nullptr); grpc_channel_credentials* composite_creds = grpc_composite_channel_credentials_create(channel_creds, call_creds, nullptr); - grpc_call_credentials_unref(call_creds); - dup = grpc_channel_credentials_duplicate_without_call_credentials( - composite_creds); + call_creds->Unref(); + dup = composite_creds->duplicate_without_call_credentials(); GPR_ASSERT(dup == channel_creds); - grpc_channel_credentials_unref(dup); + dup.reset(); - grpc_channel_credentials_unref(channel_creds); - grpc_channel_credentials_unref(composite_creds); + channel_creds->Unref(); + composite_creds->Unref(); } typedef struct { diff --git a/test/core/security/oauth2_utils.cc b/test/core/security/oauth2_utils.cc index 469129a6d03..c9e205ab743 100644 --- a/test/core/security/oauth2_utils.cc +++ b/test/core/security/oauth2_utils.cc @@ -86,9 +86,8 @@ char* grpc_test_fetch_oauth2_token_with_credentials( grpc_schedule_on_exec_ctx); grpc_error* error = GRPC_ERROR_NONE; - if (grpc_call_credentials_get_request_metadata(creds, &request.pops, null_ctx, - &request.md_array, - &request.closure, &error)) { + if (creds->get_request_metadata(&request.pops, null_ctx, &request.md_array, + &request.closure, &error)) { // Synchronous result; invoke callback directly. on_oauth2_response(&request, error); GRPC_ERROR_UNREF(error); diff --git a/test/core/security/print_google_default_creds_token.cc b/test/core/security/print_google_default_creds_token.cc index 4d251391ff2..398c58c6e17 100644 --- a/test/core/security/print_google_default_creds_token.cc +++ b/test/core/security/print_google_default_creds_token.cc @@ -96,11 +96,10 @@ int main(int argc, char** argv) { grpc_schedule_on_exec_ctx); error = GRPC_ERROR_NONE; - if (grpc_call_credentials_get_request_metadata( - (reinterpret_cast(creds)) - ->call_creds, - &sync.pops, context, &sync.md_array, &sync.on_request_metadata, - &error)) { + if (reinterpret_cast(creds) + ->mutable_call_creds() + ->get_request_metadata(&sync.pops, context, &sync.md_array, + &sync.on_request_metadata, &error)) { // Synchronous response. Invoke callback directly. on_metadata_response(&sync, error); GRPC_ERROR_UNREF(error); diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc index e82a8627d40..2a31763c73c 100644 --- a/test/core/security/security_connector_test.cc +++ b/test/core/security/security_connector_test.cc @@ -27,6 +27,7 @@ #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/security_connector/security_connector.h" #include "src/core/lib/security/security_connector/ssl_utils.h" @@ -83,22 +84,22 @@ static int check_ssl_peer_equivalence(const tsi_peer* original, static void test_unauthenticated_ssl_peer(void) { tsi_peer peer; tsi_peer rpeer; - grpc_auth_context* ctx; GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK); GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, &peer.properties[0]) == TSI_OK); - ctx = grpc_ssl_peer_to_auth_context(&peer); + grpc_core::RefCountedPtr ctx = + grpc_ssl_peer_to_auth_context(&peer); GPR_ASSERT(ctx != nullptr); - GPR_ASSERT(!grpc_auth_context_peer_is_authenticated(ctx)); - GPR_ASSERT(check_transport_security_type(ctx)); + GPR_ASSERT(!grpc_auth_context_peer_is_authenticated(ctx.get())); + GPR_ASSERT(check_transport_security_type(ctx.get())); - rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx); + rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get()); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); grpc_shallow_peer_destruct(&rpeer); tsi_peer_destruct(&peer); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } static int check_identity(const grpc_auth_context* ctx, @@ -175,7 +176,6 @@ static int check_x509_pem_cert(const grpc_auth_context* ctx, static void test_cn_only_ssl_peer_to_auth_context(void) { tsi_peer peer; tsi_peer rpeer; - grpc_auth_context* ctx; const char* expected_cn = "cn1"; const char* expected_pem_cert = "pem_cert1"; GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK); @@ -188,26 +188,27 @@ static void test_cn_only_ssl_peer_to_auth_context(void) { GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert, &peer.properties[2]) == TSI_OK); - ctx = grpc_ssl_peer_to_auth_context(&peer); + grpc_core::RefCountedPtr ctx = + grpc_ssl_peer_to_auth_context(&peer); GPR_ASSERT(ctx != nullptr); - GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx)); - GPR_ASSERT(check_identity(ctx, GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1)); - GPR_ASSERT(check_transport_security_type(ctx)); - GPR_ASSERT(check_x509_cn(ctx, expected_cn)); - GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert)); + GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get())); + GPR_ASSERT( + check_identity(ctx.get(), GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1)); + GPR_ASSERT(check_transport_security_type(ctx.get())); + GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn)); + GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert)); - rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx); + rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get()); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); grpc_shallow_peer_destruct(&rpeer); tsi_peer_destruct(&peer); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } static void test_cn_and_one_san_ssl_peer_to_auth_context(void) { tsi_peer peer; tsi_peer rpeer; - grpc_auth_context* ctx; const char* expected_cn = "cn1"; const char* expected_san = "san1"; const char* expected_pem_cert = "pem_cert1"; @@ -224,27 +225,28 @@ static void test_cn_and_one_san_ssl_peer_to_auth_context(void) { GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert, &peer.properties[3]) == TSI_OK); - ctx = grpc_ssl_peer_to_auth_context(&peer); + + grpc_core::RefCountedPtr ctx = + grpc_ssl_peer_to_auth_context(&peer); GPR_ASSERT(ctx != nullptr); - GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx)); + GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get())); GPR_ASSERT( - check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1)); - GPR_ASSERT(check_transport_security_type(ctx)); - GPR_ASSERT(check_x509_cn(ctx, expected_cn)); - GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert)); + check_identity(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1)); + GPR_ASSERT(check_transport_security_type(ctx.get())); + GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn)); + GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert)); - rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx); + rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get()); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); grpc_shallow_peer_destruct(&rpeer); tsi_peer_destruct(&peer); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) { tsi_peer peer; tsi_peer rpeer; - grpc_auth_context* ctx; const char* expected_cn = "cn1"; const char* expected_sans[] = {"san1", "san2", "san3"}; const char* expected_pem_cert = "pem_cert1"; @@ -265,28 +267,28 @@ static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) { TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_sans[i], &peer.properties[3 + i]) == TSI_OK); } - ctx = grpc_ssl_peer_to_auth_context(&peer); + grpc_core::RefCountedPtr ctx = + grpc_ssl_peer_to_auth_context(&peer); GPR_ASSERT(ctx != nullptr); - GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx)); - GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, expected_sans, - GPR_ARRAY_SIZE(expected_sans))); - GPR_ASSERT(check_transport_security_type(ctx)); - GPR_ASSERT(check_x509_cn(ctx, expected_cn)); - GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert)); - - rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx); + GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get())); + GPR_ASSERT(check_identity(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME, + expected_sans, GPR_ARRAY_SIZE(expected_sans))); + GPR_ASSERT(check_transport_security_type(ctx.get())); + GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn)); + GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert)); + + rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get()); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); grpc_shallow_peer_destruct(&rpeer); tsi_peer_destruct(&peer); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context( void) { tsi_peer peer; tsi_peer rpeer; - grpc_auth_context* ctx; const char* expected_cn = "cn1"; const char* expected_pem_cert = "pem_cert1"; const char* expected_sans[] = {"san1", "san2", "san3"}; @@ -311,21 +313,22 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context( TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_sans[i], &peer.properties[5 + i]) == TSI_OK); } - ctx = grpc_ssl_peer_to_auth_context(&peer); + grpc_core::RefCountedPtr ctx = + grpc_ssl_peer_to_auth_context(&peer); GPR_ASSERT(ctx != nullptr); - GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx)); - GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, expected_sans, - GPR_ARRAY_SIZE(expected_sans))); - GPR_ASSERT(check_transport_security_type(ctx)); - GPR_ASSERT(check_x509_cn(ctx, expected_cn)); - GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert)); - - rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx); + GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get())); + GPR_ASSERT(check_identity(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME, + expected_sans, GPR_ARRAY_SIZE(expected_sans))); + GPR_ASSERT(check_transport_security_type(ctx.get())); + GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn)); + GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert)); + + rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get()); GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer)); grpc_shallow_peer_destruct(&rpeer); tsi_peer_destruct(&peer); - GRPC_AUTH_CONTEXT_UNREF(ctx, "test"); + ctx.reset(DEBUG_LOCATION, "test"); } static const char* roots_for_override_api = "roots for override api"; diff --git a/test/core/security/ssl_server_fuzzer.cc b/test/core/security/ssl_server_fuzzer.cc index d2bbb7c1c2e..c9380126dd0 100644 --- a/test/core/security/ssl_server_fuzzer.cc +++ b/test/core/security/ssl_server_fuzzer.cc @@ -82,16 +82,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ca_cert, &pem_key_cert_pair, 1, 0, nullptr); // Create security connector - grpc_server_security_connector* sc = nullptr; - grpc_security_status status = - grpc_server_credentials_create_security_connector(creds, &sc); - GPR_ASSERT(status == GRPC_SECURITY_OK); + grpc_core::RefCountedPtr sc = + creds->create_security_connector(); + GPR_ASSERT(sc != nullptr); grpc_millis deadline = GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(); struct handshake_state state; state.done_callback_called = false; grpc_handshake_manager* handshake_mgr = grpc_handshake_manager_create(); - grpc_server_security_connector_add_handshakers(sc, nullptr, handshake_mgr); + sc->add_handshakers(nullptr, handshake_mgr); grpc_handshake_manager_do_handshake( handshake_mgr, mock_endpoint, nullptr /* channel_args */, deadline, nullptr /* acceptor */, on_handshake_done, &state); @@ -110,7 +109,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { GPR_ASSERT(state.done_callback_called); grpc_handshake_manager_destroy(handshake_mgr); - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "test"); + sc.reset(DEBUG_LOCATION, "test"); grpc_server_credentials_release(creds); grpc_slice_unref(cert_slice); grpc_slice_unref(key_slice); diff --git a/test/core/surface/secure_channel_create_test.cc b/test/core/surface/secure_channel_create_test.cc index 5610d1ec4ab..e9bb815f6ee 100644 --- a/test/core/surface/secure_channel_create_test.cc +++ b/test/core/surface/secure_channel_create_test.cc @@ -39,7 +39,7 @@ void test_unknown_scheme_target(void) { GPR_ASSERT(0 == strcmp(elem->filter->name, "lame-client")); grpc_core::ExecCtx exec_ctx; GRPC_CHANNEL_INTERNAL_UNREF(chan, "test"); - grpc_channel_credentials_unref(creds); + creds->Unref(); } void test_security_connector_already_in_arg(void) { diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc index 9634555e4b5..5a2844d518a 100644 --- a/test/cpp/common/auth_property_iterator_test.cc +++ b/test/cpp/common/auth_property_iterator_test.cc @@ -40,15 +40,14 @@ class TestAuthPropertyIterator : public AuthPropertyIterator { class AuthPropertyIteratorTest : public ::testing::Test { protected: void SetUp() override { - ctx_ = grpc_auth_context_create(nullptr); - grpc_auth_context_add_cstring_property(ctx_, "name", "chapi"); - grpc_auth_context_add_cstring_property(ctx_, "name", "chapo"); - grpc_auth_context_add_cstring_property(ctx_, "foo", "bar"); - EXPECT_EQ(1, - grpc_auth_context_set_peer_identity_property_name(ctx_, "name")); + ctx_ = grpc_core::MakeRefCounted(nullptr); + grpc_auth_context_add_cstring_property(ctx_.get(), "name", "chapi"); + grpc_auth_context_add_cstring_property(ctx_.get(), "name", "chapo"); + grpc_auth_context_add_cstring_property(ctx_.get(), "foo", "bar"); + EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx_.get(), + "name")); } - void TearDown() override { grpc_auth_context_release(ctx_); } - grpc_auth_context* ctx_; + grpc_core::RefCountedPtr ctx_; }; TEST_F(AuthPropertyIteratorTest, DefaultCtor) { @@ -59,7 +58,7 @@ TEST_F(AuthPropertyIteratorTest, DefaultCtor) { TEST_F(AuthPropertyIteratorTest, GeneralTest) { grpc_auth_property_iterator c_iter = - grpc_auth_context_property_iterator(ctx_); + grpc_auth_context_property_iterator(ctx_.get()); const grpc_auth_property* property = grpc_auth_property_iterator_next(&c_iter); TestAuthPropertyIterator iter(property, &c_iter); diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc index 6461f497433..03b3a9fdd8e 100644 --- a/test/cpp/common/secure_auth_context_test.cc +++ b/test/cpp/common/secure_auth_context_test.cc @@ -33,7 +33,7 @@ class SecureAuthContextTest : public ::testing::Test {}; // Created with nullptr TEST_F(SecureAuthContextTest, EmptyContext) { - SecureAuthContext context(nullptr, true); + SecureAuthContext context(nullptr); EXPECT_TRUE(context.GetPeerIdentity().empty()); EXPECT_TRUE(context.GetPeerIdentityPropertyName().empty()); EXPECT_TRUE(context.FindPropertyValues("").empty()); @@ -42,8 +42,10 @@ TEST_F(SecureAuthContextTest, EmptyContext) { } TEST_F(SecureAuthContextTest, Properties) { - grpc_auth_context* ctx = grpc_auth_context_create(nullptr); - SecureAuthContext context(ctx, true); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(nullptr); + SecureAuthContext context(ctx.get()); + ctx.reset(); context.AddProperty("name", "chapi"); context.AddProperty("name", "chapo"); context.AddProperty("foo", "bar"); @@ -60,8 +62,10 @@ TEST_F(SecureAuthContextTest, Properties) { } TEST_F(SecureAuthContextTest, Iterators) { - grpc_auth_context* ctx = grpc_auth_context_create(nullptr); - SecureAuthContext context(ctx, true); + grpc_core::RefCountedPtr ctx = + grpc_core::MakeRefCounted(nullptr); + SecureAuthContext context(ctx.get()); + ctx.reset(); context.AddProperty("name", "chapi"); context.AddProperty("name", "chapo"); context.AddProperty("foo", "bar"); diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index bf990a07b5a..2eaacd429de 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -414,8 +414,8 @@ class GrpclbEnd2endTest : public ::testing::Test { std::shared_ptr creds( new SecureChannelCredentials(grpc_composite_channel_credentials_create( channel_creds, call_creds, nullptr))); - grpc_call_credentials_unref(call_creds); - grpc_channel_credentials_unref(channel_creds); + call_creds->Unref(); + channel_creds->Unref(); channel_ = CreateCustomChannel(uri.str(), creds, args); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } From 45b3230ef2b6a4a7e4c7a2348fa65b2c59fe579a Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 12 Dec 2018 17:16:12 -0800 Subject: [PATCH 89/99] Add grpcio-status extension package * The new package has 2 API `from_call` and `to_status` * Utilize the experimental API `abort_with_status` * Add 5 unit test cases --- requirements.bazel.txt | 1 + src/python/grpcio_status/.gitignore | 3 + src/python/grpcio_status/MANIFEST.in | 3 + src/python/grpcio_status/README.rst | 9 + .../grpcio_status/grpc_status/BUILD.bazel | 14 ++ .../grpcio_status/grpc_status/__init__.py | 13 ++ .../grpcio_status/grpc_status/rpc_status.py | 88 +++++++++ src/python/grpcio_status/grpc_version.py | 17 ++ src/python/grpcio_status/setup.py | 86 +++++++++ src/python/grpcio_tests/setup.py | 1 + .../grpcio_tests/tests/status/BUILD.bazel | 19 ++ .../grpcio_tests/tests/status/__init__.py | 13 ++ .../tests/status/_grpc_status_test.py | 175 ++++++++++++++++++ src/python/grpcio_tests/tests/tests.json | 1 + .../grpcio_status/grpc_version.py.template | 19 ++ tools/distrib/pylint_code.sh | 1 + .../artifacts/build_artifact_python.sh | 5 + .../run_tests/helper_scripts/build_python.sh | 8 +- 18 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 src/python/grpcio_status/.gitignore create mode 100644 src/python/grpcio_status/MANIFEST.in create mode 100644 src/python/grpcio_status/README.rst create mode 100644 src/python/grpcio_status/grpc_status/BUILD.bazel create mode 100644 src/python/grpcio_status/grpc_status/__init__.py create mode 100644 src/python/grpcio_status/grpc_status/rpc_status.py create mode 100644 src/python/grpcio_status/grpc_version.py create mode 100644 src/python/grpcio_status/setup.py create mode 100644 src/python/grpcio_tests/tests/status/BUILD.bazel create mode 100644 src/python/grpcio_tests/tests/status/__init__.py create mode 100644 src/python/grpcio_tests/tests/status/_grpc_status_test.py create mode 100644 templates/src/python/grpcio_status/grpc_version.py.template diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 7794aec752e..e97843794e4 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -13,3 +13,4 @@ urllib3>=1.23 chardet==3.0.4 certifi==2017.4.17 idna==2.7 +googleapis-common-protos==1.5.5 diff --git a/src/python/grpcio_status/.gitignore b/src/python/grpcio_status/.gitignore new file mode 100644 index 00000000000..19d1523efde --- /dev/null +++ b/src/python/grpcio_status/.gitignore @@ -0,0 +1,3 @@ +build/ +grpcio_status.egg-info/ +dist/ diff --git a/src/python/grpcio_status/MANIFEST.in b/src/python/grpcio_status/MANIFEST.in new file mode 100644 index 00000000000..eca719a9c20 --- /dev/null +++ b/src/python/grpcio_status/MANIFEST.in @@ -0,0 +1,3 @@ +include grpc_version.py +recursive-include grpc_status *.py +global-exclude *.pyc diff --git a/src/python/grpcio_status/README.rst b/src/python/grpcio_status/README.rst new file mode 100644 index 00000000000..dc2f7b1dab1 --- /dev/null +++ b/src/python/grpcio_status/README.rst @@ -0,0 +1,9 @@ +gRPC Python Status Proto +=========================== + +Reference package for GRPC Python status proto mapping. + +Dependencies +------------ + +Depends on the `grpcio` package, available from PyPI via `pip install grpcio`. diff --git a/src/python/grpcio_status/grpc_status/BUILD.bazel b/src/python/grpcio_status/grpc_status/BUILD.bazel new file mode 100644 index 00000000000..223a077c3f2 --- /dev/null +++ b/src/python/grpcio_status/grpc_status/BUILD.bazel @@ -0,0 +1,14 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "grpc_status", + srcs = ["rpc_status.py",], + deps = [ + "//src/python/grpcio/grpc:grpcio", + requirement('protobuf'), + requirement('googleapis-common-protos'), + ], + imports=["../",], +) diff --git a/src/python/grpcio_status/grpc_status/__init__.py b/src/python/grpcio_status/grpc_status/__init__.py new file mode 100644 index 00000000000..38fdfc9c5cf --- /dev/null +++ b/src/python/grpcio_status/grpc_status/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 The 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. diff --git a/src/python/grpcio_status/grpc_status/rpc_status.py b/src/python/grpcio_status/grpc_status/rpc_status.py new file mode 100644 index 00000000000..36c8eba37d5 --- /dev/null +++ b/src/python/grpcio_status/grpc_status/rpc_status.py @@ -0,0 +1,88 @@ +# Copyright 2018 The 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. +"""Reference implementation for status mapping in gRPC Python.""" + +import collections + +import grpc + +# TODO(https://github.com/bazelbuild/bazel/issues/6844) +# Due to Bazel issue, the namespace packages won't resolve correctly. +# Adding this unused-import as a workaround to avoid module-not-found error +# under Bazel builds. +import google.protobuf # pylint: disable=unused-import +from google.rpc import status_pb2 + +_CODE_TO_GRPC_CODE_MAPPING = dict([(x.value[0], x) for x in grpc.StatusCode]) + +_GRPC_DETAILS_METADATA_KEY = 'grpc-status-details-bin' + + +class _Status( + collections.namedtuple( + '_Status', ('code', 'details', 'trailing_metadata')), grpc.Status): + pass + + +def _code_to_grpc_status_code(code): + try: + return _CODE_TO_GRPC_CODE_MAPPING[code] + except KeyError: + raise ValueError('Invalid status code %s' % code) + + +def from_call(call): + """Returns a google.rpc.status.Status message corresponding to a given grpc.Call. + + Args: + call: A grpc.Call instance. + + Returns: + A google.rpc.status.Status message representing the status of the RPC. + + Raises: + ValueError: If the status code, status message is inconsistent with the rich status + inside of the google.rpc.status.Status. + """ + for key, value in call.trailing_metadata(): + if key == _GRPC_DETAILS_METADATA_KEY: + rich_status = status_pb2.Status.FromString(value) + if call.code().value[0] != rich_status.code: + raise ValueError( + 'Code in Status proto (%s) doesn\'t match status code (%s)' + % (_code_to_grpc_status_code(rich_status.code), + call.code())) + if call.details() != rich_status.message: + raise ValueError( + 'Message in Status proto (%s) doesn\'t match status details (%s)' + % (rich_status.message, call.details())) + return rich_status + return None + + +def to_status(status): + """Convert a google.rpc.status.Status message to grpc.Status. + + Args: + status: a google.rpc.status.Status message representing the non-OK status + to terminate the RPC with and communicate it to the client. + + Returns: + A grpc.Status instance. + """ + return _Status( + code=_code_to_grpc_status_code(status.code), + details=status.message, + trailing_metadata=((_GRPC_DETAILS_METADATA_KEY, + status.SerializeToString()),)) diff --git a/src/python/grpcio_status/grpc_version.py b/src/python/grpcio_status/grpc_version.py new file mode 100644 index 00000000000..e009843b94f --- /dev/null +++ b/src/python/grpcio_status/grpc_version.py @@ -0,0 +1,17 @@ +# Copyright 2018 The 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/src/python/grpcio_status/grpc_version.py.template`!!! + +VERSION = '1.18.0.dev0' diff --git a/src/python/grpcio_status/setup.py b/src/python/grpcio_status/setup.py new file mode 100644 index 00000000000..0601498bc51 --- /dev/null +++ b/src/python/grpcio_status/setup.py @@ -0,0 +1,86 @@ +# Copyright 2018 The 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. +"""Setup module for the GRPC Python package's status mapping.""" + +import os + +import setuptools + +# Ensure we're in the proper directory whether or not we're being used by pip. +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +# Break import-style to ensure we can actually find our local modules. +import grpc_version + + +class _NoOpCommand(setuptools.Command): + """No-op command.""" + + description = '' + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + pass + + +CLASSIFIERS = [ + 'Development Status :: 5 - Production/Stable', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'License :: OSI Approved :: Apache Software License', +] + +PACKAGE_DIRECTORIES = { + '': '.', +} + +INSTALL_REQUIRES = ( + 'protobuf>=3.6.0', + 'grpcio>={version}'.format(version=grpc_version.VERSION), + 'googleapis-common-protos>=1.5.5', +) + +SETUP_REQUIRES = () +COMMAND_CLASS = { + # wire up commands to no-op not to break the external dependencies + 'preprocess': _NoOpCommand, + 'build_package_protos': _NoOpCommand, +} + +setuptools.setup( + name='grpcio-status', + version=grpc_version.VERSION, + description='Status proto mapping for gRPC', + author='The gRPC Authors', + author_email='grpc-io@googlegroups.com', + url='https://grpc.io', + license='Apache License 2.0', + classifiers=CLASSIFIERS, + package_dir=PACKAGE_DIRECTORIES, + packages=setuptools.find_packages('.'), + install_requires=INSTALL_REQUIRES, + setup_requires=SETUP_REQUIRES, + cmdclass=COMMAND_CLASS) diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py index f56425ac6d3..f9cb9d0cec9 100644 --- a/src/python/grpcio_tests/setup.py +++ b/src/python/grpcio_tests/setup.py @@ -40,6 +40,7 @@ INSTALL_REQUIRES = ( 'coverage>=4.0', 'enum34>=1.0.4', 'grpcio>={version}'.format(version=grpc_version.VERSION), 'grpcio-channelz>={version}'.format(version=grpc_version.VERSION), + 'grpcio-status>={version}'.format(version=grpc_version.VERSION), 'grpcio-tools>={version}'.format(version=grpc_version.VERSION), 'grpcio-health-checking>={version}'.format(version=grpc_version.VERSION), 'oauth2client>=1.4.7', 'protobuf>=3.6.0', 'six>=1.10', 'google-auth>=1.0.0', diff --git a/src/python/grpcio_tests/tests/status/BUILD.bazel b/src/python/grpcio_tests/tests/status/BUILD.bazel new file mode 100644 index 00000000000..937e50498e0 --- /dev/null +++ b/src/python/grpcio_tests/tests/status/BUILD.bazel @@ -0,0 +1,19 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +py_test( + name = "grpc_status_test", + srcs = ["_grpc_status_test.py"], + main = "_grpc_status_test.py", + size = "small", + deps = [ + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_status/grpc_status:grpc_status", + "//src/python/grpcio_tests/tests/unit:test_common", + "//src/python/grpcio_tests/tests/unit/framework/common:common", + requirement('protobuf'), + requirement('googleapis-common-protos'), + ], + imports = ["../../",], +) diff --git a/src/python/grpcio_tests/tests/status/__init__.py b/src/python/grpcio_tests/tests/status/__init__.py new file mode 100644 index 00000000000..38fdfc9c5cf --- /dev/null +++ b/src/python/grpcio_tests/tests/status/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 The 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. diff --git a/src/python/grpcio_tests/tests/status/_grpc_status_test.py b/src/python/grpcio_tests/tests/status/_grpc_status_test.py new file mode 100644 index 00000000000..5969338736f --- /dev/null +++ b/src/python/grpcio_tests/tests/status/_grpc_status_test.py @@ -0,0 +1,175 @@ +# Copyright 2018 The 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. +"""Tests of grpc_status.""" + +import unittest + +import logging +import traceback + +import grpc +from grpc_status import rpc_status + +from tests.unit import test_common + +from google.protobuf import any_pb2 +from google.rpc import code_pb2, status_pb2, error_details_pb2 + +_STATUS_OK = '/test/StatusOK' +_STATUS_NOT_OK = '/test/StatusNotOk' +_ERROR_DETAILS = '/test/ErrorDetails' +_INCONSISTENT = '/test/Inconsistent' +_INVALID_CODE = '/test/InvalidCode' + +_REQUEST = b'\x00\x00\x00' +_RESPONSE = b'\x01\x01\x01' + +_GRPC_DETAILS_METADATA_KEY = 'grpc-status-details-bin' + +_STATUS_DETAILS = 'This is an error detail' +_STATUS_DETAILS_ANOTHER = 'This is another error detail' + + +def _ok_unary_unary(request, servicer_context): + return _RESPONSE + + +def _not_ok_unary_unary(request, servicer_context): + servicer_context.abort(grpc.StatusCode.INTERNAL, _STATUS_DETAILS) + + +def _error_details_unary_unary(request, servicer_context): + details = any_pb2.Any() + details.Pack( + error_details_pb2.DebugInfo( + stack_entries=traceback.format_stack(), + detail='Intensionally invoked')) + rich_status = status_pb2.Status( + code=code_pb2.INTERNAL, + message=_STATUS_DETAILS, + details=[details], + ) + servicer_context.abort_with_status(rpc_status.to_status(rich_status)) + + +def _inconsistent_unary_unary(request, servicer_context): + rich_status = status_pb2.Status( + code=code_pb2.INTERNAL, + message=_STATUS_DETAILS, + ) + servicer_context.set_code(grpc.StatusCode.NOT_FOUND) + servicer_context.set_details(_STATUS_DETAILS_ANOTHER) + # User put inconsistent status information in trailing metadata + servicer_context.set_trailing_metadata(((_GRPC_DETAILS_METADATA_KEY, + rich_status.SerializeToString()),)) + + +def _invalid_code_unary_unary(request, servicer_context): + rich_status = status_pb2.Status( + code=42, + message='Invalid code', + ) + servicer_context.abort_with_status(rpc_status.to_status(rich_status)) + + +class _GenericHandler(grpc.GenericRpcHandler): + + def service(self, handler_call_details): + if handler_call_details.method == _STATUS_OK: + return grpc.unary_unary_rpc_method_handler(_ok_unary_unary) + elif handler_call_details.method == _STATUS_NOT_OK: + return grpc.unary_unary_rpc_method_handler(_not_ok_unary_unary) + elif handler_call_details.method == _ERROR_DETAILS: + return grpc.unary_unary_rpc_method_handler( + _error_details_unary_unary) + elif handler_call_details.method == _INCONSISTENT: + return grpc.unary_unary_rpc_method_handler( + _inconsistent_unary_unary) + elif handler_call_details.method == _INVALID_CODE: + return grpc.unary_unary_rpc_method_handler( + _invalid_code_unary_unary) + else: + return None + + +class StatusTest(unittest.TestCase): + + def setUp(self): + self._server = test_common.test_server() + self._server.add_generic_rpc_handlers((_GenericHandler(),)) + port = self._server.add_insecure_port('[::]:0') + self._server.start() + + self._channel = grpc.insecure_channel('localhost:%d' % port) + + def tearDown(self): + self._server.stop(None) + self._channel.close() + + def test_status_ok(self): + try: + _, call = self._channel.unary_unary(_STATUS_OK).with_call(_REQUEST) + except grpc.RpcError as rpc_error: + self.fail(rpc_error) + # Succeed RPC doesn't have status + status = rpc_status.from_call(call) + self.assertIs(status, None) + + def test_status_not_ok(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_STATUS_NOT_OK).with_call(_REQUEST) + rpc_error = exception_context.exception + + self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL) + # Failed RPC doesn't automatically generate status + status = rpc_status.from_call(rpc_error) + self.assertIs(status, None) + + def test_error_details(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_ERROR_DETAILS).with_call(_REQUEST) + rpc_error = exception_context.exception + + status = rpc_status.from_call(rpc_error) + self.assertEqual(rpc_error.code(), grpc.StatusCode.INTERNAL) + self.assertEqual(status.code, code_pb2.Code.Value('INTERNAL')) + + # Check if the underlying proto message is intact + self.assertEqual(status.details[0].Is( + error_details_pb2.DebugInfo.DESCRIPTOR), True) + info = error_details_pb2.DebugInfo() + status.details[0].Unpack(info) + self.assertIn('_error_details_unary_unary', info.stack_entries[-1]) + + def test_code_message_validation(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_INCONSISTENT).with_call(_REQUEST) + rpc_error = exception_context.exception + self.assertEqual(rpc_error.code(), grpc.StatusCode.NOT_FOUND) + + # Code/Message validation failed + self.assertRaises(ValueError, rpc_status.from_call, rpc_error) + + def test_invalid_code(self): + with self.assertRaises(grpc.RpcError) as exception_context: + self._channel.unary_unary(_INVALID_CODE).with_call(_REQUEST) + rpc_error = exception_context.exception + self.assertEqual(rpc_error.code(), grpc.StatusCode.UNKNOWN) + # Invalid status code exception raised during coversion + self.assertIn('Invalid status code', rpc_error.details()) + + +if __name__ == '__main__': + logging.basicConfig() + unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index 44700e979e9..b27e6f26938 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -15,6 +15,7 @@ "protoc_plugin._split_definitions_test.SplitProtoSingleProtocExecutionProtocStyleTest", "protoc_plugin.beta_python_plugin_test.PythonPluginTest", "reflection._reflection_servicer_test.ReflectionServicerTest", + "status._grpc_status_test.StatusTest", "testing._client_test.ClientTest", "testing._server_test.FirstServiceServicerTest", "testing._time_test.StrictFakeTimeTest", diff --git a/templates/src/python/grpcio_status/grpc_version.py.template b/templates/src/python/grpcio_status/grpc_version.py.template new file mode 100644 index 00000000000..727e01edb93 --- /dev/null +++ b/templates/src/python/grpcio_status/grpc_version.py.template @@ -0,0 +1,19 @@ +%YAML 1.2 +--- | + # Copyright 2018 The 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/src/python/grpcio_status/grpc_version.py.template`!!! + + VERSION = '${settings.python_version.pep440()}' diff --git a/tools/distrib/pylint_code.sh b/tools/distrib/pylint_code.sh index d17eb9fdb82..8a5f7af6c6c 100755 --- a/tools/distrib/pylint_code.sh +++ b/tools/distrib/pylint_code.sh @@ -24,6 +24,7 @@ DIRS=( 'src/python/grpcio_health_checking/grpc_health' 'src/python/grpcio_reflection/grpc_reflection' 'src/python/grpcio_testing/grpc_testing' + 'src/python/grpcio_status/grpc_status' ) TEST_DIRS=( diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh index 605470325ab..18eb70c8574 100755 --- a/tools/run_tests/artifacts/build_artifact_python.sh +++ b/tools/run_tests/artifacts/build_artifact_python.sh @@ -123,6 +123,11 @@ then ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_reflection/setup.py \ preprocess build_package_protos sdist cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR" + + # Build grpcio_status source distribution + ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_status/setup.py \ + preprocess build_package_protos sdist + cp -r src/python/grpcio_status/dist/* "$ARTIFACT_DIR" fi cp -r dist/* "$ARTIFACT_DIR" diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh index e43f1fb429c..7cd1ef9d517 100755 --- a/tools/run_tests/helper_scripts/build_python.sh +++ b/tools/run_tests/helper_scripts/build_python.sh @@ -204,12 +204,18 @@ $VENV_PYTHON "$ROOT/src/python/grpcio_reflection/setup.py" preprocess $VENV_PYTHON "$ROOT/src/python/grpcio_reflection/setup.py" build_package_protos pip_install_dir "$ROOT/src/python/grpcio_reflection" +# Build/install status proto mapping +$VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" preprocess +$VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" build_package_protos +pip_install_dir "$ROOT/src/python/grpcio_status" + # Install testing pip_install_dir "$ROOT/src/python/grpcio_testing" # Build/install tests $VENV_PYTHON -m pip install coverage==4.4 oauth2client==4.1.0 \ - google-auth==1.0.0 requests==2.14.2 + google-auth==1.0.0 requests==2.14.2 \ + googleapis-common-protos==1.5.5 $VENV_PYTHON "$ROOT/src/python/grpcio_tests/setup.py" preprocess $VENV_PYTHON "$ROOT/src/python/grpcio_tests/setup.py" build_package_protos pip_install_dir "$ROOT/src/python/grpcio_tests" From 4ec4c0b6b44976fedada0f50fe3c823314491f2a Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Thu, 13 Dec 2018 10:56:32 -0800 Subject: [PATCH 90/99] Set SSL_CTX_set_verify even if pem_client_root_certs is null --- src/core/tsi/ssl_transport_security.cc | 47 +++++++++++++------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc index d6a72ada0d8..efaf733503e 100644 --- a/src/core/tsi/ssl_transport_security.cc +++ b/src/core/tsi/ssl_transport_security.cc @@ -1850,31 +1850,30 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options( break; } SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names); - switch (options->client_certificate_request) { - case TSI_DONT_REQUEST_CLIENT_CERTIFICATE: - SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr); - break; - case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: - SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, - NullVerifyCallback); - break; - case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: - SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, nullptr); - break; - case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: - SSL_CTX_set_verify( - impl->ssl_contexts[i], - SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - NullVerifyCallback); - break; - case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: - SSL_CTX_set_verify( - impl->ssl_contexts[i], - SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - break; - } - /* TODO(jboeuf): Add revocation verification. */ } + switch (options->client_certificate_request) { + case TSI_DONT_REQUEST_CLIENT_CERTIFICATE: + SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr); + break; + case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: + SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, + NullVerifyCallback); + break; + case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: + SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, nullptr); + break; + case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: + SSL_CTX_set_verify(impl->ssl_contexts[i], + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + NullVerifyCallback); + break; + case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: + SSL_CTX_set_verify(impl->ssl_contexts[i], + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + break; + } + /* TODO(jboeuf): Add revocation verification. */ result = extract_x509_subject_names_from_pem_cert( options->pem_key_cert_pairs[i].cert_chain, From 5ea2ed602b9d7dfec109c520446e6e0570840d45 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 12 Dec 2018 18:52:26 -0800 Subject: [PATCH 91/99] Move most c-ares logs under a tracer --- .../resolver/dns/c_ares/dns_resolver_ares.cc | 42 ++++++++++------- .../dns/c_ares/grpc_ares_ev_driver.cc | 47 ++++++++++++------- .../resolver/dns/c_ares/grpc_ares_wrapper.cc | 43 +++++++++-------- 3 files changed, 74 insertions(+), 58 deletions(-) diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index fc83fc44889..abacd0c960d 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -170,7 +170,7 @@ AresDnsResolver::AresDnsResolver(const ResolverArgs& args) } AresDnsResolver::~AresDnsResolver() { - gpr_log(GPR_DEBUG, "destroying AresDnsResolver"); + GRPC_CARES_TRACE_LOG("resolver:%p destroying AresDnsResolver", this); if (resolved_result_ != nullptr) { grpc_channel_args_destroy(resolved_result_); } @@ -182,7 +182,8 @@ AresDnsResolver::~AresDnsResolver() { void AresDnsResolver::NextLocked(grpc_channel_args** target_result, grpc_closure* on_complete) { - gpr_log(GPR_DEBUG, "AresDnsResolver::NextLocked() is called."); + GRPC_CARES_TRACE_LOG("resolver:%p AresDnsResolver::NextLocked() is called.", + this); GPR_ASSERT(next_completion_ == nullptr); next_completion_ = on_complete; target_result_ = target_result; @@ -225,12 +226,14 @@ void AresDnsResolver::ShutdownLocked() { void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) { AresDnsResolver* r = static_cast(arg); GRPC_CARES_TRACE_LOG( - "%p re-resolution timer fired. error: %s. shutdown_initiated_: %d", r, - grpc_error_string(error), r->shutdown_initiated_); + "resolver:%p re-resolution timer fired. error: %s. shutdown_initiated_: " + "%d", + r, grpc_error_string(error), r->shutdown_initiated_); r->have_next_resolution_timer_ = false; if (error == GRPC_ERROR_NONE && !r->shutdown_initiated_) { if (!r->resolving_) { - GRPC_CARES_TRACE_LOG("%p start resolving due to re-resolution timer", r); + GRPC_CARES_TRACE_LOG( + "resolver:%p start resolving due to re-resolution timer", r); r->StartResolvingLocked(); } } @@ -327,8 +330,8 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { service_config_string = ChooseServiceConfig(r->service_config_json_); gpr_free(r->service_config_json_); if (service_config_string != nullptr) { - gpr_log(GPR_INFO, "selected service config choice: %s", - service_config_string); + GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s", + r, service_config_string); args_to_remove[num_args_to_remove++] = GRPC_ARG_SERVICE_CONFIG; args_to_add[num_args_to_add++] = grpc_channel_arg_string_create( (char*)GRPC_ARG_SERVICE_CONFIG, service_config_string); @@ -344,11 +347,11 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { r->backoff_.Reset(); } else if (!r->shutdown_initiated_) { const char* msg = grpc_error_string(error); - gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg); + GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed: %s", r, msg); grpc_millis next_try = r->backoff_.NextAttemptTime(); grpc_millis timeout = next_try - ExecCtx::Get()->Now(); - gpr_log(GPR_INFO, "dns resolution failed (will retry): %s", - grpc_error_string(error)); + GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed (will retry): %s", + r, grpc_error_string(error)); GPR_ASSERT(!r->have_next_resolution_timer_); r->have_next_resolution_timer_ = true; // TODO(roth): We currently deal with this ref manually. Once the @@ -357,9 +360,10 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { RefCountedPtr self = r->Ref(DEBUG_LOCATION, "retry-timer"); self.release(); if (timeout > 0) { - gpr_log(GPR_DEBUG, "retrying in %" PRId64 " milliseconds", timeout); + GRPC_CARES_TRACE_LOG("resolver:%p retrying in %" PRId64 " milliseconds", + r, timeout); } else { - gpr_log(GPR_DEBUG, "retrying immediately"); + GRPC_CARES_TRACE_LOG("resolver:%p retrying immediately", r); } grpc_timer_init(&r->next_resolution_timer_, next_try, &r->on_next_resolution_); @@ -385,10 +389,10 @@ void AresDnsResolver::MaybeStartResolvingLocked() { if (ms_until_next_resolution > 0) { const grpc_millis last_resolution_ago = grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_; - gpr_log(GPR_DEBUG, - "In cooldown from last resolution (from %" PRId64 - " ms ago). Will resolve again in %" PRId64 " ms", - last_resolution_ago, ms_until_next_resolution); + GRPC_CARES_TRACE_LOG( + "resolver:%p In cooldown from last resolution (from %" PRId64 + " ms ago). Will resolve again in %" PRId64 " ms", + this, last_resolution_ago, ms_until_next_resolution); have_next_resolution_timer_ = true; // TODO(roth): We currently deal with this ref manually. Once the // new closure API is done, find a way to track this ref with the timer @@ -405,7 +409,6 @@ void AresDnsResolver::MaybeStartResolvingLocked() { } void AresDnsResolver::StartResolvingLocked() { - gpr_log(GPR_DEBUG, "Start resolving."); // TODO(roth): We currently deal with this ref manually. Once the // new closure API is done, find a way to track this ref with the timer // callback as part of the type system. @@ -420,6 +423,8 @@ void AresDnsResolver::StartResolvingLocked() { request_service_config_ ? &service_config_json_ : nullptr, query_timeout_ms_, combiner()); last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now(); + GRPC_CARES_TRACE_LOG("resolver:%p Started resolving. pending_request_:%p", + this, pending_request_); } void AresDnsResolver::MaybeFinishNextLocked() { @@ -427,7 +432,8 @@ void AresDnsResolver::MaybeFinishNextLocked() { *target_result_ = resolved_result_ == nullptr ? nullptr : grpc_channel_args_copy(resolved_result_); - gpr_log(GPR_DEBUG, "AresDnsResolver::MaybeFinishNextLocked()"); + GRPC_CARES_TRACE_LOG("resolver:%p AresDnsResolver::MaybeFinishNextLocked()", + this); GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE); next_completion_ = nullptr; published_version_ = resolved_version_; diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc index 8abc34c6edb..d99c2e30047 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc @@ -90,15 +90,18 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver); static grpc_ares_ev_driver* grpc_ares_ev_driver_ref( grpc_ares_ev_driver* ev_driver) { - gpr_log(GPR_DEBUG, "Ref ev_driver %" PRIuPTR, (uintptr_t)ev_driver); + GRPC_CARES_TRACE_LOG("request:%p Ref ev_driver %p", ev_driver->request, + ev_driver); gpr_ref(&ev_driver->refs); return ev_driver; } static void grpc_ares_ev_driver_unref(grpc_ares_ev_driver* ev_driver) { - gpr_log(GPR_DEBUG, "Unref ev_driver %" PRIuPTR, (uintptr_t)ev_driver); + GRPC_CARES_TRACE_LOG("request:%p Unref ev_driver %p", ev_driver->request, + ev_driver); if (gpr_unref(&ev_driver->refs)) { - gpr_log(GPR_DEBUG, "destroy ev_driver %" PRIuPTR, (uintptr_t)ev_driver); + GRPC_CARES_TRACE_LOG("request:%p destroy ev_driver %p", ev_driver->request, + ev_driver); GPR_ASSERT(ev_driver->fds == nullptr); GRPC_COMBINER_UNREF(ev_driver->combiner, "free ares event driver"); ares_destroy(ev_driver->channel); @@ -108,7 +111,8 @@ static void grpc_ares_ev_driver_unref(grpc_ares_ev_driver* ev_driver) { } static void fd_node_destroy_locked(fd_node* fdn) { - gpr_log(GPR_DEBUG, "delete fd: %s", fdn->grpc_polled_fd->GetName()); + GRPC_CARES_TRACE_LOG("request:%p delete fd: %s", fdn->ev_driver->request, + fdn->grpc_polled_fd->GetName()); GPR_ASSERT(!fdn->readable_registered); GPR_ASSERT(!fdn->writable_registered); GPR_ASSERT(fdn->already_shutdown); @@ -136,7 +140,7 @@ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, memset(&opts, 0, sizeof(opts)); opts.flags |= ARES_FLAG_STAYOPEN; int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS); - gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create_locked"); + GRPC_CARES_TRACE_LOG("request:%p grpc_ares_ev_driver_create_locked", request); if (status != ARES_SUCCESS) { char* err_msg; gpr_asprintf(&err_msg, "Failed to init ares channel. C-ares error: %s", @@ -203,8 +207,9 @@ static fd_node* pop_fd_node_locked(fd_node** head, ares_socket_t as) { static void on_timeout_locked(void* arg, grpc_error* error) { grpc_ares_ev_driver* driver = static_cast(arg); GRPC_CARES_TRACE_LOG( - "ev_driver=%p on_timeout_locked. driver->shutting_down=%d. err=%s", - driver, driver->shutting_down, grpc_error_string(error)); + "request:%p ev_driver=%p on_timeout_locked. driver->shutting_down=%d. " + "err=%s", + driver->request, driver, driver->shutting_down, grpc_error_string(error)); if (!driver->shutting_down && error == GRPC_ERROR_NONE) { grpc_ares_ev_driver_shutdown_locked(driver); } @@ -216,7 +221,8 @@ static void on_readable_locked(void* arg, grpc_error* error) { grpc_ares_ev_driver* ev_driver = fdn->ev_driver; const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked(); fdn->readable_registered = false; - gpr_log(GPR_DEBUG, "readable on %s", fdn->grpc_polled_fd->GetName()); + GRPC_CARES_TRACE_LOG("request:%p readable on %s", fdn->ev_driver->request, + fdn->grpc_polled_fd->GetName()); if (error == GRPC_ERROR_NONE) { do { ares_process_fd(ev_driver->channel, as, ARES_SOCKET_BAD); @@ -239,7 +245,8 @@ static void on_writable_locked(void* arg, grpc_error* error) { grpc_ares_ev_driver* ev_driver = fdn->ev_driver; const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked(); fdn->writable_registered = false; - gpr_log(GPR_DEBUG, "writable on %s", fdn->grpc_polled_fd->GetName()); + GRPC_CARES_TRACE_LOG("request:%p writable on %s", ev_driver->request, + fdn->grpc_polled_fd->GetName()); if (error == GRPC_ERROR_NONE) { ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, as); } else { @@ -278,7 +285,8 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) { fdn->grpc_polled_fd = ev_driver->polled_fd_factory->NewGrpcPolledFdLocked( socks[i], ev_driver->pollset_set, ev_driver->combiner); - gpr_log(GPR_DEBUG, "new fd: %s", fdn->grpc_polled_fd->GetName()); + GRPC_CARES_TRACE_LOG("request:%p new fd: %s", ev_driver->request, + fdn->grpc_polled_fd->GetName()); fdn->ev_driver = ev_driver; fdn->readable_registered = false; fdn->writable_registered = false; @@ -295,8 +303,9 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) { if (ARES_GETSOCK_READABLE(socks_bitmask, i) && !fdn->readable_registered) { grpc_ares_ev_driver_ref(ev_driver); - gpr_log(GPR_DEBUG, "notify read on: %s", - fdn->grpc_polled_fd->GetName()); + GRPC_CARES_TRACE_LOG("request:%p notify read on: %s", + ev_driver->request, + fdn->grpc_polled_fd->GetName()); fdn->grpc_polled_fd->RegisterForOnReadableLocked(&fdn->read_closure); fdn->readable_registered = true; } @@ -304,8 +313,9 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) { // has not been registered with this socket. if (ARES_GETSOCK_WRITABLE(socks_bitmask, i) && !fdn->writable_registered) { - gpr_log(GPR_DEBUG, "notify write on: %s", - fdn->grpc_polled_fd->GetName()); + GRPC_CARES_TRACE_LOG("request:%p notify write on: %s", + ev_driver->request, + fdn->grpc_polled_fd->GetName()); grpc_ares_ev_driver_ref(ev_driver); fdn->grpc_polled_fd->RegisterForOnWriteableLocked( &fdn->write_closure); @@ -332,7 +342,8 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) { // If the ev driver has no working fd, all the tasks are done. if (new_list == nullptr) { ev_driver->working = false; - gpr_log(GPR_DEBUG, "ev driver stop working"); + GRPC_CARES_TRACE_LOG("request:%p ev driver stop working", + ev_driver->request); } } @@ -345,9 +356,9 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) { ? GRPC_MILLIS_INF_FUTURE : ev_driver->query_timeout_ms + grpc_core::ExecCtx::Get()->Now(); GRPC_CARES_TRACE_LOG( - "ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in %" PRId64 - " ms", - ev_driver, timeout); + "request:%p ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in " + "%" PRId64 " ms", + ev_driver->request, ev_driver, timeout); grpc_ares_ev_driver_ref(ev_driver); grpc_timer_init(&ev_driver->query_timeout, timeout, &ev_driver->on_timeout_locked); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 68977567694..1a7e5d06268 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -96,11 +96,11 @@ static void log_address_sorting_list(const ServerAddressList& addresses, for (size_t i = 0; i < addresses.size(); i++) { char* addr_str; if (grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true)) { - gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s", + gpr_log(GPR_INFO, "c-ares address sorting: %s[%" PRIuPTR "]=%s", input_output_str, i, addr_str); gpr_free(addr_str); } else { - gpr_log(GPR_DEBUG, + gpr_log(GPR_INFO, "c-ares address sorting: %s[%" PRIuPTR "]=", input_output_str, i); } @@ -209,10 +209,10 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, addresses.emplace_back(&addr, addr_len, args); char output[INET6_ADDRSTRLEN]; ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN); - gpr_log(GPR_DEBUG, - "c-ares resolver gets a AF_INET6 result: \n" - " addr: %s\n port: %d\n sin6_scope_id: %d\n", - output, ntohs(hr->port), addr.sin6_scope_id); + GRPC_CARES_TRACE_LOG( + "request:%p c-ares resolver gets a AF_INET6 result: \n" + " addr: %s\n port: %d\n sin6_scope_id: %d\n", + r, output, ntohs(hr->port), addr.sin6_scope_id); break; } case AF_INET: { @@ -226,10 +226,10 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, addresses.emplace_back(&addr, addr_len, args); char output[INET_ADDRSTRLEN]; ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN); - gpr_log(GPR_DEBUG, - "c-ares resolver gets a AF_INET result: \n" - " addr: %s\n port: %d\n", - output, ntohs(hr->port)); + GRPC_CARES_TRACE_LOG( + "request:%p c-ares resolver gets a AF_INET result: \n" + " addr: %s\n port: %d\n", + r, output, ntohs(hr->port)); break; } } @@ -252,9 +252,9 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts, static void on_srv_query_done_locked(void* arg, int status, int timeouts, unsigned char* abuf, int alen) { grpc_ares_request* r = static_cast(arg); - gpr_log(GPR_DEBUG, "on_query_srv_done_locked"); + GRPC_CARES_TRACE_LOG("request:%p on_query_srv_done_locked", r); if (status == ARES_SUCCESS) { - gpr_log(GPR_DEBUG, "on_query_srv_done_locked ARES_SUCCESS"); + GRPC_CARES_TRACE_LOG("request:%p on_query_srv_done_locked ARES_SUCCESS", r); struct ares_srv_reply* reply; const int parse_status = ares_parse_srv_reply(abuf, alen, &reply); if (parse_status == ARES_SUCCESS) { @@ -297,9 +297,9 @@ static const char g_service_config_attribute_prefix[] = "grpc_config="; static void on_txt_done_locked(void* arg, int status, int timeouts, unsigned char* buf, int len) { - gpr_log(GPR_DEBUG, "on_txt_done_locked"); char* error_msg; grpc_ares_request* r = static_cast(arg); + GRPC_CARES_TRACE_LOG("request:%p on_txt_done_locked", r); const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1; struct ares_txt_ext* result = nullptr; struct ares_txt_ext* reply = nullptr; @@ -332,7 +332,8 @@ static void on_txt_done_locked(void* arg, int status, int timeouts, service_config_len += result->length; } (*r->service_config_json_out)[service_config_len] = '\0'; - gpr_log(GPR_INFO, "found service config: %s", *r->service_config_json_out); + GRPC_CARES_TRACE_LOG("request:%p found service config: %s", r, + *r->service_config_json_out); } // Clean up. ares_free_data(reply); @@ -358,12 +359,6 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( grpc_error* error = GRPC_ERROR_NONE; grpc_ares_hostbyname_request* hr = nullptr; ares_channel* channel = nullptr; - /* TODO(zyc): Enable tracing after #9603 is checked in */ - /* if (grpc_dns_trace) { - gpr_log(GPR_DEBUG, "resolve_address (blocking): name=%s, default_port=%s", - name, default_port); - } */ - /* parse name, splitting it into host and port parts */ char* host; char* port; @@ -388,7 +383,7 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( channel = grpc_ares_ev_driver_get_channel_locked(r->ev_driver); // If dns_server is specified, use it. if (dns_server != nullptr) { - gpr_log(GPR_INFO, "Using DNS server %s", dns_server); + GRPC_CARES_TRACE_LOG("request:%p Using DNS server %s", r, dns_server); grpc_resolved_address addr; if (grpc_parse_ipv4_hostport(dns_server, &addr, false /* log_errors */)) { r->dns_server_addr.family = AF_INET; @@ -513,7 +508,7 @@ static bool resolve_as_ip_literal_locked( static bool target_matches_localhost_inner(const char* name, char** host, char** port) { if (!gpr_split_host_port(name, host, port)) { - gpr_log(GPR_INFO, "Unable to split host and port for name: %s", name); + gpr_log(GPR_ERROR, "Unable to split host and port for name: %s", name); return false; } if (gpr_stricmp(*host, "localhost") == 0) { @@ -547,6 +542,10 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( r->success = false; r->error = GRPC_ERROR_NONE; r->pending_queries = 0; + GRPC_CARES_TRACE_LOG( + "request:%p c-ares grpc_dns_lookup_ares_locked_impl name=%s, " + "default_port=%s", + r, name, default_port); // Early out if the target is an ipv4 or ipv6 literal. if (resolve_as_ip_literal_locked(name, default_port, addrs)) { GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE); From 63e73e428fdfaf940074bb59753cd26ad24d3b49 Mon Sep 17 00:00:00 2001 From: Hope Casey-Allen Date: Thu, 13 Dec 2018 16:51:58 -0800 Subject: [PATCH 92/99] Metadata tutorial --- examples/cpp/metadata/Makefile | 96 +++ examples/cpp/metadata/README.md | 69 +++ examples/cpp/metadata/greeter_client | Bin 0 -> 267800 bytes examples/cpp/metadata/greeter_client.cc | 95 +++ examples/cpp/metadata/greeter_client.o | Bin 0 -> 101304 bytes examples/cpp/metadata/greeter_server | Bin 0 -> 278392 bytes examples/cpp/metadata/greeter_server.cc | 82 +++ examples/cpp/metadata/greeter_server.o | Bin 0 -> 112144 bytes examples/cpp/metadata/helloworld.grpc.pb.cc | 70 +++ examples/cpp/metadata/helloworld.grpc.pb.h | 197 ++++++ examples/cpp/metadata/helloworld.grpc.pb.o | Bin 0 -> 398496 bytes examples/cpp/metadata/helloworld.pb.cc | 638 ++++++++++++++++++++ examples/cpp/metadata/helloworld.pb.h | 419 +++++++++++++ examples/cpp/metadata/helloworld.pb.o | Bin 0 -> 111592 bytes 14 files changed, 1666 insertions(+) create mode 100644 examples/cpp/metadata/Makefile create mode 100644 examples/cpp/metadata/README.md create mode 100755 examples/cpp/metadata/greeter_client create mode 100644 examples/cpp/metadata/greeter_client.cc create mode 100644 examples/cpp/metadata/greeter_client.o create mode 100755 examples/cpp/metadata/greeter_server create mode 100644 examples/cpp/metadata/greeter_server.cc create mode 100644 examples/cpp/metadata/greeter_server.o create mode 100644 examples/cpp/metadata/helloworld.grpc.pb.cc create mode 100644 examples/cpp/metadata/helloworld.grpc.pb.h create mode 100644 examples/cpp/metadata/helloworld.grpc.pb.o create mode 100644 examples/cpp/metadata/helloworld.pb.cc create mode 100644 examples/cpp/metadata/helloworld.pb.h create mode 100644 examples/cpp/metadata/helloworld.pb.o diff --git a/examples/cpp/metadata/Makefile b/examples/cpp/metadata/Makefile new file mode 100644 index 00000000000..46be8bfaa3c --- /dev/null +++ b/examples/cpp/metadata/Makefile @@ -0,0 +1,96 @@ +# +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + HOST_SYSTEM = $(shell uname | cut -f 1 -d_) +SYSTEM ?= $(HOST_SYSTEM) +CXX = g++ +CPPFLAGS += `pkg-config --cflags protobuf grpc` +CXXFLAGS += -std=c++11 +ifeq ($(SYSTEM),Darwin) +LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ + -lgrpc++_reflection\ + -ldl +else +LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ + -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\ + -ldl +endif +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + PROTOS_PATH = ../../protos + vpath %.proto $(PROTOS_PATH) + all: system-check greeter_client greeter_server + greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o + $(CXX) $^ $(LDFLAGS) -o $@ + greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o + $(CXX) $^ $(LDFLAGS) -o $@ + .PRECIOUS: %.grpc.pb.cc +%.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + .PRECIOUS: %.pb.cc +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + clean: + rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server + # The following is to test your system and ensure a smoother experience. +# They are by no means necessary to actually compile a grpc-enabled software. + PROTOC_CMD = which $(PROTOC) +PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3 +PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN) +HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false) +ifeq ($(HAS_PROTOC),true) +HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +endif +HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false) + SYSTEM_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_PLUGIN),true) +SYSTEM_OK = true +endif +endif + system-check: +ifneq ($(HAS_VALID_PROTOC),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have protoc 3.0.0 installed in your path." + @echo "Please install Google protocol buffers 3.0.0 and its compiler." + @echo "You can find it here:" + @echo + @echo " https://github.com/google/protobuf/releases/tag/v3.0.0" + @echo + @echo "Here is what I get when trying to evaluate your version of protoc:" + @echo + -$(PROTOC) --version + @echo + @echo +endif +ifneq ($(HAS_PLUGIN),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have the grpc c++ protobuf plugin installed in your path." + @echo "Please install grpc. You can find it here:" + @echo + @echo " https://github.com/grpc/grpc" + @echo + @echo "Here is what I get when trying to detect if you have the plugin:" + @echo + -which $(GRPC_CPP_PLUGIN) + @echo + @echo +endif +ifneq ($(SYSTEM_OK),true) + @false +endif diff --git a/examples/cpp/metadata/README.md b/examples/cpp/metadata/README.md new file mode 100644 index 00000000000..7b33074ba1e --- /dev/null +++ b/examples/cpp/metadata/README.md @@ -0,0 +1,69 @@ +# Metadata Example + +## Overview + +This example shows you how to add custom headers on the client and server and +how to access them. + +Custom metadata must follow the "Custom-Metadata" format listed in +https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md, with the +exception of binary headers, which don't have to be base64 encoded. + +### Get the tutorial source code + The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: + ```sh +$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc +``` + Change your current directory to examples/cpp/metadata + ```sh +$ cd examples/cpp/metadata +``` + +### Generating gRPC code + To generate the client and server side interfaces: + ```sh +$ make helloworld.grpc.pb.cc helloworld.pb.cc +``` +Which internally invokes the proto-compiler as: + ```sh +$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto +$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto +``` +### Try it! +Build client and server: + +```sh +$ make +``` + +Run the server, which will listen on port 50051: + +```sh +$ ./greeter_server +``` + +Run the client (in a different terminal): + +```sh +$ ./greeter_client +``` + +If things go smoothly, you will see in the client terminal: + +"Client received initial metadata from server: initial metadata value" +"Client received trailing metadata from server: trailing metadata value" +"Client received message: Hello World" + + +And in the server terminal: + +"Header key: custom-bin , value: " +"Header key: custom-header , value: Custom Value" +"Header key: user-agent , value: grpc-c++/1.16.0-dev grpc-c/6.0.0-dev (linux; chttp2; gao)" + +Note that the value for custom-bin doesn't print nicely because it's a binary +value. You can indicate a binary value through appending "-bin" to the header key. + +We did not add the user-agent metadata as a custom header. This shows how +the gRPC framework adds some headers under the hood that may show up in the +metadata map. diff --git a/examples/cpp/metadata/greeter_client b/examples/cpp/metadata/greeter_client new file mode 100755 index 0000000000000000000000000000000000000000..929a51c3a5b426131d0573b2e5cd91da16f1ecf4 GIT binary patch literal 267800 zcmdqK3tXJV)jz(upcswd1;sn@igzF(5;c_=S2vnO3_+~vs+ZZB=Wu*{os zzdHSJf{|9w&b=k+Te7cunsUTux$;9)x$;94zIhfZu+KbA``9*q=jwd#^DN}?W1ht2 zr|A8rD*oR0yQ;D&1asb+yy8{KDYOit`XVk7F zU;V}7_vRe>(1lgcU%d6Q3gk85OFHB5O&!(olfvmOEk698zUsV|jMTAXeOr(B&Fh%w z+a;?r_0rC9W7DPu_8#XOGcJAfxUr)HXQnUooi$@+QOjPVd@VlT4QKW2>&rURzsu;9 zhbvZ$&KcX{E7)f=s>y1bcHCLrS!enVoN->x;TbKyu{Y=V&Pw%_kLzCH+daeQD;<4S zj_?9De2w@v<9ju}OYr>`zTd{zeDtu91-=j9`w+el4`E=vQW_+JE06e$g8`0@!@cb>l&*S@ohV|;_OZxe;e!hz5 zYxw>S-{0f=I==k8sUE(!@O&HJeth4>_mB9#kM9TgI{1Ew?^b+2!gtzp_jad#5LmJN zgi8;)@VCzt)~(s{)M4LP{b~0hi>DoW>4C@o@R!vO9sBvRD}S7p``EyBbANWpaZ9h+ z^W~>dv|Jp!Gk#HvG_iTb{Zvbynoy@`BS|c=OY@t2eAX^v!*8A3M|k z>ek_BH*Sb5?^rW&w?}G!pa+V}o@PVD~0iiI5) zXJ@rs^oO!odD@-IDT@|VXx{>#7%Cm!

LvYO3=Q>NReJDEDZ5Vo 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%0D5LaD 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 d`es|tB;We)N~N#mwEyrq8R +#include +#include + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +class CustomHeaderClient { + public: + CustomHeaderClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + // Assembles the client's payload, sends it and presents the response back + // from the server. + std::string SayHello(const std::string& user) { + // Data we are sending to the server. + HelloRequest request; + request.set_name(user); + + // Container for the data we expect from the server. + HelloReply reply; + + // Context for the client. It could be used to convey extra information to + // the server and/or tweak certain RPC behaviors. + ClientContext context; + + // Setting custom metadata to be sent to the server + context.AddMetadata("custom-header", "Custom Value"); + + // Setting custom binary metadata + char bytes[8] = {'\0', '\1', '\2', '\3', + '\4', '\5', '\6', '\7'}; + context.AddMetadata("custom-bin", grpc::string(bytes, 8)); + + // The actual RPC. + Status status = stub_->SayHello(&context, request, &reply); + + // Act upon its status. + if (status.ok()) { + std::cout << "Client received initial metadata from server: " << context.GetServerInitialMetadata().find("custom-server-metadata")->second << std::endl; + std::cout << "Client received trailing metadata from server: " << context.GetServerTrailingMetadata().find("custom-trailing-metadata")->second << std::endl; + return reply.message(); + } else { + std::cout << status.error_code() << ": " << status.error_message() + << std::endl; + return "RPC failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + // Instantiate the client. It requires a channel, out of which the actual RPCs + // are created. This channel models a connection to an endpoint (in this case, + // localhost at port 50051). We indicate that the channel isn't authenticated + // (use of InsecureChannelCredentials()). + CustomHeaderClient greeter(grpc::CreateChannel( + "localhost:50051", grpc::InsecureChannelCredentials())); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Client received message: " << reply << std::endl; + return 0; +} diff --git a/examples/cpp/metadata/greeter_client.o b/examples/cpp/metadata/greeter_client.o new file mode 100644 index 0000000000000000000000000000000000000000..483cb0741cf7ac3f32e14729cb8280d97346ecfc GIT binary patch literal 101304 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 z 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 bdM5cie7Cal3nk;9Y{^RhooGPxcIE#7vdv

+#include +#include + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +// Logic and data behind the server's behavior. +class GreeterServiceImpl final : public Greeter::Service { + Status SayHello(ServerContext* context, const HelloRequest* request, + HelloReply* reply) override { + std::string prefix("Hello "); + + // Get the client's initial metadata + std::cout << "Client metadata: " << std::endl; + const std::multimap metadata = context->client_metadata(); + for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) { + std::cout << "Header key: " << iter->first << " , value: " << iter->second << std::endl; + } + + context->AddInitialMetadata("custom-server-metadata", "initial metadata value"); + context->AddTrailingMetadata("custom-trailing-metadata", "trailing metadata value"); + reply->set_message(prefix + request->name()); + return Status::OK; + } +}; + +void RunServer() { + std::string server_address("0.0.0.0:50051"); + GreeterServiceImpl service; + + ServerBuilder builder; + // Listen on the given address without any authentication mechanism. + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. + builder.RegisterService(&service); + // Finally assemble the server. + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. + server->Wait(); +} + +int main(int argc, char** argv) { + RunServer(); + + return 0; +} diff --git a/examples/cpp/metadata/greeter_server.o b/examples/cpp/metadata/greeter_server.o new file mode 100644 index 0000000000000000000000000000000000000000..dc197b2d14cb36605b595aec47dfbde9cb1df81b GIT binary patch literal 112144 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%0Ab0J=P1b&%@)Zc;B z$&rkoc`;#_z^_o0`p;;Aqg?hoXA1mEL7x)%RRUikaLk9>V4c9P7W9t^oP9h@{-eO> z2>N{jPYC?@{`v;XJ6GW63cO0-QGuhL6DX}(;MIbDxxkYG-yraL0^cU^`2v4i;57p8 zJ3!x{{_JBQa1_c=_(ia0tO+h6F5J6V)AN%^Sd6zHwnA}0lHokIPc-X zq&)&}Vqypf(!_@4`l7&x3A|b04qm$j0v{&u zn+0Aj@MQw86Zmq0uNL?Ufo~G{Edqa0;I|5VkHA+7eBeR)2K8?j_%MOrCh&5BuM&8Z zz*h@=jlequzFFX368NhEzg^%T34D#fk01vU_5ZTKM+y8Z0-r7LI|SY)@H+**PT*?= zzD3|)75EN;e@)<>0$(TaoP+fZ>W||OkBRvL|GJ<*UEoN+n$ji-{2PLPs=$$+>#j!N z{4N05Rto%XkU=h1@@>c3gwg#v#_;1vS@k-(b-{$qi!5%|Lb-z@N-2z3kCkDz$*m)Gl4e={O1B+Bk;!rzFFXp3w*o4pAh)#0!KUK zy66=6lY)NmVfqHkwN>CH0)I;2vjzUNz}p1=jKJ3ke4D_x2>cfU-y!g41>Py}=LA0Z zaD9XNKQHhSfxjT|*#iHiz^@nhuLQnA;8>sADQ$zmUljD)1paG*?-KY+0?$1{-=O|4 z3w)@+Stcfz3;Y#9UnlV23VgM|QN~yB4_uo9xV!!^qGfS?Dlyj?0Y~=fu!duBBtT*W z9!}|uz>l^#Bj&cWI0_gMzg(ZiJfgW#Cn;Kt!XdtOfVy<}?G5)wdES>B0v~URXGZUS z1PSO}?LZk65=GG;#igo5z7GHDd13of1 zoY(`=@U;l7Kb#Zi5boWI5) zZ{KNu)|`nsIHHFp^Q=F}RvaIXzkH9^)WSK4;ZYNeZNJWi+iwL;hrk8uuzMd#4VM*v zKh58=HO@QyD|?z{u<_!R>g)VPE$T3H_>PeNCN$4W_^Ab>AU$7&ou(*qLYcJ)_4Nw; zRG0eDN1)jIKS_4y81|qNMcp`Tizf}Jt=>MtoJCEupCjHI2XF^#sWaU3GKamQ~g7_YoJP6Bs z%nQ#V)^zgWtjO9XiK~i%)48 zCg-lcnh9CbS2GQHu`-4{)v;4ueAp9Q2+r3x8265|vR|ifhMHtQ&(jR%*Bdr1%*MAY zp=Vb(*@;^dXR6*%06&pM$6valdSBA#U`qPiU+#IB{>JR3%Iv~%;nAT7J$v?Le3gk) z=l%^vzU&~k{XVV9U-dYJ;?b6^Nj#~Ns)IjF3W>oFq2d!sGAcr31I7|0z zO1~P&n7tl!Or<}oZcNhIomlCXws$(F_y8|diaW@7YyRFK)H@1zU*WaM57?xuV-NNw z~lHX z(_a>0c)fqxreAdSr+KQAWwl2Mr!omc*sl{j16uW(ciQd4JY_*Wmq>lu*j*Ut`g~uk zIH))40XzOGm?Dg#=SHJ$ol=7>8?@pPDYnemhE_<7|Sz}MBgBIxvPef6ZrE?tf+ zj*SdfNe_N9JG=8AO|9J%=gFuYIB=efn}07gKv(Obz0u&jq?66j-sz50bnB?sY}9wC zV$k+_qndE+NqfFxZZ_?E@3dQhWdGMAuTqoCqGD^#nzizIS@G{a8F-1)&Gta|gb7$0PYp$m>OkzQdBd z!}5X>dt>|xxLQV!&wb1Lc^qlS7A4-!DHq8tytiW3)hjyhV7t$w7GY;h_s_WdTolCP zGxzgQI&PU>d*NHDj|%Q$34opc-WhGYrEz?6HW*y!;U{5<5{44%=Mcdj8q7t8KcFg&5iUns~TaCBX_4#7*8 zX}5+Hbsk&GeiodB{|{JM^XwUhriQ@zkm?{We^vGDknb6u zI!3QIMM=Z!>O?)i4!tx7n8sr^jx-}N`%Ll?ya#4OdBk3@3cBcUhAr>j33b7IdT$tk zx-*@x7gQi!LFni@KU>dQe83Dr@!%nQTDtgI=?M6dN1_gPT+h73^t+e9Xl)`fY%?{I z;jwyQ@p#Ogi5y7P4`ER=^8tA}uUa_tE}m#^PArz0Pr4LR=Z%QR=eM=Ro082fjSY#q z+SKCs!a`?6Rbzd9vH^aB+t8Rwj<{&rtl=%GMAZV~Pu9feH7Dwm@H5Hg#?~hNW8eMw z`@%W!y>473aq}j)ULv>q|I?HvX7_AHN^Ud>q>ND-8Vjol)lF(8iCy<;IIX zo1ygoBiu6|hc^Cd#qBt<{CI8|^Koe7uQTxfDGT{21OFRY@bfopr2cr$8SBlVP5*qC+W7gK0J8peX2FlPj+f+r3+`Dihc@}U6t|!M(JadUk%1r2e`C2E z+T=SxitlwHu?DmemrlE`8c%k4<&wCemuX8 z`8c%kk23J%xk=2&p^d-Pz>nuBF&~FE{&EBVpP@aOk3$>(Y~q*w7rz6_d>q>NYYg)L zl7)OeuT0ke+gb20HOPM_3;xvx{=a6yk8>?vQvZJf#`VUbt^PI``2Pm^F&~FE{>=t{ z98;K&LmNMy<%pNm|6RCeJ`QdCXzO@M{`cUX`8c%kziQw|otTe98~;uN|L!d0?;(CU z{%p-cKAug5m*mHDBw23`ZTjycep!EeAV22g(8ixj-=UHGzs*Aa5e9y26PC-NO@2P{ z%kty-i_FKNjen>?KAum=d>q>NM;Z8E%Ywhuz>nwKv0M&q^6|_Iykz~q5BJQ+p^bmG zfq!=v^6}gJc**)ln`F5h+T`Q6>x2Awt{U@kXyeCkqvIvZkLRf|ABQ&nr3U$bhy0k2 zLmU4}gZxjkkbkE^KA!u-ayhigzuO=mzpKuC9NPFd8sy_gc$tqw8$W-)ShhcYPoDWW zwDE5t`Lg}`WWm49z~46ue*Vs~l>b2%?f*xTFUybT%yGFnw3YvD13!+b%*UaPe-H6X z{SU~3ztg~fU>5v+BiQ@={SUvr&3bca(?8F^kLPYMABQ&n;|=_IS?~`v@E@85KYw3a zw*O&S@Skgte|Q%Bd_Jjcf1Fdf-Z-??-%OG(^~dwSn2$pn|CI**qqE?zHk5yG7W_>H z`DbRq&)++j^*1aF{^bV!@f(27~^1 z&LQ)0Xye~((EqqB`1$+s(*8coqWoJ8`k$DE{1*-U=u>jJIkc6ZzjH6^{~uZC|F)t2 z{+R{;9)tb`S?J$skdJFRTy73+q^COv$LmU4P z13#WK$$T8z_zMmE_)Nik9NPHLHSptE6wJq=ji1j=mi33{EHNL4HvXAJAo)jT!9T~q zKRgTmI^vi8e?%7iDFc6T7W~&6^#4~D_P^4=kLOYn?1r}bztg~9k_G>I;+OUJaTfY- zH1Oj&mYM3m*`Pn3bC)UqV+Q$nE@r0u+YIvYnL1Pc?FRYdv*6!hkUt>{{Tfw93Q<>PswneyimzqH?27W{(^{4=xQ&o}6g=VxZB zKcC|w%a7-2X3Ae;kdNnXX39UwP<}jbGgJO@13#Y2nJGV?OC!sFMHc*X4CTjjH8Yi8 zXVCxZEcp5S9BF@e9%rWVuQ%vFCky_S2L41A{C67o=Vrmb-cWyd4riw2-)N9uody5H z27WxhGgJ9n4g7eXXQuow8u;;i&rJDu5Wlpank@Kt8sy`7p_$6xW8lYgMKk5^H1Ok^ zY^MBu`-jJWJQp-m{ygHB^@ryYX39Unv1 zW~%=h13#X3nJNF>#D9eDhHC%Qf3nbjvq3(d=b5Se$B19{-Wc*B4}(<9)5ag958f96FJk=zorHv$a2AA_=U%85Uy z|57?{i|dQ&gZCFff~o%VakCs;T+dkl--dhUXZ$k2P{m;RSCahGAx&O^;;1vrO#BaJ z$d709nD~EB{HIFc5D(Tfo++ftA4n)Ml>dI94VEAGl$qr7gBNV?^j!fl&H!LG@t;eM z`*0t3SpPFD{MQiw8EN=&pO8uZox~s9n;O)=$-;j>@gJW?{?{!0PZPg9BMP$$%Kr-R zo7%6!(0+KnR|6Kq~`C z+af6c+ay0&e^(AtZ0`Bh`Yzmlzp?0FNBlTH$}6bg$DVLLq@^!<9i}g`JW~EyQFZ4 z2j&0PB0om*=MX>I&yx@j%E$LCCixH2M1Laja}bn20QgPyztK?srwsBZTI9b-^4nQ3 zg+ck}TjXyg`D=&|%m0i){^J(;m(awMZvN>H&&j6xt0Bg8^UqQX|8n9_=f7PC{HFS^ z*r^L%D9VrL>IK{XC5!y8lKgb-|AIySQj#zG{|g5B{lQN+)!)M;AN@ml1=~Ld_)X|P{?Gz#~!T(r<*^=0>7#J z+YRzxGssVo{9w6CNd6wJhWj^QPR=Te{zItX>GZ$FqW>;~{`g1@@OZ$7rAb+1l z{tl9V1`DPzDF5FU`Rho&Y=7*M!SbI2>l9EmA^*G2v05NK#*lPP>)t@*ehYt|g+Hi& z0X%1$qxNtcUbs4iT}(r{9gioQ~Na; z^#6xJ|G!w|521ncgf#Nsu*hF&kdOP{g7z~CI*6(M#*_TH0r^NPud{&PRQ~lOe-06& z{eBGbp#0Sq`5Q=ny7BW?i+t5tKweD9?=;AN)gpf%$xqjRUbe`OVP}O)_MiX4eX#t4 z;W^n<|3}e-*MTY*?@zG)8!Y_!#2TLI0O5@{gi{2h7`dVOiyMEELdG{vjFiFS76#6aS4; z7{r71*9`oo^6#bcw-GCi!{qYeqT#A7+sM9gF-v^x&UP{yi4?Lk;qeFvuSS>kOv$ z8%FY}8r)h4_P+yx-&FomgZ!fm@~^hYpG@-8&A*pf_@2B`)$rp|6<@bwckpE{wEmpzu6-Hmn1)(|FFa& zf4xEeNe20QEb{y0>-q|gUszZ2s)r70s=p)hHB~zPe^~fWBmQ*j5AOrNss6W6`Q`j^ zilO{%@SJVZe~v}}p#A*S!rx5%!*n&ce^Hja-U5D;{<{qNpJvd10d#Pa{`cf-DbuAe zhzIqb2mB`aga57><@`6)Ape^d`G3#X{OQJ@Pb~boCuhcw&zUCu=aBwj9_m8>+D8C5&T*x-0|DTCJ zUHv~`;onF6d%55g2Ib!e{HF5ff1nw*5+9bo2>u1hT0vytRPl09(&fiEYuP*|> zN&ZffFWY~lLH>sp`A40irKEfRv&SO8(;$DeLH^m`AehR3F3BGx3k&gJ{oiWgFDL#D zY4~pjepCJBQNv67EiveS3d~a`{r8gmboO_fh5x`ITJd!JD}djm{}$3;w*NT>{ok_4 zA7YV@WtG<-E%LV;#RALU04^7|B+%l}J~KPHX*Pb~7EC;5d!{zV4)t1a>!8u-%rFSi1} zsr;P=`DF(Ahr&1kaA^D=M)HIGA8F+^5co~Cy)|8s!fRQ~mb_OCR^-)512;1_hor<;F=fSxA(k0t(e_OsT)KaBWmF>`SR z?Pm?}o65h1%8zq4UO4_-3jc!sR}ADJNpSu3t3wr=lTQD~Ec_dZKVAR*De#;0--|C> z;FA6Ka)bV*AjhQt(;4dj6AS;V8S1|o=uGDqsvMSh7v{#=9nMHcym8Om=4epC4?4DzcD^53(_ zpG@+D{Ri7xUdNtkuD>gZKVAE;v+!R-{4|WZB7^ep0De>XYYgQ_Un-Y!;(mD`I0%?$ zaQs+9@<+ImbtEXiAMl&xFEz-&#vuQCi~J`@emeVGWRbtlAivHa|5J{=nZ_1lzv~8W_tIZ2xniU*I)I{q_C? zpy|ylN;#j5R`um@SEhXB>7Oi>O%Xu z(IEdT7WvnZ{Ci!=IuexMVUfRu!{@9V`@(+Y@6|XTmaQ_D77X!bk{2TwR zS!DT_8RWlUkw1at2j^eN!gmcEW!Arf_|x_O0l;t4e+TI=`~NKl{Sy}X*JLRFN{jrx z2Kg%u@_%lTzntXLFyPi%u>Kyg$j|N6EVBH!8RVZf+Fbt+lKkNNqoDkgf!|dB`6OT3 z&uWAGjTZTTBl+p%zg&Sq`;P#>N&gDcpZT%>-EPqT9*g|*!7soo zo&FzK_{%foA34@s{>zDff>y)*8!Z0_;5U_jouT}9n96UFe>cgW>Pps;p!}~}dz=)nCOEdQy{!64g^ z{jMkeOI=PK3G(Lyze)eW|JC$!h#&12e~TW}zuqGM-y|QBeHZE~uNsT|Hj*#<|J?@p zf49gl1iuom@j7t-2Fw4hMgB&E{Cf=YPd(dQ|IH*no&Dwmzp4IrkbF6QtT)L24#|%M z3bvKx4|PkfBiw!r-(!)V|G%1I4iRGe#r|cfogI-w#eUXkdNor1mzc;quW1N|0N`!>xnCX`T70?;5W7Z zPLdxZLahId2Kh0PAN>7T1<5~>1yPt6xNiV{oMR#ZyoUIL`tm)8wXA=Df9O69aQRXH z?;G^Lk@OGNUsD?SEbdyCA86Q8gZv*Drl8c@o&Y=o^Wl4^2sa6|Nj6)z7byl literal 0 HcmV?d00001 diff --git a/examples/cpp/metadata/helloworld.grpc.pb.cc b/examples/cpp/metadata/helloworld.grpc.pb.cc new file mode 100644 index 00000000000..4255687148b --- /dev/null +++ b/examples/cpp/metadata/helloworld.grpc.pb.cc @@ -0,0 +1,70 @@ +// Generated by the gRPC C++ plugin. +// If you make any local change, they will be lost. +// source: helloworld.proto + +#include "helloworld.pb.h" +#include "helloworld.grpc.pb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace helloworld { + +static const char* Greeter_method_names[] = { + "/helloworld.Greeter/SayHello", +}; + +std::unique_ptr< Greeter::Stub> Greeter::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { + (void)options; + std::unique_ptr< Greeter::Stub> stub(new Greeter::Stub(channel)); + return stub; +} + +Greeter::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel) + : channel_(channel), rpcmethod_SayHello_(Greeter_method_names[0], ::grpc::internal::RpcMethod::NORMAL_RPC, channel) + {} + +::grpc::Status Greeter::Stub::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) { + return ::grpc::internal::BlockingUnaryCall(channel_.get(), rpcmethod_SayHello_, context, request, response); +} + +void Greeter::Stub::experimental_async::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function f) { + return ::grpc::internal::CallbackUnaryCall(stub_->channel_.get(), stub_->rpcmethod_SayHello_, context, request, response, std::move(f)); +} + +::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderFactory< ::helloworld::HelloReply>::Create(channel_.get(), cq, rpcmethod_SayHello_, context, request, true); +} + +::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderFactory< ::helloworld::HelloReply>::Create(channel_.get(), cq, rpcmethod_SayHello_, context, request, false); +} + +Greeter::Service::Service() { + AddMethod(new ::grpc::internal::RpcServiceMethod( + Greeter_method_names[0], + ::grpc::internal::RpcMethod::NORMAL_RPC, + new ::grpc::internal::RpcMethodHandler< Greeter::Service, ::helloworld::HelloRequest, ::helloworld::HelloReply>( + std::mem_fn(&Greeter::Service::SayHello), this))); +} + +Greeter::Service::~Service() { +} + +::grpc::Status Greeter::Service::SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { + (void) context; + (void) request; + (void) response; + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); +} + + +} // namespace helloworld + diff --git a/examples/cpp/metadata/helloworld.grpc.pb.h b/examples/cpp/metadata/helloworld.grpc.pb.h new file mode 100644 index 00000000000..73cc75e0a62 --- /dev/null +++ b/examples/cpp/metadata/helloworld.grpc.pb.h @@ -0,0 +1,197 @@ +// Generated by the gRPC C++ plugin. +// If you make any local change, they will be lost. +// source: helloworld.proto +// Original file comments: +// 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_helloworld_2eproto__INCLUDED +#define GRPC_helloworld_2eproto__INCLUDED + +#include "helloworld.pb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc { +class CompletionQueue; +class Channel; +class ServerCompletionQueue; +class ServerContext; +} // namespace grpc + +namespace helloworld { + +// The greeting service definition. +class Greeter final { + public: + static constexpr char const* service_full_name() { + return "helloworld.Greeter"; + } + class StubInterface { + public: + virtual ~StubInterface() {} + // Sends a greeting + virtual ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) = 0; + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); + } + class experimental_async_interface { + public: + virtual ~experimental_async_interface() {} + // Sends a greeting + virtual void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) = 0; + }; + virtual class experimental_async_interface* experimental_async() { return nullptr; } + private: + virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; + }; + class Stub final : public StubInterface { + public: + Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel); + ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) override; + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); + } + class experimental_async final : + public StubInterface::experimental_async_interface { + public: + void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) override; + private: + friend class Stub; + explicit experimental_async(Stub* stub): stub_(stub) { } + Stub* stub() { return stub_; } + Stub* stub_; + }; + class experimental_async_interface* experimental_async() override { return &async_stub_; } + + private: + std::shared_ptr< ::grpc::ChannelInterface> channel_; + class experimental_async async_stub_{this}; + ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; + const ::grpc::internal::RpcMethod rpcmethod_SayHello_; + }; + static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); + + class Service : public ::grpc::Service { + public: + Service(); + virtual ~Service(); + // Sends a greeting + virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response); + }; + template + class WithAsyncMethod_SayHello : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithAsyncMethod_SayHello() { + ::grpc::Service::MarkMethodAsync(0); + } + ~WithAsyncMethod_SayHello() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestSayHello(::grpc::ServerContext* context, ::helloworld::HelloRequest* request, ::grpc::ServerAsyncResponseWriter< ::helloworld::HelloReply>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); + } + }; + typedef WithAsyncMethod_SayHello AsyncService; + template + class WithGenericMethod_SayHello : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithGenericMethod_SayHello() { + ::grpc::Service::MarkMethodGeneric(0); + } + ~WithGenericMethod_SayHello() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template + class WithRawMethod_SayHello : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithRawMethod_SayHello() { + ::grpc::Service::MarkMethodRaw(0); + } + ~WithRawMethod_SayHello() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestSayHello(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); + } + }; + template + class WithStreamedUnaryMethod_SayHello : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithStreamedUnaryMethod_SayHello() { + ::grpc::Service::MarkMethodStreamed(0, + new ::grpc::internal::StreamedUnaryHandler< ::helloworld::HelloRequest, ::helloworld::HelloReply>(std::bind(&WithStreamedUnaryMethod_SayHello::StreamedSayHello, this, std::placeholders::_1, std::placeholders::_2))); + } + ~WithStreamedUnaryMethod_SayHello() override { + BaseClassMustBeDerivedFromService(this); + } + // disable regular version of this method + ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + // replace default version of method with streamed unary + virtual ::grpc::Status StreamedSayHello(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::helloworld::HelloRequest,::helloworld::HelloReply>* server_unary_streamer) = 0; + }; + typedef WithStreamedUnaryMethod_SayHello StreamedUnaryService; + typedef Service SplitStreamedService; + typedef WithStreamedUnaryMethod_SayHello StreamedService; +}; + +} // namespace helloworld + + +#endif // GRPC_helloworld_2eproto__INCLUDED diff --git a/examples/cpp/metadata/helloworld.grpc.pb.o b/examples/cpp/metadata/helloworld.grpc.pb.o new file mode 100644 index 0000000000000000000000000000000000000000..234283660c2185112bf5a40874899672b328aa80 GIT binary patch literal 398496 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 w=02@|e2cV41O4aeXEX08#pYMFzIkvk#=-yP + +#include +#include +#include +#include +#include +#include +#include +#include +// This is a temporary google only hack +#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS +#include "third_party/protobuf/version.h" +#endif +// @@protoc_insertion_point(includes) + +namespace helloworld { +class HelloRequestDefaultTypeInternal { + public: + ::google::protobuf::internal::ExplicitlyConstructed + _instance; +} _HelloRequest_default_instance_; +class HelloReplyDefaultTypeInternal { + public: + ::google::protobuf::internal::ExplicitlyConstructed + _instance; +} _HelloReply_default_instance_; +} // namespace helloworld +namespace protobuf_helloworld_2eproto { +static void InitDefaultsHelloRequest() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::helloworld::_HelloRequest_default_instance_; + new (ptr) ::helloworld::HelloRequest(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::helloworld::HelloRequest::InitAsDefaultInstance(); +} + +::google::protobuf::internal::SCCInfo<0> scc_info_HelloRequest = + {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsHelloRequest}, {}}; + +static void InitDefaultsHelloReply() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + { + void* ptr = &::helloworld::_HelloReply_default_instance_; + new (ptr) ::helloworld::HelloReply(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::helloworld::HelloReply::InitAsDefaultInstance(); +} + +::google::protobuf::internal::SCCInfo<0> scc_info_HelloReply = + {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsHelloReply}, {}}; + +void InitDefaults() { + ::google::protobuf::internal::InitSCC(&scc_info_HelloRequest.base); + ::google::protobuf::internal::InitSCC(&scc_info_HelloReply.base); +} + +::google::protobuf::Metadata file_level_metadata[2]; + +const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloRequest, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloRequest, name_), + ~0u, // no _has_bits_ + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloReply, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloReply, message_), +}; +static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::helloworld::HelloRequest)}, + { 6, -1, sizeof(::helloworld::HelloReply)}, +}; + +static ::google::protobuf::Message const * const file_default_instances[] = { + reinterpret_cast(&::helloworld::_HelloRequest_default_instance_), + reinterpret_cast(&::helloworld::_HelloReply_default_instance_), +}; + +void protobuf_AssignDescriptors() { + AddDescriptors(); + AssignDescriptors( + "helloworld.proto", schemas, file_default_instances, TableStruct::offsets, + file_level_metadata, NULL, NULL); +} + +void protobuf_AssignDescriptorsOnce() { + static ::google::protobuf::internal::once_flag once; + ::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors); +} + +void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD; +void protobuf_RegisterTypes(const ::std::string&) { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 2); +} + +void AddDescriptorsImpl() { + InitDefaults(); + static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" + "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" + "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" + "loworld.HelloRequest\032\026.helloworld.HelloR" + "eply\"\000B6\n\033io.grpc.examples.helloworldB\017H" + "elloWorldProtoP\001\242\002\003HLWb\006proto3" + }; + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( + descriptor, 230); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( + "helloworld.proto", &protobuf_RegisterTypes); +} + +void AddDescriptors() { + static ::google::protobuf::internal::once_flag once; + ::google::protobuf::internal::call_once(once, AddDescriptorsImpl); +} +// Force AddDescriptors() to be called at dynamic initialization time. +struct StaticDescriptorInitializer { + StaticDescriptorInitializer() { + AddDescriptors(); + } +} static_descriptor_initializer; +} // namespace protobuf_helloworld_2eproto +namespace helloworld { + +// =================================================================== + +void HelloRequest::InitAsDefaultInstance() { +} +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +const int HelloRequest::kNameFieldNumber; +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 + +HelloRequest::HelloRequest() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + ::google::protobuf::internal::InitSCC( + &protobuf_helloworld_2eproto::scc_info_HelloRequest.base); + SharedCtor(); + // @@protoc_insertion_point(constructor:helloworld.HelloRequest) +} +HelloRequest::HelloRequest(const HelloRequest& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + _internal_metadata_.MergeFrom(from._internal_metadata_); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (from.name().size() > 0) { + name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); + } + // @@protoc_insertion_point(copy_constructor:helloworld.HelloRequest) +} + +void HelloRequest::SharedCtor() { + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +HelloRequest::~HelloRequest() { + // @@protoc_insertion_point(destructor:helloworld.HelloRequest) + SharedDtor(); +} + +void HelloRequest::SharedDtor() { + name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +void HelloRequest::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const ::google::protobuf::Descriptor* HelloRequest::descriptor() { + ::protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; +} + +const HelloRequest& HelloRequest::default_instance() { + ::google::protobuf::internal::InitSCC(&protobuf_helloworld_2eproto::scc_info_HelloRequest.base); + return *internal_default_instance(); +} + + +void HelloRequest::Clear() { +// @@protoc_insertion_point(message_clear_start:helloworld.HelloRequest) + ::google::protobuf::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + _internal_metadata_.Clear(); +} + +bool HelloRequest::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:helloworld.HelloRequest) + for (;;) { + ::std::pair<::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // string name = 1; + case 1: { + if (static_cast< ::google::protobuf::uint8>(tag) == + static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->name().data(), static_cast(this->name().length()), + ::google::protobuf::internal::WireFormatLite::PARSE, + "helloworld.HelloRequest.name")); + } else { + goto handle_unusual; + } + break; + } + + default: { + handle_unusual: + if (tag == 0) { + goto success; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, _internal_metadata_.mutable_unknown_fields())); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:helloworld.HelloRequest) + return true; +failure: + // @@protoc_insertion_point(parse_failure:helloworld.HelloRequest) + return false; +#undef DO_ +} + +void HelloRequest::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:helloworld.HelloRequest) + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // string name = 1; + if (this->name().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->name().data(), static_cast(this->name().length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "helloworld.HelloRequest.name"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 1, this->name(), output); + } + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); + } + // @@protoc_insertion_point(serialize_end:helloworld.HelloRequest) +} + +::google::protobuf::uint8* HelloRequest::InternalSerializeWithCachedSizesToArray( + bool deterministic, ::google::protobuf::uint8* target) const { + (void)deterministic; // Unused + // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloRequest) + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // string name = 1; + if (this->name().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->name().data(), static_cast(this->name().length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "helloworld.HelloRequest.name"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); + } + // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloRequest) + return target; +} + +size_t HelloRequest::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:helloworld.HelloRequest) + size_t total_size = 0; + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); + } + // string name = 1; + if (this->name().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void HelloRequest::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:helloworld.HelloRequest) + GOOGLE_DCHECK_NE(&from, this); + const HelloRequest* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); + if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:helloworld.HelloRequest) + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:helloworld.HelloRequest) + MergeFrom(*source); + } +} + +void HelloRequest::MergeFrom(const HelloRequest& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloRequest) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom(from._internal_metadata_); + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.name().size() > 0) { + + name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); + } +} + +void HelloRequest::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:helloworld.HelloRequest) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void HelloRequest::CopyFrom(const HelloRequest& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloRequest) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool HelloRequest::IsInitialized() const { + return true; +} + +void HelloRequest::Swap(HelloRequest* other) { + if (other == this) return; + InternalSwap(other); +} +void HelloRequest::InternalSwap(HelloRequest* other) { + using std::swap; + name_.Swap(&other->name_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); + _internal_metadata_.Swap(&other->_internal_metadata_); +} + +::google::protobuf::Metadata HelloRequest::GetMetadata() const { + protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages]; +} + + +// =================================================================== + +void HelloReply::InitAsDefaultInstance() { +} +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +const int HelloReply::kMessageFieldNumber; +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 + +HelloReply::HelloReply() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + ::google::protobuf::internal::InitSCC( + &protobuf_helloworld_2eproto::scc_info_HelloReply.base); + SharedCtor(); + // @@protoc_insertion_point(constructor:helloworld.HelloReply) +} +HelloReply::HelloReply(const HelloReply& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + _internal_metadata_.MergeFrom(from._internal_metadata_); + message_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (from.message().size() > 0) { + message_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.message_); + } + // @@protoc_insertion_point(copy_constructor:helloworld.HelloReply) +} + +void HelloReply::SharedCtor() { + message_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +HelloReply::~HelloReply() { + // @@protoc_insertion_point(destructor:helloworld.HelloReply) + SharedDtor(); +} + +void HelloReply::SharedDtor() { + message_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +void HelloReply::SetCachedSize(int size) const { + _cached_size_.Set(size); +} +const ::google::protobuf::Descriptor* HelloReply::descriptor() { + ::protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; +} + +const HelloReply& HelloReply::default_instance() { + ::google::protobuf::internal::InitSCC(&protobuf_helloworld_2eproto::scc_info_HelloReply.base); + return *internal_default_instance(); +} + + +void HelloReply::Clear() { +// @@protoc_insertion_point(message_clear_start:helloworld.HelloReply) + ::google::protobuf::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + _internal_metadata_.Clear(); +} + +bool HelloReply::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:helloworld.HelloReply) + for (;;) { + ::std::pair<::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // string message = 1; + case 1: { + if (static_cast< ::google::protobuf::uint8>(tag) == + static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_message())); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->message().data(), static_cast(this->message().length()), + ::google::protobuf::internal::WireFormatLite::PARSE, + "helloworld.HelloReply.message")); + } else { + goto handle_unusual; + } + break; + } + + default: { + handle_unusual: + if (tag == 0) { + goto success; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, _internal_metadata_.mutable_unknown_fields())); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:helloworld.HelloReply) + return true; +failure: + // @@protoc_insertion_point(parse_failure:helloworld.HelloReply) + return false; +#undef DO_ +} + +void HelloReply::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:helloworld.HelloReply) + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // string message = 1; + if (this->message().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->message().data(), static_cast(this->message().length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "helloworld.HelloReply.message"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 1, this->message(), output); + } + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); + } + // @@protoc_insertion_point(serialize_end:helloworld.HelloReply) +} + +::google::protobuf::uint8* HelloReply::InternalSerializeWithCachedSizesToArray( + bool deterministic, ::google::protobuf::uint8* target) const { + (void)deterministic; // Unused + // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloReply) + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + // string message = 1; + if (this->message().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->message().data(), static_cast(this->message().length()), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "helloworld.HelloReply.message"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->message(), target); + } + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); + } + // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloReply) + return target; +} + +size_t HelloReply::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:helloworld.HelloReply) + size_t total_size = 0; + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); + } + // string message = 1; + if (this->message().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->message()); + } + + int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); + SetCachedSize(cached_size); + return total_size; +} + +void HelloReply::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:helloworld.HelloReply) + GOOGLE_DCHECK_NE(&from, this); + const HelloReply* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); + if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:helloworld.HelloReply) + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:helloworld.HelloReply) + MergeFrom(*source); + } +} + +void HelloReply::MergeFrom(const HelloReply& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloReply) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom(from._internal_metadata_); + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if (from.message().size() > 0) { + + message_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.message_); + } +} + +void HelloReply::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:helloworld.HelloReply) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void HelloReply::CopyFrom(const HelloReply& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloReply) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool HelloReply::IsInitialized() const { + return true; +} + +void HelloReply::Swap(HelloReply* other) { + if (other == this) return; + InternalSwap(other); +} +void HelloReply::InternalSwap(HelloReply* other) { + using std::swap; + message_.Swap(&other->message_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); + _internal_metadata_.Swap(&other->_internal_metadata_); +} + +::google::protobuf::Metadata HelloReply::GetMetadata() const { + protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages]; +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace helloworld +namespace google { +namespace protobuf { +template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::helloworld::HelloRequest* Arena::CreateMaybeMessage< ::helloworld::HelloRequest >(Arena* arena) { + return Arena::CreateInternal< ::helloworld::HelloRequest >(arena); +} +template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::helloworld::HelloReply* Arena::CreateMaybeMessage< ::helloworld::HelloReply >(Arena* arena) { + return Arena::CreateInternal< ::helloworld::HelloReply >(arena); +} +} // namespace protobuf +} // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/examples/cpp/metadata/helloworld.pb.h b/examples/cpp/metadata/helloworld.pb.h new file mode 100644 index 00000000000..57f6817e310 --- /dev/null +++ b/examples/cpp/metadata/helloworld.pb.h @@ -0,0 +1,419 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: helloworld.proto + +#ifndef PROTOBUF_INCLUDED_helloworld_2eproto +#define PROTOBUF_INCLUDED_helloworld_2eproto + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 3006001 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +// @@protoc_insertion_point(includes) +#define PROTOBUF_INTERNAL_EXPORT_protobuf_helloworld_2eproto + +namespace protobuf_helloworld_2eproto { +// Internal implementation detail -- do not use these members. +struct TableStruct { + static const ::google::protobuf::internal::ParseTableField entries[]; + static const ::google::protobuf::internal::AuxillaryParseTableField aux[]; + static const ::google::protobuf::internal::ParseTable schema[2]; + static const ::google::protobuf::internal::FieldMetadata field_metadata[]; + static const ::google::protobuf::internal::SerializationTable serialization_table[]; + static const ::google::protobuf::uint32 offsets[]; +}; +void AddDescriptors(); +} // namespace protobuf_helloworld_2eproto +namespace helloworld { +class HelloReply; +class HelloReplyDefaultTypeInternal; +extern HelloReplyDefaultTypeInternal _HelloReply_default_instance_; +class HelloRequest; +class HelloRequestDefaultTypeInternal; +extern HelloRequestDefaultTypeInternal _HelloRequest_default_instance_; +} // namespace helloworld +namespace google { +namespace protobuf { +template<> ::helloworld::HelloReply* Arena::CreateMaybeMessage<::helloworld::HelloReply>(Arena*); +template<> ::helloworld::HelloRequest* Arena::CreateMaybeMessage<::helloworld::HelloRequest>(Arena*); +} // namespace protobuf +} // namespace google +namespace helloworld { + +// =================================================================== + +class HelloRequest : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:helloworld.HelloRequest) */ { + public: + HelloRequest(); + virtual ~HelloRequest(); + + HelloRequest(const HelloRequest& from); + + inline HelloRequest& operator=(const HelloRequest& from) { + CopyFrom(from); + return *this; + } + #if LANG_CXX11 + HelloRequest(HelloRequest&& from) noexcept + : HelloRequest() { + *this = ::std::move(from); + } + + inline HelloRequest& operator=(HelloRequest&& from) noexcept { + if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + #endif + static const ::google::protobuf::Descriptor* descriptor(); + static const HelloRequest& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const HelloRequest* internal_default_instance() { + return reinterpret_cast( + &_HelloRequest_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + void Swap(HelloRequest* other); + friend void swap(HelloRequest& a, HelloRequest& b) { + a.Swap(&b); + } + + // implements Message ---------------------------------------------- + + inline HelloRequest* New() const final { + return CreateMaybeMessage(NULL); + } + + HelloRequest* New(::google::protobuf::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::google::protobuf::Message& from) final; + void MergeFrom(const ::google::protobuf::Message& from) final; + void CopyFrom(const HelloRequest& from); + void MergeFrom(const HelloRequest& from); + void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) final; + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const final; + ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( + bool deterministic, ::google::protobuf::uint8* target) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(HelloRequest* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return NULL; + } + inline void* MaybeArenaPtr() const { + return NULL; + } + public: + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // string name = 1; + void clear_name(); + static const int kNameFieldNumber = 1; + const ::std::string& name() const; + void set_name(const ::std::string& value); + #if LANG_CXX11 + void set_name(::std::string&& value); + #endif + void set_name(const char* value); + void set_name(const char* value, size_t size); + ::std::string* mutable_name(); + ::std::string* release_name(); + void set_allocated_name(::std::string* name); + + // @@protoc_insertion_point(class_scope:helloworld.HelloRequest) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + ::google::protobuf::internal::ArenaStringPtr name_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + friend struct ::protobuf_helloworld_2eproto::TableStruct; +}; +// ------------------------------------------------------------------- + +class HelloReply : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:helloworld.HelloReply) */ { + public: + HelloReply(); + virtual ~HelloReply(); + + HelloReply(const HelloReply& from); + + inline HelloReply& operator=(const HelloReply& from) { + CopyFrom(from); + return *this; + } + #if LANG_CXX11 + HelloReply(HelloReply&& from) noexcept + : HelloReply() { + *this = ::std::move(from); + } + + inline HelloReply& operator=(HelloReply&& from) noexcept { + if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + #endif + static const ::google::protobuf::Descriptor* descriptor(); + static const HelloReply& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const HelloReply* internal_default_instance() { + return reinterpret_cast( + &_HelloReply_default_instance_); + } + static constexpr int kIndexInFileMessages = + 1; + + void Swap(HelloReply* other); + friend void swap(HelloReply& a, HelloReply& b) { + a.Swap(&b); + } + + // implements Message ---------------------------------------------- + + inline HelloReply* New() const final { + return CreateMaybeMessage(NULL); + } + + HelloReply* New(::google::protobuf::Arena* arena) const final { + return CreateMaybeMessage(arena); + } + void CopyFrom(const ::google::protobuf::Message& from) final; + void MergeFrom(const ::google::protobuf::Message& from) final; + void CopyFrom(const HelloReply& from); + void MergeFrom(const HelloReply& from); + void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) final; + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const final; + ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( + bool deterministic, ::google::protobuf::uint8* target) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(HelloReply* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return NULL; + } + inline void* MaybeArenaPtr() const { + return NULL; + } + public: + + ::google::protobuf::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // string message = 1; + void clear_message(); + static const int kMessageFieldNumber = 1; + const ::std::string& message() const; + void set_message(const ::std::string& value); + #if LANG_CXX11 + void set_message(::std::string&& value); + #endif + void set_message(const char* value); + void set_message(const char* value, size_t size); + ::std::string* mutable_message(); + ::std::string* release_message(); + void set_allocated_message(::std::string* message); + + // @@protoc_insertion_point(class_scope:helloworld.HelloReply) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + ::google::protobuf::internal::ArenaStringPtr message_; + mutable ::google::protobuf::internal::CachedSize _cached_size_; + friend struct ::protobuf_helloworld_2eproto::TableStruct; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// HelloRequest + +// string name = 1; +inline void HelloRequest::clear_name() { + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& HelloRequest::name() const { + // @@protoc_insertion_point(field_get:helloworld.HelloRequest.name) + return name_.GetNoArena(); +} +inline void HelloRequest::set_name(const ::std::string& value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:helloworld.HelloRequest.name) +} +#if LANG_CXX11 +inline void HelloRequest::set_name(::std::string&& value) { + + name_.SetNoArena( + &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); + // @@protoc_insertion_point(field_set_rvalue:helloworld.HelloRequest.name) +} +#endif +inline void HelloRequest::set_name(const char* value) { + GOOGLE_DCHECK(value != NULL); + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:helloworld.HelloRequest.name) +} +inline void HelloRequest::set_name(const char* value, size_t size) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast(value), size)); + // @@protoc_insertion_point(field_set_pointer:helloworld.HelloRequest.name) +} +inline ::std::string* HelloRequest::mutable_name() { + + // @@protoc_insertion_point(field_mutable:helloworld.HelloRequest.name) + return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* HelloRequest::release_name() { + // @@protoc_insertion_point(field_release:helloworld.HelloRequest.name) + + return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void HelloRequest::set_allocated_name(::std::string* name) { + if (name != NULL) { + + } else { + + } + name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name); + // @@protoc_insertion_point(field_set_allocated:helloworld.HelloRequest.name) +} + +// ------------------------------------------------------------------- + +// HelloReply + +// string message = 1; +inline void HelloReply::clear_message() { + message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& HelloReply::message() const { + // @@protoc_insertion_point(field_get:helloworld.HelloReply.message) + return message_.GetNoArena(); +} +inline void HelloReply::set_message(const ::std::string& value) { + + message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:helloworld.HelloReply.message) +} +#if LANG_CXX11 +inline void HelloReply::set_message(::std::string&& value) { + + message_.SetNoArena( + &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); + // @@protoc_insertion_point(field_set_rvalue:helloworld.HelloReply.message) +} +#endif +inline void HelloReply::set_message(const char* value) { + GOOGLE_DCHECK(value != NULL); + + message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:helloworld.HelloReply.message) +} +inline void HelloReply::set_message(const char* value, size_t size) { + + message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast(value), size)); + // @@protoc_insertion_point(field_set_pointer:helloworld.HelloReply.message) +} +inline ::std::string* HelloReply::mutable_message() { + + // @@protoc_insertion_point(field_mutable:helloworld.HelloReply.message) + return message_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* HelloReply::release_message() { + // @@protoc_insertion_point(field_release:helloworld.HelloReply.message) + + return message_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void HelloReply::set_allocated_message(::std::string* message) { + if (message != NULL) { + + } else { + + } + message_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), message); + // @@protoc_insertion_point(field_set_allocated:helloworld.HelloReply.message) +} + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ +// ------------------------------------------------------------------- + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace helloworld + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_INCLUDED_helloworld_2eproto diff --git a/examples/cpp/metadata/helloworld.pb.o b/examples/cpp/metadata/helloworld.pb.o new file mode 100644 index 0000000000000000000000000000000000000000..85671e8aaa3b10080aba2cde1b103fe994eaa612 GIT binary patch literal 111592 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 Date: Thu, 13 Dec 2018 17:05:39 -0800 Subject: [PATCH 93/99] Fix typo && remove unecessary except --- src/python/grpcio_tests/tests/status/_grpc_status_test.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/python/grpcio_tests/tests/status/_grpc_status_test.py b/src/python/grpcio_tests/tests/status/_grpc_status_test.py index 5969338736f..519c372a960 100644 --- a/src/python/grpcio_tests/tests/status/_grpc_status_test.py +++ b/src/python/grpcio_tests/tests/status/_grpc_status_test.py @@ -54,7 +54,7 @@ def _error_details_unary_unary(request, servicer_context): details.Pack( error_details_pb2.DebugInfo( stack_entries=traceback.format_stack(), - detail='Intensionally invoked')) + detail='Intentionally invoked')) rich_status = status_pb2.Status( code=code_pb2.INTERNAL, message=_STATUS_DETAILS, @@ -118,10 +118,8 @@ class StatusTest(unittest.TestCase): self._channel.close() def test_status_ok(self): - try: - _, call = self._channel.unary_unary(_STATUS_OK).with_call(_REQUEST) - except grpc.RpcError as rpc_error: - self.fail(rpc_error) + _, call = self._channel.unary_unary(_STATUS_OK).with_call(_REQUEST) + # Succeed RPC doesn't have status status = rpc_status.from_call(call) self.assertIs(status, None) From b9cb2459ea4b2956547abf5fb516b553d85f1ae2 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Thu, 13 Dec 2018 17:18:38 -0800 Subject: [PATCH 94/99] Include LICENSE in artifact --- src/python/grpcio_status/MANIFEST.in | 1 + src/python/grpcio_status/setup.py | 19 +++++---- src/python/grpcio_status/status_commands.py | 39 +++++++++++++++++++ .../artifacts/build_artifact_python.sh | 2 +- 4 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 src/python/grpcio_status/status_commands.py diff --git a/src/python/grpcio_status/MANIFEST.in b/src/python/grpcio_status/MANIFEST.in index eca719a9c20..09b8ea721e8 100644 --- a/src/python/grpcio_status/MANIFEST.in +++ b/src/python/grpcio_status/MANIFEST.in @@ -1,3 +1,4 @@ include grpc_version.py recursive-include grpc_status *.py global-exclude *.pyc +include LICENSE diff --git a/src/python/grpcio_status/setup.py b/src/python/grpcio_status/setup.py index 0601498bc51..a59cdd0f0f5 100644 --- a/src/python/grpcio_status/setup.py +++ b/src/python/grpcio_status/setup.py @@ -63,12 +63,18 @@ INSTALL_REQUIRES = ( 'googleapis-common-protos>=1.5.5', ) -SETUP_REQUIRES = () -COMMAND_CLASS = { - # wire up commands to no-op not to break the external dependencies - 'preprocess': _NoOpCommand, - 'build_package_protos': _NoOpCommand, -} +try: + import status_commands as _status_commands + # we are in the build environment, otherwise the above import fails + COMMAND_CLASS = { + # Run preprocess from the repository *before* doing any packaging! + 'preprocess': _status_commands.Preprocess, + } +except ImportError: + COMMAND_CLASS = { + # wire up commands to no-op not to break the external dependencies + 'preprocess': _NoOpCommand, + } setuptools.setup( name='grpcio-status', @@ -82,5 +88,4 @@ setuptools.setup( package_dir=PACKAGE_DIRECTORIES, packages=setuptools.find_packages('.'), install_requires=INSTALL_REQUIRES, - setup_requires=SETUP_REQUIRES, cmdclass=COMMAND_CLASS) diff --git a/src/python/grpcio_status/status_commands.py b/src/python/grpcio_status/status_commands.py new file mode 100644 index 00000000000..78cd497f622 --- /dev/null +++ b/src/python/grpcio_status/status_commands.py @@ -0,0 +1,39 @@ +# Copyright 2018 The 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. +"""Provides distutils command classes for the GRPC Python setup process.""" + +import os +import shutil + +import setuptools + +ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) +LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') + + +class Preprocess(setuptools.Command): + """Command to copy LICENSE from root directory.""" + + description = '' + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + if os.path.isfile(LICENSE): + shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh index 18eb70c8574..e451ced338f 100755 --- a/tools/run_tests/artifacts/build_artifact_python.sh +++ b/tools/run_tests/artifacts/build_artifact_python.sh @@ -126,7 +126,7 @@ then # Build grpcio_status source distribution ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_status/setup.py \ - preprocess build_package_protos sdist + preprocess sdist cp -r src/python/grpcio_status/dist/* "$ARTIFACT_DIR" fi From 40b8ca97a1d89153711e0d965cd25de1099862f1 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Fri, 14 Dec 2018 10:10:57 -0800 Subject: [PATCH 95/99] Update docstring to make it more clear * Mark API as experimental * Rephrase the raise condition * Add more detail to the returned object --- src/python/grpcio_status/grpc_status/rpc_status.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/python/grpcio_status/grpc_status/rpc_status.py b/src/python/grpcio_status/grpc_status/rpc_status.py index 36c8eba37d5..e23a20968ec 100644 --- a/src/python/grpcio_status/grpc_status/rpc_status.py +++ b/src/python/grpcio_status/grpc_status/rpc_status.py @@ -45,6 +45,8 @@ def _code_to_grpc_status_code(code): def from_call(call): """Returns a google.rpc.status.Status message corresponding to a given grpc.Call. + This is an EXPERIMENTAL API. + Args: call: A grpc.Call instance. @@ -52,8 +54,8 @@ def from_call(call): A google.rpc.status.Status message representing the status of the RPC. Raises: - ValueError: If the status code, status message is inconsistent with the rich status - inside of the google.rpc.status.Status. + ValueError: If the gRPC call's code or details are inconsistent with the + status code and message inside of the google.rpc.status.Status. """ for key, value in call.trailing_metadata(): if key == _GRPC_DETAILS_METADATA_KEY: @@ -74,12 +76,14 @@ def from_call(call): def to_status(status): """Convert a google.rpc.status.Status message to grpc.Status. + This is an EXPERIMENTAL API. + Args: status: a google.rpc.status.Status message representing the non-OK status to terminate the RPC with and communicate it to the client. Returns: - A grpc.Status instance. + A grpc.Status instance representing the input google.rpc.status.Status message. """ return _Status( code=_code_to_grpc_status_code(status.code), From 8621bd47adb7dec1f16bbd616890fd3b0df3336e Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Fri, 14 Dec 2018 11:23:18 -0800 Subject: [PATCH 96/99] Assign noop to build_package_protos for backward compatibility --- src/python/grpcio_status/setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/python/grpcio_status/setup.py b/src/python/grpcio_status/setup.py index a59cdd0f0f5..983d3ea430b 100644 --- a/src/python/grpcio_status/setup.py +++ b/src/python/grpcio_status/setup.py @@ -69,11 +69,13 @@ try: COMMAND_CLASS = { # Run preprocess from the repository *before* doing any packaging! 'preprocess': _status_commands.Preprocess, + 'build_package_protos': _NoOpCommand, } except ImportError: COMMAND_CLASS = { # wire up commands to no-op not to break the external dependencies 'preprocess': _NoOpCommand, + 'build_package_protos': _NoOpCommand, } setuptools.setup( From ca4e55e6caae393e33784d51f1e9d2352608c4dc Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 14 Dec 2018 13:03:22 -0800 Subject: [PATCH 97/99] Benchmark to show that byte buffer copy is size-independent --- CMakeLists.txt | 49 ++++++++++++++ Makefile | 49 ++++++++++++++ build.yaml | 22 +++++++ test/cpp/microbenchmarks/BUILD | 7 ++ test/cpp/microbenchmarks/bm_byte_buffer.cc | 65 +++++++++++++++++++ .../generated/sources_and_headers.json | 22 +++++++ tools/run_tests/generated/tests.json | 22 +++++++ 7 files changed, 236 insertions(+) create mode 100644 test/cpp/microbenchmarks/bm_byte_buffer.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index fb233cc3601..e296eaee734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -526,6 +526,9 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx bm_arena) endif() if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) +add_dependencies(buildtests_cxx bm_byte_buffer) +endif() +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx bm_call_create) endif() if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) @@ -11191,6 +11194,52 @@ target_link_libraries(bm_arena ) +endif() +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + +add_executable(bm_byte_buffer + test/cpp/microbenchmarks/bm_byte_buffer.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(bm_byte_buffer + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + PRIVATE third_party/googletest/googletest/include + PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(bm_byte_buffer + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_benchmark + ${_gRPC_BENCHMARK_LIBRARIES} + grpc++_test_util_unsecure + grpc_test_util_unsecure + grpc++_unsecure + grpc_unsecure + gpr_test_util + gpr + grpc++_test_config + ${_gRPC_GFLAGS_LIBRARIES} +) + + endif() endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) diff --git a/Makefile b/Makefile index c4d8a0b95cb..9cc4aeecc4d 100644 --- a/Makefile +++ b/Makefile @@ -1135,6 +1135,7 @@ auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test backoff_test: $(BINDIR)/$(CONFIG)/backoff_test bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test bm_arena: $(BINDIR)/$(CONFIG)/bm_arena +bm_byte_buffer: $(BINDIR)/$(CONFIG)/bm_byte_buffer bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create bm_channel: $(BINDIR)/$(CONFIG)/bm_channel bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack @@ -1641,6 +1642,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/backoff_test \ $(BINDIR)/$(CONFIG)/bdp_estimator_test \ $(BINDIR)/$(CONFIG)/bm_arena \ + $(BINDIR)/$(CONFIG)/bm_byte_buffer \ $(BINDIR)/$(CONFIG)/bm_call_create \ $(BINDIR)/$(CONFIG)/bm_channel \ $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \ @@ -1825,6 +1827,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/backoff_test \ $(BINDIR)/$(CONFIG)/bdp_estimator_test \ $(BINDIR)/$(CONFIG)/bm_arena \ + $(BINDIR)/$(CONFIG)/bm_byte_buffer \ $(BINDIR)/$(CONFIG)/bm_call_create \ $(BINDIR)/$(CONFIG)/bm_channel \ $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \ @@ -2259,6 +2262,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/bdp_estimator_test || ( echo test bdp_estimator_test failed ; exit 1 ) $(E) "[RUN] Testing bm_arena" $(Q) $(BINDIR)/$(CONFIG)/bm_arena || ( echo test bm_arena failed ; exit 1 ) + $(E) "[RUN] Testing bm_byte_buffer" + $(Q) $(BINDIR)/$(CONFIG)/bm_byte_buffer || ( echo test bm_byte_buffer failed ; exit 1 ) $(E) "[RUN] Testing bm_call_create" $(Q) $(BINDIR)/$(CONFIG)/bm_call_create || ( echo test bm_call_create failed ; exit 1 ) $(E) "[RUN] Testing bm_channel" @@ -16084,6 +16089,50 @@ endif endif +BM_BYTE_BUFFER_SRC = \ + test/cpp/microbenchmarks/bm_byte_buffer.cc \ + +BM_BYTE_BUFFER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_BYTE_BUFFER_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/bm_byte_buffer: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/bm_byte_buffer: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/bm_byte_buffer: $(PROTOBUF_DEP) $(BM_BYTE_BUFFER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(BM_BYTE_BUFFER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_byte_buffer + +endif + +endif + +$(BM_BYTE_BUFFER_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX +$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_byte_buffer.o: $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a + +deps_bm_byte_buffer: $(BM_BYTE_BUFFER_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(BM_BYTE_BUFFER_OBJS:.o=.dep) +endif +endif + + BM_CALL_CREATE_SRC = \ test/cpp/microbenchmarks/bm_call_create.cc \ diff --git a/build.yaml b/build.yaml index 6e2ed16398e..5f4d554a467 100644 --- a/build.yaml +++ b/build.yaml @@ -4015,6 +4015,28 @@ targets: - linux - posix uses_polling: false +- name: bm_byte_buffer + build: test + language: c++ + src: + - test/cpp/microbenchmarks/bm_byte_buffer.cc + deps: + - grpc_benchmark + - benchmark + - grpc++_test_util_unsecure + - grpc_test_util_unsecure + - grpc++_unsecure + - grpc_unsecure + - gpr_test_util + - gpr + - grpc++_test_config + benchmark: true + defaults: benchmark + platforms: + - mac + - linux + - posix + uses_polling: false - name: bm_call_create build: test language: c++ diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD index 097e92f5836..93ed962a00d 100644 --- a/test/cpp/microbenchmarks/BUILD +++ b/test/cpp/microbenchmarks/BUILD @@ -61,6 +61,13 @@ grpc_cc_binary( deps = [":helpers"], ) +grpc_cc_binary( + name = "bm_byte_buffer", + testonly = 1, + srcs = ["bm_byte_buffer.cc"], + deps = [":helpers"], +) + grpc_cc_binary( name = "bm_channel", testonly = 1, diff --git a/test/cpp/microbenchmarks/bm_byte_buffer.cc b/test/cpp/microbenchmarks/bm_byte_buffer.cc new file mode 100644 index 00000000000..a359e6f6212 --- /dev/null +++ b/test/cpp/microbenchmarks/bm_byte_buffer.cc @@ -0,0 +1,65 @@ +/* + * + * 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. + * + */ + +/* This benchmark exists to show that byte-buffer copy is size-independent */ + +#include + +#include +#include +#include +#include "test/cpp/microbenchmarks/helpers.h" +#include "test/cpp/util/test_config.h" + +namespace grpc { +namespace testing { + +auto& force_library_initialization = Library::get(); + +static void BM_ByteBuffer_Copy(benchmark::State& state) { + int num_slices = state.range(0); + size_t slice_size = state.range(1); + std::vector slices; + while (num_slices > 0) { + num_slices--; + std::unique_ptr buf(new char[slice_size]); + memset(buf.get(), 0, slice_size); + slices.emplace_back(buf.get(), slice_size); + } + grpc::ByteBuffer bb(slices.data(), num_slices); + while (state.KeepRunning()) { + grpc::ByteBuffer cc(bb); + } +} +BENCHMARK(BM_ByteBuffer_Copy)->Ranges({{1, 64}, {1, 1024 * 1024}}); + +} // namespace testing +} // namespace grpc + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + ::grpc::testing::InitTest(&argc, &argv, false); + benchmark::RunTheBenchmarksNamespaced(); + return 0; +} diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index c87d7209e7d..38cdd49fc7f 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -2789,6 +2789,28 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "benchmark", + "gpr", + "gpr_test_util", + "grpc++_test_config", + "grpc++_test_util_unsecure", + "grpc++_unsecure", + "grpc_benchmark", + "grpc_test_util_unsecure", + "grpc_unsecure" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "bm_byte_buffer", + "src": [ + "test/cpp/microbenchmarks/bm_byte_buffer.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "benchmark", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index cc28e52ae21..bca2ef53878 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -3363,6 +3363,28 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": true, + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "bm_byte_buffer", + "platforms": [ + "linux", + "mac", + "posix" + ], + "uses_polling": false + }, { "args": [], "benchmark": true, From b0b4c0d9c36d9b3185c5b792ca6e8954ff065e54 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 14 Dec 2018 13:52:25 -0800 Subject: [PATCH 98/99] Add API comments indicating that byte buffer copy is size-independent --- include/grpcpp/impl/codegen/byte_buffer.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h index 53ecb53371b..a77e36dfc50 100644 --- a/include/grpcpp/impl/codegen/byte_buffer.h +++ b/include/grpcpp/impl/codegen/byte_buffer.h @@ -93,7 +93,9 @@ class ByteBuffer final { } /// Constuct a byte buffer by referencing elements of existing buffer - /// \a buf. Wrapper of core function grpc_byte_buffer_copy + /// \a buf. Wrapper of core function grpc_byte_buffer_copy . This is not + /// a deep copy; it is just a referencing. As a result, its performance is + /// size-independent. ByteBuffer(const ByteBuffer& buf); ~ByteBuffer() { @@ -102,6 +104,9 @@ class ByteBuffer final { } } + /// Wrapper of core function grpc_byte_buffer_copy . This is not + /// a deep copy; it is just a referencing. As a result, its performance is + /// size-independent. ByteBuffer& operator=(const ByteBuffer&); /// Dump (read) the buffer contents into \a slices. @@ -117,7 +122,9 @@ class ByteBuffer final { /// Make a duplicate copy of the internals of this byte /// buffer so that we have our own owned version of it. - /// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable + /// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable. + /// This is not a deep copy; it is a referencing and its performance + /// is size-independent. void Duplicate() { buffer_ = g_core_codegen_interface->grpc_byte_buffer_copy(buffer_); } From 580d43d03f20b0b92f4b7ae950225a1dcd3387a0 Mon Sep 17 00:00:00 2001 From: Hope Casey-Allen Date: Thu, 13 Dec 2018 16:55:08 -0800 Subject: [PATCH 99/99] Address reviewer comments and remove binary files --- examples/BUILD | 15 + examples/cpp/metadata/README.md | 5 +- examples/cpp/metadata/greeter_client | Bin 267800 -> 0 bytes examples/cpp/metadata/greeter_client.o | Bin 101304 -> 0 bytes examples/cpp/metadata/greeter_server | Bin 278392 -> 0 bytes examples/cpp/metadata/greeter_server.cc | 14 +- examples/cpp/metadata/greeter_server.o | Bin 112144 -> 0 bytes examples/cpp/metadata/helloworld.grpc.pb.cc | 70 --- examples/cpp/metadata/helloworld.grpc.pb.h | 197 ------ examples/cpp/metadata/helloworld.grpc.pb.o | Bin 398496 -> 0 bytes examples/cpp/metadata/helloworld.pb.cc | 638 -------------------- examples/cpp/metadata/helloworld.pb.h | 419 ------------- examples/cpp/metadata/helloworld.pb.o | Bin 111592 -> 0 bytes 13 files changed, 29 insertions(+), 1329 deletions(-) delete mode 100755 examples/cpp/metadata/greeter_client delete mode 100644 examples/cpp/metadata/greeter_client.o delete mode 100755 examples/cpp/metadata/greeter_server delete mode 100644 examples/cpp/metadata/greeter_server.o delete mode 100644 examples/cpp/metadata/helloworld.grpc.pb.cc delete mode 100644 examples/cpp/metadata/helloworld.grpc.pb.h delete mode 100644 examples/cpp/metadata/helloworld.grpc.pb.o delete mode 100644 examples/cpp/metadata/helloworld.pb.cc delete mode 100644 examples/cpp/metadata/helloworld.pb.h delete mode 100644 examples/cpp/metadata/helloworld.pb.o diff --git a/examples/BUILD b/examples/BUILD index 0f18cfa9ba7..22f2f0a4f1a 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -51,3 +51,18 @@ cc_binary( defines = ["BAZEL_BUILD"], deps = [":helloworld", "//:grpc++"], ) + +cc_binary( + name = "metadata_client", + srcs = ["cpp/metadata/greeter_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [":helloworld", "//:grpc++"], +) + +cc_binary( + name = "metadata_server", + srcs = ["cpp/metadata/greeter_server.cc"], + defines = ["BAZEL_BUILD"], + deps = [":helloworld", "//:grpc++"], +) + diff --git a/examples/cpp/metadata/README.md b/examples/cpp/metadata/README.md index 7b33074ba1e..96ad3d19bdb 100644 --- a/examples/cpp/metadata/README.md +++ b/examples/cpp/metadata/README.md @@ -57,13 +57,10 @@ If things go smoothly, you will see in the client terminal: And in the server terminal: -"Header key: custom-bin , value: " +"Header key: custom-bin , value: 01234567" "Header key: custom-header , value: Custom Value" "Header key: user-agent , value: grpc-c++/1.16.0-dev grpc-c/6.0.0-dev (linux; chttp2; gao)" -Note that the value for custom-bin doesn't print nicely because it's a binary -value. You can indicate a binary value through appending "-bin" to the header key. - We did not add the user-agent metadata as a custom header. This shows how the gRPC framework adds some headers under the hood that may show up in the metadata map. diff --git a/examples/cpp/metadata/greeter_client b/examples/cpp/metadata/greeter_client deleted file mode 100755 index 929a51c3a5b426131d0573b2e5cd91da16f1ecf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267800 zcmdqK3tXJV)jz(upcswd1;sn@igzF(5;c_=S2vnO3_+~vs+ZZB=Wu*{os zzdHSJf{|9w&b=k+Te7cunsUTux$;9)x$;94zIhfZu+KbA``9*q=jwd#^DN}?W1ht2 zr|A8rD*oR0yQ;D&1asb+yy8{KDYOit`XVk7F zU;V}7_vRe>(1lgcU%d6Q3gk85OFHB5O&!(olfvmOEk698zUsV|jMTAXeOr(B&Fh%w z+a;?r_0rC9W7DPu_8#XOGcJAfxUr)HXQnUooi$@+QOjPVd@VlT4QKW2>&rURzsu;9 zhbvZ$&KcX{E7)f=s>y1bcHCLrS!enVoN->x;TbKyu{Y=V&Pw%_kLzCH+daeQD;<4S zj_?9De2w@v<9ju}OYr>`zTd{zeDtu91-=j9`w+el4`E=vQW_+JE06e$g8`0@!@cb>l&*S@ohV|;_OZxe;e!hz5 zYxw>S-{0f=I==k8sUE(!@O&HJeth4>_mB9#kM9TgI{1Ew?^b+2!gtzp_jad#5LmJN zgi8;)@VCzt)~(s{)M4LP{b~0hi>DoW>4C@o@R!vO9sBvRD}S7p``EyBbANWpaZ9h+ z^W~>dv|Jp!Gk#HvG_iTb{Zvbynoy@`BS|c=OY@t2eAX^v!*8A3M|k z>ek_BH*Sb5?^rW&w?}G!pa+V}o@PVD~0iiI5) zXJ@rs^oO!odD@-IDT@|VXx{>#7%Cm!

LvYO3=Q>NReJDEDZ5Vo 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%0D5LaD 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 z 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 bdM5cie7Cal3nk;9Y{^RhooGPxcIE#7vdv

metadata = context->client_metadata(); for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) { - std::cout << "Header key: " << iter->first << " , value: " << iter->second << std::endl; + std::cout << "Header key: " << iter->first << ", value: "; + // Check for binary value + size_t isbin = iter->first.find("-bin"); + if ((isbin != std::string::npos) && (isbin + 4 == iter->first.size())) { + std::cout << std::hex; + for (auto c : iter->second) { + std::cout << static_cast(c); + } + std::cout << std::dec; + } else { + std::cout << iter->second; + } + std::cout << std::endl; } context->AddInitialMetadata("custom-server-metadata", "initial metadata value"); diff --git a/examples/cpp/metadata/greeter_server.o b/examples/cpp/metadata/greeter_server.o deleted file mode 100644 index dc197b2d14cb36605b595aec47dfbde9cb1df81b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112144 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%0Ab0J=P1b&%@)Zc;B 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 diff --git a/examples/cpp/metadata/helloworld.grpc.pb.cc b/examples/cpp/metadata/helloworld.grpc.pb.cc deleted file mode 100644 index 4255687148b..00000000000 --- a/examples/cpp/metadata/helloworld.grpc.pb.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Generated by the gRPC C++ plugin. -// If you make any local change, they will be lost. -// source: helloworld.proto - -#include "helloworld.pb.h" -#include "helloworld.grpc.pb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace helloworld { - -static const char* Greeter_method_names[] = { - "/helloworld.Greeter/SayHello", -}; - -std::unique_ptr< Greeter::Stub> Greeter::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { - (void)options; - std::unique_ptr< Greeter::Stub> stub(new Greeter::Stub(channel)); - return stub; -} - -Greeter::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel) - : channel_(channel), rpcmethod_SayHello_(Greeter_method_names[0], ::grpc::internal::RpcMethod::NORMAL_RPC, channel) - {} - -::grpc::Status Greeter::Stub::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) { - return ::grpc::internal::BlockingUnaryCall(channel_.get(), rpcmethod_SayHello_, context, request, response); -} - -void Greeter::Stub::experimental_async::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function f) { - return ::grpc::internal::CallbackUnaryCall(stub_->channel_.get(), stub_->rpcmethod_SayHello_, context, request, response, std::move(f)); -} - -::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return ::grpc::internal::ClientAsyncResponseReaderFactory< ::helloworld::HelloReply>::Create(channel_.get(), cq, rpcmethod_SayHello_, context, request, true); -} - -::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return ::grpc::internal::ClientAsyncResponseReaderFactory< ::helloworld::HelloReply>::Create(channel_.get(), cq, rpcmethod_SayHello_, context, request, false); -} - -Greeter::Service::Service() { - AddMethod(new ::grpc::internal::RpcServiceMethod( - Greeter_method_names[0], - ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Greeter::Service, ::helloworld::HelloRequest, ::helloworld::HelloReply>( - std::mem_fn(&Greeter::Service::SayHello), this))); -} - -Greeter::Service::~Service() { -} - -::grpc::Status Greeter::Service::SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { - (void) context; - (void) request; - (void) response; - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); -} - - -} // namespace helloworld - diff --git a/examples/cpp/metadata/helloworld.grpc.pb.h b/examples/cpp/metadata/helloworld.grpc.pb.h deleted file mode 100644 index 73cc75e0a62..00000000000 --- a/examples/cpp/metadata/helloworld.grpc.pb.h +++ /dev/null @@ -1,197 +0,0 @@ -// Generated by the gRPC C++ plugin. -// If you make any local change, they will be lost. -// source: helloworld.proto -// Original file comments: -// 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_helloworld_2eproto__INCLUDED -#define GRPC_helloworld_2eproto__INCLUDED - -#include "helloworld.pb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace grpc { -class CompletionQueue; -class Channel; -class ServerCompletionQueue; -class ServerContext; -} // namespace grpc - -namespace helloworld { - -// The greeting service definition. -class Greeter final { - public: - static constexpr char const* service_full_name() { - return "helloworld.Greeter"; - } - class StubInterface { - public: - virtual ~StubInterface() {} - // Sends a greeting - virtual ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) = 0; - std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); - } - std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); - } - class experimental_async_interface { - public: - virtual ~experimental_async_interface() {} - // Sends a greeting - virtual void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) = 0; - }; - virtual class experimental_async_interface* experimental_async() { return nullptr; } - private: - virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; - }; - class Stub final : public StubInterface { - public: - Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel); - ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) override; - std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); - } - std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); - } - class experimental_async final : - public StubInterface::experimental_async_interface { - public: - void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) override; - private: - friend class Stub; - explicit experimental_async(Stub* stub): stub_(stub) { } - Stub* stub() { return stub_; } - Stub* stub_; - }; - class experimental_async_interface* experimental_async() override { return &async_stub_; } - - private: - std::shared_ptr< ::grpc::ChannelInterface> channel_; - class experimental_async async_stub_{this}; - ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; - ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; - const ::grpc::internal::RpcMethod rpcmethod_SayHello_; - }; - static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); - - class Service : public ::grpc::Service { - public: - Service(); - virtual ~Service(); - // Sends a greeting - virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response); - }; - template - class WithAsyncMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service *service) {} - public: - WithAsyncMethod_SayHello() { - ::grpc::Service::MarkMethodAsync(0); - } - ~WithAsyncMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - void RequestSayHello(::grpc::ServerContext* context, ::helloworld::HelloRequest* request, ::grpc::ServerAsyncResponseWriter< ::helloworld::HelloReply>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); - } - }; - typedef WithAsyncMethod_SayHello AsyncService; - template - class WithGenericMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service *service) {} - public: - WithGenericMethod_SayHello() { - ::grpc::Service::MarkMethodGeneric(0); - } - ~WithGenericMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - }; - template - class WithRawMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service *service) {} - public: - WithRawMethod_SayHello() { - ::grpc::Service::MarkMethodRaw(0); - } - ~WithRawMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - void RequestSayHello(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); - } - }; - template - class WithStreamedUnaryMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service *service) {} - public: - WithStreamedUnaryMethod_SayHello() { - ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::internal::StreamedUnaryHandler< ::helloworld::HelloRequest, ::helloworld::HelloReply>(std::bind(&WithStreamedUnaryMethod_SayHello::StreamedSayHello, this, std::placeholders::_1, std::placeholders::_2))); - } - ~WithStreamedUnaryMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable regular version of this method - ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - // replace default version of method with streamed unary - virtual ::grpc::Status StreamedSayHello(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::helloworld::HelloRequest,::helloworld::HelloReply>* server_unary_streamer) = 0; - }; - typedef WithStreamedUnaryMethod_SayHello StreamedUnaryService; - typedef Service SplitStreamedService; - typedef WithStreamedUnaryMethod_SayHello StreamedService; -}; - -} // namespace helloworld - - -#endif // GRPC_helloworld_2eproto__INCLUDED diff --git a/examples/cpp/metadata/helloworld.grpc.pb.o b/examples/cpp/metadata/helloworld.grpc.pb.o deleted file mode 100644 index 234283660c2185112bf5a40874899672b328aa80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 398496 zcmeFa3wTu36*hd5ArKWMUaF|Hjutg|fq*wa)F4C$4H&^FUPB-QL}L;|f_Oop0cDJ% zse@eKuL}K| z&g#RAs@O>8F=kR?VU-AiUpfBLN5#JZ_-GndUFM)2xcZ)o41$|lgSA_lm^i|=1 z2>K&@U&FUuu-8G~5dKZjxA6TjzCRJ{r$ReGe}?bR<@s&Uckq1|-(TSS9=@bgC+IJQ ze;@Q$!fylpweTMZ{ZMEZ=tubeMxMJtx8wU;e1C`U@A0LydqDpn{2xL8B>WDce+K;v zzJJBHSFpc<{vF?c;QO&){}lQ!(4E42G2}sC6y?C$t>&eBmzuohkfmBQD8)(Kw^dX?}EpbLa=1Z@(2q0p;A7YTn2=(WOM2YS8mi$QM?{zlLx z!Y>8=g7D3t%YHpbrWEbV*WvqJ!5#zsp74)@J|X;i(C_2B0pBMDdkXYv;hzD0R`};YpBKIj^abHJ z3VjiDlkhKrZpL>DzFP%*8T1u=e}M0+g8dNmN5a1b+AjR-Lf;VjrqH)Qe=Ph@Kz}NH z2k6g)|2gQ}!oMT*U7^1a`W|Sf@V^xLKIpH6-v;_?;Xe@iA!wKI9|`>pXt(g&L4Pa! z??8Vqd=Ka!g#RPxpM>85`e)()0{U0sdqMvu{NF+UA^gXn{}ldTpgV>4Fh!@aAO|#8 z_!#H_;qyQT3O@)mU-;dG?hd+#@Pk436n-zzA;K4c?k)U2LiYvTPx#LW-5>M-;fD%6 z5cDA74;DHM^s~Z$4)hS=b_?tj)7Jdb2O88rZ zwt(I$d>ZsN;cpk(3i?Ii?+|(?=t|*Nf!-zj-Jq+5zX$YQ;qMcAKj@c)|FY1pfUXh# z0no1s|25DDg?|Y2>%u<_x>opa2>mALw}gKL^xMLJN9d!V>xBO<=wrfvPw3-9pAfoU z==VW42>+zer$C<;{u!aqf<7nw^FrG|Ul4wy&=-Yn0)0vN%|f>b-3t1$@UMXWK=@aM z{!r+TKwlHSUFhqeZwUXU(6>N;Ec{P|{uH!B_@4>=xzM*k-x2;@p}zoqPxwyIUkd*| z=&yv|2KsB^KLGtu_%6_og#Qg_xA5CRe=Gd&Kz}cM59lB8{Ug4A5^M+PpN0Pm=wI>e z#rJQ5{T=il!ha0^3x6Bv?ZUST{i4u2gx)E1rO;JE z?-F{q(A7fk5qdA^eZt=l`X%AN4Ehz}*ML4C{8vH0Cj5h-4+;Nu(1(RzEA$&ezX|#+ z;U5wDZP4!s|ESP)px+h#F`?fBeO&k_gsunuzVI7_J_-7i@J|bU2J~6spA-5#Xq)ga z2;B(!qVSu9z682i_$@-Wg1#*LE1*9R{#Btr1pSfluL*4jeO>rBg#H-xC-{~pQonwR zoN9t<9b|c1Q{Gd=4OzeO(icgbNGFpWvLP4rMt0bqO)yKP1P1_K> ztHn!|e9TNiOUbsJjl`zFe(Z;&v?<{hpgTA~Z^}=od3%9m-!*;b&YjEKhOBB^*4DVM zD3kh0BDJOK0!X^|4nYe6y==61k{F^UF*2IOrGQ#rezBEIF!8(@iRSHbsM3{4HFYLZ z5;7o-~n=-z)yYLk_frV!HLWQ#=erufAZFS*p@ zL%9s~bKz7ZX!xZbdaBHE@b=sKy%n-Y6o=aM3DB0Pf{0k%wnnyji=DD$G@LCnWnGQC!RmC-1LDWlz_|v zduO&xKn0~OO&caYvp15P_$(z_n)+pFsvB*-H1(TA3N`VXZE}g!3yIX5up4UcM>et2 zbh7RFBE&OR=8lDAHEIB>Ya=b?6;7SZP7L)Dyua0S6g4mM(XS2P;dNIcg)mZ z5P$)BP&#fr)!b_#LztW`Kb}On%mfpuw^)b7d}X+!eL!`E27<(>k>4 zwP@FC(5_d*QopxJCer1~FMf`qJx^`B>p{5N zOJAhe{s+ei9?%;>mVnZSc>3@&F$Sh&u)qF`WBE(`sHO!CqiX8rRMw2DuANiURFxbx zudZ%hO>$IyLtSIt?54S+u1qdiP&qGIQB&QR966sN;WH^wGU@F2+{)^jWYze1;ezUG zlOy62P65|g*;qZNVov3P#tDR0G@e>mwCJR{<}+f%__#;Ql;Zdy1#!@M4fS)5r8rFs zj;%^IBE1F2&aSS7#C)>phbZ;+qpGj0uNgI`t|~b%Sv!i7fr7IeDjTk09p_cdtEsM! zA8|zduzAzVCdEY-udQp0SJzfIR#(BD4jB?q@uKB+L`Ai3K!H=&q-ErBMO3f9G9ZH?F!X&YN49K2rjr+z+@NO zPe}i(8_?1lp#Py{5h>NNr=E|xswy1eF=)#aZ>(#qtf}CZP8sfEe&}yCWF6S%$}8(? zkr#P$eCp~KRD6PlLBYLI^OH3-bywFl)KrZ;vmu#;@}p){UXviyTbP{FSl2Lqe8p6% z7a(&gs%sY{8yZc1)9T{Vzft9lO%1ils`%WxhImsgdJ-VC+65GJSIbpXokU%8Z1{kh z8nUA4-W4P3u7LIA^U2b)=0a+7u8JReO1!qIrl!7e*V||1f@^B$gw-;NEU2!9v!gm5 zIU`wHHP!gKLMiwNU+3AC3*gljG&UeS8*@%wEuNa@G_o%2R~AwO`DEoY?XIa2ZVzR{ zhkL*LB~uWm@XCPHe_k8w-!g>{IVIfhJXQwX=#%lPB!-4$A;mrF7*66Szkk@AoP<>yO_+Y_`0*G^su#>JoQ{-? z9wtXW;rPW@Lyh?K_$l$gU5p>kPGWkpzUG=sZI&Ur%lT7v$w)a>>e-ZR#J`!dQDc|$ zM{ye($>QiZpP;DG`s>@wO64tRtQtR_2Z6@^vp*SwnI9bWQBzkt4-R($27EMA^kAnd z{zLk48|z=QOL?CI(`wAhn|d%u?isS4C+REvod!o1Y)w#T>}fbHhc`rICXbDaRC!Nm z-+@A6!q1^7MXUpctS=s(u~slT^d`1&!n_FBQk+i@%(s;HBvNIp-e%T41Ykw1uDU zY`1HpmtPFp2#n{nfyfh#!;>&-8POby3$TaQc#z2s4=qh-22*?K(gKX}+Rk>g4`><6 z4OD znaNOzXcda27kAMvo^0bFsjimtZJbnB!X(uZPKw|{go9E2-KXx)1zSt`R@?9v3GHFP zB7=`Zm7SG$u6H@8+k;xX468^V79~)Re%qn)+M2ZM?I1MiriGT?+Tuwy1RB`*E!-o` z>b@t@!rO01tt>y%4s8GCj!d!8pJfG(*3LR0meo^oMx(Ut$w!Lw{gP9yqUNyqNE=}$ zcktNC8n|c1x;cNAuzx-Zg_Z&@#IFEPA+M z&<5(M-KUr+vdJjO5ZER(w$r3?jrQzs!N7IL1=sLuYT0reM z(XuC{=kHzO0I3lAB}`@PtRK3wzF=p4{>~!mT5r&9s&p^g8%!!(BWANiHX>l2yf~+X z#HJ!2a=NB>x^0hK1-dgC7-3*wG9`7H-NGIs9IniUOPB3tVun&F;A*0gA%DpFwnR?5 zNz3lB4Mo8_P}S|FEr(|oeio}d6p6OmHZ>*nlKY75GCX#arat0bvn@N{q(@k0C~sV4 zwlU*g(1gX4vG<^H&$y3>^*gyXs3oBlQYhHWWQo2|V8=e&_tVVt0220Knn z%PaS4?KojAMx}7ZM7Ef-scu_=Jv&&7X1)f2)(lziEo&RHY%@23k~KISh@;$XnKKoF zoI{=z_CygGIl@}jy`!h4aqN+%4RXJ1lsH`;2aJ7e3Ccl)Z*D8_aXw5y>};aVNc;n2 z3eC;&h@Y09?ne(&Mq5g{P#E+q=*Pahq-#iXf+UP2;6PBf*pSa5_mg;`GuMzuEIX-{hYp`{F`tpuX#|xea^wKTP zf*j*?mnND^x^h1H`agH>gr*2-nqT+v<|x5$gYNW>n{!~_(3!$oj7oGqhEDyN5_IPF zoV=e5^u9GPuV5hBDHxZToDGjz~wmlV3yK?(_ddd-#xZxxW^9GFPPNO z@u23SQdB#giS)2sblq0x_z-X_Vy#Z3aD+D_ACKrwbc8kuy3ZJj(8$)h%tZXtWH1Rn ze@3B`LlK_GhH~J(^3Q*9U-A8Ua}OHZkY!t`xGj+hDb4OmX+oqp=WxlNJb;a6rZTB5 z6EP9%#{j#QF0zNd{^%7XsuY@69KqqB%tV59>*nGCp5Mwt(oED}=>@&Jho=>|5&|_c zR^=G43EYf55+r2TtuxW#p?=f4RQV$iZy+&KFNa7=`6H>a0jQ{cPgCj4Go8Ryf$}y) zT<5kkt_Ng-O&XpQ*ftd;`pJ%0eK$Dd?7RnZyt#SsXX}F<3|K=h$)GS)3SQHf4U0re4SroG)k;nkvbY7{koG3NrEC}ok{#ZiW6NN@ zpUhEh8Jb2%=ljiVW#qef)i9;NE*mICvEARZJ6 zo~g5Tm~P&c;-1<8dle>HE(I-F6CMWEm=aE!iLq`LBCazd#iaRouBU|1$P2A$X!gNZ za(K&xQk^MzB6VozHgeBd;IXBN_^) z#~%99E{vY*ocgdW2CZa95mISG3)+hL*;qUmx1#nF!4;z{)-L8<@@4lM)1e*P{;+E% zALyIB7!{P=)uy=<^h(!&{=B12&v7obxnD`o)QtPCBkR>n3wCERXkzSfWHfSp28lRn z)0tcmwqB?u(h1Dc?VVJZ)U!jebDKy#Q9z_+IX}r^!m^KeN-r4sz~ylc>?CO;6jC$Z zH%MSCo^cw{joRfP7|x3@Z(Z5OM?O4`^VHke@T0GjF6olztx?TkkFO4=j^=4qDWd&P z^N=pX03XsK2vsgaoOMN_%PO~}E z<*l$xF`Bv~X9hz{bn||s;$>>gThjtH2(0zNdC0+2F z+Q!4iYjz=S9_5O$JA#E$kMu@=znsmyv%Yv|{n(xLMLX-!31!dR*R+^*I$ED|rA-T) zGBoJaruO7a%x`4Il-<>I+0wC5cPu!_^9@y+`c?Pg{ar_tdz#XQZRhQF9P$PYk zj{9vQ=8&Cs1Ts%Lq($@DH&jO+krh+K7I44$aQf%(k{YzDu`6l}rH(~vpf2b@Jlq={ zt8zVxwKFW7p=q?NW4ZTEMF$G66m9K&^1RLc2Wm83yy(VU_BkkzqKHrOb%Goh;tw~? z*Z6hzD40l~>``6WAT8*$)C>7)!e$h`^GQyCF2R3@vpnvZNSP*HG#L{=%RfSJ0Cx+v zc~gOPjC&mdJ!PP_wuxK@Iw+*2PafavDH(WyabT7NadYryn zc*G~!**fYf!&~{1T~65@Y0PZ0m0R$$^UZ8>mYGeOr;KL3+@Ppm!}*&+_L1+#SSjt* z*pAV%oYR#@uF{P-{iqRQrgV@0S+;A@qjj0-=z5NoT!hVOQe_A zqpZ)-q{-2fiYbR^atOtIx`Gujr zKgx*BsY&5KxgT|B1mqJkbu&F)PA7WV3z0K1OTgR6p>T|r;v$+x%LR?Hv2sBpT{bR@ zxVYHAc`=rj6Lt%6#MT7=@(_**cP+&=6f|C zjpUL9=?y4VyG&y#dZ!FNx`4ym-OzePx#Y(XO7S1a;=30 zmYGO4x4~L8!^G+;2t`+bs5He1HpN2S6c_8J2<4Y){_-x)v8%VdE3WiQ9?Ck_QuakXql%fwsPA=K8STEeXEQP~QRTFdCP4>YYS$-la zKYgVh%D&TRQz@pwlUKHHbVEF z2tT4^TlYikyRA)ReUY%c@zgy=;Ae{M!FkA73>Y04+}l&-ucoGMMRs_y9!t7DLDcX& zS`da87vQ$0%IMNb2e#+LrI&PUE{;>TYqu$&AiCiuW-(lr-J(tk*5dJA;d9{Oi1|(t znT6c~atoHmnMxCF~AEo|rn5HN3-{8Ew`bU{tHAmEysP)wt((y>9CnWVfg@>S#e! zZm1pXI=O9Nx&_nH1~Zj)$g-Qb0_fMKP57Qsm}oh_D3O|&NTkk14?ANlo{RB36VJ0K zo-_hVF=2f#JNISZwIf1D$V{&FsDoPhBbUl^rX}%DQWa zq3bFrEL0qF2L8~DF?vuMXD{kKMa#rQ^Wx5-i6N7)U&*`HQ`eXV6rBE|Br{Nwl6A;< z19lrx65hY|wW8639?IAscAzif0Hhr4j{Kn?iu@rx%^Be&){lGK>Sh`)4l#1IZpDwYRb80$skd z3hEM#L+X-_@u)6OF4@+HgS;+lX(O|WnWoOz3AO|qNSJP$7E0Or?J255Vq80|ec?e{ zn(#d%fo55TW?6`4S%l}Ac%Fr4lJi1=y5)4l<{{M{90F`>^(k^b*<= zr0IaW55VougiIB5j|?uBF_Z=ZQO45AqJ1}SPA$b?(jL9pBRU$exUMx!aVRq*1c`ig% zc~^V4N`iZi0x%OfEE8bJIpug;W=`HmGJQkj-Dc!1^3o#DpO|+ZzkP{PMUn11Jm;XJ zCgDY9IcIE%<-D1TO{zb|O7IG}%>#@UMhS#I>I*q}4-E32&e=OX2-ik7L#4)duPT7o$s0GF?J#G@E(*E3<#_$C@h^kcK5vWqyRIGEY!t4C7feCezrP zz^;aUO%~l(l#WC5G7c1aJ+M(*(0;EhMwT32}f5msA0lq4KZ{_kS;n-?J5k;oS{lkV=zj*wYz(3)UOIDs+90_x%+@(W*<1iNN*ah5hJFsb){J>|Dvzn5lh zqf&0PM|&?IOP`kpO_zdJP%hRosqz(x)YK)VspX5Xm0g-j(@{rh3!iu-TAn2k-ERpj zxB_KhD^5+lFeQbeiebozWK6}7^5!$wkfEqcH<3Ql25hZufFajm!+$Mw<2PHCrl#6j zgoE&_th8n7YMdXUCa122itC`_22}KGupCw0pc31jsI`}_bk-k0I@%| zT%?$5a%$^}<&A72T8-HKS>(J1T0vpoaI5*=J@lj^(e40W--N!j*F0>ncAAd2|Hl8xMXIwEZ5yvi-!F1r8z9y)_xnH=NNXP?c?r44mQx%>lc)Gu`H4 z{4Ij|EsbN!j83kv+X)`_SNa-`$WPGX+V^o;=Y@{WO=Q)Mu&T1UBkc=}D(tlpGFT2$ z*?4cMtgtVAL>*->$m-F79@vhYK&7Aa8rFHly#wriatQpm2VUKVqs>@19@I*6RYP0f zp3B;rj^M4>$Y_I#@*64Y#cT%KZcB5%&QJ;LD>te1<`OsBnx74VXP)*Dgt;slrBT># zrUkZ9(M%U_oufOGCP;H{4z4vqnW-F^J36WXeG`L`y(EKJgR{pvAc!^8jpdB^`Jueg zpFNwmor(BfzPQjIAyEcwIdQ$0k(ba*9)$dKHY(yA{oj!|b2E6{iDgdrMC={fN;B$QM0;vTP&YNf|G?R--!$iv(;`gd0? z(ReiUv;LR`c;?hC@j@?tc_#Bjbf*HXms*aIM^pZNmH6u;@CYV{-2?N-)vW_~yk@*iDzDXH@sVA0x-YZ?m5$P<51 z_=P}IQ+lA&3us8@m(lK%7y)5V9F4+bW(G-ZgSeEW!K zsEClQFOvS1p$!_Bv_OnSdB!&E{by1domOZX4Z>1#JKwa*hP~5&+T(_1H9?7NhvCBK z`x-j+VlAJo&Nv+@a)uv|<|pC)&Gh=y$T>KP^=vQwygv0r50h10OwyeoSjcrSNw*W&vfP9;)v#qbHb?0{@OfL74**B=j4jLa z!GXaGA(qoGM3_ylqL7L7a*uwS9JEU$$a%sKnY$>7^s{jUDV2~dtVE*4sMNv=V(Ek5 zLvT9M8stYNEvrb?L^{pF<`)Vb2VgZ%uZoi*jt2G@Dz;^XN+=h?_!lT2{f3rGEz8L) zwlY!}%nXoTv6jj#n(=O``c>-LE;i;9olI7B zFiE$Azz1z*l5Qgqt(*zDjAEW?uQGAWMez>ICpx@7ezI^fH&3$y4z6uGiK1-i$j|mr zo-`?GVJ*`&aA&p`W%>In%PFq4=TmKLyU-R3L3U0;GlD&X89@itJtinLpA4ll z1#Tg2t|zxNVca*ppfvsMS?DHx?e>IHd1^^i8-iSI=tY87bH*)H)Y7jWrmY%hl@6TBe}ex)f>|)-103;1}fh7PX<>4BgO6H&GAe ztvml;5b(wwmW-H<+FfFTLNk}h8D&U{s5F61`1+aW!qBr6|C7yY{Fz_2{PI72`s76y zVNSmqE6-M}Z&#$Ynwum5qyhLj10vVB8dZ&;v?!Viz64nLP+S}-)bCa`4jGOzJGR#5WjKEvD=%Fs~8v~WQJ(3&o|MMMh?x>^!i zo6$N$ZdcW@b|>I3l;j@4jOqZx3!ExK74VZhm*Kf~?Tv{e;cd$a?cdEZ9|Z-ml*eQIhO{>jD$97U`PCramB z>uet6^+St)dhudgAf>$kq~$oCl8&jVKTJ(!?gY?C*1ReFpG2r+XjA@O?Us^Pu{YT` z27hiGi1Vhsy035U&22orxi{8$Nq0T6g8D&L^26a&Zg+WDL?v*n6ze_#O|qTC$iANM z?Py=Gdw(lB*H4~o$d~v6L;jb{UTk}T&S*`=_WGaffYGeU^@zr+$y>xi_J-%+Mu7QB zyNB}vx=0){8y#?>rrqOfe-cjSMZJf@m$Y|(FM>P(%hOg@m)k&Tu4XQ(`-QRVcfLQ+ zLo=Xp8?j04_r5r9V(=u-X#gb{Ui_-`SJcI}NpTTP{+&)hZVZw4vUWnt9w(GN+YW{r zm>c^c?%Od6kP}c;gfvTMJJK)FF2;$xkLTatjmCHta#|q;!}}&7krs(d7`)udzP!Z1 z=9dzEWa*5aREw|`d?@Yp`uo;o*e(oBfc-^lW`b-^n35It>pU}5s5o3w>pjr`{gbG` zi_lN*Xz8)}`Fyx>GYN&`*~8hxq+x&#yd1v{{du#!z-Z&&503V)kjEmo6l6W(MLK4p z9)y;D2OY=IPfr40>W0lctb)pEn!AzezAdQJ}wFR|R$5m#ub=!?UGe(p4`z`7rlAfJ+aynE@+b^OaDG2YlS>y0? zq2J<+d~C*ZamKT|q@(m^`SOs?usd}RsNc%V%iwVxO+@K&%MzZs;4v^t5%*^60=Y-~ z+MYZNF7g=wSE|MB14%UKp1Tc#CNI9H|aE9fr=gn3} zP7eBz$2R%&^^>q=k@V*K&szQX6=JH3Dn;t24J>_v`uXIoO3AgXp7Y==%N9v~OE@<_ zzrb-**G|tYMliT~Tz`}5N?~7FkUVZ>!9D^FhxU$JkdARALF38vxtpJ--&30L755^S zzf2b)Vu_X+$kHr?oMe5s$c{&vqivS*!bWLL_DT~vm#mMXOPh7JROYSm8-hn#ytLUz zGh%HG9$|x~c7(us=A)_fFHD1TQ5sEY0!#lEv5)qtw@D-Uzh}QlbLyj|ao?0-D{cmT za`@Kn^uJ27PO~F3x>$d2ljOCRUn6}aV6zlcNNY3hjrhOE1vRcqj)ybcxeWv^MQOt~peOS;DxmD6<+L5+` zH7$M?gz8=ChFO^ zoPn3M<621S@76d&)|Y%}b|mP<^z9aIwbuoMzU6M}QBwW%H8E|-Pfffa*hovDWE)Vo z>o7ZC8@|(vYqC-lvvamOc%+@PHNhhdK8S3~8QOIt>(H(n?N(jjY^Md+60twUA=1eX z*%_Z$@hL_kbKCZ-?ZZ$$-K0_%CadLY^6b3gxFoq zn!FP}zJve6Kqp>%x&lK^x*R7tG!prp9(R#CbNGe)-9JR@jkHm#wJ)=MUw*ET(bt`R z(N|~Uq0x9onAd zG(MxcZQ00C8)uCjnM1=e-;amfi1WJ?-5R>Y)@}jUu4Cs<(VoIq_FqpZ_r>}Bic((W z=kzwerUI`+M(seOYv*mv@b>*y-)tD$cza`derfs`_y}~xmVKJv&q*wQgN#Uz)AQ+- z$-L7Ff^+Py90urRoa9G&Q*510u~cpcO1+e}#1W{?N=-7DBKP3tUuo)h!2SQe6m0gZ zmJLem%oMp*$*#+Y;LR>nD|U9$Z~qDsrbg6n`bbW%oJ?*?nAKQ<^D+PN4glHCh*C%GzHG*X(E(Q%kq^ z()gZwmM&7^QWoEwO0DYUBknZcEWoWPJn@^O`3ja*JXP{eOUXNURYP;{0Yh#+1jmE) zhin z9;Vag$bb1*luq7l=g(#n=~Vkz7VHo{1mp9?~+6Vj*Up#XLt5%eeQ?r^| zBbXw8R8Qt9e<#uM1ZRdzImkNoI%b^(u)cK)#u|}V^71W&iOb{n5DTQp) z&lLbPk4P?4Q`<8$qIc?Il)~NSP=@YZ0;#2?o2ZSuzXl3Bl<<=siJcK4;qaMbuj{^o zxl6_l7{x~$H?v_3y#O^`!#l4lYFw2E94DHhtSL^bHBpz zZshDbZ51cRy@;8jyQAY9lt+Td`$R7#e-}iT)^Bc_`*3OMeO@(~yUVl>W!~{=ogc=A z&`byRwTRtk4>@F>Uj#)6&bP9T9d^cx2=*L_wZ@2S9X{=pKwB(q0u}v}BU9$MUyb~m zsBjAXmN$+T8#IZ+a9YkBJVnzZDC+pHObbVp3=JA)Uf1ImjT%Fcpx;hx8_JBqvkPk1 z{e>j?f7d5uiRdnC=1#Iyf25pjFzd$2c!uBg;`XD*|FwMo)3wo0IWn&i^aMP9sHr;X z%!XvLG1+j^jAX;Y>N&}hGo~Fsuc3a-B?{&Gd0;*SykCs zS;D0{DUeT1E?7`GFUh!#H$6FLVPEk`F7c*>tUo$zF4kqV$!k(gb+Wc`MzXeQQcc|g z$#0A+qg17q6iWxT$SD8l6Q|eDK@sQIRV6BGt7?)BVZ9=)V%m%`nf1+3SpOiuOfFRF zNa~rPqt996A3vk9X?FHDmYISnKkAFEI&r}@wR5H?7u46)E=W#KR#s(}KcikUQ!~$> zsvTz}8R-Z8$TP%VM*U{A@6pnJKT$i>+8Q;|vD6Ny)tys6rL_7u^z&&mPO1QVe88R% zuqT4;tATzhJND-f5@Ac_&JRD^r@rlH`#JT-zWO=IL;j(!zAQfHKk7TQI_t~)YywmM zFtY*Z%o5-DrCp7G z;=H=Lc{Rzg^`yY;rnzIP>qd{eDA`aqsjmK-DYf-YjWZe>l9gBXksfXIXdltZ+3SlC`=5|4~1XQIP)pYesOXPk&OB zDULjw^7`|O(Z_`bSG~+Oq0IQ~V9f+&SDJUG{~tXzqoU5MoChUjHAWi|SXs&OG_A7C zRupy(+=E$y3(aOiCOkGfT$~-gFgrXe8{E<=H>a=xfqgM~Sxg?;iT2F$f>(iJ4=uHU zV7fPqjadE-g>2tsUSP0iFZBOy=^YEaLxMut`x|5e{De#up}blwlvxv@+?ohw&mxMH zmVae~V%zJ{wBJni#b<8(8wD(kxmIP9Ezz=MEo>6(eHHk1&9|1Z>sSvHl;B_06b~hu zXjw$tkD#~#W?szz9yxN=_eNfjWzVVX-VbS$`HOI8mn5=o&$g!$Uh!w9_KEj8$R70j z@&r0PjxsjzZ>FDE$G^`G9a&&Un^E^FLuz>;?N_G_k-X`p*y-i#=v+X4O&;7;hoF@Y z3}m}U!bwbQ&|i*hj1KrAq2!pNx8RB{xHVvt!0(gN%ZoUF{0=eLaYL>KH9EKg6Wr=4 z$)hguCiAg}jU` z6hdWViwBmRl%OA&rB|`N(`i<<`2}o+2AR^^+iVR4JD|=>$K3qW>)MU_QnQ?3`Ybd@ z96VarAf<(^RvFs_$=VX4l}Y6zq7=pPq!#fTNFVJ5(ao8g3EYi~!E~hI)`~sma8t1u z7eth?n46w^9I|v1b&zboaa+2$hqlui53#>?o5yB~{Mya>9>*7;*%k4%oF+eVL-xoC zc#h4*MYtUR49gtI$kC0n^$!P04SF#(`9i1i z47`Z79hU%$4ydvs`JtTnIXv-ipvdL0G9)GdRep zgZ!gsBQb+yv>;~mw2hU+t|&xJ`=z6cj8u5r_}RIe5-#0ne)8!T@}qlvRoHBupTKPC z)+Hu##MaGSaD38JjDl-yHe~)j6bx5E&^F`#2uQy>;xzdh+Ahs@B!*kH|270;w(za& zU7Fgkfx=UpKHCx|Fl3%ilrU0<+T4ah^UYZFz`%!cBA*)mgmW1xuB|hFE>m3ZpH_aV zTJ*bimO3x?4d!;CvP5=xem1y;XJU}-QpL8Rr2oBhR+L+7LnwO|(I>2DDt)A$m(ZMF z=B#wqIv-tjH5MqXu<2@^nc_c#Ec+E1&ioj?!1@SsiE9krYTW+yCJw!tfq(Ap2jw5f zg|3%kQdhEu-}e|aerKwXqLb9t6>xtgNSnxNJU9U|bLhrh4E$z3s%7_Q9RWP~P;+yY zZd|q6;9H9GQ4YMApANU_WxTex7r_{4w@sb6`qhCLU1E?%{`Wz22P=IRjiMd9^l#W{ zC56D*{*gDQ9hwW9n|AbO73Y7ZMtdSTWxGNNT(^vUyLN}IJ*d#&=3#rH1#bgOhkuZs zcHc(#5~OW5DjlJxogYzB{o%qKEaTjw&2~f0EEvo`h2H>6uS1*-Xzc5pA-(mZ+sSfv zXxhbpw}^C}qpb%gp06%+_5Xij7s7bmsA+mPpC3YIa2dheIUL^;=6@n@TT20tb~MUa zRf%_2WK{WCR%~Pa@X-~T`3aM(%Q1-Y572n&O=)de(ni|jWBYaH1>aBki!-y%m65>i zTu{!u3NBj|y8D3{GDK+ z`JfOw#JOkQe8X~;b@69~ ziI!EYHI}rjd?4@_(2775fotR?kGqt?Wv|am8Bn5(_~xZNbfeD7a0M)qHz7}9Wqspw z^v7@PEz8-sxMLTNVI1@|$du*S5TVz_fTUNI(fYh4&A80ZENT{S8D_SxpUX5SDHmD%>K_;@!XF831=rpHNotQf=peA zlK;qQ8qo@q6|pUCdaJnLrUg0<6$LgHG2uRXgq5YmuG=i_A~w|GgI{!*)v;^1?!)_Y zqBcp_z7}(fV=-6DkniO_g?~~@eb$cG(Obi~tDX2S`|ZpBoQ>@j|8q7pZllk+o#B7Z z#vNY&JDp9|35Gr8u>Zgy>n}|HchUcU7ybW#c+sEyTpyo|^H+P}BirSStf^$g&$xeM zll#Q?N8~<-xqU~m<-S+u9UOD<<^;NfV=mq>+uy|-rz9Erf6@y>PDyK&K}*b1v1Ou$A!(TCC!L$+qZjR%kH4WKh1dob|uUqQh2BNQ=J+7e`t64 zKXRZD*>vdp7DO8=-0nR2CkJ*%IcsCc0%o)i+rJ`?H%nB8W;7l*x?*bOHM5fyO|`h} zR8iMZF}s?%xlOfm=)%+#lZU-neO6i4J8k}zBXgZP%f;)+MO=ggwu?7$&zv-Ae7taS za&~oPZTzH>$BisH_Jk3Jp@Qru1u41)Y~ zU*H6W5r$9BwPmGTbA#@q$AfMC4aWn0>GM^52M}Y+aOSPC<^j2PQ9_i?0NSy}=UDn< z!^{u#94_*`T=|qhKDi%xmB{h`aD()xoA_}+uM&>WiTH-}yei0Jt)!vV^;VJ7?|}U> zGzRgzM1F=V&z;Bt$WCQq>xJM$I+QfWa%+Ngim**ep91=0ZFP1aFB7?D%ldxgts-Zi zXwxqX(qGq4{C1I_;ObW&#P1RL-mbhfkQZ>_^*&uB^6$Ixb06abs4bO={A5?Y(4-#+ zwn6G)BKVMe*PbeT=Q?kcBhDDT=vWF^!*7Uf0+XL_SwYg z#{pd;^8ILRwQ_1}yXW{iERispjn{}=)3HtDg~-Cs!x;-YMShzr&rSLHdwY-oeuDm3 z9i8}bk$>KmU&hhBIIv=ouXN?)TW&F7sGU?v7_FTx6ZuRxja)O4JqFlzsi)6p`ku3B z9v3@3cVzs=kzVedlq2Q$mZUeaS<&km7m?P|Zl6j7f894~TSJ6M~Y6QqBh$Tk1a zC~|FGuu|mOnDw~GFCisu{<&sh!sQpa<|B8AJe!ZC`1|ci347jU^v6%%I4F`IFLG_J zd7j9Rb>lnp=|+)j`L7iDQEq%^-SW7|v$g3s;tZ4W(Y4o*f6Tp>D~Za`+lLO6#wEGalP!9sjJsvpf_&~y(*rOJ3R9FQqYz zC$*ke@7jXKueoNfL}7|0%#Yo+OJRNxjB!;GM)SAJM6R{32SuJuPb$Zze&TQIC;k9d z4F7x&Y58?3?T^wQE^>Xo4)v4D#!I= z%jdy|%0V`NBGBU!NvGURC)aFd#3>z-U+&5&4QKsk>+QP;6Upo0pucaGv_fMxr6p@4 z%5Qr=VaWCcJZZ^ZcA6tD65Ab=>3`0?EtVc|YhLp}GrOgBF|P2 zWan*?*F)eVWxp>-XHy?KlOEedel&Pr4`-b+fG5|Umu(GA@rR2%+j@-TlSO`*o4&J; zQYCV2J-JNe+4>fx|Debxxam9XeUr#F{kHWZAHbU*o~OkhE^@7WlSQuCw@T#M%1`zD zs?^US@R53U_G%vKL(e$k?kDA>_7qB|GH5G3lEwuH|W@PM#gEmPkpeEE7J2$0`J$C znO3r`6Cxk)%AGyi`6Acqaz#J#wf)Gq_8}*m6p3x`1s|zvr_B|x@jWlw*h}dwl60D~ zrE^8lc4taDJXG4cmN`$H(h>Qi;C*{i{X7(;aleGo#*b%2uI;0}Bl7FqJaVb_&D`o^ zkyE*R9V&wShf&4jldTLSnjmsbzf1a&UoUb^|NBKgmXxqIboMcx5jj`Al{@Ey?}+>a zH@>sy`*A<F^Q?h}`YoXu?Y6F*AvukS-1hkTpVPZ{`7o6R)` zPLxKQq@nezPLXS4tH;LI_j=#pC$5aZG_t0R;h#Yu*M3Nk>|v* z1g*3v$XZE9tLv@($h$ON$S(o!ms9qf;(!t&Ki8F0e>TTX z+#YHqjMg4+6}eW%M?^lw%_DcR-=ALa=;LCM8EzH1=4&1i z`Dt!^)EP}Ps0^=){61Iiugh{Z^@VnTq*fK(F^% z{m7T}A&(>dH6p(Yyl-#P^;V-R>99${aItKiIP0%%B0t7WV_pz{02LUYbLfwa@0>vo z7rEw_Cif$+>PNn;ANhkK*X9A6M6Qjq+xkg=055#?aelbSPj&5cO<=#tBG>Y-61nF0 zmx)~K+YgF7oBiX^X_LsOy82NYnH1>QC1H3vVCz`UbSaH|&fN1}&P>A`hjRZuM#6AX zHVxUU;r=i3Nf~L7skr}({5V(ctZ#1>dA9x^N1R7Qex4hj%IWx!b_v78>gcY2MV`%; zq+`L6l(^m&ibS4GM~Yu2^3a}Et~tCRd3`_eTSY#dl(70cXU^;TiQnE&{GNW|7tp|m zkJgrpM6TJdOyt@)S18*ORpjeQ3BUZ`<%Uf1bt2dLV!OyS{d+{tTWdD`X+b|J zV8!(LaFNJ)Dq`b1cNfY;u9jcqTKjAjxmtda*N5z57M^6Ec9ADsIr<1)TZ{wi5%~of za%p1R&-dfSg6CyhGmtAiUgRk^4ZCM>U0};gB%Ib(uJ1!0N80y`yf0nbB#c(yog&ZX z_sCuzZ`ygDHa5mZu9cx!Z-k!yBNh&iul6I~ zE^@7n4Cczw+rTj*A5TWI<(EA^YO5>7zTW^JsskFMzY^4SV?X(<6!~6mKC%itgxpxP7b@r2&S;**Rj`KptGutG#%#Ob=7P;F0MV@WVLUp!8 z}xi>^gGV+F;sB9eH4rQL<(ff=iCvTCGu?cC7-cGpj>toMg2hl;0!!Fh8>G<+ek&kfGaPE85h+LcB z-74}>eK}_-kBD4bJHFaa{@eSBKbR-qo_DsZf39(YRL{qVoTu8h{Bwi;QY!LLdw0$! zYDB&*l>U310HuGc$p09U|JIj3BJ$6;^0FZRS4Do2E6+6tf|UMtk@J+u>hJ7N4`#!A zo~HjXBF|=j>MtwBzD2Q&{zB&ypQn=ovrpbA=}d6-bndgP6#2QXTpA*k<8hI{7Lvc> zr~j77uf>|tZ||`tUMy1l9U^}{6#rE}{(j?0;Cb)UA8V)FcYXQsBHzcA%h@)if1b#- zdTtcCR?jO%o~@qaNdIw>)4c^>KlIgDELabBNSIax@xz!S03PpqMV_rMQ(X={nId}L z!}Q16Aefi%3WLI}5L<2nKfn!3zT+u28Rs`&(!0qGBZp07vlSxO_O;fET-$frD)NKf z^qsTjE|Cv$<<7oo{sa=}cR&mKkth0*&lmZ=l!>*cv+uT|ANksTJ)Y7XO{#gGCRE?}db^9t#Aw@kR=6?PBq1 zg2yw`p*#GPPGLqmcL*-q1PEh34+_ry0+7YOFF4gReJuX6;4)?Q%bN#(Lix(n!^bIZ z%sT|JqMw*|sDdA+;Pw~#;k07j5lZ+YBY3gs`M4xu?Y~6u4T9V9eoOEtGw`1Y{!|8@ ziv-CIPiNqx1%D<3r^lE#BBH0kk5cfX75o?lKUTr1bwxih^Q)MMAm)u$!XKyLCn)%d z3VxD;k5llI6?}q%pQ7NWDR{AhPgL+p3SOe%XDT@T1B>V<=AEVBXDfKAf|K`%eq!D^ z3VyDF&roo>=&rh;Fn;1?A8O{3-=spx{jkzEHuhR`5j%evN`(tKiow_+kaW zLBVfS@TCggtl-NP{ALATq2MV6zeT}Y6g;iqw=4J;75q*GU#Z}$6#Q-lU#;NxDENH} z{v`$fih@6&;QST}>A?Ysd0$h))2uA|iFpqx_}3NuVFh2S;NMX2Zz=e<75q^J|E_|6 zPr;v1aGIS)KQZq~1%Fz>pH*=F-v*HkVqTjPexriFsNgRt_!b4m@#qSY3o{`RLg4>mc4ZjB#V!Y1E2!Fodb|!Aa zKOlHfMtCw-%=>|$#&-5^%=@8&zoy`?EBKoV{$mCIse*SX_|FymZ3TZwT@uc27y(Z|*!@iDI}65imyQSfdB|E+@mPQiN={ErI0L&5*7;D1%{ zzbW`X6#SnG{x1cGNwa)nUao@2B6xf^(;t_hztYF<8xbG#Xm=v|iFtz*d^ZK(UBUNI z@I4iLh=T7O!RK?i0vyfK|HQm~BjHIH^Y&Bl{T1A{azANiuz#q8AEw}+Q}DQgAEw~L z75s1oKT^R*DELtdevE>TRB$>0i+*C>7zICG!B151lN5ZMf}gD5rzrSo3O-T6CnlJ*1f&pL#?1Z_Il=5}pJx?+pciQ^DU-@SiAnhl2lH!QWBvcNP2>3jUsg|5Cx< zSMY5L{(*vjsNf$d_-_<^yMq5t!Fv?^j|#p+!T+M*y$b$!1^-yV|E1ue<*?s!V_uHC zOm^^?g6AptAO+t|!FN~i!3w^Yg4?%(`>Hb&^Y&4~@2lXSQSkj0e5isSsNe@H_%H?k zoPx&{{4fO{uHZ)~c%g!iQ1GJ^{1^p4R>4OpIGw^rKQZq(1wTQ-Pg3x43VyPJpQ7NW zDfmPMpQPX=3Vx=7Pf_r*6}(izrz-d~1-Eb057$l1o34aEPr=Vu@R;42iIPG_Q@nAf7g5Rg$_bd3975pm-{(ypi zO~D^h@P`%r8w&nS1%E`rzoX!fD)@I5{Cf)ixPm{S;OiCq`wIS~fGU)DiFun9e2ao_Rq$67{8a`2p@RQN!P^!5bp?M@!QWEwpD6fG75rxk z{&NL?TfyH|@Lwo+r-Hw);M)}Z0|oC=@ZTu-b_M^Pg7+x+9~FFug8xOqdlmfe3jVQz z)2)E$2a7?R=0`s`r&I6&3O-Q5^A&t|1s|;7dntHDKf_(%mGrQo9#e2ju0uiz&r_(=*r zR>8+B_{j=>ih|Rvo9HLz6)X5e1)rqglNJ071wT{4rzrSY3SO$*?Fm67lyht>g*pT;I-q-2#j;O+cOXK!8Y1ajFX21oqQnKE@Qso1?@9Ps z5`Jzd{K821X?P(3>C-9qOlm^m7e&I8IOfr7pi?rH{D?F$4y7_aw=>RvLXvMV#BTrz;m97cXB;)+1 zjgagD#z%%QdZ=TZ-)s?*H8XC1l^Te?&A7Z6C4jxHjLXXr9Q<#LpXMNjJ&a9%dIUd* z@iQX$V#d#k;NM|;(gYkKh@cH}_j`aoAH|?_}z@Jh~QfpPet(e7{4WgSFr18iQo@2{>2F1$@m=+{Im4p z1Mi*)o@D&K2>uM?_eb#E`3IF>ir`l={^bbX&iGd&_}>`+dIT>$kf5~@d@bXTMDR%m z5%gFD|A6uDMese?Wj`LlA7}i92);YJ@|Pm`7Z~3h!M8KMC4!&-S%O}V;5RV-;|Si) z_)jDF9~ke5;0J$>pr1wX$&CLzf~OdNJA&8q3nJc$;01Alei6aPGyYx#|1;yijNqs9 zQ1^ZWA8{B#zlz|mGrlc?pZ9r!K8WD&F}^*5&lyh8jtIVi@xMgy6AmZnZxQ@f#y^hW z1CAi*pAq~*#{Ji0`0`&dPH*oGe@;A-o<9@8XEDBi1iyvx10wiUg_O=`BlvTSe=dSQ zG=jqOe_AER|4coK*in)2Ut@es1n*`1xCmawQ}g6}($!e0`>s~E3{;EyprD}w)y@%a&a;wVbLCW7C` z_*D`7H;mI;S;C)5Mf7}q1Ygbg;t2jW<4Yp=sL_$56PN zBlzQtuZZ9U$5HrH1izT^TO#-d#&3(@!;hzQS|j*{jNci-zr^?(5&Q>?zZt=6PN4L+ zMQ}o6-cR$0W`1zrFB9TtoChg*Ou+{zc-Cy8&p;*oAO+7?aM@JMkjA{-GZ6C_v;Rar zLmKl2XCO8_FNPwrn0X6t7MvFWS#X}DXTkT5U%wNy&oqoH zEI1F^S#Tblv*0|~X2E&z%!2bEnFZ%TG7HXwUKX4Ow=6ghN?C9ol(OJFXk@{85XgeF zQ_q64lg@&(GtPpubIpRYQ_O<1Q_O;&7{LgLng1FYk;S~R5zK@ir{Loi{A2~6px~z{ z_^Aqhnt~TA_(TOiUBM?Q_+$kyQSdVq{7eN;DEJfwKTE;SR`5~A8Oyk5btQt$=^U!dTP3f`pP3l;oo1z)7# z*C_b43Vxk}U$5Yc75oMTzfr-LDELwZ|AK-yEBG=6U#{RcDfrC_zCyuM3Vw@%wu-Q75p9rzgNNUQ}Fv0{7VY{Wd;9= zg0E5V2Ne9P3jQ?(e^9|6Qt+=U_`?dmR>8la;NMj6Zz=dA3jS>c|Biw`s^IGs{JRSN zn1X*#!5>%fClq|Wf`4DZHz@d%3jUOWKds=;DEPAq{+xn8ui$M8{(^#URPYxSe3OE| zq~Mzse2ao_Rq&S;{1pZNfr7uP;6GIGA1U~23f`{ZuPgW)3jU^ozopH(|3kq)R`7o+ z_`ei0kf)^9CT=e7oqp4%FHsFMDH3Vx7+AFSZ?-yfo% zSeEl*qfhj_*x=FgVuQz(^bb|=!xa4U3O-!H4_ELb6#Pg9FI4am3VxJ=AFbfWDEP4o zK2pJ>=kmt>MN0V53LZVjH|a#r@eO{wlFkVVexia$?*o|h$135+DfoB=KUu*iDEKJ~ zeyW0>rr^a2K2gD=_Z*BJCMn@3D|m^5pP}GqDtJP{rzrSY3VybNmnwMlUWc(m^j?R- z&r#ATQ}F0L5R=YyCHxEpKTpBS6+C*+#N>N{5`LzFU#Q^G`zj{=i$YcQo-jc_&f!lui(`Rez}5Qq2SSbKE`fWD&cDtyiURE z6+C*6$mH9ggkPZGjSAkR;L&?ZCf}=-@QW1u8U?>r!LL*B==~_8PxOA2!EaE~xlzHF zDELwZ|AK-yEBG=6U#{RcDfrC_zCyuM3Vw@%wu-Q75p9r|3B=V2Yg(`@yCx|Lp5N!EF04ttW$SrZf7i8wuB@w5W@K+ zoh4y4PAAz0LJ7_E-U$$T$Mg;cOn}fkgic5Tfe?C0DF2y#JNtgG?CDNA87H6reZZ2w zH*a>f&GvogS@`)Deu0Jm-oh`m@QW<`VhjI+gP zW8v3Y_;nV3y@lUk;Wt|NA`8FC!f&?lTP*xm3%||6Z@2I}Ec{Ljzsth!w(xr_{9X&c z&%*Dw@CPh>v4uZq;SX8(!xp~8!XL5lKU(;s7XFxpKW^cFvhXJ?{7DOc%EF(v@MkRi zSqp#8!k@SB7cBfm3xCPNU$*d9Ec{gqf6c=GY~in4_!}1friH&{;cr{`I~M+~g}-Ov zf3fiQE&Q(*{x=K%yM=#X;U8M~KP>zs3;)={|7qc$Sopsz{8J16%)&pn@GmUTaCz&MU;nxm`SmP(eG8Yj zXSw=+Q67mD!uz8)(_a-SzNyi(p5~Q`%UiYd`_<{Y3B=cN)tcXCDfumpp3(Z7vn}#3 zEBO&dUcwz-!FCoJE;|F_#KXe9)WTo3=-IrI^~>A8B9Tk9ol}U9Sl+!iU{%cs3M)HM`txfv;QrkICareE$YiWME;@cT{;foaC-tdjI{GTlR zeZ}Q1X!^bH^vsVIKKxf~=MF~yaIODWijOs%9#@~4#KY2gp+)`z#iK^g6s_kgi=L7l z*`A>M35u5(J$+gazrQ}rp2D42Pf-34#ohNH%d@{%yu#?0{Q9Hf;{yC&itlLn2HKvL zcII&1_aKX&LJQwj@tuvHGOcGH;$oXd>PNyNf3V`a8a?akht5-cyx~%R?^1k%;df~H z*NKOP`<{}YWaKH?)n~a~IKDB%Culy5c$l6_i~MxOry4y}Jk)1D3qL^dX-0k`@GBLsG4fNj{F4^`nc}+}`N>*- z_3<2TkdIWn!N}KW`SFUo?|q)Ac|!5MjJ()?nBsdIUZUkMQrvy-v-qF;6#uo6r)ENZ zK3DuVhD$kIj|xU%WIw~jzf~w6H+&PVr^Uk0R(!UR7yXYao-lkXt>**9n+!it^T+dprW6j499|8ApO1<90B7dmj2N*rlpShZNm_3V>e2G@2_7q6hrj);8IZmg#?z+X_j-0(vE;4b743M1}&e8acU;a;Tp0>dS~&sz9$)7Vb;ecumhJ=YSKuryLX zK34L-HTnzmmsQhQ&mo2{(R`uehZpw{GV+@yiag~L?r1-*s{JJwZT=)IpDXqU+@#BoV_~*kFKi+Whw>Mh&n~I-ktjfHeBR86hFuCky`$I3x8bkbB+8NT7LBItp9w&rCc>C{(Hms(((%wzsT^Bx+dSK zxcmOc`C9%P#l^cs%t_QTO29&R|G1Q&2E{Kk`h_2$_~nKV)A}z`+ss&=WwqwT-x^%3vX21eJ}aGTF+gIyYICWKd^BF>krCzD}JpBSN!~$#79InSxKvn zNdDesk$+3^>x~}q^DFGZ;ofNYep=z)itlRtt;jF3$gjL7>$%D3k@3!^#79Ji8#@cM z{;^7alF`4Z=BHWoT&egiM*lCh{Jo0Dj2>z()o06DY)??WRPo!49*I|#;&&Lnoz`=d z;#Effd73Xz1-lU5+b;EPB=HfEVS)HgBEF7(7JoEY^z ztBNl+oT`=jd`)~rWW9i$>+j9+3d%rWFO5n0FBKVI`oE%GlY{!~EE3cu!XgSSOO zARd;#ODytVDgHu0&uDTKg^?hirT9xmUhG+@_$!8szj{n@_r2$`GWRX<5s|e5>9)~t zINYH8Zi>Hd^v~1j++yL!DE^j_7dx+1{2jx`>ffGG{5`{^UVo*y`#$uv4tEoBP=yiq zedq^hzO&+gH+l**pQHE(hOef})j7mRMAkIvK;1?4xx*s=q2eDIJ*`@PwK&@o7diqlqb{TZi!o=$v3#C;Ei*!ieM{wKwkH+m$Ui<>yy6$~G%^*0d@tM3OW`IU_P zrds}N3%^hCRgC--T7KJR4%dCJ^jezFSG?ND7i<0p#ohO|OZ&A#lJx}jcPYNQ(IfG_ zLh&^WpQ82uRq>gIi#?;}uzvTw@W0met6p*Ueb${?&&7(n@3W@vg!(+aMucwv*?IzL66<&V?y4`}(}^k8A6&e%Cx^SO!-GhE8mSr-1F;u{+IowS|}sN&On zZ-Cb+9+baA@!>{(OReW?#m5*f`8BqU^#|n-ReTd8FY&t7!ar1eGb1nMaFhL6e~?cn z9+sYG5g!q8-@`Iq+kd;#3%)!Se3=%}>_+TjDG~M~6UeUw!tc0$dnz z-+TTGDd$~|{1Tu1lf(-n1;$QE|LX2={v>e@w{S%#yiK(JPl=C+xbN%PM%%MKHGGAU zxY7SB%`a9wY4~}XPfD?To8i5he@r|q+;w^!zSByMpyY3a8gS7l6eXJ+wA7&|@Hu9si{2vtWGhF=eDC%exM%?$gi=9^~?!M1m z_;&Nd)9u&93nT7(-X&g(6%UTPS6vXUr^dp6PrNYVzAwH~$LnLo4>j@HMDyJbWclE@ z@+!sM_sExN`5zUZVD!*%Ons^;!D-&faM6F6;ztGe4~idScvS1z>0s6q)PJ1f!SU%o z6+h1C*;MP9^;^~x9EaYm_(?`y+RchXSl)f_{B~N;C5oS5qJ+CN!iQ)Td zzQXTVkNbZ4-8COWJgmO&V&OBDo?!d_2gTj@)JysKLh(I}J(6EFN3cCXey!r}``;ha zPfkCQ+^{C>la*YSE;@x_MUr++*3DAx0k;ZomUQQUnGds_SdeU4`NXN>$< zt^X3me`9!s<~tw5^6q=sMgB3xgYr!aSw3O(NIAJp@x}oEN%5utuRWIaGza*FiU-@H z3CFSg^G1GcZU1tVfHeL!TRm<;x0?WT_`1zVwoXGrD!*9@h^^=&l7{0OQ zV=cTv@nF081Mv|N_kDTNF1Mb{`rY@=OL_QM@wp~k$@kq)VfnWL{8q)^HvBAY=kBMn z{JVx1YJR5T?-@Qu^R-W7`S%U4(R@e6-S^9jKRHG5zZ-esuPgpxfbVrW>v!KTFY=El z{;`plc43<{SpIOsrJf$5_$P)-J$*@W_r3F?fA=$4&*w&7_zj9LG+gwIrUWdEd>!Bi zDIS#nLh&z+{4P4(=AO-Zg8u&{#lJQ360h2GSU%{_?^fJ>uf6n_HaVB&-S^r{yv|qr zN27m+wrA9NEbqS8Ui|+JiZ8dK7K=Qte;Gj)gvPUmZ>9M{#ohPXPtrVk0n4vqt8ZPnO@xpNbUq!qya-NB=q{C&3uVwTIA9)eWUl5Q# zRPl8J@^34Cp^@KG+qufctS89FDt@t%FV^x0D89bYFXNQqe_%Zu8eXU6-&TC%06+hd z@N~GBcwuByBQNRvgW|#VuI5sf-^|EM`M*T*tBn1UZeJ_Dg^?HDc^T`u#>iJ``%kv; zMT%c%9FIKY`^<{Rq<~lu3|kw`BkrGey7nR_Ww)qV1MJ}Ygm5N zijqFJ>tFh=Wj@+)@k=i&zK!9M4%=SG^4l7|zSeWF;`bYSq@B7#@$HPf_>-p<5B6t{ zy`J@tG4fkz{RiE^{9&VC+S$j5kBF?ilEh2WZP<*qto@OT#7oPg6YDKivE-maj1Kv$URn zD?ZNf?KHpRZkFHC@MAS!cn|ZP4HtiM2k{Y+0+XJ@wS39FEWc|&{z=6r7%ui)av#f2 zGF-}e-~G&k{jPs29y9V%o)3P2<=-&*wVt-;8^zxY@B{>u~(_Pf4QyxPc%pN~DndV>9~hZLU?kS}_eCJ=#OrRw8v?xi5ta}3mu^sePa`k+wZb1+elNq<(BXC|9_*(rQG9PBzk`;a z@F?r~wc%2a?o|9YhKv0rkFk8*aH*#!Djw`dZS*+HCyacd4)=G8HyJK^J|w=5mcbvZ z{E7868+oZmzg2vW;alm4)_j8HTMdtD{s+bPH(c7UO`l}>cEcsUXDHqo;Ojrd^6MEc z<*ion4Fddn#fJy@Pl^Zo8+A{!{%#{L zea^7(`xOtiry&zR@G;v*nA-4>Vlz>t@9dGF1F1J2KeEMA8xp`Up~xSqX;7eKc(A^_t$47$Z25QA zbGy+a_O~j2hv8!9!-@y%#n=y6&s|1d^c<{supGXm_}xZc@^S2ktmj_Chw1oUN<7S8 z-K*q-<#6ObSkHY%&-Gf*Ly8B>;rbu3`~yZ_?2jwH*lQ;tv}=67K7YFELzpY|Qy5>;I$SB7ckG!Sb;3CoKPHK)zA&VEW&y_+v(1`UxBS zi}n1;@NIN@9-;VChOevnhl)RKc$MZ2pR%4O4KL9AF2$cUT;etSGnNmga|`jX@~}k7 zKWFqvx!U-1*7Jhl;ve=^JQ&~G6o1jkkJEOJ{DSqoY`EBYk>alyUZ>^1Q2aH+rJPiK z$$ElzUZ{A`&UY36v(Y2zJnbvi6Abr4#osjYV&^Jfv;6CZOS`b2;%^x){e%Y;58A)M zH>@Wp->3LHM$b&04zE~v<+rToJtM!TmcLx__YIF~zT9^#|2M<8)x28qpq{%F|G>y^ zspU8PH|q)NPbnVMf1lz(J)8W8$I&BK(rP0M<(KbSf5PzhHUCcWCc~+isn36YVELrs z8)*LbA6fslh7Z?#^`DrJ4)9*$g^^E9e5KsJtN7=JOMiGqWI2-WGe+L- zYQ zQhb`>V%yP*&oErtsY?~FHC*H$R(wOlD|O_WXhYG6NWI~b&MU0N>9)V&(ym>mc)Q_J zzhY~%y!*cUSGE3c6?flvPu(;1xpf_uf70lYeA#DRwr3B+#r{sk_X_aS6#up1lFs)i zzMtWu=Y8VxyEaAr_{Dl0ZlRH%ufIH2@dpeS{cF<%SD2o0#79K7GV)T+x1@tPBO(tO zF3;8|{z!n&Q~Zhmzf$pQ0{kPzuMhBzHsEmY4e-f|Z)13ij_-|%Z*RD?BhM?ogW=LY z|6K8?;k#-*WgBw1rG{Us`5THaGF;LjvJuPQ65yj0zdgXGDt=dhw<}&@xTJsG@bLVa zPkcn=S4MuSwsVQ%I~!i4`L~LXH(bhp;l`|IlHrrJ{QinhF~Q z(UHtgGkk3=zn|i#2l(-dpAq19Dt=~w|5fp`3}0XCA3lo1Jv+dsD}GLZAENlV0e+L> z=NT^fGI}f4e}Un$61hn6VEXSqn&mGv@>gp+A5{Ee!$nWk*5UbbfrUR#yfAW!(NnJV z@3IZ^%M6!s_oKu|M6NP?jF$gK@#_p9ulbJKviyyPOFyJV@tX}V(DKJCep`UwsQ8@$ z{(|E71o$_K-*33|w?}Qq_B?3#?{v7=DE_SBQg?RUp5>PqF7fSB{87V4X+38v{*2)g z?h?hHH~dsBzxSBsA_e+)&yUt*dwbWsu2g&T4lSwfrX9K)cW7#g#P_LBS4YQnwOVZA~_b;<9+$uPNTs*4fgY zjMWD9kqxdsyIgTah}Pz|p6*1tsWn7zanz&NCrQamY1r1)*4f5M%BfwFpqywTQ&RCn zs>OljZ7rQ$siZFnSaox9PNKIx9j8a;#=E=P+nN@{SggFItBWF9*`4Z2cQy9TsUA1C ztutLx+>w}{`TMrc4BwZRW`3T&w>=*%n%kS%0xe;};KV4R_$5;+b~<^Y>C}RFx(iWJ zqPeTvNrJGbS5mOaRA-{Sy0~KQjJD3HR9us(J(H=Pwyw@8U8(A}##AB|o^0@JdDyeH zoV-n;Dds*}66HthlHJKfI@vs>E!o~Y!O3GXpuX+EWIxYS!qjvoyXMSD^vvx~v}CS? zlZEuSxeW`tlUWExOXtq)O4lZu<|do75ig!w)!CP5Z*zr9*{iroQd~TDVp}JtdMeeG znw(50+S+@jC&M$Lx};Pk+T>(UQ>v|-YKBVoI2-T$Goxx|Xu@Ri`Jyt#k@icv$_|Sr(mbh5K)L3Of^3UmNijURw2Ta3yo za<$4EP34oSOG@S{cQUbe4mCBiQf<^&%t*|4{;W=RQU`}?_&zheF042@i5luga*4Cr z(yjIBM7p=9A<@#@9;@xEFOJ8e)SsxWi#0Ut9iOtt%t;MZH8bOJZl0n=ZeOdqxM;Uj zGD#uEJ5&P4I};tr9tf|vY*Kq$vNJuQXF+FEU9zW}>SVG`wO~~qRnelU+=V0W-@YIg zbId5Un^8)AhaNJTx=-BqXd`ERApOaNvD^`e;28)l8*jh%;~VE$>5Zaqr^|8 zIX7Z`Lli`G94C2|lTcLX63vNpf--uDf}@(++15k7Nh(OSGwb8!PVveR;BM756DL$t zmi9KrtKz;=R-wyS#mwZq`gCt&tZsUJI$G4znn)#^?x~2=V4$jrLW1c%; zL@f)YZ}5p5&sjdvCHgN$%An87)@cS{F-C^o$a6 zSmYRLy6cmj{`wpKK(xYrU`Dd1C(&Yxq{=T>vuXfpx*h+_`X{w_x#ia(Ys3+EuNMu1hxc`J7I;(ZyQ5V+%i)N&UFG?k1<@R2kL8RkVT_cRp0D^xB?LJm^ZO z>V^0bQzA_yqa}_FQ)!Ujo=kai))guzyXupvJ}T>8lZ)c6UB-CwHbrrtVmC$=T9GFW z1$x4dR_;c_6+JLy57LtCq^BB9EW!l58p?cyH}kioyl#3)F%Obxjzvm+`~WWYG%Z0M zqOmuf?BVeJBYXC|Vg6NOnXSAS7$RR>B>uamH;vw1dFremkPsZdR{^~)r$a*)b8Cmr z#m&5EP~NW3>BWWVbLM@57C29cM(m?W>lrQKHqbPUIfxclCg*o2Q*9m8k4v=26Wo=f zUYBlT^QK5LJk0n~wmlkR2d5ELe=b<{>B>2}C9ay%=d?1~K~rNWW_o>tr5DUv$2oSkHxwKN9AoA5Kdq_f28RRy&HM&3H$pmla)_MjKQr^We>O3l8=SfX_7nR%jX=>k9 zzpz*jI>=G=5LC=F5HaPZKIi@yCH@4SCX2VW(R`gmPxT8Wqno;VJJVH}b9BHDdUGMy z-s7aQs@m4RSgavlUlFGwRbq0px3i6s3;Nw|Yv*keV;onR;B8J)PbgW%LrW^8Ra8Vt zIS&w=sv9jDyjnM<%KMT{G|g7UB{qZJK;s;0aS2&WJ?i>$Wx4e3hb#y;7Ma``Wp0fn zPr|&8@}Hrx3(XI|lbp!Y^EBAlgQq;XCs;*Iyl?#OtxCa~YSXCR)lZ1mPoiSirz#?w=*<~lSCI;Z>e2XwxR`tTs@|LnILr{w7|c!z z%j=TeX0etcpgKZ_1#>d2%Jk=nOfFgZY*w2{`k>aDYNGof>cPaEAngY3&9X z6PkW1Ay-)%_xRX8m`jD}y^>P<9J`FtG8J61HKf_dSHaCx$n5h(125D$7F=I6W%?|q zdSnZdi>z`>GrMZKtE$^dsH-uPnsxfM)cv*0{k5EaH6spHEC;w?K|KmJaqaCFap-Z= zTQ6nLWT{6DaWz*I=rJwD9-Hc!QPKR_`)2GYV$xlqu}~vTv?r5sUT5Q7F4W4Gb|>0W zRnwi$8BU1D^l*n7wKQ!ul1DpvEt-1>j-M(nG2f{DNnxsUAAZJUz(T$xL*QlUUYet> znpT^+YiS)jsKH!GoO*UnS6UW7Ob=;jdO~jhhkIb+!FZUKkG>ucicCFpH+My85Ka4- zI%pEi(n%?7#+20arTdGU3jGftKS zACQ*|>&@m^wj^Pcr`)NEKKQ2vUQJlAMI#Ux|u=;Cys~d|{JD{Fl8rco8 z4-V>m?Lc5gz}o(hR+#TC>FA>E)_HD5d8(FMOlmsy^wQv)W-hMcrL!&$_Hx@_QLsPh zDF$STw-`mk(!IZ8DSd2RGTq+AfHT?F9n8j9d(>k-L$h(t*%wSMF;X{uUO&6q9t^6# zT<$l01DQSOWemsd(yBq3sT&?YlvM!=iK#zp^6D{ooyb`xs%Z#xf%{Fw5J#;BWL!w= zXoAHIT1a_KgR^fbSjEFy{$M)v7uGZijQ01%D5%NZ_P_>J;GEPlDdqDJAq`D18oJ!6 zP9eqWn(EXp#Ljsg zwe0kp+iAZuxfZI~v}u6kKLPE*#jt-7}(*&ORkx20&OncDZ~G-_FCm{iOYfthx?W~HXs^ovu;re1YG zDc;VB5m)v zo_my~BzUaiYMPH+&{j=H<zu-Q3ZXcsK* znhQl4S0Ko-Q+C_7Zb3!Cqnq5W$TPP<|eE3^! zgm$;CDo?3o^kZ0E^=X7+I8UHa)ImKvwVSRi(90*>(TG&4Q}E46`E`d z+v5N*Y&x8lOr$IpkDE;Mzio7qUDx42T&br*kN4QVF0G%J=%y(zr+!H#aFeQRPd;I6 z37qOuG99Ob?^IG^wb6358M%>KUd>E>!01#q$rIsu5G@t~-fm?JIpjPHXOY*5xX}nZ zKf}3|gM3pTr;=k&Fr6wJDH(hQyREg?y9xI@HqAXHL>LxKx0}Q#M%6L78Hw)V=x)h$ z@VvLjAJayS4!X#ots~Jb$I;+qRE+oYrAyn%<5$tIYCowg8}nC$VzJUW)DMf*nF*Rf zD|EdNcY+48blu5k&%_`;RYn!jaoPh^*qwHs&)w@N7tqu}=IE`+Y>ukg)D(1L6A_+? zC5e=$$b0t=6&G`TYfd)yw#1#**=b+~;hA%fBKPK{Z>H;k-%5Shm5y(qeL@sYE>c;~18(EJT-AJJzFq3vgj6cAfYSmi zRqpA@>j0+K(Q3Nd9-udC@KKI+SbE zT?WIJrDAS*6L#bVogdjGP?PC1Q4EK2Z;a#IoU^P$9F*(!hB89k-A=)BdMe)2rJlZ# z_baTy-ZQD#Khh4#^Jtmh`*V#qLo}&lf?*oI!cn zgl4)?BUW3XI;UOTweGp?Y_frFH{n|XSc7{o)jTK*_MBBRwT5LlqhM%>2+^2L3_>2u zY`L?6IC!u+)Owq6XbddEQGLe-CzU$G4PL+`ljYfLQo!%ISZf?04SPds%S%cGZZpK+6n^n$Pp6w^=?Ax*}xtHOA@C>v+z*m(7ZVd?C zrEK?AAsVtuExT3yB$!U-!1V>;Ro*5Yo>UfTT7*&;>u_AGW!!|5-}OZ14GTV(wQEt<)DnO`!W#6P-=1 zvK>U9oft6U0O*7CXP z*F`ZzzvXJBOz9K;h%JG_rNx_OZBd3K3J*c*XZ9iJL<;Plp+XcMM6`4Qoz+7;sK0ck zx|XMQdS9*DE~Td%gM#Hf>aJ3B8X-axsg2m9JEm0GOe(FPOMX6cXyZ7wC-F5swgB~A zT_L%nHUNg^kMoQrf3(7o{ORZNFC1-pt{c;rgL(WurkVcUnnTX_l0!O!f~o3=m1EL} zi~UAA@&vS=@3`i$xLBXGW~TKCcH&N0p^>#d z2fobo=$%xIw}dJRNRPcoH`&!M~SoxXmi3#z2O@Lgb`yoO9j(ZMS8N&T6^E#Tm9 z<)Z~*K6*wc95UV)7^~qce9Kcwbxw`81*;uf$*P8UtTfFRjn?O zj(iz3U20v|+Zn4ZbrxwnmoM^sk#nW2zFbpXdDxY58@m2N;4(A#RP@a?SPBpC2;_^! zeYuCZOgR+)^o><@=)8tH zHRhkX2~**7tU35#ijtaaB}4Ob1*Y2a>SQ?2MwzL_Y;Ie0(%0Ndm>+{wo*9GkqSJM+ zIYv-CZoX0*^m*oct!0u*29;ow!dX6~k}$`IAdRvMMdA`xzExZ5*zTLzw#KxdEj=LgwH<`!7`m79Ic8JZ88Z`%fZI&05HNMP1+7}OJd=IJZZ>~zrnl;=e2FWJvoO=;kj>*OXGpNW2qDAUSvz2j)qJ1 zyQ$TgpDRr#QSTLOBBQgtT$h))oV73gjt6f=4#YjA4hNeOYI40P;SL(Izc&{%%5R2r zr!&b&&nTlz7G*Khe2@_ol)?)5RTy+_#KSzk;XOgm1KxA&J#p}}nBX}c`78 z6l)b2NJjFj1cG%W=h0hn*oL^=?V-5M;P=tewU+M5&HY@(Vbt5+WOJr(=*J(1deuSm*zPZdr7OGA?nW5Mm_ z%SKL8YzOj?q|qql5uMfJ7mB2uxkD}x{%vQzDQe%Ixmc`;EY0hmA=?C{JO8{i zF~k?_x*-i&WT3PSab(C@sEQqL=yvbNR3(QSBYH1$I@PtHDnD2Gs-1x3;MrSIJ41&6 zX&59k@k1O>Nl~s2nJQXv^Ik~(p}G-^xpQi)vtOr>y<+qW)Yj07&%8vcxvDO38D>x= z-=Rjg-h{2r@fk~JdCqBdqUE$yqu)laUyrFyW#%Du)LoOYac&bu_iekI66HO(k+ND6 zpe}cym^R=`_=c~_D z1&Dc)GB&BIn0!=!Z$9%0EcF+C6uU3_a3_$LYAQwhOC{*0^s@?)sfR)nc&3Nq(Wr`< ze^x$|ChCENYRWi~pGl$BG;F23r7J^M49%mS3AD^haYct);VftWxgqynNJtYS6B9kj zct@g>UZc%#dKq}pEDNo`w8ZFjPE>)3c`I0GJ`C$b@kH-@SSzBCX=mY_L_2ljc+JSASRHJr%m2%nRa5R+uu(a)G~dxI+dcC63ND!|Tk4T93r$143gqfnuUTAb z;YtT=DWohfem6Vw+I-b7zn@$k!5I3W^>%LV1mu4SO0Peufnf$G5?o!Oc>7mU)qFNJ z>b&NXizAt?JqffRL-vX~T!^Vq3o+Egp*;hhMHnz7bd@3>t7aT5ti#}|JXH_Yd6g$M zxI?#8Lvwxcrq*QBT)OSAlO|G~OWKDpMBLxwrg2AGo|aVYNviIG56Mb;gA282(X!?? zzCfFuSKj)h_63t~pm!(KHK?Pq z>{*6-skWk7uk$M#`t%B|Ui?cX)2*qldD(Ulvv-@=z0KI2%U&hF@+CJ%?Dpt9i<%+R z8@x5Qt%=?sly2>6wsw3&cHodj{dTLfk7BUH*q^P^7wcC}_hER%<8SBuJBEVx!logb zZ{@{j8p^rvxFL6x9+&J)H1d06=Tz<0lOm@}gFjkXuAQ>ub_>TRq?(Cda6>sbzWx0;i#`-u`=3j+ee(c!6w)qA}4P4f-l18WZF7)!u0Ik>!x&HQvR9A+&vx-FEsa#P&(? z`WcSx#gyI3zt9HeW;1_JyA9gg`RFSRon`-vFE$yLS7>*RS^Z&u5UhP+6VUzbSqL4_ z=B_AgFqXZo=x&M3740SvC+51LogG023 z?0+sBWP&c-SA+MDM&S>ix8 zn$pep2e9vNaK$^PeSfCw@IP1bX(f?gsc}F& zooI={tBguY?FaSg>|$yTU0v%d|DKME-k2bb@nF@tP2ONNg;(`_xw#2HsKn**ZhZOhnz1k@rfv%*1hMJ44G(G($T>zN(pH3zvD! z!1YoM8)tUabkiH+OK9R_CQa?qug-hp)vskPb>17F-9Td*u(bcmu?!fQRq0+9?8M?Z zzzy`Yfj19(_@z}Hpb`C-3Tdmj1T*$*P%O1`3tO&H?6Uw1TeLOr^Pd zQN?|;&V+v9i|Td{w!*e%BGeS-B6&` zMG~}ysZni{(hGLWYUFq)CLdPs?&1ifc>NjHF4%Zphx&O-NmF~(G(J&C%c8U(OYcIZ z#(Q!@Q+p*XQK?tTHCI?>d` zZ$0KMhU0jD87ZC96^qq1#ChqXVNi!E25~CNDLCP#;{N(vk01@^oQEU|uaqpKC7Sn0 zH??>1t5dNgQ@K_<^8Z`wDc>2Sw+DD5*1zw8nIG@sT|Z~U26X}?MzaN!=FV<-s#!me z5lu2%H8lI!>7A+ZR9j1Hnx^io`@DxHXxghnd#C373?Y*fcK5dXFCC(dP>$akie2@b z+|Dk7jN8E}D?GPO$)!|I;rHybSNjI()IF8d!ELnXEA_1<0CrRjV52=>Ye08(>3d{` zc&9zZgWG$Pd+wnN)fLDxCIj7R?~iKETkX}p!jLPODAkJe28MVWb#oGQ>nTr>Mfe&lVsl{ z`{2RvAEcdZ^x@l)CODg;vZ-^yop>3l-E^*Z>}Ne5B3SXb$_zd}p>Ie4PyRFP@^w0g zL%-3ylCC_B_t4g1XU&q5e8~2+yO&sUV8=3(9%^Y2dDrLQOPktBO`hHfMz^)JOIvTNrqd3pMJXn8ynDO( z9#Y!RO-2Ns&4*pQML$MYJn@k}XL~p8+??QCe@5*b_XMC$44HR!_jr>X>hOn3j=Z~= zJhbdVmqvNx-;u045(8`8;YJ8|o+FF*8mXNM=HZ++4)=ct#5kvb>US{JPU&wuZ~q!q zGeRlk_A{+pD|rufcoOqHAzAh@2c%t}xd<(Yc7+)lx$H`yfB#I#i%+HV>%V{vTBvB8o&RHqpnM=LGQdKv7DXtCrS9`d3!RL|GVh`Q% z+0)yeruQ69)7Jtxr%Y;Sf}d{hte=)?k!LW8nx};mGq;w<`$l{-qn24&9&!4=>Thz? ze+fMFk!jpWr@cCR+uLRJu!`*}kDt$F7>d^BExlSuzNcIpgxotWhw zG3QieTTgeFJ_O7~!!t=z-9eL(A)RD@KhigKOJhH2sp#RN_|zmFb93I+(NQFC-7>AT z@3O6!nrDLNeHIlBVp>!-iv;627_D4DS}BS&{x5fiGl70RzvU+|)aWl2r}475bI@B2Ms<^)GREG;Y;IvlsKjp3po|*8|P+k zI+a{e%uT&n)=+*fFOg7_d-{$9`zs4L!G?O3z@6EpiF8%WmWs!5XIAOb65aX^&3vV* zM3kdW9u02*CSs~xS+^W`}CgtIr%adc0Jx-~{!y4sLRw55A| zhnu{I`}$($5n48xKC`@~tE;6wS=pWHN_WwXh!t|4P94B3nz$gHoY>2E_rz-XRixC{ zl^YV4>QFh;ZP|4BvblhPvbDsFpw)&1r?2N8XY6l$Pq$GHYDXBqyMXr<$QDi-ZP0BZ z#wNOVlI}F7rCfR^T@CdyYiRcYzl_5f?oEdt(g60*cyDCjk*OJO@-kTqzXLbZK(rzt z&Rd3*X_Td;$JUE|Ca72l9$K%IBB9ocl51CH0?p?q~RWL)L? zg@KK$2KhXA5wnNO=b#1}HBjx`77L|t$i@UR{!j(0pK)ril~T^%wHx-e1+QQ6Wo=NI ztu3HJBppp$)f%wA(92k`$`4s$yWL1V2TM~a?maka8GR}A^5}wXrwi+B9SG^@scdBr z?tG^vZ-%V*$4m7wS{s*p&?d*-tJw3@{gX{rS0rOQ@avA5X`RH2laaff##m* ztX#0Y7etdtQO_h)c0MYDLeiGWb=seFI*5aK*7Yws?N!Z>mhYDAq+VB(biMec@pM^C zE%%_DzLHwEOT|1#7JP4R@LjTyYd>rzx{U$!6gXkSb@`cfqIZpuGT#OwT1wCkEab~P2Hxy! zGvnCACz)Nyd5au(o}Dd2+%GN?r{{}o9^=#9?QEM<5yGBGRz)^g;v5$kQfjlRWOje1 zU8}BO)BPj2XjBi~s;L)WTxPseL)SjZRM#Zhc2=LJb)gQvT8Hj*XzMC2k}qm{)7`yk z{dL|O8R(1m+j9=4rsKukhSb-d400A!H!bz)trls3Aigbv%(sSSFu+S)#~G~#PK|K~EdVoDodDBKgP9oLfT zZc>+K*H)-sySi)DPBU*m>VGZ;%JpS~JXK1SIc%g>q3`YInh>b(QTF=Ijs8>h%PKP~ zQSTu2uHS{cmXv!f-jpAjfMhXyse~1}t$b+W6)mdk?bI2Mf_{t*xh34T*RU zfUKMkUbCFo9!#v&Yuvf52{>0@YqJcT#c+$Qtv9p`7&*Z1%rap4VEZG>Kooo(3U9;e zE6`M(^`X80){71MuMhwIaU5WE`tOhUU~A)le+qq$)$N@=e6MdsE4HUt22O zn`n0$zp!pvw4^@W+h`8|a(%P(8-0?+Aw5VshDQBdK18hbDDM=u%*|b4|6-JNc_~_^ z7RM*Fx6zbtb6sK{-Ne+_1`WC=1n%NEoo$LpNEp#^vV>LD=~=;&?m@I{QWsrIl;k6{ zyZ0vP&0H8%{hq$@RK8rXK9Z<-zu_MkVtclXvDK)Ln$#6k!wedd~)W)rR9BX~CCYGM{K{>x=R|Ks{}A z9VxvHQN7;XxmuP5>-lixjATcAPG?nrJFgwLVaA&?Y3+vEDdj6^n@Ku3pKgJ4W@o%p zV$ODL&pSMv*wEto&wHb9NK(;G@V*X9S`CrkTxKrc2rXlo8Y@me|DuTu+u)jwjC#Xf zT9QdGys5}L#TyMNVZI!*z5OjLykhMgoENTesJb)2!u3AILo@NI(yc!86trVaSZ~vL zgC$r?IoaMubC45w0+JR-x@m71Es}5#uHTgON7&cnl1$GwbJPweTLSZ!*xSnP)fu6M z%&#Uaqfv%CcKyk4kFP%&?g~Q6=e;MB>295&a3{8`a$>nB6;Zdf;n#JCHZ@M2$-|I~ z>z}p6+h*G>&-g}KI@iLq`y{g%lj%z188PXt$4&tX88O*6{fX1@sDlAmeQpCVF)nlf zCSTeHVEwp*Ol^i*zR^eOu#G^MkoN(YIP-vFsHC25n?HiS1*g!;ZSA%Nl!e?G#u{lu zS!G*SkGc?|lvfU%-AVE0p00SST96DAa>h(*8iLM{&2LMykav8NqkFD&mKbWfoil}l zQ&u*ixtTS2R-yw24#~>vfEEs8GpFy--WMYm=BxqHZo;4G()jim%`4D}96AD{_lo}(Au}bUx%3j^R_WkFq&=MW=$=<^nvWZVcVIW6tqfxrfS0B_(IzcJ+s6r?^?BGxXfO8zV~E}NDNH^E;GHt zXer;p)TK@>_+S5NDuU0&NGAP^Lx`-*#^C~uOft8XC`@CE?1gENk-adDHnJBcn?svq zUn}pkJl99a{#+lSSY&u48@G-Xw=Xt0r|z^RmHH?lG!KEpgt`mvZ3aBGUM&$AFT$HP zqB%4#L*py*F!w3vhP(z!J51_@2;@sZ&*i{NfxiZPJ>VY!Umy4yD{!owc%lAc;N>8{3-EP-*I4*In)~B*I>=+V zcLA>i{ht9x`Hfhywjbqp2EGK+c{1>wNxzhnUf{bxxW@tC75F)t^A9Zl*Mt0ckiXj^ zzXas5yuAYaVX*%_;7qq&GfTMgNa7?$|HRtqaT@tT7LH^@aT>cx7|0nQf;HYP==IpmW0r?)#|1aPq zratWc*w4#nOZ^M$9tG)ejOJ|r*1*rO@CP(!J==gh+s7Z)LpZV%|3RM$=Z8w0F(AL2 z<|3cgf7gKgFF`&5da7iELGl8$I^)RmkzM+M$Z{eF* z_;3qHJ26}=pL>HnQ?wo~=lcNP$fAD>3*XejrCj;bAy@fa({mKqlYn?(xcdXQl~1gv zSgxA2eoi+mpIyMQd`f=#<+lNO)H7CdPB$_$ansd1GfWHYG+o_+R-%H{qeO6%u z>BD*!fSyf(W4y-bewshrO5hl7EpYU23E(K-4jjwFLBLV|Xy7P6TE)tV*TE34H8khw z9ZFpKhr@s$2J!`(b9}MivN^~f3G!n={wUzhAdh}V{4?8w{Cbe*zLS*O`+y$<{6*jk zfqww}Sm2vOdDsj1RNyFo2ym3gaoKU8XR(&&bi;Ib9`s;*U$gMxx*YNkQg6y_4{)@n zOvjhQ#d14YbI~K|RSojkpKJm7BOqRffIRvi>{np8Nc+foFyAi$Jy?Ht0{_5cMu`{B zJ52=sTadpI_zA$ffuEx}+k^Ra6>zMl_X9^e-vj-m-i%wn0(tZ^D{{iqhkqOd_N=41 z-=58Yqdg-*59aT77T#vz-4=eW=6-wbweaVFqn&>Rj_Le0aFkyi+IN)S066-|Qk9xc zdfo%+iS7RV#Mjhv=qDcl`2zht#~0iEZ8c|e?*#c-z#js>Ht*C*TD-T)+Jz!Jel;9`!s!T+*iqZ6&{sisJHT`FRooIi9h0A;n+w*6z=L(R= z_}-*Br*jd==Q_`@E9gf%r61xiZ?{_H@3C+h_pu%_Gm_TzK52hxWe(^2~45_G3S%6ViDc#24c= z-op0;j^X~s$KTN5%6OLl{0oGO!jA>cc5bHo$2d-BzPIM* zf;{TK*utL&J_q9U1@ONC|50-;&$jxA>45z-vBjr%i+223x(&;=B$|vgI&cg4t@P{oN=gl~O#h!OSp1IVEU+QwoKhPd&H~d`Y zRs4Jcqyy@~aS+R~fJMu>SQy&%VI1f7JvW^KpL*$NtqY(0@6|V|#rYaNPH@ zSaZK0!}K2x`q7_YKMKbM8-x5v2p4$`aEvduN64|gzA*MA;WDoVj^%tNa7>?C;HaPX(uAc$orTu}7kfBf4I!NE+ynSl+J2Uw z1zg%e=6eC(UCXncy@59Zp9;J~bJm0XB8=}oAdl(4FL0FK4>s=XDV9_t_8s}pd z$QOVf97jmKWBG27M?a5#rWW)dmvID_hXX*5lpp3P;8-5gz%iXsKlV%KfqW9|nGgH` z;C;Y{21U3z!w6K13wmcC-CEd z9|0WO5vh0ne8Kh+*I#hH`gqVk3iO{uT>8%#uaiL@?Y|H5QT&GAo{d5Osh|hf(@z0D z0pw2uj{YCp!B&tz9pn!Neg<$!H!fFa0>2RCQ9t^Dvp^pG+u6V|ojHuNwBCBqkK8Z+ znwGFf z{{S5OKUV-pd#(h&8R)_G4(t0>Adl&PHSjG!4^@lE=3EizgYDflAityYwVDsS7C5#e z*8xYreLe8QK@ZxGzCdFda&Hy1{~{Y0yvh#JAjWSJNU!);Jh4`=es~&`r&Nu-N5%?CG=r_4{-GJkHsGe)+eBud{*^ zKmMBI+pOcek&j=b`7eQE`JV|K_j@#I&W~ffdVpiRjsZQW|9s%6|3=`Lo_B+OY>%*A z!0|Zxc^n^YhwR}$N#DMqrfrWpSJK1 zf#bM!WvF)r6tK*1YzQ3vQWQAq*$p_3-(`KD%NyFcFUTX8^?jB{{bztY+IbW34Isas z1dj6n=x5Nceh>0kzcz+?gym-p@QoncO5j*N_Xdvs7Wbu}2I+qy$fLi#5;*$XJAk9V zeH1wQ+t-0_2=;#p9R2VLQ14y?`Hg|!4ECenz;qZ7@*_Zgx~2Zg`ZJsL3kbIx^kDwt zxeu(5$ALWBbD@P_ZLtUEC0-|cr2m8ckhg%3hI*H;e#qO94h332y9MkIqdo6sVGoWI zZT+9WWD#y5#P`o2zb){;fjvh6|2xQ^3H$@#IM0Ul_g;|4`itX1%=cG89{tbT7XB4* zDz=gDwIBZ8$GOkPpS8fBV7)5<{vpH*$B&rK)gX`g{u|)`06ndmvw2wl*H>0K{U|o^ zjny20?IXr(v`@aj^;~REasCkJEk6c3$AbQU0^bGrk-%pFKLYr^z<&pPF7U&F9}WBy z;5d)*FW@nd{}lM1z&`_?1dj2-a{f8Up9k_^0LS#S^-sP6`CR)aV<6mbLC*x>X9CA` z{suVC_kIoh7|?_BjX0kA4&+CJ{J(*Z1diu|aU6%d3gm04KudoH!~GugBmWUN&Nu!9 z9OajzJrQC0m$&d0EPN#kUm5rg5U*8%WBpwXING^7aGa;bc{W_9!~PYPhczsEegPcI z)mp%-wf*du)&{;8#0%wHEc_7QRgf=d07pGn07pCTwD3)V`UV}-W?JV|S zeL;J+2YGBquwR7oV?Z9;_g?~^2j5V}TzA@!lKCFpMlJ{9;} z;7QK>iBI$CE)G+uyT+WBYpva9jJ^2ln82uo&v^ zT(D;k;0FSq1^hDLdjh`?IL;d{v2f|PaQc&)$Qk?(ecp9`sC7n0Pins0a?TelzaKG~ zU)lsX_uYh#0FL%-W8pJ_<9gP9z-NPgxsR9asRw=<$bSR;TFtpU%!hojozr{_^q~EC z?=IRY>vXIi*YV~46G`W-sLb(4_Cc}y>0oC$3(|*w;5t6;Yr^&GSz2Dj3-rtZJ$Qcb zK;W33CjrOwlykJKAItgm5H8xY7&xw{%l-lW8tr)xeRcFDBLym z-=l%=NL=bQmbd%B?_v38dqloK>tR2J{acLJ@4+5Sw;doIFkTmeyy)k6m4Q6QYjxrh zuR?7P`?2LAUT8mun~VJygFR^f!(b2EzXUkiUkn_};hMm)9996Y)bZkU7zZ5F`41L5 zF9D8rUJ4xTybL(nc{y;j^9taYFSzb6dN^PHLiS7gOT3uldN=yve}FvZBgaehY(>xW zhxJ?q9Mk7&uoLrj&T%uiL?%@t|Msu4jby-vRPy|0kdy?f)0> z0?_{{aJ2t(;AsCBz|sCMfuo&wf}I#H<|BrS9K%J9;UdRy?}BhKeO>`OF@0VIj(YC4 z=y?I;QO}FOQO~^=J@)}eJ@*60bbA0errToRm~IaOM|&Ouj_Jeq2g(QSc>*}GK@OWBOou$VSie7Cl%#v(fW{ zMGv+|+30!Eq6gbe)MLx{mq1T8`HuO8`HuO5`TjEK$9#VUIOhASz%k!n1D;L1{tWWj z#4FeGjO7#Kh2JcgSuzx{X6kL5gH_1BgTA3(U64mSA@E%LT<@(+;5a)Rx0HsO8*dbZXN@VM_R z>W9d95cd_I2Ye5ZzXo_a@J~s<=)rxw7lHhFAioIsEx>Vp`)&)zdATz|56-`x3p@#W zt_FS>@Xx^h^MPLo^0x!O0eG(K9krn63kX;019>i0H%h1V+za>}V9)P>p9cI) z;I{+64)|@r@%}?zbCdkV_laP7egk^G2Rnbk2}2+Lf$53o!Z1Cjg8U^AZZq(kf%gHw z75MSM@qFufz_Hw3tvT1DAHe=QK_2atb73t1Bgo^qFx3Aqi+(&8hWh0^sb7EL3KSrH zm={5Oah-y2WG8(-Wm^`e4+qa&&fOF-q>pf3cm7aP&VI z?g1dr{7W6~aln6qa&kFvJfFB2IF|FRfwO+;L*x1v+Vd-)yrhGyPx;fK4di+9OY$At z>ldLsoC)%HUh)p$c>eJv;25vZfMfcs3H}7rXEboMryMxigMJe2=>d7P2h$n*E!h8A zLbA{|EamSii7;k^ns`LAdjQ zuMGTT;Hv& z57w7)ATRw=_LF#DO*QD}KAQM}Ujsh^`2N6g-d=*!}%j15YIqF-deaHPgDa~0P#~qTt%yIvW)Gy|^5A6(#p38xw zo@;=kp4)(9|7V!yoSs`ix{U&U3gmAo@UwwW27WPc-0z3uDct{g0?4EOHKDv=Is651 z>=$7^Vz{I}va`;|dTl4CGv;F_*pK=6Tad?mJOMbS|2d!s{q{u`{s?f~Z}t}Ok0E`& z0sa|qyiWuD1Mc5L|A6PdQO`cmzHbZqvE3gD`~)q}>A4o<%S)gK(-ZgC;kf1pkViY$ zJ@?3eb7IkwkRS(rY|vAs?z>hN_S zzpy=R1pOz0Jlc7#=3LIv&j0ssKdI0E`!^>Y{@=ej>G1#l%}IxB{M)+VmnMM!DF(kZ z7x*5)4+K67_+`NV|D1y3|LY-r{{NhUQ$GLO&nf6)uJ)PO)*siS`sM#{ch)Aqevb0P za+Kd7NBIqNl;0>v`QbUrZ)}mbt>JdRIuoqxL={6?!b zl>3=D|9KE_od3lBB+h?c3Gz4&y}`n9KIcrZ2j@R+>%W(QJobBW{_}JQ7w11^zJlY6 z^Pe|?JlcP!g=?I#o^Ap8m5uzC7J0VyKpIowhs#xz(m_52`WKefLrq1-14s3sp z)Qo=|27Dy&i-C^hF5 zRV&EL+8^_Uz@rTGN5=d7wXCV}S2C_=E^ANBp9DQJ_r?5U;Ig*Jd`%eV%Gi*(yl0#r zlQlc$r64b3TjmYGrHn971D82c=4Sxkk%9i)3VbJl^z%jFI|Kg`xU3EF*TZ<=OCPph z*4p^*QsCnm=uZRi2?FV78u&!uzXd)C_&LBQ1HTh^4EU?SrvU#J_-?=pbQ$J&O$9z4 zxXd~8*Rz3(?`7TwT;?{J9|>IM*qO6W<`0J}Yqk9M65ul#=+FDWYXs8I6}6vZJ+jA! zza9nL_!8oif!DF1{xk!ZIavPcNZ<`3Og}FJz6bCn!1o0HKJZz<`7T8Mu>E_f-<*He z)J~cC-oVEIm$eE0x(xWfAm0G|H^9@t_XBg&}VA-2B<4KHx_Jmo;(z z`ZD12L4FDF1;F12E@OQDdc`#yA+}%o0!&5$mp&fz$-rf;gn27)S@UAP5cr`C^yezz zhY6&gHvvB!_^ZHw2mD*$M*ttbrt=5K>qy|0z>fmH7x1Hj&j)@C@N0zV%3@LxE8u>B_huLOP~@V$Va1bja5lYyTD{1o7K0zVb_tH4hK{w{Fo^Yho= z13v@gH(Sg3gX483@U4KK1$;d4vw_bBeh%<9;O7Eg2weKM{Pk79&j9T zUv+Kg502L&;M)Md3HVgtHv?}4ehcu0z;6Y974X}D-vs=2;LifT1Ndve?*#rO@VkHy zTgUl><9j#oQsDOhZvcKT@HFuIfS&>Ue&DwPUkv;{;12?S1NcM0{|fwJ;E{EmKR8}X zfENIN1o&j&e+1qN{88WwfjAafPVn|3E-=)=lsF;KM8yr;7e--#!z`q6lHt^xYoIlu>cYs#{=kJcwc1{4!cIsjrnGO71 z&~q4Y)-#R&q0ePLF7IK#9ysgYTuD<|0?sPttl)g{sgEzweAoug_bmIK^Q-!|6gYoZ zsK-$|1LttJ*U!ub&hm2a{b4>nM~`PN_Ho{8!k?>wv;Jv{(%DJif6g}^@qeiiV40DlblN5DS-{xR@XH*)@9`~L}i8{nS+ zp9=h6z*~WT3Vb2(&w!r_oYP;%REvOr4)V_e{{r}Hz*$eb{_acQUxNIw;m#i%->-mg z4xIIL>+dRoe+}{zfU|sBf4492Z$SQF;NJqj82ER<7X$w{@OOa!2Y6&-=MRq8_rO;J z&UVh%-)#f@2at~fXZbVqch$gu1o=IHv-~;wyKdk=f&3}JBie`Y*NcG5U1ZGf0?zs` zU`U@=fy+DAnZFC1<*#SRpG}+}oIWc+xT^tYdFfk>0lp&0R|A)KqOs<7;IdbN`3b;R z0X^3Nm%CnB{z>4gf&9n7R|ozTaJK(BRzja)n>s%^zH5MdDR9{<&XPL=XFbwZ?F;-D zpyy!V^3D;~b20F>L4GlCIs3!%?*LyHpcbd4j{h>_*mf20xtsoDR6lw8tY%Dfd6&uF9!Ld0)^H5X9@6H;BtnJCA)!_f&3}J z<;)1nF9I%mN}1mUobyZS%&WjFLI1bF#{pk%1U*b2t}m=-ivF$u_^&{ITi`5Tr@yNP zz9Y!D1K$bw3BY#-ejV^#fIkU*SKuE59}j%ZLNbm%9Ipw$HvrD|pRB(t1wIkvYk^M& z-VI#NLUMSg0GG66z6iLyQ;+$xz^8)#Z-G|<-)tm5<-}_m@U4JzyspvTO$I(4 z_+!9l0sp`9&IP`T>e~PDS!z*H(Z+YG)JBV#6JEh*fCLkH#Uv^!^&}(*5(!C64j6o* zMN3<%*rG+H7A;z|sHswo*4k82(Ne{V79ZDgz0^{rmRf4LUT^Pz?b&P2S+nQ2GqWL4 z+W&k$y-+b3z`~8@i%_7{tS4-K`@5}11_W$|f{CpAa@9|dWm5J~R#rX{)e5wdv zAj183fvM}P5aIqaT~+uR5uOy+*&@PgM0o$>luFxQE5Zvz_%sn-A;RlKc&iAn7vYOU zcuItKityT!g1Z_!T02u?W9Xgs&3eSBdcTBK&F*zD-eWpC`iSi|}P4{5lc7T7+LO!Z(TVZ;0?cc|vA)GIxOp zA0)!RDZ)!c__suOy$Jud2%j&)7mD!ZBK$id{C*Lx+Ltc=ZLJ8uL7cxug!^r*@_hfn z>aVVU7K!r*i}0I7_yiIDT@l_S!oMfN7mD!3B7CI?zgdK@72&st@K;5+itk4LZL0|X zzBqrtiC(n4c5R6WFA(9kitq{%ewzqy72&sw@I@kgsR-{B;Xe@J>qPh+B7Ca||DgyU zFeGdLG7(-N!tWH}6(amD5q`c1SAN^XzjcW4ABppqi16hiyi0`NEy6d6@Own~o+oAP z|FH-kB*IsS@DdSzuL!Rf;eH=VU3tC;|A{z%xd>k=!dHv%`$hOB5&nP(-?JcV|AQiY zkO=P-;Uyycry{&wgg+$0=Zo-%Mfh?NzDk6z7U4e=;hRMGBO-jyMArUCMfe~Q?$;UW z%n}j)m^i;)gg-9A=Zo;4i}2+l{0R}hT7>^Xgl`hzPm1t83$ynBQiKl@;oTyq!ut=++W(vgA1uPxi0}y_{CN@HB*I@1 z;R{9huSNJu5x!Q0uNC3H5#g_ja8*BS=ij!8@E67T1BYef^^yo5Cc@W=@M;nMvItL$ z@ZXB?D@C}nXP|0u=~yPhUlHebi}3X#e4_||RfPKwE>V|#O@!wS_b^_2@jDS-EW$U4 z@EQ^Rx(J^q!ru_#%S8B_BD`CKza_#qitzss;r@eBl>Kju@VpUO`+qOOj~C&}pQp1w z%S5=}mZ~c>i17au*I6LK-x1*}MEHM+@HHabZ*$c3H;eE;i1Yi8RKMze$h#uEK!pEM zgjb00%_6*2g#Sr|FB0K@7U7*D`~wlbPK0k2;af%cUq$$UqOASfM0kM+|GNmU5aB9G z5_@ZXs|ZhUTB%`);EB7CGcze0o; ziSYA9xXN#1__q!bK1!UwM1-Fr!n;Jce=oDLXM+eoL!7@|gpU^CxhE@?&R4!I>i@zX(^? z8MKEArFl*fK3iO8s|fe+{a5D?I9>hKez;VeUm(I&aOOUdA?CXoL zTU)BBc1Swak^qx20-lC5oz2>FSnrZPS>!=~VlK##xQ&(#FON zYf`MM6eh;DG`G*5m8vgoPB*rtCZ^ikYiFcN$>xkBRD5GyY;0j^#iXi4GBN6cR9nl~ zme#q#-qMIG7Bx1fQ*F()O{1z?%A3KJ<{;#G*7Fl^oqXH>nb8RB~dnwyuu6qg>-B)cELAD5DHZj+@(6g;FH9ggqYObRqL^VA9-Qhy!8^_6~>b5bnr_C9_*8MQhVu;j+efWMzu3*WU9TT= zZ7r?v@|b@mKi6g*GyL4zrbbH=O3Nt!rqW4jw#nh86^Rk5o=r}pG~lpo<_V=w5uK=Y zqJ;>Zl_>O2OSYyxSNTSVPaT=HzoNx!VJQz(=%VhTs+*(S6H1n_mx`uQ41Bx7Nu6zQ zxW0)|Q(J2$zL?H|VOFMFpql!0t!l<6*0vTV&P=7pG&a|^%`H_GbV;ZNwVJe}7YsNW zUu0-)n=R819oy8HYEDx>OB``7MzqOt+BZ=-B{a{oW&kY zPH(E6;dO#~a(K~Ls<)d`s?T%w?9}X3b?uDkR6?SHP?q!Zc-Dy{$2B%J`N=!Ft*v&h zYRS??vt~D?8)wzFmhVVErD|ldDm|=;+T(KiT1vea`fqD(V_W%n^%Dh^mR8KFtQtcN zW*~7Bh3BVDlg6N=4(S=4fwF7o%Zz zPj$t}Y{ujfS!9Mxgf)(qgDV6rwxmu%8>_2imG#FqwU|S?U=2khY_H%Mk_44~Rjp^P zp(;8jD2lPu1%eUoA&CkL{UmCelWJ2I_dIOO<`0W7F`_CJyws;uWvF3mlDiFXG#Y6- z^7;DNnW~!ut88akVidTRnzKnJg6)2UZ|sI4_c)sw%Q>92bSYBNa?F#a zkY?Dt0-3!Obc}MAQwB1xiaZp~K#ZVPeX?cf8_KCBDCouLPOV?cd%g}%%wej6NEB40 z+NQU(&6?cWu6$RJOcePQN1CSe=*QZ+6lE>{8oINSiHLWRVRdvRSr?*{3hOQjpOP4= zD;4f2C%n0XU`r{gSiid)&=e*@jcAhE+(=eop}m{zM>g0hjH+y{qyASzOT9N9t5ega zBPpzUZmaT8I74K-)T2^$eQEqj6Vs`BH3*~LZ;~>0Lv3?&swtZUJrfc`wPj_s&Gk*G zw&;$#aeicd#0ulgY4`gwECGTg$Uu63$fcTubb!!x9|R zMcIMR2S$WWjB5dTt#bU(Z0}bOIFpyC5ofYCO_ONTX4BG055t5|q+(w(Mm&aBG|jG? zY2*oA~n#Fc`A6I&WiQy?uY z@E49I&rWAny5d=kwed{0Xg!<#qzNq`k%O@=F>G{GQ_H38qnjFOSp+1N9=?yPP|JII zVzx3>TklQJdVMi58%ue^Uee=U0p!)NG^#k;6!9(|PJWvchE1YbuF{H%@pCF@F*9&= zZnMLdjA-|ku|j3S#uzcCwr=J*t)*hM)OPBys+o;}6Rk#!Qd6yCTV^+V{e^(x;fs6I zL~1@hl;CO!H(rwWe2rKJxFov9fdXZVT}hlo*H`ruJ)GvYi-RNtDWk96L&_uy8d9pT zwzM_Xk36$2m7-oMbtKcXr)7FeAjWZ2;mF5O6&9sBT2pO}vuI|3CS7aW=Qh_Ry=i;Z zb>1;cBCZ*z|RSq#5q|rc&D8QD`or(q!~>UjHv2H)oP}DSrf6S_;xM7EDEOl%Dsa0h7VV z4pC{Ing?RR&KsHAQ_~U^)n1|dEo-d!s#RgNRl&Zr6lL=$8k*Lnl5Mk_)ta%N0!9-P z%a&0p$s6k`=}HyDboVn*Y}Ft#&=>X6zopG=&tk!bDvUok$m|(vYN2s*xS=p&gEGBQ zyMcm6L&(BpQVt?LL%}$5!lY5jhmh69tu)4x8Rc`zI=^hKIA0SnJ!dYY*kE8GePN zCQ(KvE2q)szEmnn>v?Up>6W(a8lX-)RU@fw8fyPcDaE<8v{~(o3R}3Nmun4oB+0O0 znW9;z`kLiEmqD2Jj@QuTI8<16ewB52Hra<8$xc5}5G8xN+6QQkbw3sKh`P*Hra)i% zQ-Kew3+Ktgp_x2cN2|+elr!B6c4^g!Ox9If=K^u9O7|tSwH2jopAu1#a^1!_wy?aS zVNPi&Rd!TMjISDMdQBC0Y8bOEC~qAt=ZYgdA=_gio-nPTRQ)T(6+*%6=0>Xg^>nXS z0cLta#!POhsy^yd(`#vO1Z^RqE=sE0tGFme)J{{BDp1{>=mi3-hepgv)#-}0M?`p9 z6~$vH5+l8BGut|HB>t>dp zRars#n=0ZtC9RXIDWhlF{9&_N=A_Ci1D%@C=%#eC+9^MxEu~IY4W+lkF;!ljEFG3s zOC6J`2!-mLp2kaF*GiQ*(~w|?Dh4>zF*VB0h_SV4Z>m+TVR_Cl;+h>qP|j0MnnNC% zT&;G|`aKCl;Sv0iM`5Yxe8(uBf}Usgd7QaGjZXnS#24R>r#5g&R8y2J>Lp1 zd0fQEAk|Iev)Vu|FaQSktcv<4^1)FO~)De%FZ2r*NFDI%8H8C|S zIlZ}jVjy+=>A}pXY+SI)Av=cBK8nDCvNuShb@0$2jlu%nDIHs0=oL_n_HGm@uPRAS zn3kZ*m%ap3rYb#RmbNi$1YJ68gseuw)(kVOnMA#TP;{xn$$EzJI@RG-XJ+d<`jsYF zF0E~=FOL|_mQpoYiQ5I@a>J0RLj%|KGNc*3o~}pLvTkVL^~MJh*zikFmyIwp;O#&< z_YieqYM>Gc6jw9LNm3}qC`ZD~K%G1zu5>1a1uUgb6peVZDNacv)mYWs zd41qu#?INpOsHa_*PPC_0Cz~wcjm13EK|!VJE-gIR>>Hjx znGzbg^bO9RUoo^DF8mJX!(gn;y)ojYw9t((YKA6QR8?>PEYWsS!$< ziPR;{+#a&i*BegPtF5nB-CVMx)w|`+Z&lQ!K{n&4a^-mITy_Jxo*FT8mf9rk=PaH~ zQJbXg^CzE$HQ76)0?z)doCEWv>L*(>=8hzs8j$vwb6xWSb>k;e2BR6Ew%K)Qnv0;S z*qe(ms$vzBzLL3lhWO$<*a)og^Ci%2$lJ$|EpH@0z+g_a2k%Tz>f0aP3;^+-?S z_L$};667DAVF}!zrIN&qaL-LZ#50!`fB#+1~wJJi%zDUEgFsld|*mmdf9u zdOv_Mn!-@-232gF_9Ap0dy~=A#OknibrWe1fmM74K!Abn#!~^ zec?>uesNJ51#Guo38atx-0=1a~5Hfy>MTL?qZUk;GT+LQvLhI zI4Ym@&ZIwe`Mmj<9iE7%3QSGv7?oHsaeBwp5td!Y)K}|a!yiQutr?pJhL;N57f^Q6 zm-Ltj?Mov<+1WGoL?6GS>_wobIsD*UYhbRi`O;GFFDjYDa< zW)gM#>FcoU*WuZ(Bj_vIlGkIl+!ai=czFklJgqKxkBSSfj49tGGph&Q4WZWcR&(KQ zXDT4Qbz8L>esxAYSej<@*4Xs?%BQ#(=q>tD&E+lo34@FW$j zPt2~?1S;Fms!4d!a5!2tjJHlyT9}~WUvo=ZKWHwQY5Qn(u(WiVS{l!|m8PiuZ6iBw zE3HyED~$~;QFG-E~4nRu_<0jMUqtU(Fh0{o_GI0qFCJ*%j%V`5_f)@XD0Zz8itv_^QK}&c~kmyi;sw=>% zt6G{ZzJ0d*S(R*SoY6qr*FAsuJFnHMpjY{3>W@A$fY!9>Svu1{GrpRN;QhWvaTSY( zUi%i@biQM&%~YLDOwv7XskY=aS}v{kylyUe(XzB9G4vFX-z=#asvX%YpSlF@l@BbF z_F9Z-hA}xaHCH|OPL(&1zXEQjv-BFhE^7gwtK}Ff6tui=^cHr+32J~A%OY``&4?te z63~N&X_1?@0MWztdR{kI%PC@}%TKnx-Po<-71Px*W40p;uj(;vBI_rCRMP@U1UtRcl1FtH9g4Tj}kLG29xxTog0L z-u4W=NjzidqUULiFe=roURpu&pin#;+mpKE z)zmoCyFH5Pg~9}ddf7A6?QEorm8&~rNmb!INndCrNe2H>}<;XnSL5=86B4$ z#b+X2F>YF5!iXvn+N}&{B;w4RnRk!+PI1EYnbXGDokl+ar;SNgO@L0DLw*wJJUKWc z6US3(N4YHiSx-e>yU*N18~SZ|O6~Oz=c%#Ds)^D)nY%v>cl2<_1NGM|JGT4*2fmY} z=S?F{LnSoR8FBeu7$zCj7C`+A&y-@^9A+tYhdro>{2!DKS?R6A5u54ZFnc ztUGyO{p7hxEq-d5gI21z#8h(VcHO!;(^Qwq@4^Lh+`nDsp?N*^JoQWH#Zoiq$xXp3 zStrEKZa=VXjN0kzS{7q7IkLABYnNH%k1Xj%j2(-luGegvDt2s<-)8a-u9zoA(qpIE z(rROn_iQ?PRhl`zQN8Ye-L*)1=AyG`#DjiQQyrh-HiNn*nv|xQGqnqQRFd9kLVdlG>bj;P8k2YnvGr+sVn}PX zH<3PTdV6bKQ>Ld^oh+T+>IqsWSCtukTGdkpug@!23j?Fn{4rgBdJE0hRVU4=*QS(< z$Dif~2W;c6TGG_bq;*X#>S0vUk(3X;<>r5bBBqwqc`_pyM~50D*b@qlS@5W%cQ!zj zavw_$|EQ>B7A1S}uHwL|Cs^M#>Y~0ef?n36?%Ad32>Xhl-``ZVVc>RYe|=jgPhcI^ zo9x$Xv2r0+OgiqsLaDlsh3?=D-m(|-lI|;trQYG*KQ1@xugPqI78;f8`bL# zIUc$rkaP^=f$k-P;j?PtFXiQL*}D_3AtL(%E$o9q$=Vy)7f zy$-Kest#~rl5dps*66(lr;$_q$?x7-ckrG~=q+Q0r}D^v$UGii&+H+ak5~Cz)s68p zy7EKs+|t(5qv6P=K3jwf@^8&sTWDFZVO$eH}a!e?JK2) zXw`1&^-j!UtE~lrcZZrKhpJgPbpPze z-*gW_c3#@cMP5IhUW3^(o!-g16E{BW%*_N;+$%%#9%>lHQzzw><3Gi_M$Bm()dx^3 z%ib&w-Jai0Pkp5aZ=S`Q`1H!#WSSJ98}F;mGAb?-?_ya1O%wISsM#2>Mvt2*``I5D zp!`O_$j0?pROtow}p zqSOTlj(F%21<5jcff7ITi}t`qjVZlB0jPDuChp9BS~aq7AiHReYJ^d|2xRsP5^DY3 z)fZ=}`BUpCczAXc46<0Cb&7yvMb7RsY+!s?p}W!?Z7*F#i$VY2`O%T;Fqe8wfcXex z)dcVuw0Fk&9xB|s1VswvSBE}cHp`9=nJQVt-) z4b{%q4r*!+&yyLAV6T_*50mnZ0YS6 zB4?V7v$q6MnyoTJ3Bb!1qv(;)jdah}W!}A=)orzn>GmG?9nC4tNN5pn{3P>DnIrw} zJ>HX2rgR~G6(%T4b)u>K_OR?DQKdW2`D zM^DcNOwCXaTJNc^KQeT>+JvBN&0e&CX2f@5+(6zL(MCI&TW0aAO|m9>%SwKeN+}!c zo5!kv%pSl0JcM8~6})iFPQNIvYT0nds;l6>IP)bdRAmW@dS8{*8^GvrkWL*H(htNX0`p6!-}w}TW?b_IO|&oip((7$=(&_3%psCzg{ zX|~zFlcPjE1ihEjmTIA1%9G)AcgU8wklNcudOH!lr9cn+{5%sX`6{p5FJWZzup{(D z%7`;l&D5Bxx5s-es(PIS-6tj9q^#fgS{gtZ54-msGLvmvcC2}wBn!n3RQ0Mrn_CS+ zKEnxN6meKvX6p;OTO=}1?PMP`Jm9ZNH`9ESiVqb{+smoKc@))6-oSyLB169!0|J`Y zGK-*bMlV{R-&N-4ZeUF>vg*N&Yt)X8%{=nE*Bq<*JbK;Ae@3kzLxl*;s>RBS;Uv{{ zgIjjAj1r7|4_L7(p~%Zv#tc>I)Fq#Go~8*||D`IumgYTm&}kJDbYJu&^*yZYtYB_1hok1aIVvAL+>F)3#94|D)^ZpYklVZ)@?0A)RXX=h9objKG(?E#+@Gi-DqlY z{9p4fHh=xy5_{BZ&TK~J5@eBrwyxLTuH;+q*XW-H6U?lBD%k98R~Cn(wDRsJO%w%Q z5nrp`p=Wx|Neo=zrr+_n_;y=-;HAV4-sI$8I*^%m@LIq_J7Zc&q{D()(5R+%fg93% z=k}Ct|Gsw+qS$9!mz}*M(|UDODCzm7>Dkk~yZENlt9ExrTL|hE+VjJY#h-S~=#@MPXx0V$=nxwwAH9RkXahb#}TcO>YjFg)U%r01}~>e8w@h=*+g( zx(SWb+SH3^>4B0n=y^ghbiG~<_})_edQjC@p}RTLv)jEJPvrxo^;4sVs|QFAr#ZVx z)SaZS-czIF*xggdAe-AWu`?&HfoG5kyu1P#hovp_K(&;5%<0*)Q?pambn`W)(o`ONv*zX6a+&3>pRfW## z>b^t5T#edDS&<1lqfU)|ef^Y|pcBx=Gv~o8?@WghrN9n$b!|0h&n0LV>5_`n{a5Tk zgA&_Y_3|$B^bM3%d%YFfrDAI@?Y%KlFtdDbToYPstVg)8O zGfwEO&O%?jWvr(r+4iuk(!{WFjr4FTdb)0_@EyEtVwCDYnhWswv6?%G7(wky zV|##0lC7hSkrv75Hb z_@H<4FjZ&#EN;ggNV|+5;uQhMvRb68>&dO95xsxM>kc1XU#~7IyVK#ZMIv(#UHseb z5(&C(+rPCyzj!uqcb)xK0i(gEou}eC+qx#nv{r$86GHE1-KqQ7)Z6K3!I*BcRc{&z zy(ZJ>zz!W-o33kUY@RW0c5|Itkmb&B`2}8AS?xFs^p=A+Eru+gM4JYUTP?hxz$;jH ztWWOs$OHFnWcLi>&R}m<*S*lm4&NSOG%bGqkNJ3?fIq3XpXmqn^oaW2^2aVyWhI8G zr? zLU+jVJb$1SGOF!BO&h++Ja#h}Y;XK>*BjMbltOUJMlg%*sIIqK$6n|y#N5i^7pAz4SWjNtfosKB zIw`bt6?(Fy2Tcs3Z1+?<+!G0$>qt-=HRBTaTt|Z1{~4FS=Q6XOL_RSfA$m|N%ATJps4ZnUw_eurg=LtoKui9q^@O_dT)Ks5PG+2YRH+B&N-1D zj#@X9^{IyBbhXZ#Gh{|v%k0*iojrDYBPZtoaFJpT>&KsO?v;~sH2vF?|L=d=^kqPw z=b*0u`Y$=?r?9?1e=7TrbT`_1o#si>>mvD6CL!!fc=vk z^u<75;h>+udYON}>EOSqfd4HAeFN)d{yEpd{#Kwr&q3b-?4RPGpAY!oc8LE%z+dQ~ zU&4Bse&2D>uK@g7hxo4o`e_dOZr026uXE6^0s49e{W_peIp{Zl_)mAxZvy-o4*D%X z-{7F%2J|;LO{ZX`k%J)+XU>t-+|u&^ba`b=L7wN4*Er`m-Tn2gMJz7W&U}{LB9g%A9m1p0{ton zeHYOG%t7A`^p7~`*8u&a4*GRKf2%|O-N1TT|J~-G-^6;^f4kj5za8+GI_UT00xIqQ zfrEYk>!tm7IOqof{#u9hD**Z*I`B_reXedsz5cW6lW}n7(^h{~1O1&2`X<)P`r|GK z{S~a2>Gzg{{}!-b)<17J=obP0j~wh@%6gf9mOJP>0sn3X{S$zHkAr?4>!ttx)?O2R-g`)gkTQ*FnDl=pS^je-rCv z`B8HkT&-n3ZSAirtLl*HcZh@iDzB?U#{Y{B`hIk-sUPT|SLd4gLml*aK>t$*{|yHE zhaB`pK>x6Vz69u3Ip`~Z{$~#QsX+gTgT4XiA9c{DfnLqY#m)coSTFN`Ifcd5F97^D zDid+_i-Eq~LB9;xuiBKj{1t#d$3ede=pS?Ne>c!S?x0@_^z$9;-vIR2JLoq7{Wl!+ zTUjsj-vS5ycEJCZgMQD?h3n66I_L)g{m&iJ?+B!K;O7JV6At`gK>rH|eKF8K>7btg z^uKh_PXT&Wr^YS+^+5j{2miOSUgqBe9rzu9uhvB3+CLxga~=2#0sk-u{Sv@G+(Ew# z@PFkH|CNA0)PcVW@Sk$vcLV(}2mV^1AK{?i0Q9O)6*vEE0{W*N;=dK>Pj}#d!g^VL zu5r-s$wH~W)U0o{dS;V=b+znA6DkmcK&#f#N+y}8|c63pkE90-*V7z0Qxr^{J)9yGW|Ys;BNu? ze>mv30sT!5`cFXozw4my_XS=5%J_fJK|g@?vi?jvi0{wqD*xvy3KXBluf&LB${XC$5+rj>YK>vFO{Su&G z?qL6NpufjK-wE_TcF;co^lD8pZuwoqdRc#LbnxFgz`xId{}#~y#6iCq=vO-Ew*meA z4tjs%h4kM84*Gsv@yh!5K?nUnpzn0h=K=l04*J1B|1$@D5$mP@4xu^uxcRpj@E>#F zPXPQcI`FFj|8WO?4dCZG@EZXC=MMZd;Qzuwe+A(Gr$ha*0O)_^z+VjX?>O+60sVhD z=vM;0x+g1c{_O(#R~+KMn)R~$tas3_1^QPV^y`8BzjM%U1pL<>^qW~P$FF~I@c$>k z{&yYp{q_ydAOF!oKM?5ufCy4+5Iq07N z`ppjIe+|&@?$G|P2l_o6^c#WxPY(8PVZBWM_Z;-w0KcDu{W<%E>)+2i==%fxJ`Va^ zpnu;X{)2#iUk82x>!ttqbI=z7zS>h5xBpTC^anWTD}eq$2mMr_KgdDf0Q3VL^l6|! z*g-!J=(jlJpM^kwxC4I)(Er(izZ~d~ao~3X{Z}0HPq1F*f3+tyZvI^j_{Tfw*8%+r z4*Iu%{;Ll9%|JicLBEal(tjs9=syAclN|K@_7B(JYEN+7^cx8DA2{USJl4zj|HVO{ z5BMiL*gp*DPjS!}1N+r8J>vSW4Dioz;8z2_+LIlZKNavtJLnsLevE@Y4fKC?@ZUV3 zALqbd$a{XS0KeRUzY6I8=D_a;`tc6@wLm|?LB9d$w>j9q ziS;u5|L&mQ0{9gU_HPIJN(cR(eB-0Ezsf=1pY=QqecF^Yn{W%W$LBRfV9rS~N z{yYc$Frfd)A^lGU`U@TSC9IeJpX#8m0Q`#_^iu%;9}e-a2mD$GeiPuUdvfBoUmbuy z-9bMO@Mk#a7XrR|CRbeh7X$rF2mVrEf0KiL1>nze(02lTi-W!k*#F-S{#y<7Z4Uf( z!2a0|`VBze?x5cY>`y!Bw*dYe2mLm{|JcF*{zLI)`}02z`hNUSeOdoq;b8wj)=U1C z4*DYi{}TuM^8x>V9rOi2f31W4MZo^+9P}lCukI;~TYpUe{C_&ce+tn5pM$<0=+!d~ z(4Xd@UkUU#IOw}rFV_$Ebcp|2z~9G# zzX9;~a^PiHY#zr7vo&t<)=f8TN74+8qP9rOi2|E7cfRG|Mq zhx@n7fPN1Lel^g4R&~F2L^-O}e?SIZe zy8e{$f7wCbkM*+t{Jw*JAmIPjL4O3`t7j_2jekDizv7@T0Q@^0^rr&;dIx<8;NR<@ zuK@g49rRNG|9%I3J>b9Lpl<^FpE~F}0RJrq{XD?`frEY_;Qxn%elg%b?4Vx;_-{Mt zR{;Jh2mLC*|Gk6$3BdoEgMJO*Z*Vd0 z_vDVdY=6`o2;{aG*DpT`~axq$x%2YnvkKjEMs4D?Sq=!<~;n;rDUfd90EegfeC z$w6NY_^TcCHGuz~gT4XqpK;Kq0snmm{S|<}*g?Ml=x=t=F9!DC;-Fs&_#ZmxR{;Iz z9LDdfSkE8c`dvQ<{Tjf(-NF9#K)=F4zY*w{JLtCn{oM}w?LdEzgMQD0!~19MbI=a} z`ky%Hk6^uQKUO;E2Lb*A4*CM1f6zgHDzLxPL0X~G5+s_K1|Eq(3D$s9t&^G}6 z-yHO5p#RuGKM&|X?@)g%1o}@L_)AzX^Y8yT=$8S#dYE(E^j`t=yE*7Pfqr)feHYO0 z;h^sZdi6}axba^D^m{qz*8%VB| z{S?4I$ie;^z<ff6f=f z?Z;XNet*^zGE;vZ>A)Wd_`h`E=K;NXrgGf)4+i%C%0WL2@c-zbF9!Uh9Q;=X_=h{_ zs{#LL2mMsQ|0-C2%%j|)UKLGCi-Dto^*0(n&=#J+aX9@?rD<^>G$&_@+AKrIW@4&C zwciJmn4;hv{(Fs%qyH(sK3o5${{G|0?05N%Uu&HS8cg5RHEnwHeDnVa(yA~sUO7im zARYd5;Pn4;a`OBy{5gs~m40vI0u}lCgd_Mo|HI@@qaTpIiS@h;>dU=zGykD4trq=N ztmkd$8HvfC&wA5;i&)<;qtsu_|6fhPDE*7oWECBLI;-?Q5~TkvbPkID66UM?ArHgN zIXBUd9^d$33g90N_-~OO@t3;*0b3BQWejV$dmB!O|Q$L8r$o^Kgzl`{fQZ+ z{$gNq{$R1cLrr$jA@ko?fc+{@Dw|Axn)!Sio_8(v$K;=3(O(-=Kh2_F#CooVt^8{( z`W37nkx}X|ru}!Z-b}x@S+DY@Jk0b{&s0VJdx!PD|NU#2e6^<-=|5(@s$b<{>iv5< zij5x@arzgqSmoc7=$wB1f8VadD4QVuu&?S9$4NMSH!wK|lOC1dZop3f{#6$KWz3%w z!Jlj4Z)JWB>s9=R0{%wko9Vxm`MixhV}+UilPL1Ye>tjQro+^m{_C*l2e3Y>{I`=H z`M+WxiWnV!I;;4P1o2;K;h!Fp|6>ck0q{ow{+kwl6Z3f*%8QHoWBTtO7X7s`?LV6Q zg3_;(^}{n{{l(-TMtU+K$1H#IK>SYw@h`UU-(@~;qs>@h^6M@7?W~V#zi+VU_u-89 zXoigA@4r*ZjQHm$S zN9n&2@Jj*zpUgMwpVNkDu)4N9%=qW;jq~pq)}JiJ^xd@oSkfc=2Yf--AJTti!2Zz| z{uRvUZeYd=ldsDsY%~89bNp*qujx6`*)`?InuYW-tYhV7clkzOMH}m%Ru@~2KEVKc#0T@I$@ib> zVES(z;GYfnXEWc-|NmruRQ|ulV*l=(aVJOE@86SU+Mm-uod2tV{c2ApO210xkBQ*> zdjd>;0pOnt_-alP@fR~cD*yf6qQ8&zLnG{0bBc)nHtVDM?_(|ck60hoe?Oh{DF4^6 z|78E?Lg2rvEd0T0VuX&U_E){<2gUz%*6*h;lle;~1df+1`U$K*EO2(X{@#n;vw-;1 zW7@CYlY;aetp9QZ{}j?A|91fY*8=}HS@?G_|FQ`F3=4k|^J`eI>hC(h{}%Jj`X{$g z3kMi{^Bl>h0#e)XOYlzvl~f3vQ}to&Cj{Jed&Z~z;u z{MP{ZNA9EfrvLuT9p^(cWc|hTUo-2?`G>u^;79de@381|Ssyiix|Q@O{}$}8<1g!v zCJ_HGd;$A^9P__p#Gl=n2`#ti*R$UApQ%^RiAVOA0sC8k{a0D|A29#8jHUXE$)9WC z*D#-}ac}vCfTR3( zI`gC2zjG}5ikSNETlCXd-xd*n^_&o7|9aLR5~0sM0PEjlJvT#{tB?x=$3dh=`F{h* zf8PfFKik63J6&U*575HpUp*%R@%tU5%U?I^Rr-Gi@cUB&Bmcd}{DJC6ahUP{9O)5% z4f6|FtN1qpewBs)&oi{JQn1xmlRwGA-wyaU0sf5^enqhcN9CVqE&A!K&)1j9{59=Y z_lY9^-@y7CGD`i$)E`TFzApWx~{3AwdUX=YSE&3AH9~)u+A1wL?)-R6G zZ?wd}nBy<=->o426X`w$YugfpJF|^Cvcejk1hJwSWiC(4pU!96&&*4 z7S>buB5;`cnHK#gtREUshy8!IMPG2H7EX=OFC#rFfB9bw*MIkt@n--1b2LGS;=hpj zheq&sCq3d91O86{f24(f5A%Qg-r&;(50RKV2Ut{5) zP^Q5=jLcX;mk1nBTligo|5L!Y$_i_g&^krT-qJ zNBJ)|SLc73{yzi!d<(ye`6oog|5yvZjQRAlcc}XRQNVAp@ZVv6RR8B<3%`c>-GcuZ z;NNcHx0Y+6+FvIRxVkSPBic9ypCY-ucgH~se|(xd!4Ky3`7qsIHI_pf#X{#nd7 z{Wp{OQU1HyVt*^^qx^T7#r{^dU;6K9VE+mW{}$#y$?^9;O#l7J!e7Sx4Z?rV0RCT? zZ~Cu#ycU}MA2a`*NfUG^{in13XhUGyKZf)u{W}iV>7U1XResh0`xjaG*H6&)AMQJj zKTZCxE&97yPwojErv6!r{Y#F}_EYil4rRZ3e|)BgXm*uUl&oquXruhLJwKh3m%KU&~XHktN6#r&x9 zU&?y3{6EY3sPbP-dgT9np7@jHU%h|Gw7=ED-@<%<{?B)#>A#s4{uJiR^jGiyG5L2{ z_*2i*#8-_3H~BxX@H+*qx>_E`7-~g_g|R)n`Pn8j~V|43%?V@U%mgpnr=CA=`fsI${{izy1*{FX zzdyF{2OOvKugpK{CR3CDo`s)(fd)sFzx-pc|4(N9NrwHq8UH_)^vHk3Y<~@(uj+sG z{CU&>^M4(nh0|}5h2O<|Isc%Zzh=h& zbI0QL@9YaT*v$W?|F2`c+5XkAJ}Uj6v*_DcKQ1EvPmvy_|Dvz#;VH{lul%pJq?_?S zU=YrKUCckh;G6O9PkO}Pz16(?5&Qw9S8*yf_+5a12;iqJ{4LCe>32#DOHodKLJz`G1I@0`G*H$AFe<5AwBYc z&Itsg!_TLx{!mj|CV#wzKZ*J0MDWL1__@rN?e9^5Kg+^j9y9(87JeCse;(j(xA41T z^8aSx*8sj6(wY7r_Z6J}Z!$k>|H2H5e(z~I;V63s4zv7BBR$GL9l(Cor8Dh++QJ{q z{KEqDaQ=PL!e0dVs!1^UhvZ}bjbr{X5&V=z-@tmBUI`q#2mVLvOQc8sTLJ7>L8kqk z7XJ0jH`{NM{}T(p8}J7M{x%E0llf8g|6eTp4S+uc@J~G+r{5OlN9CW9q(}bW3it(p z|EPt(cb!h?DE>nhe!s60j1F1<76Se-O5ok-JhT4Ki^)HU^eFy$fIkfI@3ZhvX8ti= zEV6&h{Fg@+6taIR>&^Ph)E`bKAp47e{Ud?>H(B@#m>*Ss7h3ogfIkZG_ZW=he-HCJ zvaa*KneqRph2Ow@U$5HlQvm;53;(Ek4UWpcXOkZJeau^@Z|e`fl2PBk7U<%1$I> z>5%>J3BdlRE&P3^d-9wp`}ZXPihnNaoAqTff6e&!BR#UegY93$N>%Z0ds|LCEZ|Fs4U-q!#c|IIm!^oXB-62a(Lp)cdze|jO{A2bZ}FK*Prk*xPW%>1(- z=@EY&^JV`18sI->;or&plYKCMn(<#{;co`~B;ZdNj^qC(^P}po@`OAr< zNBnN)%ltP3@UOM-*D!xJ+wXsv`Tt4_e*^Pn{nH5ei6R{T(`Ra8)cV1l7JUWlAM_39 zPt*RTq(}a%NQBd`3D`e?7T8ew1bQ`wxr$W7bFIpARkeF97ym3hclB6zso2v$W%)_}7pg`EMEE&jtL0 zXo3u--z4To<=_2CkN91He>vcP-NJ8TK2;Ba!z@2nS@`P!|4P9B4-0=e^A8Kq!{uj# zg})i_uLk^yr(yp;$$V;_1BV&^GSVae=L{tn9kTph1NaYE_}gN}|6U8ffcdii{5s$t za5|3vemwAs@_&EQqxhEr{&j%gYT@TIpSt&f!}R~-7X1aRj~c)H%wm5Huzvxt|Fko( z|K`Nx7m*(MuLJPE1^5qH_}^uIMZkOE@^in1zlixV|1JdlV~TP7-(miK5&Zis`mL-# z!O*L^QXY2~WB+vn|J?}e&l`>HKdePlj+8L^ZsxzkNsrQR1K{5T_}5zaBbjgd&y4>j zi@ucg)V&BCrvCS&NA_<8>Ax7*fB6{fzpI!Z)qc()J>uu7#RfWL{dEiAzi;8MV7_{0 zp*)QL=Dcg+7ct-8m!SGzO8|e_SRDUPF45Ge`tx?uqxg4>AQ&Ao{ON8M6Lj@^82ByO}TRzh!{` zXAA#Y=1+~_Z?^EaGGDGA+y(f9N^$zX&HS??_(zj|PddlX=l^P0R97j zf2W0iSX#&TIQ^0NYsP=6g}(ssI{{xk=R&oq=KNJL^P~EoFI)Is%$ND^A;90~Ow6Ck z{HXeOFVds*UkCWB0RI9D{|e?u<^OXm{LRd-;gnPP{}I5SKou17|FbdE|4h=O_?M~0 zdOBqO?*jbODT0WDlxI%NKP0`Si{3&;O$=6_pbGk;Bf1?f@z^O#@5N)`Vn0smVT{>5{(@E1B7R{nJs z{ygSyV7=mZ1OE8&IR0O`QX>z{ko6apSLCtOqCc7Shsu-byXn90lOFkRirQ>IhfKex zf&JSo{A%V?_6Qs%|1TDPEAwkut^D^4;J-To`|l3sN7di|NqQ9jbJ{rA5C{IwSTlB+fUB+ftnhha|6a~A%967ByQ7OMRB65t)3N!l;d(YE?sPX@xN~|Bq`ZM%pGJj3}(WFP|*UJ8r`DZ=w z-&PC1iut!^$oh-Pf8WAi#{5OBSLyc};IFB|@&ADN4@B^vCOwLOf!eG@hvciapdVk) zuUGG>#{8w%=o7!q=ldUK{<)L%h~Lfp8WyVfzXA9K=V1OJ+glZ+b_%CJHY-!reOQWFrTW&z+w9D0MaA=8s^LPYZKs?S@_>&e$@DT zg+;$Irv673`v<7aestt=>{a>sBe4I!E&OL=@~=4``+s9h{S~A~{?7;YzlZF%@IPjL z5y#*EFw=jVg4Dh!B{wXxUiTK^j zKRiGWk6%WR9>u>4@IM0l+b#UJm>)I&c#DO<4)C`F{+GUnR-k_!rjV_z(Jq2AktAlfTuXFJwJ+?*oVFzxPRx{I`Vdm-&AmVE;F#Vf(LVepLN4 zpY({o5%{k^;2%(j`74qW%{QUs`b_@Sm3*St?TP*wmXYJvon=C&A0Drf7 z9RH2XH}j8~{^b_^2duw1kb5*s29=PW%nGgF<+J@V{~Saon)S~|7XFk4ni6IIMJXKr z>8z*Wec&+Te?IAv{jI?MLxBBXosRikG3{Sq(LWp0{;!iB+1~~1KNQ%1)(mWa?l

IMzq?ziuKuvOi~hIR763?B8bLk7j;U`TvWBp9}a$0sf^8*nd-*e`p~0h1>r& z(xdnn0Dd0eue9*zF#q@n{*NvEGUm(n^BBPYPYZt;^B;-ezh&WfFu$Ais{b+w@Ly@f z{y+CyS{OC{c#-tT|3wpY{*&=P4)8}&1*z&3bNsWI`BC}*yB2*X>ks1i`yXcevDKnq z&HAYR=li5b@o(Vx%l7945dWiQ;`qPA{G)us`O~!jaN1{${FlQMmr>>C5Yi+2=K=dq z1opRE_=hpy?7x`yH(U5iK>j%i@PBRL7c)Pq{5)&nuVH>S`(2fv1mORI_W2_Jf5iOO zi1h0sJ@Ws8iMssM2>wvOZ*9i>=?k^6EP_9i^oYNi`Lg^D2mEyw{sYXX>CwPp_8)$2 z;pa}$@%Qal{vQeWT`f5NdwoY^PYBTUxiaWs(xdp-Fki-h6yVRJ1V-s!zj~9`XB44)-5U1N>Vo{Pi*UH(B_3fPV(y zpWKGy{{i!(^51aMqxcswU*^BjfPZ*9=9k`}6V7bE%=~`{=@EY(i2qo?|JcH>VSZHm z^>+(@3E-Ck{x@i!49b63GJkL;=j$(K{I4ZFihn2bW%)Z3@cYlk{Ck;i=6{p_InpEk zMiBpUz`w!5U(I}T{mv|ZFI)7lv3@_pf2RJ}IXM2CV(OP#^dGYRAj4rM|NEpz{@c#} zYhb;qza|0y?RP1*fA2*);$Mk~|K~}M_%&yT`=1qn-(umP$o#1MbFqcLi21VrR|)uA zE&MZM^53`cR{(xB;9p7&j7lQ2|2>WQX8mQRe;etM|GNSIT)_XWg?|v|LvLi~oD$L_`!@jl&jUv(Ld|6iCNm47FZ z9>qVeGTi=u4e(#L@b|e%8y?mFUvJ?T0e%wjPrn?;zkvD282&f&?MnaJDBu{-wphCCE)+U!oSGEH{;)B;co!^s{y}cK8}9}^N-^E=YN>_ z=M2)*Wkc(4TLJ$Xz`w!5zlHe+`e6PvB=MCgA(dNM0ye?RrGE;?lYWj>wQ z&kN1&E7<=!?7u%U|13V=|1j;}hxCYF#C%!*T@Uz87JlK)niw_ym|@{p0R95NUv1$} zV*Vk1#QD?AKl@*g{a4R=v;GSCkMziY4Z!|y1N-M%_*cc`r!D+>fd3u9|Eq<+g!xh9 zw}x+E|1D?zu@U~SBR%rp5@7!#VE<+d|2gJI)&J)$!1lk&dNco;>0e2DWPc~H|9imx zUt0KEnIDz^9=Gt<0RGK@e(uXpR)eC74Y|^bvhLP3z%=_AG7|r#iDOu{g?><-9&oizkIg8jP(&$NHOMZcQ$QRBC(NssJr1^)jbu>W9MXF~RW#QgIj{5OE~h`#{%?@qwK z#KNEWeGQJve@zztIuQRK0sh+-{*0LX*Dd_bfPXjOUqtIH$p6m=4{Bu6(k^ghf z3zxqi1O7u6{vFIeBqII)+oE3;(|_A6_U8io?*sNHZ@~V0k@+JG`<1WdaRKR({|W$q zCE&kh;qSRbQ_T9ym$+|C{OGkMzj@-N65k0{=H#_>*JW|ExuS5$mJsuU}d0-vI1?9N2#x%@ZL1 zUB>)@M*5ri_il^+2G-wi=uQ7GBR%r}Rs9&t1+f1t8Yd$APq|GCqw>$47JWJE zqw>#E(j)sfP6@Xk-N636sGp4NuV;Q#`MJQNZ;2WI`z-n^S+CytC=WCJ?j}8o|8|al zfp&v8f3zCJ{}k#cq4;c}PR^zl! z*MRt+Pwgy<|IeA9FP%@{P5Y}!kN8uVpDXw;0RC?*{7uZyGx(RGJ_V0Oz79J3x zzt^HanDym`-i-fp(xdpda{T4^<3$kv!>FD@_Fu&OsQP2RMc>5wsQUYA(j)u3K>EE5 z?Ek%mzkvCN82&TU??fu+DE@b_ew3j%{hv>IWdAyl|JMWi@3ioL7t{aww`2R?WqqY# zzZw5yNssK$`I;`jHLO?V_jkblYc2euA8KJ#{r$E@U&8vR@>97K$NyZ`508ldMAD=9 z*Kqu0{q-h@|AQ9(x0xSRevYMj2IaroSbs)@{YQ}=*}n+b|2DAyMhpK9=1+>?f6Kz} zX1=U{HUj?tSorzNH2B;I{zn#mzl*~8_Z`4*r*eY)e--l+5&UM-BmXxrU*?}pfd7Vt z-^u*rBlxdc_)C~C+rM`Kzkt#i#s3ZFA05H}D(O-DI{|+);4fkR9%jXKrv?`p{C>v& zzh~jEVg4dMU)5jl0sbw^bo@l_cv?-{Fj$ueoajN zTGAta7vO&Y_|?SOjchdMj~6iCZ2!z;noQ>*er}D9zbyY-0sq$){!`39j{WC3x=(*HElqxdgkehnM0^4~VVzk&It{|8XGI-<(|H!b|FApRc# z{)-m=$;^-P|MM1pUad}l>HqD3zu%9r|7)0E?0F&k$1H!JCq43i1@l+1RQdm7z#nJf zFJpdG{WIFa-_Cql|9k@YcQW5h{|(F^pN+crZFl4UOD+5b)AsPrtl{%j{Qn8~TP^%S z6t0f1>W|D{lmEVjznS?m{d33$KmGi6>5Sz#{VSLs<^PjOPtgjkzvtHN;n^(xzdPXn z)52d6lmFiq{tCd~6YxK|8^^ypCjTF#NAWMJ*YU66lvC-yH{f4z59V)YelhF)4?q3< z|DQv8#9zYv4n9%w`vLwf7Jd==RUP^IBlFkf-(=wrNa^^?{I?I_Z?*7im|vD5>n|q% zeG9*s`Q5Bn@$V1#U-~ij{|e?8v)=zO`A3i*`9Ej6j{ge5-w*JoSooV`@~bTT70j3E zKLGG=wea)r)`sW#5$8`c{);XAycs(FWvo;FKM?R=wD8Mf@}IZx8vuVG;O|Wdv>VxI z_CFh#A65VDMtYR~oy?c@-ywkiq=mmMX8a$s@QWM5{?7&c_bmKw=I2MG{~s*;1mxp|GSu9Bl6!7fPbNdpGWnII-=r#u7#i57_R@00{mMn{4(a} zYBMr_`(?iAFE?5EWy~+*^HurF1N@`!)BfMx=vdS+->*M>Y@YvxKUc8cEI%7qzrZ-( zwEst>N9nhS?ccz9W&g3j{@Z_Iv7hP%b-bfLGJo?j-}ILoR^t3uwnG0N<^OMz9@*b; zak%^)2khUQ7N}JH6Y@XvXBhV88UMeE^``&V#I%1d>5=`N!2aWb{SR2|-^hG({$hY( z|JxS(b0}Y{Bg+4;TkPKs>>mv5|H1><|EgY6hq?Z2+F!(a)BnXW?H@{dYw8t!uB^%y`l~? zznT9366ulsMYFX11^P1H`ezZa|7zx&_0K%!m$Bae$n(GO=LU=YYgivueqXWJ-@x|! zd{zIS0_;EZVeJ2n%=hE(n{C>E0qf23JAmpHbwv699MU8IcLM*P4(z|lVt*dSc9A*?-K>aQ&0VdNaOe z{c|Mgk^h&m{eJmV<@YRL|3%C<>z`ugoAY0JUaYczZnN0m%KH55sopo!{+liKuLJ&{ z2<%^Nv40u!4>kCvKR>Y8-yPHcf3n!0+Y+w-D}eonKZ48eI_5|9f67>Imfx+cUtq-F z^#54Wqx@6G_RIFS3fTX#h2KH_3U!$NHu-+H)%FP5&*k z=uP`ak{d~33Cu6hm(j-1Uz7j1gl=_RQ&m}#|KOL8c?Y|P(|D~rf|DVkNFoJ&s=@Gx^iZK6b zz(0O9=5M8XSshXBU*0oVzcex3T{~u0zWdC+x|FyvW4hw%E)hp^)q(3r$&Gc)x z@VlNmV`Qu_<6lL3=ii7_`hf2cU-0YU&I2%{}$k{eGbQeOt;2fAE1ZZpXW%A z;@^3-=F9eHA>enc!TdGMKRtrqPI|=8pQrh<|8)c4zh&X?{VNSVDuTb^d2Ih6)*l|B zzxf5MFJ}Gz5&AV2eMLSwf$m%;RZ=&xD-UO;*j{}uDK;VW3F_;&#Q8y5a7s#nz!75`T) z{EF)|U&enK;Lmyy$G?Eer8-9FkIY}w{|%%^@n7&w&6nwa7vTTd!k^CksQdpmTlmYE z?~mV<|Ca;)H8j9baWd!M8pyBe7@$8gfBR*==`UB19>ss%LLGlu|K9`nPcq+}|Cz`9 z!3HnS`2R;1eK+fu8t0q(AFadjuOYvxBP#xPkRHW9=R4u}-v{EqjrpPYGr!ogBKs#V z`_=naN&_U6e%&$cFD5;*zW~^OKd}EQ=9~6!WPZM3uWA3I7W?~Ax~e0}{|{O0uL1UV z0{b^x?9XF2LafV@&(cV7*!Y=1{$$j;Q>9 zGU-wN$-5z3|2zTgpKGx{kNL-IGctekGT-!@z{_jWif;yu7zn=8S|4V@Xp91zD@+!7JkNHvUUlr?3 z`zvDFKZ*3n{x!hNh^I5;aIN$7lc3JG-&h~e+ zUge)P!2Zi$)BZR4Q>k81$GiF?^Vj6hAwBY6*NwXTb+c0OUjY2meuw#Es9dPyVEvK# zYw|x}y_x<~SRa*t|3rFZf5)P5{qY-Me?BFU>VKH^-#q3=)gRMXZ`$7()BdlK9@)PF z*uM_gzvt`N{%+>ql<~a&l4tz?9@6heVcJ{SAE!{gpboRX^Z)OE-bs4Tetml8?*_I% zmqS$kc?H=2DBExPuO@=;gC6qvM#kC-_^$%~>&!3kFUX$_%skibG w=02@|e2cV41O4aeXEX08#pYMFzIkvk#=-yP - -#include -#include -#include -#include -#include -#include -#include -#include -// This is a temporary google only hack -#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS -#include "third_party/protobuf/version.h" -#endif -// @@protoc_insertion_point(includes) - -namespace helloworld { -class HelloRequestDefaultTypeInternal { - public: - ::google::protobuf::internal::ExplicitlyConstructed - _instance; -} _HelloRequest_default_instance_; -class HelloReplyDefaultTypeInternal { - public: - ::google::protobuf::internal::ExplicitlyConstructed - _instance; -} _HelloReply_default_instance_; -} // namespace helloworld -namespace protobuf_helloworld_2eproto { -static void InitDefaultsHelloRequest() { - GOOGLE_PROTOBUF_VERIFY_VERSION; - - { - void* ptr = &::helloworld::_HelloRequest_default_instance_; - new (ptr) ::helloworld::HelloRequest(); - ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); - } - ::helloworld::HelloRequest::InitAsDefaultInstance(); -} - -::google::protobuf::internal::SCCInfo<0> scc_info_HelloRequest = - {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsHelloRequest}, {}}; - -static void InitDefaultsHelloReply() { - GOOGLE_PROTOBUF_VERIFY_VERSION; - - { - void* ptr = &::helloworld::_HelloReply_default_instance_; - new (ptr) ::helloworld::HelloReply(); - ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); - } - ::helloworld::HelloReply::InitAsDefaultInstance(); -} - -::google::protobuf::internal::SCCInfo<0> scc_info_HelloReply = - {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsHelloReply}, {}}; - -void InitDefaults() { - ::google::protobuf::internal::InitSCC(&scc_info_HelloRequest.base); - ::google::protobuf::internal::InitSCC(&scc_info_HelloReply.base); -} - -::google::protobuf::Metadata file_level_metadata[2]; - -const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - ~0u, // no _has_bits_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloRequest, _internal_metadata_), - ~0u, // no _extensions_ - ~0u, // no _oneof_case_ - ~0u, // no _weak_field_map_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloRequest, name_), - ~0u, // no _has_bits_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloReply, _internal_metadata_), - ~0u, // no _extensions_ - ~0u, // no _oneof_case_ - ~0u, // no _weak_field_map_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::helloworld::HelloReply, message_), -}; -static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - { 0, -1, sizeof(::helloworld::HelloRequest)}, - { 6, -1, sizeof(::helloworld::HelloReply)}, -}; - -static ::google::protobuf::Message const * const file_default_instances[] = { - reinterpret_cast(&::helloworld::_HelloRequest_default_instance_), - reinterpret_cast(&::helloworld::_HelloReply_default_instance_), -}; - -void protobuf_AssignDescriptors() { - AddDescriptors(); - AssignDescriptors( - "helloworld.proto", schemas, file_default_instances, TableStruct::offsets, - file_level_metadata, NULL, NULL); -} - -void protobuf_AssignDescriptorsOnce() { - static ::google::protobuf::internal::once_flag once; - ::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors); -} - -void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD; -void protobuf_RegisterTypes(const ::std::string&) { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 2); -} - -void AddDescriptorsImpl() { - InitDefaults(); - static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" - "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" - "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" - "loworld.HelloRequest\032\026.helloworld.HelloR" - "eply\"\000B6\n\033io.grpc.examples.helloworldB\017H" - "elloWorldProtoP\001\242\002\003HLWb\006proto3" - }; - ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( - descriptor, 230); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( - "helloworld.proto", &protobuf_RegisterTypes); -} - -void AddDescriptors() { - static ::google::protobuf::internal::once_flag once; - ::google::protobuf::internal::call_once(once, AddDescriptorsImpl); -} -// Force AddDescriptors() to be called at dynamic initialization time. -struct StaticDescriptorInitializer { - StaticDescriptorInitializer() { - AddDescriptors(); - } -} static_descriptor_initializer; -} // namespace protobuf_helloworld_2eproto -namespace helloworld { - -// =================================================================== - -void HelloRequest::InitAsDefaultInstance() { -} -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int HelloRequest::kNameFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -HelloRequest::HelloRequest() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - ::google::protobuf::internal::InitSCC( - &protobuf_helloworld_2eproto::scc_info_HelloRequest.base); - SharedCtor(); - // @@protoc_insertion_point(constructor:helloworld.HelloRequest) -} -HelloRequest::HelloRequest(const HelloRequest& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - _internal_metadata_.MergeFrom(from._internal_metadata_); - name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (from.name().size() > 0) { - name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); - } - // @@protoc_insertion_point(copy_constructor:helloworld.HelloRequest) -} - -void HelloRequest::SharedCtor() { - name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -HelloRequest::~HelloRequest() { - // @@protoc_insertion_point(destructor:helloworld.HelloRequest) - SharedDtor(); -} - -void HelloRequest::SharedDtor() { - name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -void HelloRequest::SetCachedSize(int size) const { - _cached_size_.Set(size); -} -const ::google::protobuf::Descriptor* HelloRequest::descriptor() { - ::protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); - return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; -} - -const HelloRequest& HelloRequest::default_instance() { - ::google::protobuf::internal::InitSCC(&protobuf_helloworld_2eproto::scc_info_HelloRequest.base); - return *internal_default_instance(); -} - - -void HelloRequest::Clear() { -// @@protoc_insertion_point(message_clear_start:helloworld.HelloRequest) - ::google::protobuf::uint32 cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void) cached_has_bits; - - name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - _internal_metadata_.Clear(); -} - -bool HelloRequest::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:helloworld.HelloRequest) - for (;;) { - ::std::pair<::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // string name = 1; - case 1: { - if (static_cast< ::google::protobuf::uint8>(tag) == - static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) { - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->name().data(), static_cast(this->name().length()), - ::google::protobuf::internal::WireFormatLite::PARSE, - "helloworld.HelloRequest.name")); - } else { - goto handle_unusual; - } - break; - } - - default: { - handle_unusual: - if (tag == 0) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, _internal_metadata_.mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:helloworld.HelloRequest) - return true; -failure: - // @@protoc_insertion_point(parse_failure:helloworld.HelloRequest) - return false; -#undef DO_ -} - -void HelloRequest::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:helloworld.HelloRequest) - ::google::protobuf::uint32 cached_has_bits = 0; - (void) cached_has_bits; - - // string name = 1; - if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->name().data(), static_cast(this->name().length()), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "helloworld.HelloRequest.name"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 1, this->name(), output); - } - - if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); - } - // @@protoc_insertion_point(serialize_end:helloworld.HelloRequest) -} - -::google::protobuf::uint8* HelloRequest::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - (void)deterministic; // Unused - // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloRequest) - ::google::protobuf::uint32 cached_has_bits = 0; - (void) cached_has_bits; - - // string name = 1; - if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->name().data(), static_cast(this->name().length()), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "helloworld.HelloRequest.name"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 1, this->name(), target); - } - - if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); - } - // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloRequest) - return target; -} - -size_t HelloRequest::ByteSizeLong() const { -// @@protoc_insertion_point(message_byte_size_start:helloworld.HelloRequest) - size_t total_size = 0; - - if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); - } - // string name = 1; - if (this->name().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->name()); - } - - int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); - SetCachedSize(cached_size); - return total_size; -} - -void HelloRequest::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:helloworld.HelloRequest) - GOOGLE_DCHECK_NE(&from, this); - const HelloRequest* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:helloworld.HelloRequest) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:helloworld.HelloRequest) - MergeFrom(*source); - } -} - -void HelloRequest::MergeFrom(const HelloRequest& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloRequest) - GOOGLE_DCHECK_NE(&from, this); - _internal_metadata_.MergeFrom(from._internal_metadata_); - ::google::protobuf::uint32 cached_has_bits = 0; - (void) cached_has_bits; - - if (from.name().size() > 0) { - - name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); - } -} - -void HelloRequest::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:helloworld.HelloRequest) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void HelloRequest::CopyFrom(const HelloRequest& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloRequest) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool HelloRequest::IsInitialized() const { - return true; -} - -void HelloRequest::Swap(HelloRequest* other) { - if (other == this) return; - InternalSwap(other); -} -void HelloRequest::InternalSwap(HelloRequest* other) { - using std::swap; - name_.Swap(&other->name_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(), - GetArenaNoVirtual()); - _internal_metadata_.Swap(&other->_internal_metadata_); -} - -::google::protobuf::Metadata HelloRequest::GetMetadata() const { - protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); - return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages]; -} - - -// =================================================================== - -void HelloReply::InitAsDefaultInstance() { -} -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int HelloReply::kMessageFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -HelloReply::HelloReply() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - ::google::protobuf::internal::InitSCC( - &protobuf_helloworld_2eproto::scc_info_HelloReply.base); - SharedCtor(); - // @@protoc_insertion_point(constructor:helloworld.HelloReply) -} -HelloReply::HelloReply(const HelloReply& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - _internal_metadata_.MergeFrom(from._internal_metadata_); - message_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (from.message().size() > 0) { - message_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.message_); - } - // @@protoc_insertion_point(copy_constructor:helloworld.HelloReply) -} - -void HelloReply::SharedCtor() { - message_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -HelloReply::~HelloReply() { - // @@protoc_insertion_point(destructor:helloworld.HelloReply) - SharedDtor(); -} - -void HelloReply::SharedDtor() { - message_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -void HelloReply::SetCachedSize(int size) const { - _cached_size_.Set(size); -} -const ::google::protobuf::Descriptor* HelloReply::descriptor() { - ::protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); - return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; -} - -const HelloReply& HelloReply::default_instance() { - ::google::protobuf::internal::InitSCC(&protobuf_helloworld_2eproto::scc_info_HelloReply.base); - return *internal_default_instance(); -} - - -void HelloReply::Clear() { -// @@protoc_insertion_point(message_clear_start:helloworld.HelloReply) - ::google::protobuf::uint32 cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void) cached_has_bits; - - message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - _internal_metadata_.Clear(); -} - -bool HelloReply::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:helloworld.HelloReply) - for (;;) { - ::std::pair<::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // string message = 1; - case 1: { - if (static_cast< ::google::protobuf::uint8>(tag) == - static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) { - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_message())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->message().data(), static_cast(this->message().length()), - ::google::protobuf::internal::WireFormatLite::PARSE, - "helloworld.HelloReply.message")); - } else { - goto handle_unusual; - } - break; - } - - default: { - handle_unusual: - if (tag == 0) { - goto success; - } - DO_(::google::protobuf::internal::WireFormat::SkipField( - input, tag, _internal_metadata_.mutable_unknown_fields())); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:helloworld.HelloReply) - return true; -failure: - // @@protoc_insertion_point(parse_failure:helloworld.HelloReply) - return false; -#undef DO_ -} - -void HelloReply::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:helloworld.HelloReply) - ::google::protobuf::uint32 cached_has_bits = 0; - (void) cached_has_bits; - - // string message = 1; - if (this->message().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->message().data(), static_cast(this->message().length()), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "helloworld.HelloReply.message"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 1, this->message(), output); - } - - if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { - ::google::protobuf::internal::WireFormat::SerializeUnknownFields( - (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); - } - // @@protoc_insertion_point(serialize_end:helloworld.HelloReply) -} - -::google::protobuf::uint8* HelloReply::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - (void)deterministic; // Unused - // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloReply) - ::google::protobuf::uint32 cached_has_bits = 0; - (void) cached_has_bits; - - // string message = 1; - if (this->message().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->message().data(), static_cast(this->message().length()), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "helloworld.HelloReply.message"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 1, this->message(), target); - } - - if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { - target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( - (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); - } - // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloReply) - return target; -} - -size_t HelloReply::ByteSizeLong() const { -// @@protoc_insertion_point(message_byte_size_start:helloworld.HelloReply) - size_t total_size = 0; - - if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { - total_size += - ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( - (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); - } - // string message = 1; - if (this->message().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->message()); - } - - int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); - SetCachedSize(cached_size); - return total_size; -} - -void HelloReply::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:helloworld.HelloReply) - GOOGLE_DCHECK_NE(&from, this); - const HelloReply* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:helloworld.HelloReply) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:helloworld.HelloReply) - MergeFrom(*source); - } -} - -void HelloReply::MergeFrom(const HelloReply& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloReply) - GOOGLE_DCHECK_NE(&from, this); - _internal_metadata_.MergeFrom(from._internal_metadata_); - ::google::protobuf::uint32 cached_has_bits = 0; - (void) cached_has_bits; - - if (from.message().size() > 0) { - - message_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.message_); - } -} - -void HelloReply::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:helloworld.HelloReply) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void HelloReply::CopyFrom(const HelloReply& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloReply) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool HelloReply::IsInitialized() const { - return true; -} - -void HelloReply::Swap(HelloReply* other) { - if (other == this) return; - InternalSwap(other); -} -void HelloReply::InternalSwap(HelloReply* other) { - using std::swap; - message_.Swap(&other->message_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(), - GetArenaNoVirtual()); - _internal_metadata_.Swap(&other->_internal_metadata_); -} - -::google::protobuf::Metadata HelloReply::GetMetadata() const { - protobuf_helloworld_2eproto::protobuf_AssignDescriptorsOnce(); - return ::protobuf_helloworld_2eproto::file_level_metadata[kIndexInFileMessages]; -} - - -// @@protoc_insertion_point(namespace_scope) -} // namespace helloworld -namespace google { -namespace protobuf { -template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::helloworld::HelloRequest* Arena::CreateMaybeMessage< ::helloworld::HelloRequest >(Arena* arena) { - return Arena::CreateInternal< ::helloworld::HelloRequest >(arena); -} -template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::helloworld::HelloReply* Arena::CreateMaybeMessage< ::helloworld::HelloReply >(Arena* arena) { - return Arena::CreateInternal< ::helloworld::HelloReply >(arena); -} -} // namespace protobuf -} // namespace google - -// @@protoc_insertion_point(global_scope) diff --git a/examples/cpp/metadata/helloworld.pb.h b/examples/cpp/metadata/helloworld.pb.h deleted file mode 100644 index 57f6817e310..00000000000 --- a/examples/cpp/metadata/helloworld.pb.h +++ /dev/null @@ -1,419 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: helloworld.proto - -#ifndef PROTOBUF_INCLUDED_helloworld_2eproto -#define PROTOBUF_INCLUDED_helloworld_2eproto - -#include - -#include - -#if GOOGLE_PROTOBUF_VERSION < 3006001 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 3006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include // IWYU pragma: export -#include // IWYU pragma: export -#include -// @@protoc_insertion_point(includes) -#define PROTOBUF_INTERNAL_EXPORT_protobuf_helloworld_2eproto - -namespace protobuf_helloworld_2eproto { -// Internal implementation detail -- do not use these members. -struct TableStruct { - static const ::google::protobuf::internal::ParseTableField entries[]; - static const ::google::protobuf::internal::AuxillaryParseTableField aux[]; - static const ::google::protobuf::internal::ParseTable schema[2]; - static const ::google::protobuf::internal::FieldMetadata field_metadata[]; - static const ::google::protobuf::internal::SerializationTable serialization_table[]; - static const ::google::protobuf::uint32 offsets[]; -}; -void AddDescriptors(); -} // namespace protobuf_helloworld_2eproto -namespace helloworld { -class HelloReply; -class HelloReplyDefaultTypeInternal; -extern HelloReplyDefaultTypeInternal _HelloReply_default_instance_; -class HelloRequest; -class HelloRequestDefaultTypeInternal; -extern HelloRequestDefaultTypeInternal _HelloRequest_default_instance_; -} // namespace helloworld -namespace google { -namespace protobuf { -template<> ::helloworld::HelloReply* Arena::CreateMaybeMessage<::helloworld::HelloReply>(Arena*); -template<> ::helloworld::HelloRequest* Arena::CreateMaybeMessage<::helloworld::HelloRequest>(Arena*); -} // namespace protobuf -} // namespace google -namespace helloworld { - -// =================================================================== - -class HelloRequest : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:helloworld.HelloRequest) */ { - public: - HelloRequest(); - virtual ~HelloRequest(); - - HelloRequest(const HelloRequest& from); - - inline HelloRequest& operator=(const HelloRequest& from) { - CopyFrom(from); - return *this; - } - #if LANG_CXX11 - HelloRequest(HelloRequest&& from) noexcept - : HelloRequest() { - *this = ::std::move(from); - } - - inline HelloRequest& operator=(HelloRequest&& from) noexcept { - if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { - if (this != &from) InternalSwap(&from); - } else { - CopyFrom(from); - } - return *this; - } - #endif - static const ::google::protobuf::Descriptor* descriptor(); - static const HelloRequest& default_instance(); - - static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY - static inline const HelloRequest* internal_default_instance() { - return reinterpret_cast( - &_HelloRequest_default_instance_); - } - static constexpr int kIndexInFileMessages = - 0; - - void Swap(HelloRequest* other); - friend void swap(HelloRequest& a, HelloRequest& b) { - a.Swap(&b); - } - - // implements Message ---------------------------------------------- - - inline HelloRequest* New() const final { - return CreateMaybeMessage(NULL); - } - - HelloRequest* New(::google::protobuf::Arena* arena) const final { - return CreateMaybeMessage(arena); - } - void CopyFrom(const ::google::protobuf::Message& from) final; - void MergeFrom(const ::google::protobuf::Message& from) final; - void CopyFrom(const HelloRequest& from); - void MergeFrom(const HelloRequest& from); - void Clear() final; - bool IsInitialized() const final; - - size_t ByteSizeLong() const final; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) final; - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const final; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const final; - int GetCachedSize() const final { return _cached_size_.Get(); } - - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const final; - void InternalSwap(HelloRequest* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return NULL; - } - inline void* MaybeArenaPtr() const { - return NULL; - } - public: - - ::google::protobuf::Metadata GetMetadata() const final; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // string name = 1; - void clear_name(); - static const int kNameFieldNumber = 1; - const ::std::string& name() const; - void set_name(const ::std::string& value); - #if LANG_CXX11 - void set_name(::std::string&& value); - #endif - void set_name(const char* value); - void set_name(const char* value, size_t size); - ::std::string* mutable_name(); - ::std::string* release_name(); - void set_allocated_name(::std::string* name); - - // @@protoc_insertion_point(class_scope:helloworld.HelloRequest) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - ::google::protobuf::internal::ArenaStringPtr name_; - mutable ::google::protobuf::internal::CachedSize _cached_size_; - friend struct ::protobuf_helloworld_2eproto::TableStruct; -}; -// ------------------------------------------------------------------- - -class HelloReply : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:helloworld.HelloReply) */ { - public: - HelloReply(); - virtual ~HelloReply(); - - HelloReply(const HelloReply& from); - - inline HelloReply& operator=(const HelloReply& from) { - CopyFrom(from); - return *this; - } - #if LANG_CXX11 - HelloReply(HelloReply&& from) noexcept - : HelloReply() { - *this = ::std::move(from); - } - - inline HelloReply& operator=(HelloReply&& from) noexcept { - if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { - if (this != &from) InternalSwap(&from); - } else { - CopyFrom(from); - } - return *this; - } - #endif - static const ::google::protobuf::Descriptor* descriptor(); - static const HelloReply& default_instance(); - - static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY - static inline const HelloReply* internal_default_instance() { - return reinterpret_cast( - &_HelloReply_default_instance_); - } - static constexpr int kIndexInFileMessages = - 1; - - void Swap(HelloReply* other); - friend void swap(HelloReply& a, HelloReply& b) { - a.Swap(&b); - } - - // implements Message ---------------------------------------------- - - inline HelloReply* New() const final { - return CreateMaybeMessage(NULL); - } - - HelloReply* New(::google::protobuf::Arena* arena) const final { - return CreateMaybeMessage(arena); - } - void CopyFrom(const ::google::protobuf::Message& from) final; - void MergeFrom(const ::google::protobuf::Message& from) final; - void CopyFrom(const HelloReply& from); - void MergeFrom(const HelloReply& from); - void Clear() final; - bool IsInitialized() const final; - - size_t ByteSizeLong() const final; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) final; - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const final; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const final; - int GetCachedSize() const final { return _cached_size_.Get(); } - - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const final; - void InternalSwap(HelloReply* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return NULL; - } - inline void* MaybeArenaPtr() const { - return NULL; - } - public: - - ::google::protobuf::Metadata GetMetadata() const final; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // string message = 1; - void clear_message(); - static const int kMessageFieldNumber = 1; - const ::std::string& message() const; - void set_message(const ::std::string& value); - #if LANG_CXX11 - void set_message(::std::string&& value); - #endif - void set_message(const char* value); - void set_message(const char* value, size_t size); - ::std::string* mutable_message(); - ::std::string* release_message(); - void set_allocated_message(::std::string* message); - - // @@protoc_insertion_point(class_scope:helloworld.HelloReply) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - ::google::protobuf::internal::ArenaStringPtr message_; - mutable ::google::protobuf::internal::CachedSize _cached_size_; - friend struct ::protobuf_helloworld_2eproto::TableStruct; -}; -// =================================================================== - - -// =================================================================== - -#ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif // __GNUC__ -// HelloRequest - -// string name = 1; -inline void HelloRequest::clear_name() { - name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& HelloRequest::name() const { - // @@protoc_insertion_point(field_get:helloworld.HelloRequest.name) - return name_.GetNoArena(); -} -inline void HelloRequest::set_name(const ::std::string& value) { - - name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:helloworld.HelloRequest.name) -} -#if LANG_CXX11 -inline void HelloRequest::set_name(::std::string&& value) { - - name_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:helloworld.HelloRequest.name) -} -#endif -inline void HelloRequest::set_name(const char* value) { - GOOGLE_DCHECK(value != NULL); - - name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:helloworld.HelloRequest.name) -} -inline void HelloRequest::set_name(const char* value, size_t size) { - - name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:helloworld.HelloRequest.name) -} -inline ::std::string* HelloRequest::mutable_name() { - - // @@protoc_insertion_point(field_mutable:helloworld.HelloRequest.name) - return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* HelloRequest::release_name() { - // @@protoc_insertion_point(field_release:helloworld.HelloRequest.name) - - return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void HelloRequest::set_allocated_name(::std::string* name) { - if (name != NULL) { - - } else { - - } - name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name); - // @@protoc_insertion_point(field_set_allocated:helloworld.HelloRequest.name) -} - -// ------------------------------------------------------------------- - -// HelloReply - -// string message = 1; -inline void HelloReply::clear_message() { - message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& HelloReply::message() const { - // @@protoc_insertion_point(field_get:helloworld.HelloReply.message) - return message_.GetNoArena(); -} -inline void HelloReply::set_message(const ::std::string& value) { - - message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:helloworld.HelloReply.message) -} -#if LANG_CXX11 -inline void HelloReply::set_message(::std::string&& value) { - - message_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:helloworld.HelloReply.message) -} -#endif -inline void HelloReply::set_message(const char* value) { - GOOGLE_DCHECK(value != NULL); - - message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:helloworld.HelloReply.message) -} -inline void HelloReply::set_message(const char* value, size_t size) { - - message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:helloworld.HelloReply.message) -} -inline ::std::string* HelloReply::mutable_message() { - - // @@protoc_insertion_point(field_mutable:helloworld.HelloReply.message) - return message_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* HelloReply::release_message() { - // @@protoc_insertion_point(field_release:helloworld.HelloReply.message) - - return message_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void HelloReply::set_allocated_message(::std::string* message) { - if (message != NULL) { - - } else { - - } - message_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), message); - // @@protoc_insertion_point(field_set_allocated:helloworld.HelloReply.message) -} - -#ifdef __GNUC__ - #pragma GCC diagnostic pop -#endif // __GNUC__ -// ------------------------------------------------------------------- - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace helloworld - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_INCLUDED_helloworld_2eproto diff --git a/examples/cpp/metadata/helloworld.pb.o b/examples/cpp/metadata/helloworld.pb.o deleted file mode 100644 index 85671e8aaa3b10080aba2cde1b103fe994eaa612..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111592 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