View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.net;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.IOException;
21  import java.io.OutputStream;
22  import java.io.Serializable;
23  import java.net.InetAddress;
24  import java.net.InetSocketAddress;
25  import java.net.Socket;
26  import java.net.UnknownHostException;
27  
28  import javax.net.ssl.SSLSocket;
29  import javax.net.ssl.SSLSocketFactory;
30  
31  import org.apache.logging.log4j.Level;
32  import org.apache.logging.log4j.core.Layout;
33  import org.apache.logging.log4j.core.appender.ManagerFactory;
34  import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
35  import org.apache.logging.log4j.util.Strings;
36  
37  /**
38   *
39   */
40  public class SslSocketManager extends TcpSocketManager {
41      public static final int DEFAULT_PORT = 6514;
42      private static final SslSocketManagerFactory FACTORY = new SslSocketManagerFactory();
43      private final SslConfiguration sslConfig;
44  
45      /**
46       *
47       *
48       * @param name          The unique name of this connection.
49       * @param os            The OutputStream.
50       * @param sock          The Socket.
51       * @param inetAddress          The Internet address of the host.
52       * @param host          The name of the host.
53       * @param port          The port number on the host.
54       * @param connectTimeoutMillis the connect timeout in milliseconds.
55       * @param delay         Reconnection interval.
56       * @param immediateFail
57       * @param layout        The Layout.
58       */
59      public SslSocketManager(final String name, final OutputStream os, final Socket sock,
60              final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
61              int connectTimeoutMillis, final int delay, final boolean immediateFail,
62              final Layout<? extends Serializable> layout) {
63          super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout);
64          this.sslConfig = sslConfig;
65      }
66  
67      private static class SslFactoryData {
68          protected SslConfiguration sslConfig;
69          private final String host;
70          private final int port;
71          private final int connectTimeoutMillis;
72          private final int delayMillis;
73          private final boolean immediateFail;
74          private final Layout<? extends Serializable> layout;
75  
76          public SslFactoryData(final SslConfiguration sslConfig, final String host, final int port,
77                  int connectTimeoutMillis, final int delayMillis, final boolean immediateFail,
78                  final Layout<? extends Serializable> layout) {
79              this.host = host;
80              this.port = port;
81              this.connectTimeoutMillis = connectTimeoutMillis;
82              this.delayMillis = delayMillis;
83              this.immediateFail = immediateFail;
84              this.layout = layout;
85              this.sslConfig = sslConfig;
86          }
87      }
88  
89      public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
90              int connectTimeoutMillis, int delayMillis, final boolean immediateFail,
91              final Layout<? extends Serializable> layout) {
92          if (Strings.isEmpty(host)) {
93              throw new IllegalArgumentException("A host name is required");
94          }
95          if (port <= 0) {
96              port = DEFAULT_PORT;
97          }
98          if (delayMillis == 0) {
99              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 }