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

com.firefly.net.tcp.SimpleTcpServer Maven / Gradle / Ivy

There is a newer version: 5.0.0-dev6
Show newest version
package com.firefly.net.tcp;

import java.nio.ByteBuffer;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

import org.eclipse.jetty.alpn.ALPN;

import com.firefly.net.Handler;
import com.firefly.net.Session;
import com.firefly.net.tcp.aio.AsynchronousTcpServer;
import com.firefly.net.tcp.ssl.SSLSession;
import com.firefly.utils.function.Action0;
import com.firefly.utils.function.Action1;
import com.firefly.utils.function.Action2;
import com.firefly.utils.function.Func1;
import com.firefly.utils.lang.AbstractLifeCycle;

public class SimpleTcpServer extends AbstractLifeCycle {

	// accept TCP connection callback
	protected Action1 accept;
	protected Action2 failedAcceptance;

	// ALPN callback
	protected Action0 alpnUnsupported;
	protected Func1, String> alpnSelectProtocols;

	protected AsynchronousTcpServer server;
	protected TcpServerConfiguration config;

	public SimpleTcpServer() {
		this(new TcpServerConfiguration());
	}

	public SimpleTcpServer(TcpServerConfiguration config) {
		this.config = config;
		server = new AsynchronousTcpServer(config);
	}

	public SimpleTcpServer accept(Action1 accept) {
		this.accept = accept;
		return this;
	}

	public SimpleTcpServer accept(Action1 accept, Action2 failed) {
		this.accept = accept;
		this.failedAcceptance = failed;
		return this;
	}

	public SimpleTcpServer alpnUnsupported(Action0 alpnUnsupported) {
		this.alpnUnsupported = alpnUnsupported;
		return this;
	}

	public SimpleTcpServer alpnSelectProtocols(Func1, String> alpnSelectProtocols) {
		this.alpnSelectProtocols = alpnSelectProtocols;
		return this;
	}

	public void listen(String host, int port) {
		config.setHost(host);
		config.setPort(port);
		start();
	}

	public abstract class AbstractHandler implements Handler {

		@Override
		public void sessionClosed(Session session) throws Throwable {
			Object o = session.getAttachment();
			if (o != null && o instanceof AbstractTcpConnection) {
				AbstractTcpConnection c = (AbstractTcpConnection) o;
				if (c.closeCallback != null) {
					c.closeCallback.call();
				}
			}
		}

		@Override
		public void messageRecieved(Session session, Object message) throws Throwable {
		}

		@Override
		public void exceptionCaught(Session session, Throwable t) throws Throwable {
			Object o = session.getAttachment();
			if (o != null && o instanceof AbstractTcpConnection) {
				AbstractTcpConnection c = (AbstractTcpConnection) o;
				if (c.exception != null) {
					c.exception.call(t);
				}
			}

		}

		@Override
		public void failedAcceptingSession(Integer sessionId, Throwable t) throws Throwable {
			if (failedAcceptance != null) {
				failedAcceptance.call(sessionId, t);
			}
		}

	}

	@Override
	protected void init() {
		if (config.isSecureConnectionEnabled() == false) {
			config.setDecoder((ByteBuffer buf, Session session) -> {
				Object o = session.getAttachment();
				if (o != null) {
					TcpConnectionImpl c = (TcpConnectionImpl) o;
					if (c.buffer != null) {
						c.buffer.call(buf);
					}
				}
			});
			config.setHandler(new AbstractHandler() {

				@Override
				public void sessionOpened(Session session) throws Throwable {
					TcpConnectionImpl c = new TcpConnectionImpl(session);
					session.attachObject(c);
					if (accept != null) {
						accept.call(c);
					}
				}

			});
		} else {
			config.setDecoder((ByteBuffer buf, Session session) -> {
				Object o = session.getAttachment();
				if (o != null && o instanceof SecureTcpConnectionImpl) {
					SecureTcpConnectionImpl c = (SecureTcpConnectionImpl) o;
					ByteBuffer plaintext = c.sslSession.read(buf);
					if (plaintext != null && c.sslSession.isHandshakeFinished()) {
						if (c.buffer != null) {
							c.buffer.call(plaintext);
						}
					}
				}
			});
			config.setHandler(new AbstractHandler() {

				private SSLContext sslContext = config.getSslContextFactory().getSSLContext();

				@Override
				public void sessionOpened(Session session) throws Throwable {

					final SSLEngine sslEngine = sslContext.createSSLEngine();
					SSLSession sslSession = new SSLSession(sslContext, sslEngine, session, false, (ssl) -> {
						Object o = session.getAttachment();
						if (o != null && o instanceof SecureTcpConnectionImpl) {
							SecureTcpConnectionImpl c = (SecureTcpConnectionImpl) o;
							if (accept != null) {
								accept.call(c);
							}
						}
					}, new ALPN.ServerProvider() {

						@Override
						public void unsupported() {
							try {
								alpnUnsupported.call();
							} finally {
								ALPN.remove(sslEngine);
							}
						}

						@Override
						public String select(List protocols) {
							try {
								return alpnSelectProtocols.call(protocols);
							} finally {
								ALPN.remove(sslEngine);
							}
						}
					});
					SecureTcpConnectionImpl c = new SecureTcpConnectionImpl(session, sslSession);
					session.attachObject(c);
				}

				@Override
				public void sessionClosed(Session session) throws Throwable {
					try {
						super.sessionClosed(session);
					} finally {
						Object o = session.getAttachment();
						if (o != null && o instanceof SecureTcpConnectionImpl) {
							SecureTcpConnectionImpl c = (SecureTcpConnectionImpl) o;
							c.sslSession.close();
						}
					}
				}

			});
		}
		server.listen(config.getHost(), config.getPort());
	}

	@Override
	protected void destroy() {
		server.stop();
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy