From bce07d9355acdbd2ae7964de6f6553a9c7bc9718 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Sat, 23 Apr 2022 23:36:54 -0700 Subject: [PATCH 01/11] netty: implement UdsNameResolver and UdsNettyChannelProvider When the scheme is "unix:" we get the UdsNettyChannelProvider to create a NettyChannelBuilder with DomainSocketAddress type and other related params needed for UDS sockets --- .../java/io/grpc/ManagedChannelRegistry.java | 5 + netty/build.gradle | 6 +- .../java/io/grpc/netty/UdsNameResolver.java | 66 ++++++++++ .../grpc/netty/UdsNameResolverProvider.java | 60 +++++++++ .../grpc/netty/UdsNettyChannelProvider.java | 91 +++++++++++++ netty/src/main/java/io/grpc/netty/Utils.java | 5 + .../services/io.grpc.ManagedChannelProvider | 1 + .../services/io.grpc.NameResolverProvider | 1 + .../netty/UdsNameResolverProviderTest.java | 124 ++++++++++++++++++ .../io/grpc/netty/UdsNameResolverTest.java | 81 ++++++++++++ .../netty/UdsNettyChannelProviderTest.java | 112 ++++++++++++++++ 11 files changed, 549 insertions(+), 3 deletions(-) create mode 100644 netty/src/main/java/io/grpc/netty/UdsNameResolver.java create mode 100644 netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java create mode 100644 netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java create mode 100644 netty/src/main/resources/META-INF/services/io.grpc.NameResolverProvider create mode 100644 netty/src/test/java/io/grpc/netty/UdsNameResolverProviderTest.java create mode 100644 netty/src/test/java/io/grpc/netty/UdsNameResolverTest.java create mode 100644 netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java diff --git a/api/src/main/java/io/grpc/ManagedChannelRegistry.java b/api/src/main/java/io/grpc/ManagedChannelRegistry.java index 677856ed8d8..52a19d55ecb 100644 --- a/api/src/main/java/io/grpc/ManagedChannelRegistry.java +++ b/api/src/main/java/io/grpc/ManagedChannelRegistry.java @@ -145,6 +145,11 @@ static List> getHardCodedClasses() { } catch (ClassNotFoundException e) { logger.log(Level.FINE, "Unable to find NettyChannelProvider", e); } + try { + list.add(Class.forName("io.grpc.netty.UdsNettyChannelProvider")); + } catch (ClassNotFoundException e) { + logger.log(Level.FINE, "Unable to find UdsNettyChannelProvider", e); + } return Collections.unmodifiableList(list); } diff --git a/netty/build.gradle b/netty/build.gradle index 5fdc8f20f08..25c8e0442f8 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -17,7 +17,8 @@ evaluationDependsOn(project(':grpc-core').path) dependencies { api project(':grpc-core'), - libraries.netty + libraries.netty, + libraries.netty_epoll implementation libraries.netty_proxy_handler, libraries.guava, libraries.errorprone, @@ -29,8 +30,7 @@ dependencies { project(':grpc-testing'), project(':grpc-testing-proto') testRuntimeOnly libraries.netty_tcnative, - libraries.conscrypt, - libraries.netty_epoll + libraries.conscrypt signature "org.codehaus.mojo.signature:java17:1.0@signature" alpnagent libraries.jetty_alpn_agent } diff --git a/netty/src/main/java/io/grpc/netty/UdsNameResolver.java b/netty/src/main/java/io/grpc/netty/UdsNameResolver.java new file mode 100644 index 00000000000..6dab99eddb8 --- /dev/null +++ b/netty/src/main/java/io/grpc/netty/UdsNameResolver.java @@ -0,0 +1,66 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.netty; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Preconditions; +import io.grpc.EquivalentAddressGroup; +import io.grpc.NameResolver; +import io.netty.channel.unix.DomainSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class UdsNameResolver extends NameResolver { + private NameResolver.Listener2 listener; + private final String authority; + + UdsNameResolver(String authority, String targetPath) { + checkArgument(authority == null, "non-null authority not supported"); + this.authority = targetPath; + } + + @Override + public String getServiceAuthority() { + return this.authority; + } + + @Override + public void start(Listener2 listener) { + Preconditions.checkState(this.listener == null, "already started"); + this.listener = checkNotNull(listener, "listener"); + resolve(); + } + + @Override + public void refresh() { + resolve(); + } + + private void resolve() { + ResolutionResult.Builder resolutionResultBuilder = ResolutionResult.newBuilder(); + List servers = new ArrayList<>(1); + servers.add(new EquivalentAddressGroup(new DomainSocketAddress(authority))); + resolutionResultBuilder.setAddresses(Collections.unmodifiableList(servers)); + listener.onResult(resolutionResultBuilder.build()); + } + + @Override + public void shutdown() {} +} diff --git a/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java b/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java new file mode 100644 index 00000000000..33010200aed --- /dev/null +++ b/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.netty; + +import com.google.common.base.Preconditions; +import io.grpc.NameResolver; +import io.grpc.NameResolverProvider; +import java.net.URI; + +public class UdsNameResolverProvider extends NameResolverProvider { + + private static final String SCHEME = "unix"; + + @Override + public UdsNameResolver newNameResolver(URI targetUri, NameResolver.Args args) { + if (SCHEME.equals(targetUri.getScheme())) { + return new UdsNameResolver(targetUri.getAuthority(), getTargetPathFromUri(targetUri)); + } else { + return null; + } + } + + static String getTargetPathFromUri(URI targetUri) { + Preconditions.checkArgument(SCHEME.equals(targetUri.getScheme()), "scheme must be " + SCHEME); + String targetPath = targetUri.getPath(); + if (targetPath == null) { + targetPath = Preconditions.checkNotNull(targetUri.getSchemeSpecificPart(), "targetPath"); + } + return targetPath; + } + + @Override + public String getDefaultScheme() { + return SCHEME; + } + + @Override + protected boolean isAvailable() { + return true; + } + + @Override + protected int priority() { + return 3; + } +} diff --git a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java new file mode 100644 index 00000000000..029262529d9 --- /dev/null +++ b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java @@ -0,0 +1,91 @@ +/* + * Copyright 2015 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. + */ + +package io.grpc.netty; + +import io.grpc.CallCredentials; +import io.grpc.ChannelCredentials; +import io.grpc.InsecureChannelCredentials; +import io.grpc.Internal; +import io.grpc.ManagedChannelProvider; +import io.grpc.internal.SharedResourcePool; +import io.netty.channel.epoll.EpollDomainSocketChannel; +import io.netty.channel.unix.DomainSocketAddress; +import java.net.SocketAddress; +import java.net.URI; +import java.util.Collection; +import java.util.Collections; + +/** Provider for {@link NettyChannelBuilder} instances for UDS channels. */ +@Internal +public final class UdsNettyChannelProvider extends ManagedChannelProvider { + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public int priority() { + return 3; + } + + @Override + public NettyChannelBuilder builderForAddress(String name, int port) { + throw new UnsupportedOperationException("host:port not supported"); + } + + @Override + public NettyChannelBuilder builderForTarget(String target) { + ChannelCredentials creds = InsecureChannelCredentials.create(); + ProtocolNegotiators.FromChannelCredentialsResult result = ProtocolNegotiators.from(creds); + if (result.error != null) { + throw new RuntimeException(result.error); + } + return getNettyChannelBuilder(target, creds, null, result.negotiator); + } + + @Override + public NewChannelBuilderResult newChannelBuilder(String target, ChannelCredentials creds) { + ProtocolNegotiators.FromChannelCredentialsResult result = ProtocolNegotiators.from(creds); + if (result.error != null) { + return NewChannelBuilderResult.error(result.error); + } + return NewChannelBuilderResult.channelBuilder( + getNettyChannelBuilder(target, creds, result.callCredentials, result.negotiator)); + } + + private static NettyChannelBuilder getNettyChannelBuilder( + String target, + ChannelCredentials creds, + CallCredentials callCredentials, + ProtocolNegotiator.ClientFactory negotiator) { + String targetPath = UdsNameResolverProvider.getTargetPathFromUri(URI.create(target)); + NettyChannelBuilder builder = + new NettyChannelBuilder( + new DomainSocketAddress(targetPath), creds, callCredentials, negotiator); + builder = + builder + .eventLoopGroupPool(SharedResourcePool.forResource(Utils.UDS_CHANNELS_EVENT_LOOP_GROUP)) + .channelType(EpollDomainSocketChannel.class); + return builder; + } + + @Override + protected Collection> getSupportedSocketAddressTypes() { + return Collections.singleton(DomainSocketAddress.class); + } +} diff --git a/netty/src/main/java/io/grpc/netty/Utils.java b/netty/src/main/java/io/grpc/netty/Utils.java index c2f2fa4a7bf..abf5f9634c2 100644 --- a/netty/src/main/java/io/grpc/netty/Utils.java +++ b/netty/src/main/java/io/grpc/netty/Utils.java @@ -44,6 +44,7 @@ import io.netty.channel.EventLoopGroup; import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.ServerChannel; +import io.netty.channel.epoll.Epoll; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; @@ -89,6 +90,10 @@ class Utils { = new DefaultEventLoopGroupResource(1, "grpc-nio-boss-ELG", EventLoopGroupType.NIO); public static final Resource NIO_WORKER_EVENT_LOOP_GROUP = new DefaultEventLoopGroupResource(0, "grpc-nio-worker-ELG", EventLoopGroupType.NIO); + public static final Resource UDS_CHANNELS_EVENT_LOOP_GROUP = + Epoll.isAvailable() ? new DefaultEventLoopGroupResource(1, "UdsChannels", + EventLoopGroupType.EPOLL) : null; + public static final Resource DEFAULT_BOSS_EVENT_LOOP_GROUP; public static final Resource DEFAULT_WORKER_EVENT_LOOP_GROUP; diff --git a/netty/src/main/resources/META-INF/services/io.grpc.ManagedChannelProvider b/netty/src/main/resources/META-INF/services/io.grpc.ManagedChannelProvider index ebd1bcdf024..e7b37ea49ac 100644 --- a/netty/src/main/resources/META-INF/services/io.grpc.ManagedChannelProvider +++ b/netty/src/main/resources/META-INF/services/io.grpc.ManagedChannelProvider @@ -1 +1,2 @@ io.grpc.netty.NettyChannelProvider +io.grpc.netty.UdsNettyChannelProvider diff --git a/netty/src/main/resources/META-INF/services/io.grpc.NameResolverProvider b/netty/src/main/resources/META-INF/services/io.grpc.NameResolverProvider new file mode 100644 index 00000000000..ec775013c1e --- /dev/null +++ b/netty/src/main/resources/META-INF/services/io.grpc.NameResolverProvider @@ -0,0 +1 @@ +io.grpc.netty.UdsNameResolverProvider diff --git a/netty/src/test/java/io/grpc/netty/UdsNameResolverProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNameResolverProviderTest.java new file mode 100644 index 00000000000..6a329c8fc68 --- /dev/null +++ b/netty/src/test/java/io/grpc/netty/UdsNameResolverProviderTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2015 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. + */ + +package io.grpc.netty; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.verify; + +import io.grpc.EquivalentAddressGroup; +import io.grpc.NameResolver; +import io.netty.channel.unix.DomainSocketAddress; +import java.net.SocketAddress; +import java.net.URI; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Unit tests for {@link UdsNameResolverProvider}. */ +@RunWith(JUnit4.class) +public class UdsNameResolverProviderTest { + + @Rule + public final MockitoRule mocks = MockitoJUnit.rule(); + + @Mock + private NameResolver.Listener2 mockListener; + + @Captor + private ArgumentCaptor resultCaptor; + + UdsNameResolverProvider udsNameResolverProvider = new UdsNameResolverProvider(); + + + @Test + public void testUnixRelativePath() { + UdsNameResolver udsNameResolver = + udsNameResolverProvider.newNameResolver(URI.create("unix:sock.sock"), null); + assertThat(udsNameResolver).isNotNull(); + udsNameResolver.start(mockListener); + verify(mockListener).onResult(resultCaptor.capture()); + NameResolver.ResolutionResult result = resultCaptor.getValue(); + List list = result.getAddresses(); + assertThat(list).isNotNull(); + assertThat(list).hasSize(1); + EquivalentAddressGroup eag = list.get(0); + assertThat(eag).isNotNull(); + List addresses = eag.getAddresses(); + assertThat(addresses).hasSize(1); + assertThat(addresses.get(0)).isInstanceOf(DomainSocketAddress.class); + DomainSocketAddress domainSocketAddress = (DomainSocketAddress) addresses.get(0); + assertThat(domainSocketAddress.path()).isEqualTo("sock.sock"); + } + + @Test + public void testUnixAbsolutePath() { + UdsNameResolver udsNameResolver = + udsNameResolverProvider.newNameResolver(URI.create("unix:/sock.sock"), null); + assertThat(udsNameResolver).isNotNull(); + udsNameResolver.start(mockListener); + verify(mockListener).onResult(resultCaptor.capture()); + NameResolver.ResolutionResult result = resultCaptor.getValue(); + List list = result.getAddresses(); + assertThat(list).isNotNull(); + assertThat(list).hasSize(1); + EquivalentAddressGroup eag = list.get(0); + assertThat(eag).isNotNull(); + List addresses = eag.getAddresses(); + assertThat(addresses).hasSize(1); + assertThat(addresses.get(0)).isInstanceOf(DomainSocketAddress.class); + DomainSocketAddress domainSocketAddress = (DomainSocketAddress) addresses.get(0); + assertThat(domainSocketAddress.path()).isEqualTo("/sock.sock"); + } + + @Test + public void testUnixAbsoluteAlternatePath() { + UdsNameResolver udsNameResolver = + udsNameResolverProvider.newNameResolver(URI.create("unix:///sock.sock"), null); + assertThat(udsNameResolver).isNotNull(); + udsNameResolver.start(mockListener); + verify(mockListener).onResult(resultCaptor.capture()); + NameResolver.ResolutionResult result = resultCaptor.getValue(); + List list = result.getAddresses(); + assertThat(list).isNotNull(); + assertThat(list).hasSize(1); + EquivalentAddressGroup eag = list.get(0); + assertThat(eag).isNotNull(); + List addresses = eag.getAddresses(); + assertThat(addresses).hasSize(1); + assertThat(addresses.get(0)).isInstanceOf(DomainSocketAddress.class); + DomainSocketAddress domainSocketAddress = (DomainSocketAddress) addresses.get(0); + assertThat(domainSocketAddress.path()).isEqualTo("/sock.sock"); + } + + @Test + public void testUnixPathWithAuthority() { + try { + udsNameResolverProvider.newNameResolver(URI.create("unix://localhost/sock.sock"), null); + fail("exception expected"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessageThat().isEqualTo("non-null authority not supported"); + } + } +} diff --git a/netty/src/test/java/io/grpc/netty/UdsNameResolverTest.java b/netty/src/test/java/io/grpc/netty/UdsNameResolverTest.java new file mode 100644 index 00000000000..8eb010e23e5 --- /dev/null +++ b/netty/src/test/java/io/grpc/netty/UdsNameResolverTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2015 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. + */ + +package io.grpc.netty; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.verify; + +import io.grpc.EquivalentAddressGroup; +import io.grpc.NameResolver; +import io.netty.channel.unix.DomainSocketAddress; +import java.net.SocketAddress; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Unit tests for {@link UdsNameResolver}. */ +@RunWith(JUnit4.class) +public class UdsNameResolverTest { + + @Rule + public final MockitoRule mocks = MockitoJUnit.rule(); + + @Mock + private NameResolver.Listener2 mockListener; + + @Captor + private ArgumentCaptor resultCaptor; + + private UdsNameResolver udsNameResolver; + + @Test + public void testValidTargetPath() { + udsNameResolver = new UdsNameResolver(null, "sock.sock"); + udsNameResolver.start(mockListener); + verify(mockListener).onResult(resultCaptor.capture()); + NameResolver.ResolutionResult result = resultCaptor.getValue(); + List list = result.getAddresses(); + assertThat(list).isNotNull(); + assertThat(list).hasSize(1); + EquivalentAddressGroup eag = list.get(0); + assertThat(eag).isNotNull(); + List addresses = eag.getAddresses(); + assertThat(addresses).hasSize(1); + assertThat(addresses.get(0)).isInstanceOf(DomainSocketAddress.class); + DomainSocketAddress domainSocketAddress = (DomainSocketAddress) addresses.get(0); + assertThat(domainSocketAddress.path()).isEqualTo("sock.sock"); + assertThat(udsNameResolver.getServiceAuthority()).isEqualTo("sock.sock"); + } + + @Test + public void testNonNullAuthority() { + try { + udsNameResolver = new UdsNameResolver("authority", "sock.sock"); + fail("exception expected"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessageThat().isEqualTo("non-null authority not supported"); + } + } +} diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java new file mode 100644 index 00000000000..5e0960fc443 --- /dev/null +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2015 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. + */ + +package io.grpc.netty; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; +import io.grpc.InternalServiceProviders; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.ManagedChannelProvider; +import io.grpc.ManagedChannelProvider.NewChannelBuilderResult; +import io.grpc.ManagedChannelRegistryAccessor; +import io.grpc.TlsChannelCredentials; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link UdsNettyChannelProvider}. */ +@RunWith(JUnit4.class) +public class UdsNettyChannelProviderTest { + private UdsNettyChannelProvider provider = new UdsNettyChannelProvider(); + + @Test + public void provided() { + for (ManagedChannelProvider current + : InternalServiceProviders.getCandidatesViaServiceLoader( + ManagedChannelProvider.class, getClass().getClassLoader())) { + if (current instanceof UdsNettyChannelProvider) { + return; + } + } + fail("ServiceLoader unable to load UdsNettyChannelProvider"); + } + + @Test + public void providedHardCoded() { + for (Class current : ManagedChannelRegistryAccessor.getHardCodedClasses()) { + if (current == UdsNettyChannelProvider.class) { + return; + } + } + fail("Hard coded unable to load UdsNettyChannelProvider"); + } + + @Test + public void basicMethods() { + assertTrue(provider.isAvailable()); + assertEquals(3, provider.priority()); + } + + @Test + public void builderForTarget() { + assertThat(provider.builderForTarget("unix:sock.sock")).isInstanceOf(NettyChannelBuilder.class); + } + + @Test + public void builderForTarget_badScheme() { + try { + provider.builderForTarget("dns:sock.sock"); + fail("exception expected"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessageThat().isEqualTo("scheme must be unix"); + } + } + + @Test + public void newChannelBuilder_success() { + NewChannelBuilderResult result = + provider.newChannelBuilder("unix:sock.sock", TlsChannelCredentials.create()); + assertThat(result.getChannelBuilder()).isInstanceOf(NettyChannelBuilder.class); + } + + @Test + public void newChannelBuilder_badScheme() { + try { + provider.newChannelBuilder("dns:sock.sock", InsecureChannelCredentials.create()); + fail("exception expected"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessageThat().isEqualTo("scheme must be unix"); + } + } + + @Test + public void managedChannelRegistry_newChannelBuilder() { + ManagedChannelBuilder managedChannelBuilder + = Grpc.newChannelBuilder("unix:///sock.sock", InsecureChannelCredentials.create()); + assertThat(managedChannelBuilder).isNotNull(); + ManagedChannel channel = managedChannelBuilder.build(); + assertThat(channel).isNotNull(); + assertThat(channel.authority()).isEqualTo("/sock.sock"); + channel.shutdownNow(); + } +} From e8835c693358873e49cb7e213ca2612207e2a040 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Thu, 28 Apr 2022 22:52:46 -0700 Subject: [PATCH 02/11] fix UdsNameResolver to return DomainSocketAddess and address review comments --- .../java/io/grpc/netty/UdsNameResolver.java | 2 +- .../grpc/netty/UdsNameResolverProvider.java | 13 +++- .../netty/UdsNettyChannelProviderTest.java | 69 +++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/UdsNameResolver.java b/netty/src/main/java/io/grpc/netty/UdsNameResolver.java index 6dab99eddb8..8fa8ea06250 100644 --- a/netty/src/main/java/io/grpc/netty/UdsNameResolver.java +++ b/netty/src/main/java/io/grpc/netty/UdsNameResolver.java @@ -27,7 +27,7 @@ import java.util.Collections; import java.util.List; -public final class UdsNameResolver extends NameResolver { +final class UdsNameResolver extends NameResolver { private NameResolver.Listener2 listener; private final String authority; diff --git a/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java b/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java index 33010200aed..ffc07ff6ecb 100644 --- a/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java +++ b/netty/src/main/java/io/grpc/netty/UdsNameResolverProvider.java @@ -17,11 +17,17 @@ package io.grpc.netty; import com.google.common.base.Preconditions; +import io.grpc.Internal; import io.grpc.NameResolver; import io.grpc.NameResolverProvider; +import io.netty.channel.unix.DomainSocketAddress; +import java.net.SocketAddress; import java.net.URI; +import java.util.Collection; +import java.util.Collections; -public class UdsNameResolverProvider extends NameResolverProvider { +@Internal +public final class UdsNameResolverProvider extends NameResolverProvider { private static final String SCHEME = "unix"; @@ -57,4 +63,9 @@ protected boolean isAvailable() { protected int priority() { return 3; } + + @Override + protected Collection> getProducedSocketAddressTypes() { + return Collections.singleton(DomainSocketAddress.class); + } } diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index 5e0960fc443..9cdf359dff2 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -29,7 +29,21 @@ import io.grpc.ManagedChannelProvider; import io.grpc.ManagedChannelProvider.NewChannelBuilderResult; import io.grpc.ManagedChannelRegistryAccessor; +import io.grpc.Server; import io.grpc.TlsChannelCredentials; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import io.grpc.testing.protobuf.SimpleRequest; +import io.grpc.testing.protobuf.SimpleResponse; +import io.grpc.testing.protobuf.SimpleServiceGrpc; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.epoll.EpollServerDomainSocketChannel; +import io.netty.channel.unix.DomainSocketAddress; +import java.io.IOException; +import org.junit.Assume; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -37,8 +51,17 @@ /** Unit tests for {@link UdsNettyChannelProvider}. */ @RunWith(JUnit4.class) public class UdsNettyChannelProviderTest { + + private static final String TEST_SOCKET = "/tmp/test.socket"; + @Rule + public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); + + private UdsNettyChannelProvider provider = new UdsNettyChannelProvider(); + private EventLoopGroup elg; + private EventLoopGroup boss; + @Test public void provided() { for (ManagedChannelProvider current @@ -109,4 +132,50 @@ public void managedChannelRegistry_newChannelBuilder() { assertThat(channel.authority()).isEqualTo("/sock.sock"); channel.shutdownNow(); } + + @Test + public void udsClientServerTestUsingProvider() throws IOException { + Assume.assumeTrue(Epoll.isAvailable()); + createUdsServer(TEST_SOCKET); + ManagedChannelBuilder channelBuilder = + Grpc.newChannelBuilder("unix://" + TEST_SOCKET, InsecureChannelCredentials.create()); + SimpleServiceGrpc.SimpleServiceBlockingStub stub = + SimpleServiceGrpc.newBlockingStub(cleanupRule.register(channelBuilder.build())); + assertThat(unaryRpc("buddy", stub)).isEqualTo("Hello buddy"); + } + + /** Say hello to server. */ + private static String unaryRpc( + String requestMessage, SimpleServiceGrpc.SimpleServiceBlockingStub blockingStub) { + SimpleRequest request = SimpleRequest.newBuilder().setRequestMessage(requestMessage).build(); + SimpleResponse response = blockingStub.unaryRpc(request); + return response.getResponseMessage(); + } + + private void createUdsServer(String name) throws IOException { + elg = new EpollEventLoopGroup(); + boss = new EpollEventLoopGroup(1); + Server server = + cleanupRule.register(NettyServerBuilder.forAddress(new DomainSocketAddress(name)) + .bossEventLoopGroup(boss) + .workerEventLoopGroup(elg) + .channelType(EpollServerDomainSocketChannel.class) + .addService(new SimpleServiceImpl()) + .directExecutor() + .build() + .start()); + } + + private static class SimpleServiceImpl extends SimpleServiceGrpc.SimpleServiceImplBase { + + @Override + public void unaryRpc(SimpleRequest req, StreamObserver responseObserver) { + SimpleResponse response = + SimpleResponse.newBuilder() + .setResponseMessage("Hello " + req.getRequestMessage()) + .build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } + } } From 449a7fc46eb93a1b219594e34776b665ea64e9c7 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 29 Apr 2022 00:15:56 -0700 Subject: [PATCH 03/11] fix build issue --- .../test/java/io/grpc/netty/UdsNettyChannelProviderTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index 9cdf359dff2..6e8cedade59 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -29,7 +29,6 @@ import io.grpc.ManagedChannelProvider; import io.grpc.ManagedChannelProvider.NewChannelBuilderResult; import io.grpc.ManagedChannelRegistryAccessor; -import io.grpc.Server; import io.grpc.TlsChannelCredentials; import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; @@ -155,8 +154,8 @@ private static String unaryRpc( private void createUdsServer(String name) throws IOException { elg = new EpollEventLoopGroup(); boss = new EpollEventLoopGroup(1); - Server server = - cleanupRule.register(NettyServerBuilder.forAddress(new DomainSocketAddress(name)) + cleanupRule.register( + NettyServerBuilder.forAddress(new DomainSocketAddress(name)) .bossEventLoopGroup(boss) .workerEventLoopGroup(elg) .channelType(EpollServerDomainSocketChannel.class) From ed055c3dd8cfc273b564990f8540259f030c39bd Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 29 Apr 2022 14:45:46 -0700 Subject: [PATCH 04/11] address 2nd set of review comments --- netty/build.gradle | 9 ++++--- .../grpc/netty/UdsNettyChannelProvider.java | 3 +-- netty/src/main/java/io/grpc/netty/Utils.java | 17 +++++++++++-- .../netty/UdsNettyChannelProviderTest.java | 25 +++++++++++++++---- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/netty/build.gradle b/netty/build.gradle index 25c8e0442f8..40c48694da0 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -17,12 +17,12 @@ evaluationDependsOn(project(':grpc-core').path) dependencies { api project(':grpc-core'), - libraries.netty, - libraries.netty_epoll + libraries.netty implementation libraries.netty_proxy_handler, libraries.guava, libraries.errorprone, - libraries.perfmark + libraries.perfmark, + ("io.netty:netty-transport-native-epoll:${nettyVersion}") // Tests depend on base class defined by core module. testImplementation project(':grpc-core').sourceSets.test.output, @@ -30,7 +30,8 @@ dependencies { project(':grpc-testing'), project(':grpc-testing-proto') testRuntimeOnly libraries.netty_tcnative, - libraries.conscrypt + libraries.conscrypt, + libraries.netty_epoll signature "org.codehaus.mojo.signature:java17:1.0@signature" alpnagent libraries.jetty_alpn_agent } diff --git a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java index 029262529d9..34d6e725474 100644 --- a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java +++ b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java @@ -22,7 +22,6 @@ import io.grpc.Internal; import io.grpc.ManagedChannelProvider; import io.grpc.internal.SharedResourcePool; -import io.netty.channel.epoll.EpollDomainSocketChannel; import io.netty.channel.unix.DomainSocketAddress; import java.net.SocketAddress; import java.net.URI; @@ -80,7 +79,7 @@ private static NettyChannelBuilder getNettyChannelBuilder( builder = builder .eventLoopGroupPool(SharedResourcePool.forResource(Utils.UDS_CHANNELS_EVENT_LOOP_GROUP)) - .channelType(EpollDomainSocketChannel.class); + .channelType(Utils.EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE); return builder; } diff --git a/netty/src/main/java/io/grpc/netty/Utils.java b/netty/src/main/java/io/grpc/netty/Utils.java index abf5f9634c2..1c2645fe209 100644 --- a/netty/src/main/java/io/grpc/netty/Utils.java +++ b/netty/src/main/java/io/grpc/netty/Utils.java @@ -44,7 +44,6 @@ import io.netty.channel.EventLoopGroup; import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.ServerChannel; -import io.netty.channel.epoll.Epoll; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; @@ -91,7 +90,7 @@ class Utils { public static final Resource NIO_WORKER_EVENT_LOOP_GROUP = new DefaultEventLoopGroupResource(0, "grpc-nio-worker-ELG", EventLoopGroupType.NIO); public static final Resource UDS_CHANNELS_EVENT_LOOP_GROUP = - Epoll.isAvailable() ? new DefaultEventLoopGroupResource(1, "UdsChannels", + isEpollAvailable() ? new DefaultEventLoopGroupResource(1, "UdsChannels", EventLoopGroupType.EPOLL) : null; public static final Resource DEFAULT_BOSS_EVENT_LOOP_GROUP; @@ -109,6 +108,7 @@ private static final class ByteBufAllocatorPreferHeapHolder { public static final ChannelFactory DEFAULT_SERVER_CHANNEL_FACTORY; public static final Class DEFAULT_CLIENT_CHANNEL_TYPE; + public static final Class EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE; @Nullable private static final Constructor EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR; @@ -117,6 +117,7 @@ private static final class ByteBufAllocatorPreferHeapHolder { // Decide default channel types and EventLoopGroup based on Epoll availability if (isEpollAvailable()) { DEFAULT_CLIENT_CHANNEL_TYPE = epollChannelType(); + EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE = epollDomainSocketChannelType(); DEFAULT_SERVER_CHANNEL_FACTORY = new ReflectiveChannelFactory<>(epollServerChannelType()); EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR = epollEventLoopGroupConstructor(); DEFAULT_BOSS_EVENT_LOOP_GROUP @@ -127,6 +128,7 @@ private static final class ByteBufAllocatorPreferHeapHolder { logger.log(Level.FINE, "Epoll is not available, using Nio.", getEpollUnavailabilityCause()); DEFAULT_SERVER_CHANNEL_FACTORY = nioServerChannelFactory(); DEFAULT_CLIENT_CHANNEL_TYPE = NioSocketChannel.class; + EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE = null; DEFAULT_BOSS_EVENT_LOOP_GROUP = NIO_BOSS_EVENT_LOOP_GROUP; DEFAULT_WORKER_EVENT_LOOP_GROUP = NIO_WORKER_EVENT_LOOP_GROUP; EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR = null; @@ -331,6 +333,17 @@ private static Class epollChannelType() { } } + // Must call when epoll is available + private static Class epollDomainSocketChannelType() { + try { + Class channelType = Class + .forName("io.netty.channel.epoll.EpollDomainSocketChannel").asSubclass(Channel.class); + return channelType; + } catch (ClassNotFoundException e) { + throw new RuntimeException("Cannot load EpollDomainSocketChannel", e); + } + } + // Must call when epoll is available private static Constructor epollEventLoopGroupConstructor() { try { diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index 6e8cedade59..7ed01c564d4 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -36,14 +36,15 @@ import io.grpc.testing.protobuf.SimpleResponse; import io.grpc.testing.protobuf.SimpleServiceGrpc; import io.netty.channel.EventLoopGroup; -import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.epoll.EpollServerDomainSocketChannel; import io.netty.channel.unix.DomainSocketAddress; import java.io.IOException; +import org.junit.After; import org.junit.Assume; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -51,7 +52,9 @@ @RunWith(JUnit4.class) public class UdsNettyChannelProviderTest { - private static final String TEST_SOCKET = "/tmp/test.socket"; + @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); + + private static final String TEST_SOCKET = "/test.socket"; @Rule public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); @@ -61,6 +64,16 @@ public class UdsNettyChannelProviderTest { private EventLoopGroup elg; private EventLoopGroup boss; + @After + public void tearDown() { + if (elg != null) { + elg.shutdownGracefully(); + } + if (boss != null) { + boss.shutdownGracefully(); + } + } + @Test public void provided() { for (ManagedChannelProvider current @@ -123,6 +136,7 @@ public void newChannelBuilder_badScheme() { @Test public void managedChannelRegistry_newChannelBuilder() { + Assume.assumeTrue(Utils.isEpollAvailable()); ManagedChannelBuilder managedChannelBuilder = Grpc.newChannelBuilder("unix:///sock.sock", InsecureChannelCredentials.create()); assertThat(managedChannelBuilder).isNotNull(); @@ -134,10 +148,11 @@ public void managedChannelRegistry_newChannelBuilder() { @Test public void udsClientServerTestUsingProvider() throws IOException { - Assume.assumeTrue(Epoll.isAvailable()); - createUdsServer(TEST_SOCKET); + Assume.assumeTrue(Utils.isEpollAvailable()); + String socketPath = tempFolder.getRoot().getAbsolutePath() + TEST_SOCKET; + createUdsServer(socketPath); ManagedChannelBuilder channelBuilder = - Grpc.newChannelBuilder("unix://" + TEST_SOCKET, InsecureChannelCredentials.create()); + Grpc.newChannelBuilder("unix://" + socketPath, InsecureChannelCredentials.create()); SimpleServiceGrpc.SimpleServiceBlockingStub stub = SimpleServiceGrpc.newBlockingStub(cleanupRule.register(channelBuilder.build())); assertThat(unaryRpc("buddy", stub)).isEqualTo("Hello buddy"); From c53ee5b801a59791105e5114251c4e4f763f9579 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 29 Apr 2022 15:28:59 -0700 Subject: [PATCH 05/11] fix tests for Mac by checking isEpollAvailable() --- .../test/java/io/grpc/netty/UdsNettyChannelProviderTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index 7ed01c564d4..7a2c03a1808 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -104,6 +104,7 @@ public void basicMethods() { @Test public void builderForTarget() { + Assume.assumeTrue(Utils.isEpollAvailable()); assertThat(provider.builderForTarget("unix:sock.sock")).isInstanceOf(NettyChannelBuilder.class); } @@ -119,6 +120,7 @@ public void builderForTarget_badScheme() { @Test public void newChannelBuilder_success() { + Assume.assumeTrue(Utils.isEpollAvailable()); NewChannelBuilderResult result = provider.newChannelBuilder("unix:sock.sock", TlsChannelCredentials.create()); assertThat(result.getChannelBuilder()).isInstanceOf(NettyChannelBuilder.class); From ffc58d0a7e4eed9728fc38d8a5f8258efb8e6fbf Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 29 Apr 2022 16:29:29 -0700 Subject: [PATCH 06/11] address next set of review comments --- netty/build.gradle | 5 +++-- .../main/java/io/grpc/netty/UdsNettyChannelProvider.java | 6 +++++- netty/src/main/java/io/grpc/netty/Utils.java | 3 --- .../java/io/grpc/netty/UdsNettyChannelProviderTest.java | 3 +-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/netty/build.gradle b/netty/build.gradle index 40c48694da0..731cae8ec9c 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -22,13 +22,14 @@ dependencies { libraries.guava, libraries.errorprone, libraries.perfmark, - ("io.netty:netty-transport-native-epoll:${nettyVersion}") + ("io.netty:netty-transport-native-unix-common:${nettyVersion}") // Tests depend on base class defined by core module. testImplementation project(':grpc-core').sourceSets.test.output, project(':grpc-api').sourceSets.test.output, project(':grpc-testing'), - project(':grpc-testing-proto') + project(':grpc-testing-proto'), + ("io.netty:netty-transport-native-epoll:${nettyVersion}") testRuntimeOnly libraries.netty_tcnative, libraries.conscrypt, libraries.netty_epoll diff --git a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java index 34d6e725474..2fa780f06e1 100644 --- a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java +++ b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java @@ -72,13 +72,17 @@ private static NettyChannelBuilder getNettyChannelBuilder( ChannelCredentials creds, CallCredentials callCredentials, ProtocolNegotiator.ClientFactory negotiator) { + if (Utils.EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE == null) { + throw new IllegalStateException("Epoll is not available"); + } String targetPath = UdsNameResolverProvider.getTargetPathFromUri(URI.create(target)); NettyChannelBuilder builder = new NettyChannelBuilder( new DomainSocketAddress(targetPath), creds, callCredentials, negotiator); builder = builder - .eventLoopGroupPool(SharedResourcePool.forResource(Utils.UDS_CHANNELS_EVENT_LOOP_GROUP)) + .eventLoopGroupPool( + SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP)) .channelType(Utils.EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE); return builder; } diff --git a/netty/src/main/java/io/grpc/netty/Utils.java b/netty/src/main/java/io/grpc/netty/Utils.java index 1c2645fe209..58712096cc2 100644 --- a/netty/src/main/java/io/grpc/netty/Utils.java +++ b/netty/src/main/java/io/grpc/netty/Utils.java @@ -89,9 +89,6 @@ class Utils { = new DefaultEventLoopGroupResource(1, "grpc-nio-boss-ELG", EventLoopGroupType.NIO); public static final Resource NIO_WORKER_EVENT_LOOP_GROUP = new DefaultEventLoopGroupResource(0, "grpc-nio-worker-ELG", EventLoopGroupType.NIO); - public static final Resource UDS_CHANNELS_EVENT_LOOP_GROUP = - isEpollAvailable() ? new DefaultEventLoopGroupResource(1, "UdsChannels", - EventLoopGroupType.EPOLL) : null; public static final Resource DEFAULT_BOSS_EVENT_LOOP_GROUP; public static final Resource DEFAULT_WORKER_EVENT_LOOP_GROUP; diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index 7a2c03a1808..f94cebdad5e 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -54,7 +54,6 @@ public class UdsNettyChannelProviderTest { @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); - private static final String TEST_SOCKET = "/test.socket"; @Rule public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); @@ -151,7 +150,7 @@ public void managedChannelRegistry_newChannelBuilder() { @Test public void udsClientServerTestUsingProvider() throws IOException { Assume.assumeTrue(Utils.isEpollAvailable()); - String socketPath = tempFolder.getRoot().getAbsolutePath() + TEST_SOCKET; + String socketPath = tempFolder.getRoot().getAbsolutePath() + "/test.socket"; createUdsServer(socketPath); ManagedChannelBuilder channelBuilder = Grpc.newChannelBuilder("unix://" + socketPath, InsecureChannelCredentials.create()); From dbaa1a917267c6b7ca1ac20da4a19cf8a73894b2 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 29 Apr 2022 17:07:17 -0700 Subject: [PATCH 07/11] fix more tests for Mac by checking isEpollAvailable() --- .../test/java/io/grpc/netty/UdsNettyChannelProviderTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index f94cebdad5e..4bb11af21f0 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -109,6 +109,7 @@ public void builderForTarget() { @Test public void builderForTarget_badScheme() { + Assume.assumeTrue(Utils.isEpollAvailable()); try { provider.builderForTarget("dns:sock.sock"); fail("exception expected"); @@ -127,6 +128,7 @@ public void newChannelBuilder_success() { @Test public void newChannelBuilder_badScheme() { + Assume.assumeTrue(Utils.isEpollAvailable()); try { provider.newChannelBuilder("dns:sock.sock", InsecureChannelCredentials.create()); fail("exception expected"); From 339d0677bb9406fcc692490a469a02a99c257a89 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Mon, 2 May 2022 14:55:10 -0700 Subject: [PATCH 08/11] define netty_unix_common in libraries and fix UdsNettyChannelProvider.isAvailable --- build.gradle | 1 + netty/build.gradle | 2 +- netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f982f600bbe..f898a2d11eb 100644 --- a/build.gradle +++ b/build.gradle @@ -176,6 +176,7 @@ subprojects { netty: "io.netty:netty-codec-http2:[${nettyVersion}]", netty_epoll: "io.netty:netty-transport-native-epoll:${nettyVersion}:linux-x86_64", + netty_unix_common: "io.netty:netty-transport-native-unix-common:${nettyVersion}", netty_epoll_arm64: "io.netty:netty-transport-native-epoll:${nettyVersion}:linux-aarch_64", netty_proxy_handler: "io.netty:netty-handler-proxy:${nettyVersion}", diff --git a/netty/build.gradle b/netty/build.gradle index 731cae8ec9c..e912e09fe0b 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -22,7 +22,7 @@ dependencies { libraries.guava, libraries.errorprone, libraries.perfmark, - ("io.netty:netty-transport-native-unix-common:${nettyVersion}") + libraries.netty_unix_common // Tests depend on base class defined by core module. testImplementation project(':grpc-core').sourceSets.test.output, diff --git a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java index 2fa780f06e1..271f056d21f 100644 --- a/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java +++ b/netty/src/main/java/io/grpc/netty/UdsNettyChannelProvider.java @@ -34,7 +34,7 @@ public final class UdsNettyChannelProvider extends ManagedChannelProvider { @Override public boolean isAvailable() { - return true; + return (Utils.EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE != null); } @Override From 0b5b71ea94a3370601f759e37e67b1c8981d222f Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Mon, 2 May 2022 15:04:35 -0700 Subject: [PATCH 09/11] define netty_epoll_common in libraries and use it from grpc-netty --- build.gradle | 1 + netty/build.gradle | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f898a2d11eb..bb36575570b 100644 --- a/build.gradle +++ b/build.gradle @@ -176,6 +176,7 @@ subprojects { netty: "io.netty:netty-codec-http2:[${nettyVersion}]", netty_epoll: "io.netty:netty-transport-native-epoll:${nettyVersion}:linux-x86_64", + netty_epoll_common: "io.netty:netty-transport-native-epoll:${nettyVersion}", netty_unix_common: "io.netty:netty-transport-native-unix-common:${nettyVersion}", netty_epoll_arm64: "io.netty:netty-transport-native-epoll:${nettyVersion}:linux-aarch_64", netty_proxy_handler: "io.netty:netty-handler-proxy:${nettyVersion}", diff --git a/netty/build.gradle b/netty/build.gradle index e912e09fe0b..78fb3b4e356 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -29,7 +29,7 @@ dependencies { project(':grpc-api').sourceSets.test.output, project(':grpc-testing'), project(':grpc-testing-proto'), - ("io.netty:netty-transport-native-epoll:${nettyVersion}") + libraries.netty_epoll_common testRuntimeOnly libraries.netty_tcnative, libraries.conscrypt, libraries.netty_epoll From f87fd5687f636681989680187983ddecf9b3b99e Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Mon, 2 May 2022 15:57:34 -0700 Subject: [PATCH 10/11] change the test to make it dependent on provider being available --- .../test/java/io/grpc/netty/UdsNettyChannelProviderTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java index 4bb11af21f0..047c1018dab 100644 --- a/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java +++ b/netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java @@ -18,7 +18,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import io.grpc.Grpc; @@ -97,7 +96,7 @@ public void providedHardCoded() { @Test public void basicMethods() { - assertTrue(provider.isAvailable()); + Assume.assumeTrue(provider.isAvailable()); assertEquals(3, provider.priority()); } From a835b31303a0eb13f56cb10273ead9776f89eb95 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Mon, 2 May 2022 16:09:41 -0700 Subject: [PATCH 11/11] fix bazel build --- netty/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/netty/BUILD.bazel b/netty/BUILD.bazel index 668abc3ca30..c1768b61e75 100644 --- a/netty/BUILD.bazel +++ b/netty/BUILD.bazel @@ -20,6 +20,7 @@ java_library( "@io_netty_netty_codec_http2//jar", "@io_netty_netty_codec_socks//jar", "@io_netty_netty_common//jar", + "@io_netty_netty_transport_native_unix_common//jar", "@io_netty_netty_handler//jar", "@io_netty_netty_handler_proxy//jar", "@io_netty_netty_resolver//jar",