summaryrefslogtreecommitdiffstats
path: root/simple/simple-transport/src/main/java/org/simpleframework/transport/connect/SocketAcceptor.java
diff options
context:
space:
mode:
Diffstat (limited to 'simple/simple-transport/src/main/java/org/simpleframework/transport/connect/SocketAcceptor.java')
-rw-r--r--simple/simple-transport/src/main/java/org/simpleframework/transport/connect/SocketAcceptor.java315
1 files changed, 315 insertions, 0 deletions
diff --git a/simple/simple-transport/src/main/java/org/simpleframework/transport/connect/SocketAcceptor.java b/simple/simple-transport/src/main/java/org/simpleframework/transport/connect/SocketAcceptor.java
new file mode 100644
index 0000000..ca6fc92
--- /dev/null
+++ b/simple/simple-transport/src/main/java/org/simpleframework/transport/connect/SocketAcceptor.java
@@ -0,0 +1,315 @@
+/*
+ * Acceptor.java October 2002
+ *
+ * Copyright (C) 2002, Niall Gallagher <niallg@users.sf.net>
+ *
+ * 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 org.simpleframework.transport.connect;
+
+import static org.simpleframework.transport.connect.ConnectionEvent.ACCEPT;
+import static org.simpleframework.transport.connect.ConnectionEvent.ERROR;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.simpleframework.transport.SocketProcessor;
+import org.simpleframework.transport.Socket;
+import org.simpleframework.transport.SocketWrapper;
+import org.simpleframework.transport.reactor.Operation;
+import org.simpleframework.transport.trace.Trace;
+import org.simpleframework.transport.trace.TraceAnalyzer;
+
+/**
+ * The <code>SocketAcceptor</code> object is used to accept incoming
+ * TCP connections from a specified socket address. This is used by
+ * the <code>Connection</code> object as a background process to
+ * accept the connections and hand them to a socket connector.
+ * <p>
+ * This is capable of processing SSL connections created by the
+ * internal server socket. All SSL connections are forced to finish
+ * the SSL handshake before being dispatched to the server. This
+ * ensures that there are no problems with reading the request.
+ *
+ * @author Niall Gallagher
+ *
+ * @see org.simpleframework.transport.connect.SocketConnection
+ */
+class SocketAcceptor implements Operation {
+
+ /**
+ * This is the server socket channel used to accept connections.
+ */
+ private final ServerSocketChannel listener;
+
+ /**
+ * The handler that manages the incoming TCP connections.
+ */
+ private final SocketProcessor processor;
+
+ /**
+ * This is the server socket to bind the socket address to.
+ */
+ private final ServerSocket socket;
+
+ /**
+ * If provided the SSL context is used to create SSL engines.
+ */
+ private final SSLContext context;
+
+ /**
+ * This is the tracing analyzer used to trace accepted sockets.
+ */
+ private final TraceAnalyzer analyzer;
+
+ /**
+ * This is the local address to bind the listen socket to.
+ */
+ private final SocketAddress address;
+
+ /**
+ * This is used to collect trace events with the acceptor.
+ */
+ private final Trace trace;
+
+ /**
+ * Constructor for the <code>SocketAcceptor</code> object. This
+ * accepts new TCP connections from the specified server socket.
+ * Each of the connections that is accepted is configured for
+ * performance for the application.
+ *
+ * @param address this is the address to accept connections from
+ * @param processor this is used to initiate the HTTP processing
+ * @param analyzer this is the tracing analyzer to be used
+ */
+ public SocketAcceptor(SocketAddress address, SocketProcessor processor, TraceAnalyzer analyzer) throws IOException {
+ this(address, processor, analyzer, null);
+ }
+
+ /**
+ * Constructor for the <code>SocketAcceptor</code> object. This
+ * accepts new TCP connections from the specified server socket.
+ * Each of the connections that is accepted is configured for
+ * performance for the applications.
+ *
+ * @param address this is the address to accept connections from
+ * @param processor this is used to initiate the HTTP processing
+ * @param analyzer this is the tracing analyzer to be used
+ * @param context this is the SSL context used for secure HTTPS
+ */
+ public SocketAcceptor(SocketAddress address, SocketProcessor processor, TraceAnalyzer analyzer, SSLContext context) throws IOException {
+ this.listener = ServerSocketChannel.open();
+ this.trace = analyzer.attach(listener);
+ this.socket = listener.socket();
+ this.context = context;
+ this.analyzer = analyzer;
+ this.processor = processor;
+ this.address = address;
+ }
+
+ /**
+ * This is used to acquire the local socket address that this is
+ * listening to. This required in case the socket address that
+ * is specified is an emphemeral address, that is an address that
+ * is assigned dynamically when a port of 0 is specified.
+ *
+ * @return this returns the address for the listening address
+ */
+ public SocketAddress getAddress() {
+ return socket.getLocalSocketAddress();
+ }
+
+ /**
+ * This is used to acquire the trace object that is associated
+ * with the operation. A trace object is used to collection details
+ * on what operations are being performed. For instance it may
+ * contain information relating to I/O events or errors.
+ *
+ * @return this returns the trace associated with this operation
+ */
+ public Trace getTrace() {
+ return trace;
+ }
+
+ /**
+ * This is the <code>SelectableChannel</code> which is used to
+ * determine if the operation should be executed. If the channel
+ * is ready for a given I/O event it can be run. For instance if
+ * the operation is used to perform some form of read operation
+ * it can be executed when ready to read data from the channel.
+ *
+ * @return this returns the channel used to govern execution
+ */
+ public SelectableChannel getChannel() {
+ return listener;
+ }
+
+ /**
+ * This is used to configure the server socket for non-blocking
+ * mode. It will also bind the server socket to the socket port
+ * specified in the <code>SocketAddress</code> object. Once done
+ * the acceptor is ready to accept newly arriving connections.
+ *
+ * @param address this is the server socket address to bind to
+ */
+ public void bind() throws IOException {
+ listener.configureBlocking(false);
+ socket.setReuseAddress(true);
+ socket.bind(address, 100);
+ }
+
+ /**
+ * This is used to accept a new TCP connections. When the socket
+ * is ready to accept a connection this method is invoked. It will
+ * then create a HTTP pipeline object using the accepted socket
+ * and if provided with an <code>SSLContext</code> it will also
+ * provide an <code>SSLEngine</code> which is handed to the
+ * processor to handle the HTTP requests.
+ */
+ public void run() {
+ try {
+ accept();
+ } catch(Exception cause) {
+ pause();
+ }
+ }
+
+ /**
+ * This is used to throttle the acceptor when there is an error
+ * such as exhaustion of file descriptors. This will prevent the
+ * CPU from being hogged by the acceptor on such occasions. If
+ * the thread can not be put to sleep then this will freeze.
+ */
+ private void pause() {
+ try {
+ Thread.sleep(10);
+ } catch(Exception cause) {
+ trace.trace(ERROR, cause);
+ }
+ }
+
+ /**
+ * This is used to cancel the operation if the reactor decides to
+ * reject it for some reason. Typically this method will never be
+ * invoked as this operation never times out. However, should the
+ * reactor cancel the operation this will close the socket.
+ */
+ public void cancel() {
+ try {
+ close();
+ } catch(Throwable cause) {
+ trace.trace(ERROR, cause);
+ }
+ }
+
+ /**
+ * The main processing done by this object is done using a thread
+ * calling the <code>run</code> method. Here the TCP connections
+ * are accepted from the <code>ServerSocketChannel</code> which
+ * creates the socket objects. Each socket is then encapsulated in
+ * to a pipeline and dispatched to the processor for processing.
+ *
+ * @throws IOException if there is a problem accepting the socket
+ */
+ private void accept() throws IOException {
+ SocketChannel channel = listener.accept();
+
+ while(channel != null) {
+ Trace trace = analyzer.attach(channel);
+
+ configure(channel);
+
+ if(context == null) {
+ process(channel, trace, null);
+ } else {
+ process(channel, trace);
+ }
+ channel = listener.accept();
+ }
+ }
+
+ /**
+ * This method is used to configure the accepted channel. This
+ * will disable Nagles algorithm to improve the performance of the
+ * channel, also this will ensure the accepted channel disables
+ * blocking to ensure that it works within the processor object.
+ *
+ * @param channel this is the channel that is to be configured
+ */
+ private void configure(SocketChannel channel) throws IOException {
+ channel.socket().setTcpNoDelay(true);
+ channel.configureBlocking(false);
+ }
+
+ /**
+ * This method is used to dispatch the socket for processing. The
+ * socket will be configured and connected to the client, this
+ * will hand processing to the <code>Server</code> which will
+ * create the pipeline instance used to wrap the socket object.
+ *
+ * @param channel this is the connected socket to be processed
+ * @param trace this is the trace to associate with the socket
+ */
+ private void process(SocketChannel channel, Trace trace) throws IOException {
+ SSLEngine engine = context.createSSLEngine();
+
+ try {
+ process(channel, trace, engine);
+ } catch(Exception cause) {
+ trace.trace(ERROR, cause);
+ channel.close();
+ }
+ }
+
+ /**
+ * This method is used to dispatch the socket for processing. The
+ * socket will be configured and connected to the client, this
+ * will hand processing to the <code>Server</code> which will
+ * create the pipeline instance used to wrap the socket object.
+ *
+ * @param channel this is the connected socket to be processed
+ * @param trace this is the trace to associate with the socket
+ * @param engine this is the SSL engine used for secure HTTPS
+ */
+ private void process(SocketChannel channel, Trace trace, SSLEngine engine) throws IOException {
+ Socket socket = new SocketWrapper(channel, trace, engine);
+
+ try {
+ trace.trace(ACCEPT);
+ processor.process(socket);
+ } catch(Exception cause) {
+ trace.trace(ERROR, cause);
+ channel.close();
+ }
+ }
+
+ /**
+ * This is used to close the server socket channel so that the
+ * port that it is bound to is released. This allows the acceptor
+ * to close off the interface to the server. Ensuring the socket
+ * is closed allows it to be recreated at a later point.
+ *
+ * @throws IOException thrown if the socket can not be closed
+ */
+ public void close() throws IOException {
+ listener.close();
+ }
+}