All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aerospike.client.async.NettyEventLoops Maven / Gradle / Ivy

/*
 * Copyright 2012-2021 Aerospike, Inc.
 *
 * Portions may be licensed to Aerospike, Inc. under one or more contributor
 * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
 *
 * 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 com.aerospike.client.async;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.KeyManagerFactory;

import com.aerospike.client.AerospikeException;
import com.aerospike.client.policy.ClientPolicy;
import com.aerospike.client.policy.TCPKeepAlive;
import com.aerospike.client.policy.TlsPolicy;
import com.aerospike.client.util.Util;

import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.ssl.CipherSuiteFilter;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
import io.netty.handler.ssl.JdkSslContext;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.util.concurrent.EventExecutor;

/**
 * Aerospike wrapper around netty event loops.
 * Implements the Aerospike EventLoops interface.
 */
public final class NettyEventLoops implements EventLoops, CipherSuiteFilter {

	private final Map eventLoopMap;
	private final NettyEventLoop[] eventLoopArray;
	private final EventLoopGroup group;
	TlsPolicy tlsPolicy;
	TCPKeepAlive keepAlive;
	SslContext sslContext;
	final EventLoopType eventLoopType;
	private int eventIter;

	/**
	 * Create Aerospike event loop wrappers from given netty event loops.
	 */
	public NettyEventLoops(EventLoopGroup group) {
		this(new EventPolicy(), group);
	}

	/**
	 * Create Aerospike event loop wrappers from given netty event loops.
	 */
	public NettyEventLoops(EventPolicy policy, EventLoopGroup group) {
		if (policy.minTimeout < 5) {
			throw new AerospikeException("Invalid minTimeout " + policy.minTimeout + ". Must be at least 5ms.");
		}
		this.group = group;

		if (group instanceof NioEventLoopGroup) {
			this.eventLoopType = EventLoopType.NETTY_NIO;
		}
		else if (group instanceof EpollEventLoopGroup) {
			this.eventLoopType = EventLoopType.NETTY_EPOLL;
		}
		else if (group instanceof KQueueEventLoopGroup) {
			this.eventLoopType = EventLoopType.NETTY_KQUEUE;
		}
		else {
			throw new AerospikeException("Unexpected EventLoopGroup");
		}

		ArrayList list = new ArrayList();
		Iterator iter = group.iterator();
		int count = 0;

		while (iter.hasNext()) {
			EventExecutor eventExecutor = iter.next();
			list.add(new NettyEventLoop(policy, (io.netty.channel.EventLoop)eventExecutor, this, count++));
		}

		eventLoopArray = list.toArray(new NettyEventLoop[count]);
		eventLoopMap = new IdentityHashMap(count);

		for (NettyEventLoop eventLoop : eventLoopArray) {
			eventLoopMap.put(eventLoop.eventLoop, eventLoop);
		}

		// Start timer in each event loop thread.
		for (NettyEventLoop eventLoop : eventLoopArray) {
			eventLoop.execute(new Runnable() {
				public void run() {
					eventLoop.timer.start();
				}
			});
		}
	}

	/**
	 * Initialize event loops with client policy. For internal use only.
	 */
	@Override
	public void init(ClientPolicy policy) {
		if (policy.tlsPolicy != null) {
			initTlsContext(policy.tlsPolicy);
		}
		this.keepAlive = policy.keepAlive;
	}

	/**
	 * Initialize TLS context. For internal use only.
	 */
	public void initTlsContext(TlsPolicy policy) {
		if (this.tlsPolicy != null) {
			// Already initialized.
			return;
		}

		this.tlsPolicy = policy;

		if (policy.context != null) {
			CipherSuiteFilter csf = (policy.ciphers != null)? this : IdentityCipherSuiteFilter.INSTANCE;
			sslContext = new JdkSslContext(policy.context, true, null, csf, null, ClientAuth.NONE, null, false);
			return;
		}

		try {
			SslContextBuilder builder = SslContextBuilder.forClient();

			if (policy.protocols != null) {
				builder.protocols(policy.protocols);
			}

			if (policy.ciphers != null) {
				builder.ciphers(Arrays.asList(policy.ciphers));
			}

			String keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");

			// Keystore is only required for mutual authentication.
			if (keyStoreLocation != null) {
				String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
				char[] pass = (keyStorePassword != null) ? keyStorePassword.toCharArray() : null;

				KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
				FileInputStream is = new FileInputStream(keyStoreLocation);

				try {
					ks.load(is, pass);
				}
				finally {
					is.close();
				}

				KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
				kmf.init(ks, pass);

				builder.keyManager(kmf);
			}

			sslContext = builder.build();
		}
		catch (Exception e) {
			throw new AerospikeException("Failed to init netty TLS: " + Util.getErrorMessage(e));
		}
	}

	/**
	 * Filter cipher suites.  For internal use only.
	 */
	@Override
	public String[] filterCipherSuites(Iterable ciphers, List defaultCiphers, Set supportedCiphers) {
		if (tlsPolicy.ciphers != null) {
			return tlsPolicy.ciphers;
		}
		return tlsPolicy.context.getSupportedSSLParameters().getCipherSuites();
	}

	/**
	 * Return corresponding Aerospike event loop given netty event loop.
	 */
	public NettyEventLoop get(EventExecutor eventExecutor) {
		return eventLoopMap.get(eventExecutor);
	}

	/**
	 * Return array of Aerospike event loops.
	 */
	@Override
	public NettyEventLoop[] getArray() {
		return eventLoopArray;
	}

	/**
	 * Return number of event loops in this group.
	 */
	@Override
	public int getSize() {
		return eventLoopArray.length;
	}

	/**
	 * Return Aerospike event loop given array index..
	 */
	@Override
	public NettyEventLoop get(int index) {
		return eventLoopArray[index];
	}

	/**
	 * Return next Aerospike event loop in round-robin fashion.
	 */
	@Override
	public NettyEventLoop next() {
		int iter = eventIter++; // Not atomic by design
		iter = iter % eventLoopArray.length;

		if (iter < 0) {
			iter += eventLoopArray.length;
		}
		return eventLoopArray[iter];
	}

	@Override
	public void close() {
		group.shutdownGracefully();
		/*
		for (NettyEventLoop el : eventLoopArray) {
			el.timer.printRemaining();
		}*/
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy