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.ByteArrayOutputStream;
020import java.io.IOException;
021import java.io.OutputStream;
022import java.io.Serializable;
023import java.net.InetAddress;
024import java.net.InetSocketAddress;
025import java.net.Socket;
026import java.net.UnknownHostException;
027
028import javax.net.ssl.SSLSocket;
029import javax.net.ssl.SSLSocketFactory;
030
031import org.apache.logging.log4j.Level;
032import org.apache.logging.log4j.core.Layout;
033import org.apache.logging.log4j.core.appender.ManagerFactory;
034import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
035import org.apache.logging.log4j.util.Strings;
036
037/**
038 *
039 */
040public class SslSocketManager extends TcpSocketManager {
041    public static final int DEFAULT_PORT = 6514;
042    private static final SslSocketManagerFactory FACTORY = new SslSocketManagerFactory();
043    private final SslConfiguration sslConfig;
044
045    /**
046     *
047     *
048     * @param name          The unique name of this connection.
049     * @param os            The OutputStream.
050     * @param sock          The Socket.
051     * @param inetAddress          The Internet address of the host.
052     * @param host          The name of the host.
053     * @param port          The port number on the host.
054     * @param connectTimeoutMillis the connect timeout in milliseconds.
055     * @param delay         Reconnection interval.
056     * @param immediateFail
057     * @param layout        The Layout.
058     */
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            int connectTimeoutMillis, final int delay, final boolean immediateFail,
062            final Layout<? extends Serializable> layout) {
063        super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout);
064        this.sslConfig = sslConfig;
065    }
066
067    private static class SslFactoryData {
068        protected SslConfiguration sslConfig;
069        private final String host;
070        private final int port;
071        private final int connectTimeoutMillis;
072        private final int delayMillis;
073        private final boolean immediateFail;
074        private final Layout<? extends Serializable> layout;
075
076        public SslFactoryData(final SslConfiguration sslConfig, final String host, final int port,
077                int connectTimeoutMillis, final int delayMillis, final boolean immediateFail,
078                final Layout<? extends Serializable> layout) {
079            this.host = host;
080            this.port = port;
081            this.connectTimeoutMillis = connectTimeoutMillis;
082            this.delayMillis = delayMillis;
083            this.immediateFail = immediateFail;
084            this.layout = layout;
085            this.sslConfig = sslConfig;
086        }
087    }
088
089    public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
090            int connectTimeoutMillis, int delayMillis, final boolean immediateFail,
091            final Layout<? extends Serializable> layout) {
092        if (Strings.isEmpty(host)) {
093            throw new IllegalArgumentException("A host name is required");
094        }
095        if (port <= 0) {
096            port = DEFAULT_PORT;
097        }
098        if (delayMillis == 0) {
099            delayMillis = DEFAULT_RECONNECTION_DELAY_MILLIS;
100        }
101        return (SslSocketManager) getManager("TLS:" + host + ':' + port, new SslFactoryData(sslConfig, host, port,
102                connectTimeoutMillis, delayMillis, immediateFail, layout), FACTORY);
103    }
104
105    @Override
106    protected Socket createSocket(final String host, final int port) throws IOException {
107        final SSLSocketFactory socketFactory = createSslSocketFactory(sslConfig);
108        final InetSocketAddress address = new InetSocketAddress(host, port);
109        final Socket newSocket = socketFactory.createSocket();
110        newSocket.connect(address, getConnectTimeoutMillis());
111        return newSocket;
112    }
113
114    private static SSLSocketFactory createSslSocketFactory(final SslConfiguration sslConf) {
115        SSLSocketFactory socketFactory;
116
117        if (sslConf != null) {
118            socketFactory = sslConf.getSslSocketFactory();
119        } else {
120            socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
121        }
122
123        return socketFactory;
124    }
125
126
127    private static class SslSocketManagerFactory implements ManagerFactory<SslSocketManager, SslFactoryData> {
128
129        private class TlsSocketManagerFactoryException extends Exception {
130
131            private static final long serialVersionUID = 1L;
132        }
133
134        @Override
135        public SslSocketManager createManager(final String name, final SslFactoryData data) {
136            InetAddress inetAddress = null;
137            OutputStream os = null;
138            Socket socket = null;
139
140            try {
141                inetAddress = resolveAddress(data.host);
142                socket = createSocket(data);
143                os = socket.getOutputStream();
144                checkDelay(data.delayMillis, os);
145            }
146            catch (final IOException e) {
147                LOGGER.error("SslSocketManager ({})", name, e);
148                os = new ByteArrayOutputStream();
149            }
150            catch (final TlsSocketManagerFactoryException e) {
151                LOGGER.catching(Level.DEBUG, e);
152                return null;
153            }
154            return new SslSocketManager(name, os, socket, data.sslConfig, inetAddress, data.host, data.port, 0,
155                    data.delayMillis, data.immediateFail, data.layout);
156        }
157
158        private InetAddress resolveAddress(final String hostName) throws TlsSocketManagerFactoryException {
159            InetAddress address;
160
161            try {
162                address = InetAddress.getByName(hostName);
163            } catch (final UnknownHostException ex) {
164                LOGGER.error("Could not find address of {}", hostName, ex);
165                throw new TlsSocketManagerFactoryException();
166            }
167
168            return address;
169        }
170
171        private void checkDelay(final int delay, final OutputStream os) throws TlsSocketManagerFactoryException {
172            if (delay == 0 && os == null) {
173                throw new TlsSocketManagerFactoryException();
174            }
175        }
176
177        private Socket createSocket(final SslFactoryData data) throws IOException {
178            SSLSocketFactory socketFactory;
179            SSLSocket socket;
180
181            socketFactory = createSslSocketFactory(data.sslConfig);
182            socket = (SSLSocket) socketFactory.createSocket(data.host, data.port);
183            return socket;
184        }
185    }
186}