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 org.apache.logging.log4j.core.Layout;
020import org.apache.logging.log4j.core.appender.ManagerFactory;
021import org.apache.logging.log4j.core.helpers.Strings;
022import org.apache.logging.log4j.core.net.ssl.SSLConfiguration;
023
024import javax.net.ssl.SSLSocket;
025import javax.net.ssl.SSLSocketFactory;
026import java.io.ByteArrayOutputStream;
027import java.io.IOException;
028import java.io.OutputStream;
029import java.net.InetAddress;
030import java.net.Socket;
031import java.net.UnknownHostException;
032
033/**
034 *
035 */
036public class TLSSocketManager extends TCPSocketManager {
037    public static final int DEFAULT_PORT = 6514;
038    private static final TLSSocketManagerFactory FACTORY = new TLSSocketManagerFactory();
039    private 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 addr          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 delay         Reconnection interval.
051     * @param immediateFail
052     * @param layout        The Layout.
053     */
054    public TLSSocketManager(String name, OutputStream os, Socket sock, SSLConfiguration sslConfig, InetAddress addr,
055                            String host, int port, int delay, boolean immediateFail, Layout layout) {
056        super(name, os, sock, addr, host, port, delay, immediateFail, layout);
057        this.sslConfig = sslConfig;
058    }
059
060    private static class TLSFactoryData {
061        protected SSLConfiguration sslConfig;
062        private final String host;
063        private final int port;
064        private final int delay;
065        private final boolean immediateFail;
066        private final Layout layout;
067
068        public TLSFactoryData(SSLConfiguration sslConfig, String host, int port, int delay, boolean immediateFail,
069                              Layout layout) {
070            this.host = host;
071            this.port = port;
072            this.delay = delay;
073            this.immediateFail = immediateFail;
074            this.layout = layout;
075            this.sslConfig = sslConfig;
076        }
077    }
078
079    public static TLSSocketManager getSocketManager(final SSLConfiguration sslConfig, final String host, int port,
080                                                    int delay, final boolean immediateFail, final Layout layout ) {
081        if (Strings.isEmpty(host)) {
082            throw new IllegalArgumentException("A host name is required");
083        }
084        if (port <= 0) {
085            port = DEFAULT_PORT;
086        }
087        if (delay == 0) {
088            delay = DEFAULT_RECONNECTION_DELAY;
089        }
090        return (TLSSocketManager) getManager("TLS:" + host + ":" + port,
091                new TLSFactoryData(sslConfig, host, port, delay, immediateFail, layout), FACTORY);
092    }
093
094    @Override
095    protected Socket createSocket(String host, int port) throws IOException {
096        SSLSocketFactory socketFactory = createSSLSocketFactory(sslConfig);
097        return socketFactory.createSocket(host, port);
098    }
099
100    private static SSLSocketFactory createSSLSocketFactory(SSLConfiguration sslConf) {
101        SSLSocketFactory socketFactory;
102
103        if (sslConf != null) {
104            socketFactory = sslConf.getSSLSocketFactory();
105        } else {
106            socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
107        }
108
109        return socketFactory;
110    }
111
112
113    private static class TLSSocketManagerFactory implements ManagerFactory<TLSSocketManager, TLSFactoryData> {
114
115        private class TLSSocketManagerFactoryException extends Exception {
116
117            private static final long serialVersionUID = 1L;
118        }
119
120        @Override
121        public TLSSocketManager createManager(final String name, final TLSFactoryData data) {
122            InetAddress address = null;
123            OutputStream os = null;
124            Socket socket = null;
125
126            try {
127                address = resolveAddress(data.host);
128                socket = createSocket(data);
129                os = socket.getOutputStream();
130                checkDelay(data.delay, os);
131            }
132            catch (IOException e) {
133                LOGGER.error("TLSSocketManager (" + name + ") " + e);
134                os = new ByteArrayOutputStream();
135            }
136            catch (TLSSocketManagerFactoryException e) {
137                return null;
138            }
139            return createManager(name, os, socket, data.sslConfig, address, data.host, data.port, data.delay, data.immediateFail, data.layout);
140        }
141
142        private InetAddress resolveAddress(String hostName) throws TLSSocketManagerFactoryException {
143            InetAddress address;
144
145            try {
146                address = InetAddress.getByName(hostName);
147            } catch (final UnknownHostException ex) {
148                LOGGER.error("Could not find address of " + hostName, ex);
149                throw new TLSSocketManagerFactoryException();
150            }
151
152            return address;
153        }
154
155        private void checkDelay(int delay, OutputStream os) throws TLSSocketManagerFactoryException {
156            if (delay == 0 && os == null) {
157                throw new TLSSocketManagerFactoryException();
158            }
159        }
160
161        private Socket createSocket(TLSFactoryData data) throws IOException {
162            SSLSocketFactory socketFactory;
163            SSLSocket socket;
164
165            socketFactory = createSSLSocketFactory(data.sslConfig);
166            socket = (SSLSocket) socketFactory.createSocket(data.host, data.port);
167            return socket;
168        }
169
170        private TLSSocketManager createManager(String name, OutputStream os, Socket socket, SSLConfiguration sslConfig, InetAddress address, String host, int port, int delay, boolean immediateFail, Layout layout) {
171            return new TLSSocketManager(name, os, socket, sslConfig, address, host, port, delay, immediateFail, layout);
172        }
173    }
174}