Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
class GrpcServerIntegrationTests {

@Nested
@SpringBootTest(properties = { "spring.grpc.server.address=0.0.0.0", "spring.grpc.server.port=0" })
@SpringBootTest(properties = { "spring.grpc.server.host=0.0.0.0", "spring.grpc.server.port=0" })
class ServerWithAnyIPv4AddressAndRandomPort {

@Test
Expand All @@ -55,7 +55,7 @@ void servesResponseToClientWithAnyIPv4AddressAndRandomPort(@Autowired GrpcChanne
}

@Nested
@SpringBootTest(properties = { "spring.grpc.server.address=::", "spring.grpc.server.port=0" })
@SpringBootTest(properties = { "spring.grpc.server.host=::", "spring.grpc.server.port=0" })
class ServerWithAnyIPv6AddressAndRandomPort {

@Test
Expand All @@ -67,7 +67,7 @@ void servesResponseToClientWithAnyIPv4AddressAndRandomPort(@Autowired GrpcChanne
}

@Nested
@SpringBootTest(properties = { "spring.grpc.server.address=127.0.0.1", "spring.grpc.server.port=0" })
@SpringBootTest(properties = { "spring.grpc.server.host=127.0.0.1", "spring.grpc.server.port=0" })
class ServerWithLocalhostAndRandomPort {

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024-2024 the original author or 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
*
* https://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 org.springframework.grpc.internal;

public class GrpcUtils {

public static int DEFAULT_PORT = 9090;

public static int getPort(String address) {
String value = address;
if (value.contains(":")) {
value = value.substring(value.lastIndexOf(":") + 1);
}
if (value.contains("/")) {
value = value.substring(0, value.indexOf("/"));
}
if (value.matches("[0-9]+")) {
return Integer.parseInt(value);
}
if (address.startsWith("unix:")) {
return -1;
}
return DEFAULT_PORT;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@
import java.util.Set;

import com.google.common.collect.Lists;

import io.grpc.Grpc;
import io.grpc.InsecureServerCredentials;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.ServerCredentials;
import io.grpc.ServerProvider;
import io.grpc.ServerServiceDefinition;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.grpc.internal.GrpcUtils;

/**
* Default implementation for {@link GrpcServerFactory gRPC service factories}.
Expand All @@ -48,25 +54,17 @@ public class DefaultGrpcServerFactory<T extends ServerBuilder<T>> implements Grp

private final String address;

private final int port;

private final List<ServerBuilderCustomizer<T>> serverBuilderCustomizers;

public DefaultGrpcServerFactory(String address, int port,
List<ServerBuilderCustomizer<T>> serverBuilderCustomizers) {
public DefaultGrpcServerFactory(String address, List<ServerBuilderCustomizer<T>> serverBuilderCustomizers) {
this.address = address;
this.port = port;
this.serverBuilderCustomizers = Objects.requireNonNull(serverBuilderCustomizers, "serverBuilderCustomizers");
}

protected String getAddress() {
protected String address() {
return this.address;
}

protected int getPort() {
return this.port;
}

@Override
public Server createServer() {
T builder = newServerBuilder();
Expand All @@ -85,7 +83,23 @@ public void addService(ServerServiceDefinition service) {
*/
@SuppressWarnings("unchecked")
protected T newServerBuilder() {
return (T) ServerBuilder.forPort(port);
return (T) Grpc.newServerBuilderForPort(port(), credentials());
}

/**
* Returns the port number on which the server should listen. Use 0 to let the system
* choose a port. Use -1 to denote that this server does not listen on a socket.
* @return the port number
*/
protected int port() {
return GrpcUtils.getPort(address());
}

/**
* @return some server credentials (default is insecure)
*/
protected ServerCredentials credentials() {
return InsecureServerCredentials.create();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

package org.springframework.grpc.server;

import java.net.InetSocketAddress;
import java.util.List;

import com.google.common.net.InetAddresses;
import javax.net.ssl.KeyManagerFactory;

import io.grpc.ServerCredentials;
import io.grpc.TlsServerCredentials;
import io.grpc.netty.NettyServerBuilder;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerDomainSocketChannel;
Expand All @@ -33,34 +35,33 @@
*/
public class NettyGrpcServerFactory extends DefaultGrpcServerFactory<NettyServerBuilder> {

private static final String ANY_IP_ADDRESS = "*";
private KeyManagerFactory keyManager;

public NettyGrpcServerFactory(String address, int port,
public NettyGrpcServerFactory(String address, KeyManagerFactory keyManager,
List<ServerBuilderCustomizer<NettyServerBuilder>> serverBuilderCustomizers) {
super(address, port, serverBuilderCustomizers);
super(address, serverBuilderCustomizers);
this.keyManager = keyManager;
}

/**
* Creates a new server builder.
* @return The newly created server builder.
*/
@Override
protected NettyServerBuilder newServerBuilder() {
String address = getAddress();
int port = getPort();
if (address != null) {
if (address.startsWith("unix:")) {
String path = address.substring(5);
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
.channelType(EpollServerDomainSocketChannel.class)
.bossEventLoopGroup(new EpollEventLoopGroup(1))
.workerEventLoopGroup(new EpollEventLoopGroup());
}
if (!ANY_IP_ADDRESS.equals(address)) {
return NettyServerBuilder.forAddress(new InetSocketAddress(InetAddresses.forString(address), port));
}
// TODO: Add more support for address resolution
String address = address();
if (address.startsWith("unix:")) {
String path = address.substring(5);
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
.channelType(EpollServerDomainSocketChannel.class)
.bossEventLoopGroup(new EpollEventLoopGroup(1))
.workerEventLoopGroup(new EpollEventLoopGroup());
}
return super.newServerBuilder();
}

@Override
protected ServerCredentials credentials() {
if (this.keyManager == null || port() == -1) {
return super.credentials();
}
return TlsServerCredentials.newBuilder().keyManager(this.keyManager.getKeyManagers()).build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

package org.springframework.grpc.server;

import java.net.InetSocketAddress;
import java.util.List;

import com.google.common.net.InetAddresses;
import javax.net.ssl.KeyManagerFactory;

import io.grpc.ServerCredentials;
import io.grpc.TlsServerCredentials;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup;
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerDomainSocketChannel;
Expand All @@ -33,34 +35,33 @@
*/
public class ShadedNettyGrpcServerFactory extends DefaultGrpcServerFactory<NettyServerBuilder> {

private static final String ANY_IP_ADDRESS = "*";
private KeyManagerFactory keyManager;

public ShadedNettyGrpcServerFactory(String address, int port,
public ShadedNettyGrpcServerFactory(String address, KeyManagerFactory keyManager,
List<ServerBuilderCustomizer<NettyServerBuilder>> serverBuilderCustomizers) {
super(address, port, serverBuilderCustomizers);
super(address, serverBuilderCustomizers);
this.keyManager = keyManager;
}

/**
* Creates a new server builder.
* @return The newly created server builder.
*/
@Override
protected NettyServerBuilder newServerBuilder() {
String address = getAddress();
int port = getPort();
if (address != null) {
if (address.startsWith("unix:")) {
String path = address.substring(5);
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
.channelType(EpollServerDomainSocketChannel.class)
.bossEventLoopGroup(new EpollEventLoopGroup(1))
.workerEventLoopGroup(new EpollEventLoopGroup());
}
if (!ANY_IP_ADDRESS.equals(address)) {
return NettyServerBuilder.forAddress(new InetSocketAddress(InetAddresses.forString(address), port));
}
// TODO: Add more support for address resolution
String address = address();
if (address.startsWith("unix:")) {
String path = address.substring(5);
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
.channelType(EpollServerDomainSocketChannel.class)
.bossEventLoopGroup(new EpollEventLoopGroup(1))
.workerEventLoopGroup(new EpollEventLoopGroup());
}
return super.newServerBuilder();
}

@Override
protected ServerCredentials credentials() {
if (this.keyManager == null || port() == -1) {
return super.credentials();
}
return TlsServerCredentials.newBuilder().keyManager(this.keyManager.getKeyManagers()).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.springframework.grpc.internal;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

class GrpcUtilsTests {

@Test
void testGetPortFromAddress() {
assertEquals(8080, GrpcUtils.getPort("localhost:8080"));
}

@Test
void testGetNoPort() {
assertEquals(9090, GrpcUtils.getPort("localhost"));
}

@Test
void testGetPortFromAddressWithPath() {
String address = "example.com:1234/path";
assertEquals(1234, GrpcUtils.getPort(address));
}

@Test
void testGetDomainAddress() {
String address = "unix:/some/file/somewhere";
assertEquals(-1, GrpcUtils.getPort(address));
}

@Test
void testGetStaticSchema() {
String address = "static://localhost";
assertEquals(9090, GrpcUtils.getPort(address));
}

@Test
void testGetInvalidAddress() {
String address = "invalid:broken";
assertEquals(9090, GrpcUtils.getPort(address)); // -1?
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
|spring.grpc.client.default-channel.ssl.bundle | | SSL bundle name.
|spring.grpc.client.default-channel.ssl.enabled | | Whether to enable SSL support. Enabled automatically if "bundle" is provided unless specified otherwise.
|spring.grpc.client.default-channel.user-agent | |
|spring.grpc.server.address | `+++*+++` | Server address to bind to. The default is any IP address ('*').
|spring.grpc.server.address | | The address to bind to. could be a host:port combination or a pseudo URL like static://host:port. Can not be set if host or port are set independently.
|spring.grpc.server.host | `+++*+++` | Server address to bind to. The default is any IP address ('*').
|spring.grpc.server.keep-alive.max-age | | Maximum time a connection may exist before being gracefully terminated (default infinite).
|spring.grpc.server.keep-alive.max-age-grace | | Maximum time for graceful connection termination (default infinite).
|spring.grpc.server.keep-alive.max-idle | | Maximum time a connection can remain idle before being gracefully terminated (default infinite).
Expand All @@ -26,7 +27,7 @@
|spring.grpc.server.keep-alive.timeout | `+++20s+++` | Maximum time to wait for read activity after sending a keep alive ping. If sender does not receive an acknowledgment within this time, it will close the connection (default 20s).
|spring.grpc.server.max-inbound-message-size | `+++4194304B+++` | Maximum message size allowed to be received by the server (default 4MiB).
|spring.grpc.server.max-inbound-metadata-size | `+++8192B+++` | Maximum metadata size allowed to be received by the server (default 8KiB).
|spring.grpc.server.port | `+++9090+++` | Server port to listen on. When the value is 0, a random available port is selected. The default is 9090.
|spring.grpc.server.port | | Server port to listen on. When the value is 0, a random available port is selected. The default is 9090.
|spring.grpc.server.shutdown-grace-period | `+++30s+++` | Maximum time to wait for the server to gracefully shutdown. When the value is negative, the server waits forever. When the value is 0, the server will force shutdown immediately. The default is 30 seconds.
|spring.grpc.server.ssl.bundle | | SSL bundle name.
|spring.grpc.server.ssl.enabled | | Whether to enable SSL support. Enabled automatically if "bundle" is provided unless specified otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package org.springframework.grpc.autoconfigure.client;

import java.net.URI;
import java.util.List;

import javax.net.ssl.SSLException;
Expand All @@ -33,7 +32,6 @@
import org.springframework.grpc.client.ShadedNettyGrpcChannelFactory;
import org.springframework.grpc.client.VirtualTargets;

import io.grpc.ManagedChannelBuilder;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
Expand Down Expand Up @@ -142,21 +140,6 @@ private static io.grpc.netty.NegotiationType of(final NegotiationType negotiatio

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ManagedChannelBuilder.class)
@ConditionalOnMissingBean(GrpcChannelFactory.class)
public static class DefaultChannelFactoryConfiguration {

@Bean
public DefaultGrpcChannelFactory defaultGrpcChannelFactory(final List<GrpcChannelConfigurer> configurers,
GrpcClientProperties channels) {
DefaultGrpcChannelFactory factory = new DefaultGrpcChannelFactory(configurers);
factory.setVirtualTargets(new NamedChannelVirtualTargets(channels));
return factory;
}

}

static class NamedChannelVirtualTargets implements VirtualTargets {

private final GrpcClientProperties channels;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(GrpcClientProperties.class)
@Import({ GrpcChannelFactoryConfigurations.ShadedNettyChannelFactoryConfiguration.class,
GrpcChannelFactoryConfigurations.NettyChannelFactoryConfiguration.class,
GrpcChannelFactoryConfigurations.DefaultChannelFactoryConfiguration.class })
GrpcChannelFactoryConfigurations.NettyChannelFactoryConfiguration.class })
public class GrpcClientAutoConfiguration {

@Bean
Expand Down
Loading