package org.iota.compass; import com.beust.jcommander.JCommander; import io.grpc.Server; import io.grpc.netty.GrpcSslContexts; import io.grpc.netty.NettyServerBuilder; import io.grpc.stub.StreamObserver; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import org.iota.compass.conf.SignatureSourceServerConfiguration; import org.iota.compass.proto.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; public class SignatureSourceServer { private static final Logger log = LoggerFactory.getLogger(SignatureSourceServer.class); private final SignatureSourceServerConfiguration config; private final SignatureSource signatureSource; private Server server; public SignatureSourceServer(SignatureSourceServerConfiguration config) { this.config = config; this.signatureSource = new InMemorySignatureSource(config.sigMode, config.seed, config.security); } public static void main(String[] args) throws IOException, InterruptedException { SignatureSourceServerConfiguration config = new SignatureSourceServerConfiguration(); JCommander.newBuilder() .addObject(config) .build() .parse(args); final SignatureSourceServer server = new SignatureSourceServer(config); server.start(); server.blockUntilShutdown(); } public void start() throws IOException { NettyServerBuilder builder = NettyServerBuilder.forPort(config.port) .addService(new SignatureSourceImpl(signatureSource)); if (!config.plaintext) { if (config.certChain == null || config.certChain.isEmpty()) { throw new IllegalArgumentException("-certChain is required if not running in plaintext mode"); } if (config.privateKey == null || config.privateKey.isEmpty()) { throw new IllegalArgumentException("-privateKey is required if not running in plaintext mode"); } SslContextBuilder sslClientContextBuilder = SslContextBuilder.forServer(new File(config.certChain), new File(config.privateKey)); if (config.trustCertCollection != null) { sslClientContextBuilder.trustManager(new File(config.trustCertCollection)); sslClientContextBuilder.clientAuth(ClientAuth.REQUIRE); } builder = builder.sslContext(GrpcSslContexts.configure(sslClientContextBuilder, SslProvider.OPENSSL).build()); } server = builder.build(); server.start(); log.info("Server started, listening on " + config.port); Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.err.println("*** shutting down gRPC server since JVM is shutting down"); SignatureSourceServer.this.stop(); System.err.println("*** server shut down"); })); } public void stop() { if (server != null) { server.shutdown(); } } public void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } static class SignatureSourceImpl extends SignatureSourceGrpc.SignatureSourceImplBase { private final SignatureSource signatureSource; public SignatureSourceImpl(SignatureSource signatureSource) { super(); this.signatureSource = signatureSource; } @Override public void getSecurity(GetSecurityRequest request, StreamObserver<GetSecurityResponse> responseObserver) { log.info("Responding to getSecurity"); responseObserver.onNext(GetSecurityResponse.newBuilder() .setSecurity(signatureSource.getSecurity()) .build()); responseObserver.onCompleted(); } @Override public void getSignatureMode(GetSignatureModeRequest request, StreamObserver<GetSignatureModeResponse> responseObserver) { log.info("Responding to getSignatureMode"); SignatureMode mode; switch (signatureSource.getSignatureMode()) { case CURLP27: mode = SignatureMode.CURLP27; break; case CURLP81: mode = SignatureMode.CURLP81; break; case KERL: mode = SignatureMode.KERL; break; default: throw new RuntimeException(); } responseObserver.onNext(GetSignatureModeResponse.newBuilder() .setMode(mode) .build()); responseObserver.onCompleted(); } @Override public void getSignature(GetSignatureRequest request, StreamObserver<GetSignatureResponse> responseObserver) { log.info("Responding to getSignature for index: " + request.getIndex() + " and hash: " + request.getHash()); responseObserver.onNext(GetSignatureResponse.newBuilder() .setSignature(signatureSource.getSignature(request.getIndex(), request.getHash())) .build()); responseObserver.onCompleted(); } @Override public void getAddress(GetAddressRequest request, StreamObserver<GetAddressResponse> responseObserver) { log.info("Responding to getAddress for index: " + request.getIndex()); responseObserver.onNext(GetAddressResponse.newBuilder() .setAddress(signatureSource.getAddress(request.getIndex())) .build()); responseObserver.onCompleted(); } } }