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;
025import java.util.List;
026
027import javax.net.ssl.SSLSocket;
028import javax.net.ssl.SSLSocketFactory;
029
030import org.apache.logging.log4j.core.Layout;
031import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
032import org.apache.logging.log4j.util.Strings;
033
034/**
035 *
036 */
037public class SslSocketManager extends TcpSocketManager {
038    public static final int DEFAULT_PORT = 6514;
039    private static final SslSocketManagerFactory FACTORY = new SslSocketManagerFactory();
040    private final SslConfiguration sslConfig;
041
042    /**
043    *
044    *
045    * @param name          The unique name of this connection.
046    * @param os            The OutputStream.
047    * @param sock          The Socket.
048    * @param inetAddress          The Internet address of the host.
049    * @param host          The name of the host.
050    * @param port          The port number on the host.
051    * @param connectTimeoutMillis the connect timeout in milliseconds.
052    * @param reconnectionDelayMillis         Reconnection interval.
053    * @param immediateFail
054    * @param layout        The Layout.
055    * @param bufferSize The buffer size.
056    * @deprecated Use {@link #SslSocketManager(String, OutputStream, Socket, SslConfiguration, InetAddress, String, int, int, int, boolean, Layout, int, SocketOptions)}.
057    */
058   @Deprecated
059   public SslSocketManager(final String name, final OutputStream os, final Socket sock,
060           final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
061           final int connectTimeoutMillis, final int reconnectionDelayMillis, final boolean immediateFail,
062           final Layout<? extends Serializable> layout, final int bufferSize) {
063       super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, reconnectionDelayMillis, immediateFail, layout, bufferSize, null);
064       this.sslConfig = sslConfig;
065   }
066
067   /**
068   *
069   *
070   * @param name          The unique name of this connection.
071   * @param os            The OutputStream.
072   * @param sock          The Socket.
073   * @param inetAddress          The Internet address of the host.
074   * @param host          The name of the host.
075   * @param port          The port number on the host.
076   * @param connectTimeoutMillis the connect timeout in milliseconds.
077   * @param reconnectionDelayMillis         Reconnection interval.
078   * @param immediateFail
079   * @param layout        The Layout.
080   * @param bufferSize The buffer size.
081   */
082  public SslSocketManager(final String name, final OutputStream os, final Socket sock,
083          final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
084          final int connectTimeoutMillis, final int reconnectionDelayMillis, final boolean immediateFail,
085          final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
086      super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, reconnectionDelayMillis, immediateFail, layout, bufferSize, socketOptions);
087      this.sslConfig = sslConfig;
088  }
089
090    private static class SslFactoryData extends FactoryData {
091        protected SslConfiguration sslConfiguration;
092
093        public SslFactoryData(final SslConfiguration sslConfiguration, final String host, final int port,
094                final int connectTimeoutMillis, final int reconnectDelayMillis, final boolean immediateFail,
095                final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
096            super(host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize,
097                    socketOptions);
098            this.sslConfiguration = sslConfiguration;
099        }
100
101        @Override
102        public String toString() {
103            return "SslFactoryData [sslConfiguration=" + sslConfiguration + ", host=" + host + ", port=" + port
104                    + ", connectTimeoutMillis=" + connectTimeoutMillis + ", reconnectDelayMillis="
105                    + reconnectDelayMillis + ", immediateFail=" + immediateFail + ", layout=" + layout + ", bufferSize="
106                    + bufferSize + ", socketOptions=" + socketOptions + "]";
107        }
108    }
109
110    /**
111     * @deprecated Use {@link SslSocketManager#getSocketManager(SslConfiguration, String, int, int, int, boolean, Layout, int, SocketOptions)}.
112     */
113    @Deprecated
114    public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, final int port,
115            final int connectTimeoutMillis, final int reconnectDelayMillis, final boolean immediateFail,
116            final Layout<? extends Serializable> layout, final int bufferSize) {
117        return getSocketManager(sslConfig, host, port, connectTimeoutMillis, reconnectDelayMillis, immediateFail, layout, bufferSize, null);
118    }
119
120    public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
121            final int connectTimeoutMillis, int reconnectDelayMillis, final boolean immediateFail,
122            final Layout<? extends Serializable> layout, final int bufferSize, final SocketOptions socketOptions) {
123        if (Strings.isEmpty(host)) {
124            throw new IllegalArgumentException("A host name is required");
125        }
126        if (port <= 0) {
127            port = DEFAULT_PORT;
128        }
129        if (reconnectDelayMillis == 0) {
130            reconnectDelayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
131        }
132        final String name = "TLS:" + host + ':' + port;
133        return (SslSocketManager) getManager(name, new SslFactoryData(sslConfig, host, port, connectTimeoutMillis,
134                reconnectDelayMillis, immediateFail, layout, bufferSize, socketOptions), FACTORY);
135    }
136
137    @Override
138    protected Socket createSocket(final InetSocketAddress socketAddress) throws IOException {
139        final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfig);
140        final Socket newSocket = socketFactory.createSocket();
141        newSocket.connect(socketAddress, 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            List<InetSocketAddress> socketAddresses = resolver.resolveHost(data.host, data.port);
171            IOException ioe = null;
172            for (InetSocketAddress socketAddress : socketAddresses) {
173                try {
174                    return SslSocketManager.createSocket(socketAddress, data.connectTimeoutMillis,
175                            data.sslConfiguration, data.socketOptions);
176                } catch (IOException ex) {
177                    ioe = ex;
178                }
179            }
180            throw new IOException(errorMessage(data, socketAddresses) , ioe);
181        }
182    }
183
184    static Socket createSocket(final InetSocketAddress socketAddress, final int connectTimeoutMillis,
185            final SslConfiguration sslConfiguration, final SocketOptions socketOptions) throws IOException {
186        final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfiguration);
187        final SSLSocket socket = (SSLSocket) socketFactory.createSocket();
188        if (socketOptions != null) {
189            // Not sure which options must be applied before or after the connect() call.
190            socketOptions.apply(socket);
191        }
192        socket.connect(socketAddress, connectTimeoutMillis);
193        if (socketOptions != null) {
194            // Not sure which options must be applied before or after the connect() call.
195            socketOptions.apply(socket);
196        }
197        return socket;
198    }
199}