View Javadoc

1   /*
2    * ------------------------------------------------------------------------------
3    * Hermes FTP Server
4    * Copyright (c) 2005-2007 Lars Behnke
5    * ------------------------------------------------------------------------------
6    * 
7    * This file is part of Hermes FTP Server.
8    * 
9    * Hermes FTP Server is free software; you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as published by
11   * the Free Software Foundation; either version 2 of the License, or
12   * (at your option) any later version.
13   * 
14   * Hermes FTP Server is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public License
20   * along with Hermes FTP Server; if not, write to the Free Software
21   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22   * ------------------------------------------------------------------------------
23   */
24  
25  package net.sf.hermesftp.cmd;
26  
27  import java.io.IOException;
28  import java.net.Socket;
29  
30  import javax.net.SocketFactory;
31  import javax.net.ssl.SSLSocket;
32  import javax.net.ssl.SSLSocketFactory;
33  
34  import net.sf.hermesftp.common.FtpConstants;
35  import net.sf.hermesftp.common.FtpSessionContext;
36  import net.sf.hermesftp.exception.FtpConfigException;
37  import net.sf.hermesftp.utils.IOUtils;
38  
39  /***
40   * Provider for the client socket (active transfer). The creation of the socket is deferred until it
41   * is needed.
42   * 
43   * @author Behnke
44   */
45  public class ActiveModeSocketProvider implements SocketProvider {
46  
47      private FtpSessionContext ctx;
48  
49      private DataChannelInfo   dataChannelInfo;
50  
51      private Socket            socket;
52  
53      /***
54       * Constructor.
55       * 
56       * @param ctx Session context.
57       * @param info Channel about the data channel to open.
58       */
59      public ActiveModeSocketProvider(FtpSessionContext ctx, DataChannelInfo info) {
60          this.ctx = ctx;
61          this.dataChannelInfo = info;
62      }
63  
64      /***
65       * {@inheritDoc}
66       */
67      public DataChannelInfo init() throws IOException {
68          closeSocket();
69          return dataChannelInfo;
70      }
71  
72      /***
73       * {@inheritDoc}
74       */
75      public Socket provideSocket() throws IOException {
76          if (socket == null) {
77              socket = createClientSocket();
78          }
79          return socket;
80      }
81  
82      /***
83       * {@inheritDoc}
84       */
85      public void closeSocket() {
86          if (socket != null) {
87              IOUtils.closeGracefully(socket);
88              socket = null;
89          }
90  
91      }
92  
93      private Socket createClientSocket() throws IOException {
94          Socket dataSocket;
95          Boolean dataProtection = (Boolean) ctx.getAttribute(FtpConstants.ATTR_DATA_PROT);
96          boolean ssl = dataProtection != null && dataProtection.booleanValue();
97          if (ssl) {
98              SSLSocketFactory factory;
99              try {
100                 factory = ctx.getOptions().getSslContext().getSocketFactory();
101             } catch (FtpConfigException e) {
102                 throw new IOException("Setting up SSL failed.");
103             }
104             SSLSocket sslSocket = (SSLSocket) factory.createSocket(dataChannelInfo.getAddress(),
105                 dataChannelInfo.getPort());
106             sslSocket.setUseClientMode(false);
107             enableCipherSuites(sslSocket);
108             dataSocket = sslSocket;
109         } else {
110             dataSocket = SocketFactory.getDefault().createSocket(dataChannelInfo.getAddress(),
111                 dataChannelInfo.getPort());
112         }
113         return dataSocket;
114     }
115 
116     /***
117      * Enables the configured cipher suites in the passed socket.
118      * 
119      * @param sslSocket The socket.
120      */
121     private void enableCipherSuites(SSLSocket sslSocket) {
122         String[] cipherSuites = ctx.getOptions().getStringArray(FtpConstants.OPT_SSL_CIPHER_SUITES, null);
123         if (cipherSuites != null) {
124             if (cipherSuites.length == 1 && FtpConstants.WILDCARD.equals(cipherSuites[0])) {
125                 sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
126             } else {
127                 sslSocket.setEnabledCipherSuites(cipherSuites);
128             }
129         }
130     }
131 
132 }