001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.net;
018
019import java.io.IOException;
020import java.io.OutputStream;
021import java.io.Serializable;
022import java.net.InetAddress;
023import java.net.InetSocketAddress;
024import java.net.Socket;
025
026import javax.net.ssl.SSLSocket;
027import javax.net.ssl.SSLSocketFactory;
028
029import org.apache.logging.log4j.core.Layout;
030import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
031import org.apache.logging.log4j.util.Strings;
032
033/**
034 *
035 */
036public class SslSocketManager extends TcpSocketManager {
037    public static final int DEFAULT_PORT = 6514;
038    private static final SslSocketManagerFactory FACTORY = new SslSocketManagerFactory();
039    private final SslConfiguration sslConfig;
040
041    /**
042    *
043    *
044    * @param name          The unique name of this connection.
045    * @param os            The OutputStream.
046    * @param sock          The Socket.
047    * @param inetAddress          The Internet address of the host.
048    * @param host          The name of the host.
049    * @param port          The port number on the host.
050    * @param connectTimeoutMillis the connect timeout in milliseconds.
051    * @param reconnectionDelayMillis         Reconnection interval.
052    * @param immediateFail
053    * @param layout        The Layout.
054    * @param bufferSize The buffer size.
055    * @deprecated Use {@link #SslSocketManager(String, OutputStream, Socket, SslConfiguration, InetAddress, String, int, int, int, boolean, Layout, int, SocketOptions)}.
056    */
057   @Deprecated
058   public SslSocketManager(final String name, final OutputStream os, final Socket sock,
059           final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
060           final int connectTimeoutMillis, final int reconnectionDelayMillis, final boolean immediateFail,
061           final Layout<? extends Serializable> layout, final int bufferSize) {
062       super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, reconnectionDelayMillis, immediateFail, layout, bufferSize, null);
063       this.sslConfig = sslConfig;
064   }
065
066   /**
067   *
068   *
069   * @param name          The unique name of this connection.
070   * @param os            The OutputStream.
071   * @param sock          The Socket.
072   * @param inetAddress          The Internet address of the host.
073   * @param host          The name of the host.
074   * @param port          The port number on the host.
075   * @param connectTimeoutMillis the connect timeout in milliseconds.
076   * @param reconnectionDelayMillis         Reconnection interval.
077   * @param immediateFail
078   * @param layout        The Layout.
079   * @param bufferSize The buffer size.
080   */
081  public SslSocketManager(final String name, final OutputStream os, final Socket sock,
082          final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
083          final int connectTimeoutMillis, final int reconnectionDelayMillis, final boolean immediateFail,
084          final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
085      super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, reconnectionDelayMillis, immediateFail, layout, bufferSize, socketOptions);
086      this.sslConfig = sslConfig;
087  }
088
089    private static class SslFactoryData extends FactoryData {
090        protected SslConfiguration sslConfiguration;
091
092        public SslFactoryData(final SslConfiguration sslConfiguration, final String host, final int port,
093                final int connectTimeoutMillis, final int reconnectDelayMillis, final boolean immediateFail,
094                final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
095            super(host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize,
096                    socketOptions);
097            this.sslConfiguration = sslConfiguration;
098        }
099
100        @Override
101        public String toString() {
102            return "SslFactoryData [sslConfiguration=" + sslConfiguration + ", host=" + host + ", port=" + port
103                    + ", connectTimeoutMillis=" + connectTimeoutMillis + ", reconnectDelayMillis="
104                    + reconnectDelayMillis + ", immediateFail=" + immediateFail + ", layout=" + layout + ", bufferSize="
105                    + bufferSize + ", socketOptions=" + socketOptions + "]";
106        }
107    }
108
109    /**
110     * @deprecated Use {@link SslSocketManager#getSocketManager(SslConfiguration, String, int, int, int, boolean, Layout, int, SocketOptions)}.
111     */
112    @Deprecated
113    public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, final int port,
114            final int connectTimeoutMillis, final int reconnectDelayMillis, final boolean immediateFail,
115            final Layout<? extends Serializable> layout, final int bufferSize) {
116        return getSocketManager(sslConfig, host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize, null);
117    }
118
119    public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
120            final int connectTimeoutMillis, int reconnectDelayMillis, final boolean immediateFail,
121            final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
122        if (Strings.isEmpty(host)) {
123            throw new IllegalArgumentException("A host name is required");
124        }
125        if (port <= 0) {
126            port = DEFAULT_PORT;
127        }
128        if (reconnectDelayMillis == 0) {
129            reconnectDelayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
130        }
131        final String name = "TLS:" + host + ':' + port;
132        return (SslSocketManager) getManager(name, new SslFactoryData(sslConfig, host, port, connectTimeoutMillis,
133                reconnectDelayMillis, immediateFail, layout, bufferSize, socketOptions), FACTORY);
134    }
135
136    @Override
137    protected Socket createSocket(final String host, final int port) throws IOException {
138        final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfig);
139        final InetSocketAddress address = new InetSocketAddress(host, port);
140        final Socket newSocket = socketFactory.createSocket();
141        newSocket.connect(address, getConnectTimeoutMillis());
142        return newSocket;
143    }
144
145    private static SSLSocketFactory createSslSocketFactory(final SslConfiguration sslConf) {
146        SSLSocketFactory socketFactory;
147
148        if (sslConf != null) {
149            socketFactory = sslConf.getSslSocketFactory();
150        } else {
151            socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
152        }
153
154        return socketFactory;
155    }
156
157
158    private static class SslSocketManagerFactory extends TcpSocketManagerFactory<SslSocketManager, SslFactoryData> {
159
160        @Override
161        SslSocketManager createManager(final String name, final OutputStream os, final Socket socket, final InetAddress inetAddress,
162                final SslFactoryData data) {
163            return new SslSocketManager(name, os, socket, data.sslConfiguration, inetAddress, data.host, data.port,
164                    data.connectTimeoutMillis, data.reconnectDelayMillis, data.immediateFail, data.layout, data.bufferSize,
165                    data.socketOptions);
166        }
167
168        @Override
169        Socket createSocket(final SslFactoryData data) throws IOException {
170            return SslSocketManager.createSocket(data.host, data.port, data.connectTimeoutMillis, data.sslConfiguration,
171                    data.socketOptions);
172        }
173    }
174
175    static Socket createSocket(final String host, final int port, final int connectTimeoutMillis,
176            final SslConfiguration sslConfiguration, final SocketOptions socketOptions) throws IOException {
177        final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfiguration);
178        final SSLSocket socket = (SSLSocket) socketFactory.createSocket();
179        if (socketOptions != null) {
180            // Not sure which options must be applied before or after the connect() call.
181            socketOptions.apply(socket);
182        }
183        socket.connect(new InetSocketAddress(host, port), connectTimeoutMillis);
184        if (socketOptions != null) {
185            // Not sure which options must be applied before or after the connect() call.
186            socketOptions.apply(socket);
187        }
188        return socket;
189    }
190}