This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-net.git
The following commit(s) were added to refs/heads/master by this push:
new 3439e4e1 Javadoc @see tags do not need to use a FQCN for classes in
java.lang
3439e4e1 is described below
commit 3439e4e1576b74ff486a05cab6a0ddb4c0850aac
Author: Gary Gregory <[email protected]>
AuthorDate: Mon Aug 29 07:17:36 2022 -0400
Javadoc @see tags do not need to use a FQCN for classes in java.lang
---
.../org/apache/commons/net/ftp/FTPSClient.java | 1828 ++++++++++----------
.../java/org/apache/commons/net/ntp/TimeStamp.java | 936 +++++-----
2 files changed, 1382 insertions(+), 1382 deletions(-)
diff --git a/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
b/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
index 7f0875b8..df4de5cf 100644
--- a/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
+++ b/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
@@ -1,914 +1,914 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.net.ftp;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.Socket;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-
-import org.apache.commons.net.util.Base64;
-import org.apache.commons.net.util.SSLContextUtils;
-import org.apache.commons.net.util.SSLSocketUtils;
-import org.apache.commons.net.util.TrustManagerUtils;
-
-/**
- * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all
can be used to
- * see wire-level SSL details.
- *
- * Warning: the hostname is not verified against the certificate by default,
use
- * {@link #setHostnameVerifier(HostnameVerifier)} or {@link
#setEndpointCheckingEnabled(boolean)}
- * (on Java 1.7+) to enable verification. Verification is only performed on
client mode connections.
- * @since 2.0
- */
-public class FTPSClient extends FTPClient {
-
-// From http://www.iana.org/assignments/port-numbers
-
-// ftps-data 989/tcp ftp protocol, data, over TLS/SSL
-// ftps-data 989/udp ftp protocol, data, over TLS/SSL
-// ftps 990/tcp ftp protocol, control, over TLS/SSL
-// ftps 990/udp ftp protocol, control, over TLS/SSL
-
- public static final int DEFAULT_FTPS_DATA_PORT = 989;
- public static final int DEFAULT_FTPS_PORT = 990;
-
- /** The value that I can set in PROT command (C = Clear, P = Protected) */
- private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"};
- /** Default PROT Command */
- private static final String DEFAULT_PROT = "C";
- /** Default secure socket protocol name, i.e. TLS */
- private static final String DEFAULT_PROTOCOL = "TLS";
-
- /** The AUTH (Authentication/Security Mechanism) command. */
- private static final String CMD_AUTH = "AUTH";
- /** The ADAT (Authentication/Security Data) command. */
- private static final String CMD_ADAT = "ADAT";
- /** The PROT (Data Channel Protection Level) command. */
- private static final String CMD_PROT = "PROT";
- /** The PBSZ (Protection Buffer Size) command. */
- private static final String CMD_PBSZ = "PBSZ";
- /** The MIC (Integrity Protected Command) command. */
- private static final String CMD_MIC = "MIC";
- /** The CONF (Confidentiality Protected Command) command. */
- private static final String CMD_CONF = "CONF";
- /** The ENC (Privacy Protected Command) command. */
- private static final String CMD_ENC = "ENC";
- /** The CCC (Clear Command Channel) command. */
- private static final String CMD_CCC = "CCC";
-
- /** @deprecated - not used - may be removed in a future release */
- @Deprecated
- public static String KEYSTORE_ALGORITHM;
- /** @deprecated - not used - may be removed in a future release */
- @Deprecated
- public static String TRUSTSTORE_ALGORITHM;
- /** @deprecated - not used - may be removed in a future release */
- @Deprecated
- public static String PROVIDER;
- /** @deprecated - not used - may be removed in a future release */
- @Deprecated
- public static String STORE_TYPE;
- /** The security mode. (True - Implicit Mode / False - Explicit Mode) */
- private final boolean isImplicit;
- /** The secure socket protocol to be used, e.g. SSL/TLS. */
- private final String protocol;
- /** The AUTH Command value */
- private String auth = DEFAULT_PROTOCOL;
- /** The context object. */
- private SSLContext context;
- /** The socket object. */
- private Socket plainSocket;
- /** Controls whether a new SSL session may be established by this socket.
Default true. */
- private boolean isCreation = true;
- /** The use client mode flag. */
- private boolean isClientMode = true;
-
- /** The need client auth flag. */
- private boolean isNeedClientAuth;
-
- /** The want client auth flag. */
- private boolean isWantClientAuth;
-
- /** The cipher suites */
- private String[] suites;
-
- /** The protocol versions */
- private String[] protocols;
-
- /** The FTPS {@link TrustManager} implementation, default validate only
- * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}.
- */
- private TrustManager trustManager =
TrustManagerUtils.getValidateServerCertificateTrustManager();
-
- /** The {@link KeyManager}, default null (i.e. use system default). */
- private KeyManager keyManager;
-
- /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no
verification). */
- private HostnameVerifier hostnameVerifier;
-
- /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */
- private boolean tlsEndpointChecking;
-
- /**
- * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}.
- *
- * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security
mode to explicit (isImplicit = false)
- */
- public FTPSClient() {
- this(DEFAULT_PROTOCOL, false);
- }
-
- /**
- * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
- * Calls {@link #FTPSClient(String, boolean)}
- * @param isImplicit The security mode (Implicit/Explicit).
- */
- public FTPSClient(final boolean isImplicit) {
- this(DEFAULT_PROTOCOL, isImplicit);
- }
-
-
- /**
- * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
- * The default TrustManager is set from {@link
TrustManagerUtils#getValidateServerCertificateTrustManager()}
- * @param isImplicit The security mode(Implicit/Explicit).
- * @param context A pre-configured SSL Context
- */
- public FTPSClient(final boolean isImplicit, final SSLContext context) {
- this(DEFAULT_PROTOCOL, isImplicit);
- this.context = context;
- }
-
- /**
- * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
- * and isImplicit {@code false}
- * Calls {@link #FTPSClient(boolean, SSLContext)}
- * @param context A pre-configured SSL Context
- */
- public FTPSClient(final SSLContext context) {
- this(false, context);
- }
-
-
- /**
- * Constructor for FTPSClient, using explict mode, calls {@link
#FTPSClient(String, boolean)}.
- *
- * @param protocol the protocol to use
- */
- public FTPSClient(final String protocol) {
- this(protocol, false);
- }
-
- /**
- * Constructor for FTPSClient allowing specification of protocol
- * and security mode. If isImplicit is true, the port is set to
- * {@link #DEFAULT_FTPS_PORT} i.e. 990.
- * The default TrustManager is set from {@link
TrustManagerUtils#getValidateServerCertificateTrustManager()}
- * @param protocol the protocol
- * @param isImplicit The security mode(Implicit/Explicit).
- */
- public FTPSClient(final String protocol, final boolean isImplicit) {
- this.protocol = protocol;
- this.isImplicit = isImplicit;
- if (isImplicit) {
- setDefaultPort(DEFAULT_FTPS_PORT);
- }
- }
-
- /**
- * Because there are so many connect() methods,
- * the _connectAction_() method is provided as a means of performing
- * some action immediately after establishing a connection,
- * rather than reimplementing all of the connect() methods.
- * @throws IOException If it throw by _connectAction_.
- * @see org.apache.commons.net.SocketClient#_connectAction_()
- */
- @Override
- protected void _connectAction_() throws IOException {
- // Implicit mode.
- if (isImplicit) {
- applySocketAttributes();
- sslNegotiation();
- }
- super._connectAction_();
- // Explicit mode.
- if (!isImplicit) {
- execAUTH();
- sslNegotiation();
- }
- }
-
- /**
- * Returns a socket of the data connection.
- * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
- * @param command The int representation of the FTP command to send.
- * @param arg The arguments to the FTP command.
- * If this parameter is set to null, then the command is sent with
- * no arguments.
- * @return corresponding to the established data connection.
- * Null is returned if an FTP protocol error is reported at any point
- * during the establishment and initialization of the connection.
- * @throws IOException If there is any problem with the connection.
- * @see FTPClient#_openDataConnection_(int, String)
- * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd,
String)} instead
- */
- @Override
- // Strictly speaking this is not needed, but it works round a Clirr bug
- // So rather than invoke the parent code, we do it here
- @Deprecated
- protected Socket _openDataConnection_(final int command, final String arg)
- throws IOException {
- return _openDataConnection_(FTPCommand.getCommand(command), arg);
- }
-
- /**
- * Returns a socket of the data connection. Wrapped as an {@link
SSLSocket}, which carries out handshake processing.
- *
- * @param command The textual representation of the FTP command to send.
- * @param arg The arguments to the FTP command. If this parameter is set
to null, then the command is sent with no
- * arguments.
- * @return corresponding to the established data connection. Null is
returned if an FTP protocol error is reported
- * at any point during the establishment and initialization of the
connection.
- * @throws IOException If there is any problem with the connection.
- * @see FTPClient#_openDataConnection_(int, String)
- * @since 3.2
- */
- @Override
- protected Socket _openDataConnection_(final String command, final String
arg) throws IOException {
- final Socket socket = super._openDataConnection_(command, arg);
- _prepareDataSocket_(socket);
- if (socket instanceof SSLSocket) {
- final SSLSocket sslSocket = (SSLSocket) socket;
-
- sslSocket.setUseClientMode(isClientMode);
- sslSocket.setEnableSessionCreation(isCreation);
-
- // server mode
- if (!isClientMode) {
- sslSocket.setNeedClientAuth(isNeedClientAuth);
- sslSocket.setWantClientAuth(isWantClientAuth);
- }
- if (suites != null) {
- sslSocket.setEnabledCipherSuites(suites);
- }
- if (protocols != null) {
- sslSocket.setEnabledProtocols(protocols);
- }
- sslSocket.startHandshake();
- }
-
- return socket;
- }
-
- /**
- * Performs any custom initialization for a newly created SSLSocket
(before the SSL handshake happens). Called
- * by {@link #_openDataConnection_(int, String)} immediately after
creating the socket. The default
- * implementation is a no-op
- *
- * @param socket the socket to set up
- * @throws IOException on error
- * @since 3.1
- */
- protected void _prepareDataSocket_(final Socket socket)
- throws IOException {
- }
-
- /**
- * Check the value that can be set in PROT Command value.
- * @param prot Data Channel Protection Level.
- * @return True - A set point is right / False - A set point is not right
- */
- private boolean checkPROTValue(final String prot) {
- for (final String element : PROT_COMMAND_VALUE)
- {
- if (element.equals(prot)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Create SSL socket from plain socket.
- *
- * @param socket
- * @return SSL Socket
- * @throws IOException
- */
- private SSLSocket createSSLSocket(final Socket socket) throws IOException {
- if (socket != null) {
- final SSLSocketFactory f = context.getSocketFactory();
- return (SSLSocket) f.createSocket(socket, _hostname_,
socket.getPort(), false);
- }
- return null;
- }
-
- /**
- * Closes the connection to the FTP server and restores
- * connection parameters to the default values.
- * <p>
- * Calls {@code setSocketFactory(null)} and {@code
setServerSocketFactory(null)}
- * to reset the factories that may have been changed during the session,
- * e.g. by {@link #execPROT(String)}
- * @throws IOException If an error occurs while disconnecting.
- * @since 3.0
- */
- @Override
- public void disconnect() throws IOException
- {
- super.disconnect();
- if (plainSocket != null) {
- plainSocket.close();
- }
- setSocketFactory(null);
- setServerSocketFactory(null);
- }
-
- /**
- * Send the ADAT command with the specified authentication data.
- * @param data The data to send with the command.
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @since 3.0
- */
- public int execADAT(final byte[] data) throws IOException
- {
- if (data != null)
- {
- return sendCommand(CMD_ADAT,
Base64.encodeBase64StringUnChunked(data));
- }
- return sendCommand(CMD_ADAT);
- }
-
- /**
- * AUTH command.
- * @throws SSLException If it server reply code not equal "234" and "334".
- * @throws IOException If an I/O error occurs while either sending
- * the command.
- */
- protected void execAUTH() throws SSLException, IOException {
- final int replyCode = sendCommand(CMD_AUTH, auth);
- if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) {
- // replyCode = 334
- // I carry out an ADAT command.
- } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) {
- throw new SSLException(getReplyString());
- }
- }
-
- /**
- * Send the AUTH command with the specified mechanism.
- * @param mechanism The mechanism name to send with the command.
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @since 3.0
- */
- public int execAUTH(final String mechanism) throws IOException
- {
- return sendCommand(CMD_AUTH, mechanism);
- }
-
- /**
- * Send the CCC command to the server.
- * The CCC (Clear Command Channel) command causes the underlying {@link
SSLSocket} instance to be assigned
- * to a plain {@link Socket} instances
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @since 3.0
- */
- public int execCCC() throws IOException
- {
- final int repCode = sendCommand(CMD_CCC);
-// This will be performed by sendCommand(String, String)
-// if (FTPReply.isPositiveCompletion(repCode)) {
-// _socket_.close();
-// _socket_ = plainSocket;
-// _controlInput_ = new BufferedReader(
-// new InputStreamReader(
-// _socket_.getInputStream(), getControlEncoding()));
-// _controlOutput_ = new BufferedWriter(
-// new OutputStreamWriter(
-// _socket_.getOutputStream(), getControlEncoding()));
-// }
- return repCode;
- }
-
- /**
- * Send the CONF command with the specified data.
- * @param data The data to send with the command.
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @since 3.0
- */
- public int execCONF(final byte[] data) throws IOException
- {
- if (data != null)
- {
- return sendCommand(CMD_CONF,
Base64.encodeBase64StringUnChunked(data));
- }
- return sendCommand(CMD_CONF, ""); // perhaps "=" or just
sendCommand(String)?
- }
-
- /**
- * Send the ENC command with the specified data.
- * @param data The data to send with the command.
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @since 3.0
- */
- public int execENC(final byte[] data) throws IOException
- {
- if (data != null)
- {
- return sendCommand(CMD_ENC,
Base64.encodeBase64StringUnChunked(data));
- }
- return sendCommand(CMD_ENC, ""); // perhaps "=" or just
sendCommand(String)?
- }
-
- /**
- * Send the MIC command with the specified data.
- * @param data The data to send with the command.
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @since 3.0
- */
- public int execMIC(final byte[] data) throws IOException
- {
- if (data != null)
- {
- return sendCommand(CMD_MIC,
Base64.encodeBase64StringUnChunked(data));
- }
- return sendCommand(CMD_MIC, ""); // perhaps "=" or just
sendCommand(String)?
- }
-
- /**
- * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
- * @param pbsz Protection Buffer Size.
- * @throws SSLException If the server reply code does not equal "200".
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @see #parsePBSZ(long)
- */
- public void execPBSZ(final long pbsz) throws SSLException, IOException {
- if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
- throw new IllegalArgumentException();
- }
- final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz));
- if (FTPReply.COMMAND_OK != status) {
- throw new SSLException(getReplyString());
- }
- }
-
- /**
- * PROT command.
- * <ul>
- * <li>C - Clear</li>
- * <li>S - Safe(SSL protocol only)</li>
- * <li>E - Confidential(SSL protocol only)</li>
- * <li>P - Private</li>
- * </ul>
- * <b>N.B.</b> the method calls
- * {@link #setSocketFactory(javax.net.SocketFactory)} and
- * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)}
- *
- * @param prot Data Channel Protection Level, if {@code null}, use {@link
#DEFAULT_PROT}.
- * @throws SSLException If the server reply code does not equal {@code
200}.
- * @throws IOException If an I/O error occurs while sending
- * the command.
- */
- public void execPROT(String prot) throws SSLException, IOException {
- if (prot == null) {
- prot = DEFAULT_PROT;
- }
- if (!checkPROTValue(prot)) {
- throw new IllegalArgumentException();
- }
- if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
- throw new SSLException(getReplyString());
- }
- if (DEFAULT_PROT.equals(prot)) {
- setSocketFactory(null);
- setServerSocketFactory(null);
- } else {
- setSocketFactory(new FTPSSocketFactory(context));
- setServerSocketFactory(new FTPSServerSocketFactory(context));
- initSslContext();
- }
- }
-
- /**
- * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
- * @param prefix the prefix to find
- * @param reply where to find the prefix
- * @return the remainder of the string after the prefix, or null if the
prefix was not present.
- */
- private String extractPrefixedData(final String prefix, final String
reply) {
- final int idx = reply.indexOf(prefix);
- if (idx == -1) {
- return null;
- }
- // N.B. Cannot use trim before substring as leading space would affect
the offset.
- return reply.substring(idx+prefix.length()).trim();
- }
-
- /**
- * Return AUTH command use value.
- * @return AUTH command use value.
- */
- public String getAuthValue() {
- return this.auth;
- }
-
- /**
- * Returns the names of the cipher suites which could be enabled
- * for use on this connection.
- * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns null.
- * @return An array of cipher suite names, or <code>null</code>
- */
- public String[] getEnabledCipherSuites() {
- if (_socket_ instanceof SSLSocket) {
- return ((SSLSocket)_socket_).getEnabledCipherSuites();
- }
- return null;
- }
-
- /**
- * Returns the names of the protocol versions which are currently
- * enabled for use on this connection.
- * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns null.
- * @return An array of protocols, or <code>null</code>
- */
- public String[] getEnabledProtocols() {
- if (_socket_ instanceof SSLSocket) {
- return ((SSLSocket)_socket_).getEnabledProtocols();
- }
- return null;
- }
-
- /**
- * Returns true if new SSL sessions may be established by this socket.
- * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an
- * instance of {@link SSLSocket} with {@link SSLSocket}{@link
#getEnableSessionCreation()}) enabled,
- * this returns False.
- * @return true - Indicates that sessions may be created;
- * this is the default.
- * false - indicates that an existing session must be resumed.
- */
- public boolean getEnableSessionCreation() {
- if (_socket_ instanceof SSLSocket) {
- return ((SSLSocket)_socket_).getEnableSessionCreation();
- }
- return false;
- }
-
- /**
- * Get the currently configured {@link HostnameVerifier}.
- * The verifier is only used on client mode connections.
- * @return A HostnameVerifier instance.
- * @since 3.4
- */
- public HostnameVerifier getHostnameVerifier()
- {
- return hostnameVerifier;
- }
-
- /**
- * Gets the {@link KeyManager} instance.
- *
- * @return The {@link KeyManager} instance
- */
- private KeyManager getKeyManager() {
- return keyManager;
- }
-
- /**
- * Returns true if the socket will require client authentication.
- * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns false.
- * @return true - If the server mode socket should request
- * that the client authenticate itself.
- */
- public boolean getNeedClientAuth() {
- if (_socket_ instanceof SSLSocket) {
- return ((SSLSocket)_socket_).getNeedClientAuth();
- }
- return false;
- }
-
- /**
- * Get the currently configured {@link TrustManager}.
- *
- * @return A TrustManager instance.
- */
- public TrustManager getTrustManager() {
- return trustManager;
- }
-
- /**
- * Returns true if the socket is set to use client mode
- * in its first handshake.
- * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns false.
- * @return true - If the socket should start its first handshake
- * in "client" mode.
- */
- public boolean getUseClientMode() {
- if (_socket_ instanceof SSLSocket) {
- return ((SSLSocket)_socket_).getUseClientMode();
- }
- return false;
- }
-
- /**
- * Returns true if the socket will request client authentication.
- * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns false.
- * @return true - If the server mode socket should request
- * that the client authenticate itself.
- */
- public boolean getWantClientAuth() {
- if (_socket_ instanceof SSLSocket) {
- return ((SSLSocket)_socket_).getWantClientAuth();
- }
- return false;
- }
-
- /**
- * Performs a lazy init of the SSL context
- * @throws IOException
- */
- private void initSslContext() throws IOException {
- if (context == null) {
- context = SSLContextUtils.createSSLContext(protocol,
getKeyManager(), getTrustManager());
- }
- }
-
- /**
- * Return whether or not endpoint identification using the HTTPS algorithm
- * on Java 1.7+ is enabled. The default behavior is for this to be
disabled.
- *
- * This check is only performed on client mode connections.
- *
- * @return True if enabled, false if not.
- * @since 3.4
- */
- public boolean isEndpointCheckingEnabled()
- {
- return tlsEndpointChecking;
- }
-
- /**
- * Parses the given ADAT response line and base64-decodes the data.
- * @param reply The ADAT reply to parse.
- * @return the data in the reply, base64-decoded.
- * @since 3.0
- */
- public byte[] parseADATReply(final String reply)
- {
- if (reply == null) {
- return null;
- }
- return Base64.decodeBase64(extractPrefixedData("ADAT=", reply));
- }
-
- /**
- * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
- * Issues the command and parses the response to return the negotiated
value.
- *
- * @param pbsz Protection Buffer Size.
- * @throws SSLException If the server reply code does not equal "200".
- * @throws IOException If an I/O error occurs while sending
- * the command.
- * @return the negotiated value.
- * @see #execPBSZ(long)
- * @since 3.0
- */
- public long parsePBSZ(final long pbsz) throws SSLException, IOException {
- execPBSZ(pbsz);
- long minvalue = pbsz;
- final String remainder = extractPrefixedData("PBSZ=",
getReplyString());
- if (remainder != null) {
- final long replysz = Long.parseLong(remainder);
- if (replysz < minvalue) {
- minvalue = replysz;
- }
- }
- return minvalue;
- }
-
- /**
- * Send an FTP command.
- * A successful CCC (Clear Command Channel) command causes the underlying
{@link SSLSocket}
- * instance to be assigned to a plain {@link Socket}
- * @param command The FTP command.
- * @return server reply.
- * @throws IOException If an I/O error occurs while sending the command.
- * @throws SSLException if a CCC command fails
- * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String)
- */
- // Would like to remove this method, but that will break any existing
clients that are using CCC
- @Override
- public int sendCommand(final String command, final String args) throws
IOException {
- final int repCode = super.sendCommand(command, args);
- /* If CCC is issued, restore socket i/o streams to unsecured versions
*/
- if (CMD_CCC.equals(command)) {
- if (FTPReply.COMMAND_OK != repCode) {
- throw new SSLException(getReplyString());
- }
- _socket_.close();
- _socket_ = plainSocket;
- _controlInput_ = new BufferedReader(
- new InputStreamReader(
- _socket_ .getInputStream(), getControlEncoding()));
- _controlOutput_ = new BufferedWriter(
- new OutputStreamWriter(
- _socket_.getOutputStream(), getControlEncoding()));
- }
- return repCode;
- }
-
- /**
- * Set AUTH command use value.
- * This processing is done before connected processing.
- * @param auth AUTH command use value.
- */
- public void setAuthValue(final String auth) {
- this.auth = auth;
- }
-
- /**
- * Controls which particular cipher suites are enabled for use on this
- * connection. Called before server negotiation.
- * @param cipherSuites The cipher suites.
- */
- public void setEnabledCipherSuites(final String[] cipherSuites) {
- suites = cipherSuites.clone();
- }
-
- /**
- * Controls which particular protocol versions are enabled for use on this
- * connection. I perform setting before a server negotiation.
- * @param protocolVersions The protocol versions.
- */
- public void setEnabledProtocols(final String[] protocolVersions) {
- protocols = protocolVersions.clone();
- }
-
- /**
- * Controls whether a new SSL session may be established by this socket.
- * @param isCreation The established socket flag.
- */
- public void setEnabledSessionCreation(final boolean isCreation) {
- this.isCreation = isCreation;
- }
-
- /**
- * Automatic endpoint identification checking using the HTTPS algorithm
- * is supported on Java 1.7+. The default behavior is for this to be
disabled.
- *
- * This check is only performed on client mode connections.
- *
- * @param enable Enable automatic endpoint identification checking using
the HTTPS algorithm on Java 1.7+.
- * @since 3.4
- */
- public void setEndpointCheckingEnabled(final boolean enable)
- {
- tlsEndpointChecking = enable;
- }
-
- /**
- * Override the default {@link HostnameVerifier} to use.
- * The verifier is only used on client mode connections.
- * @param newHostnameVerifier The HostnameVerifier implementation to set
or <code>null</code> to disable.
- * @since 3.4
- */
- public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier)
- {
- hostnameVerifier = newHostnameVerifier;
- }
-
- /**
- * Set a {@link KeyManager} to use
- *
- * @param keyManager The KeyManager implementation to set.
- * @see org.apache.commons.net.util.KeyManagerUtils
- */
- public void setKeyManager(final KeyManager keyManager) {
- this.keyManager = keyManager;
- }
-
- /**
- * Configures the socket to require client authentication.
- * @param isNeedClientAuth The need client auth flag.
- */
- public void setNeedClientAuth(final boolean isNeedClientAuth) {
- this.isNeedClientAuth = isNeedClientAuth;
- }
-
- // DEPRECATED - for API compatibility only - DO NOT USE
-
- /**
- * Override the default {@link TrustManager} to use; if set to {@code
null},
- * the default TrustManager from the JVM will be used.
- *
- * @param trustManager The TrustManager implementation to set, may be
{@code null}
- * @see org.apache.commons.net.util.TrustManagerUtils
- */
- public void setTrustManager(final TrustManager trustManager) {
- this.trustManager = trustManager;
- }
-
- /**
- * Configures the socket to use client (or server) mode in its first
- * handshake.
- * @param isClientMode The use client mode flag.
- */
- public void setUseClientMode(final boolean isClientMode) {
- this.isClientMode = isClientMode;
- }
-
- /**
- * Configures the socket to request client authentication,
- * but only if such a request is appropriate to the cipher
- * suite negotiated.
- * @param isWantClientAuth The want client auth flag.
- */
- public void setWantClientAuth(final boolean isWantClientAuth) {
- this.isWantClientAuth = isWantClientAuth;
- }
-
- /**
- * SSL/TLS negotiation. Acquires an SSL socket of a control
- * connection and carries out handshake processing.
- * @throws IOException If server negotiation fails
- */
- protected void sslNegotiation() throws IOException {
- plainSocket = _socket_;
- initSslContext();
- final SSLSocket socket = createSSLSocket(_socket_);
- socket.setEnableSessionCreation(isCreation);
- socket.setUseClientMode(isClientMode);
-
- // client mode
- if (isClientMode) {
- if (tlsEndpointChecking) {
- SSLSocketUtils.enableEndpointNameVerification(socket);
- }
- } else { // server mode
- socket.setNeedClientAuth(isNeedClientAuth);
- socket.setWantClientAuth(isWantClientAuth);
- }
-
- if (protocols != null) {
- socket.setEnabledProtocols(protocols);
- }
- if (suites != null) {
- socket.setEnabledCipherSuites(suites);
- }
- socket.startHandshake();
-
- // TODO the following setup appears to duplicate that in the super
class methods
- _socket_ = socket;
- _controlInput_ = new BufferedReader(new InputStreamReader(
- socket .getInputStream(), getControlEncoding()));
- _controlOutput_ = new BufferedWriter(new OutputStreamWriter(
- socket.getOutputStream(), getControlEncoding()));
-
- if (isClientMode && (hostnameVerifier != null &&
- !hostnameVerifier.verify(_hostname_, socket.getSession()))) {
- throw new SSLHandshakeException("Hostname doesn't match
certificate");
- }
- }
-
-}
-/* kate: indent-width 4; replace-tabs on; */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.ftp;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import org.apache.commons.net.util.Base64;
+import org.apache.commons.net.util.SSLContextUtils;
+import org.apache.commons.net.util.SSLSocketUtils;
+import org.apache.commons.net.util.TrustManagerUtils;
+
+/**
+ * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all
can be used to
+ * see wire-level SSL details.
+ *
+ * Warning: the hostname is not verified against the certificate by default,
use
+ * {@link #setHostnameVerifier(HostnameVerifier)} or {@link
#setEndpointCheckingEnabled(boolean)}
+ * (on Java 1.7+) to enable verification. Verification is only performed on
client mode connections.
+ * @since 2.0
+ */
+public class FTPSClient extends FTPClient {
+
+// From http://www.iana.org/assignments/port-numbers
+
+// ftps-data 989/tcp ftp protocol, data, over TLS/SSL
+// ftps-data 989/udp ftp protocol, data, over TLS/SSL
+// ftps 990/tcp ftp protocol, control, over TLS/SSL
+// ftps 990/udp ftp protocol, control, over TLS/SSL
+
+ public static final int DEFAULT_FTPS_DATA_PORT = 989;
+ public static final int DEFAULT_FTPS_PORT = 990;
+
+ /** The value that I can set in PROT command (C = Clear, P = Protected) */
+ private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"};
+ /** Default PROT Command */
+ private static final String DEFAULT_PROT = "C";
+ /** Default secure socket protocol name, i.e. TLS */
+ private static final String DEFAULT_PROTOCOL = "TLS";
+
+ /** The AUTH (Authentication/Security Mechanism) command. */
+ private static final String CMD_AUTH = "AUTH";
+ /** The ADAT (Authentication/Security Data) command. */
+ private static final String CMD_ADAT = "ADAT";
+ /** The PROT (Data Channel Protection Level) command. */
+ private static final String CMD_PROT = "PROT";
+ /** The PBSZ (Protection Buffer Size) command. */
+ private static final String CMD_PBSZ = "PBSZ";
+ /** The MIC (Integrity Protected Command) command. */
+ private static final String CMD_MIC = "MIC";
+ /** The CONF (Confidentiality Protected Command) command. */
+ private static final String CMD_CONF = "CONF";
+ /** The ENC (Privacy Protected Command) command. */
+ private static final String CMD_ENC = "ENC";
+ /** The CCC (Clear Command Channel) command. */
+ private static final String CMD_CCC = "CCC";
+
+ /** @deprecated - not used - may be removed in a future release */
+ @Deprecated
+ public static String KEYSTORE_ALGORITHM;
+ /** @deprecated - not used - may be removed in a future release */
+ @Deprecated
+ public static String TRUSTSTORE_ALGORITHM;
+ /** @deprecated - not used - may be removed in a future release */
+ @Deprecated
+ public static String PROVIDER;
+ /** @deprecated - not used - may be removed in a future release */
+ @Deprecated
+ public static String STORE_TYPE;
+ /** The security mode. (True - Implicit Mode / False - Explicit Mode) */
+ private final boolean isImplicit;
+ /** The secure socket protocol to be used, e.g. SSL/TLS. */
+ private final String protocol;
+ /** The AUTH Command value */
+ private String auth = DEFAULT_PROTOCOL;
+ /** The context object. */
+ private SSLContext context;
+ /** The socket object. */
+ private Socket plainSocket;
+ /** Controls whether a new SSL session may be established by this socket.
Default true. */
+ private boolean isCreation = true;
+ /** The use client mode flag. */
+ private boolean isClientMode = true;
+
+ /** The need client auth flag. */
+ private boolean isNeedClientAuth;
+
+ /** The want client auth flag. */
+ private boolean isWantClientAuth;
+
+ /** The cipher suites */
+ private String[] suites;
+
+ /** The protocol versions */
+ private String[] protocols;
+
+ /** The FTPS {@link TrustManager} implementation, default validate only
+ * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}.
+ */
+ private TrustManager trustManager =
TrustManagerUtils.getValidateServerCertificateTrustManager();
+
+ /** The {@link KeyManager}, default null (i.e. use system default). */
+ private KeyManager keyManager;
+
+ /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no
verification). */
+ private HostnameVerifier hostnameVerifier;
+
+ /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */
+ private boolean tlsEndpointChecking;
+
+ /**
+ * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}.
+ *
+ * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security
mode to explicit (isImplicit = false)
+ */
+ public FTPSClient() {
+ this(DEFAULT_PROTOCOL, false);
+ }
+
+ /**
+ * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
+ * Calls {@link #FTPSClient(String, boolean)}
+ * @param isImplicit The security mode (Implicit/Explicit).
+ */
+ public FTPSClient(final boolean isImplicit) {
+ this(DEFAULT_PROTOCOL, isImplicit);
+ }
+
+
+ /**
+ * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
+ * The default TrustManager is set from {@link
TrustManagerUtils#getValidateServerCertificateTrustManager()}
+ * @param isImplicit The security mode(Implicit/Explicit).
+ * @param context A pre-configured SSL Context
+ */
+ public FTPSClient(final boolean isImplicit, final SSLContext context) {
+ this(DEFAULT_PROTOCOL, isImplicit);
+ this.context = context;
+ }
+
+ /**
+ * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
+ * and isImplicit {@code false}
+ * Calls {@link #FTPSClient(boolean, SSLContext)}
+ * @param context A pre-configured SSL Context
+ */
+ public FTPSClient(final SSLContext context) {
+ this(false, context);
+ }
+
+
+ /**
+ * Constructor for FTPSClient, using explict mode, calls {@link
#FTPSClient(String, boolean)}.
+ *
+ * @param protocol the protocol to use
+ */
+ public FTPSClient(final String protocol) {
+ this(protocol, false);
+ }
+
+ /**
+ * Constructor for FTPSClient allowing specification of protocol
+ * and security mode. If isImplicit is true, the port is set to
+ * {@link #DEFAULT_FTPS_PORT} i.e. 990.
+ * The default TrustManager is set from {@link
TrustManagerUtils#getValidateServerCertificateTrustManager()}
+ * @param protocol the protocol
+ * @param isImplicit The security mode(Implicit/Explicit).
+ */
+ public FTPSClient(final String protocol, final boolean isImplicit) {
+ this.protocol = protocol;
+ this.isImplicit = isImplicit;
+ if (isImplicit) {
+ setDefaultPort(DEFAULT_FTPS_PORT);
+ }
+ }
+
+ /**
+ * Because there are so many connect() methods,
+ * the _connectAction_() method is provided as a means of performing
+ * some action immediately after establishing a connection,
+ * rather than reimplementing all of the connect() methods.
+ * @throws IOException If it throw by _connectAction_.
+ * @see org.apache.commons.net.SocketClient#_connectAction_()
+ */
+ @Override
+ protected void _connectAction_() throws IOException {
+ // Implicit mode.
+ if (isImplicit) {
+ applySocketAttributes();
+ sslNegotiation();
+ }
+ super._connectAction_();
+ // Explicit mode.
+ if (!isImplicit) {
+ execAUTH();
+ sslNegotiation();
+ }
+ }
+
+ /**
+ * Returns a socket of the data connection.
+ * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
+ * @param command The int representation of the FTP command to send.
+ * @param arg The arguments to the FTP command.
+ * If this parameter is set to null, then the command is sent with
+ * no arguments.
+ * @return corresponding to the established data connection.
+ * Null is returned if an FTP protocol error is reported at any point
+ * during the establishment and initialization of the connection.
+ * @throws IOException If there is any problem with the connection.
+ * @see FTPClient#_openDataConnection_(int, String)
+ * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd,
String)} instead
+ */
+ @Override
+ // Strictly speaking this is not needed, but it works round a Clirr bug
+ // So rather than invoke the parent code, we do it here
+ @Deprecated
+ protected Socket _openDataConnection_(final int command, final String arg)
+ throws IOException {
+ return _openDataConnection_(FTPCommand.getCommand(command), arg);
+ }
+
+ /**
+ * Returns a socket of the data connection. Wrapped as an {@link
SSLSocket}, which carries out handshake processing.
+ *
+ * @param command The textual representation of the FTP command to send.
+ * @param arg The arguments to the FTP command. If this parameter is set
to null, then the command is sent with no
+ * arguments.
+ * @return corresponding to the established data connection. Null is
returned if an FTP protocol error is reported
+ * at any point during the establishment and initialization of the
connection.
+ * @throws IOException If there is any problem with the connection.
+ * @see FTPClient#_openDataConnection_(int, String)
+ * @since 3.2
+ */
+ @Override
+ protected Socket _openDataConnection_(final String command, final String
arg) throws IOException {
+ final Socket socket = super._openDataConnection_(command, arg);
+ _prepareDataSocket_(socket);
+ if (socket instanceof SSLSocket) {
+ final SSLSocket sslSocket = (SSLSocket) socket;
+
+ sslSocket.setUseClientMode(isClientMode);
+ sslSocket.setEnableSessionCreation(isCreation);
+
+ // server mode
+ if (!isClientMode) {
+ sslSocket.setNeedClientAuth(isNeedClientAuth);
+ sslSocket.setWantClientAuth(isWantClientAuth);
+ }
+ if (suites != null) {
+ sslSocket.setEnabledCipherSuites(suites);
+ }
+ if (protocols != null) {
+ sslSocket.setEnabledProtocols(protocols);
+ }
+ sslSocket.startHandshake();
+ }
+
+ return socket;
+ }
+
+ /**
+ * Performs any custom initialization for a newly created SSLSocket
(before the SSL handshake happens). Called
+ * by {@link #_openDataConnection_(int, String)} immediately after
creating the socket. The default
+ * implementation is a no-op
+ *
+ * @param socket the socket to set up
+ * @throws IOException on error
+ * @since 3.1
+ */
+ protected void _prepareDataSocket_(final Socket socket)
+ throws IOException {
+ }
+
+ /**
+ * Check the value that can be set in PROT Command value.
+ * @param prot Data Channel Protection Level.
+ * @return True - A set point is right / False - A set point is not right
+ */
+ private boolean checkPROTValue(final String prot) {
+ for (final String element : PROT_COMMAND_VALUE)
+ {
+ if (element.equals(prot)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Create SSL socket from plain socket.
+ *
+ * @param socket
+ * @return SSL Socket
+ * @throws IOException
+ */
+ private SSLSocket createSSLSocket(final Socket socket) throws IOException {
+ if (socket != null) {
+ final SSLSocketFactory f = context.getSocketFactory();
+ return (SSLSocket) f.createSocket(socket, _hostname_,
socket.getPort(), false);
+ }
+ return null;
+ }
+
+ /**
+ * Closes the connection to the FTP server and restores
+ * connection parameters to the default values.
+ * <p>
+ * Calls {@code setSocketFactory(null)} and {@code
setServerSocketFactory(null)}
+ * to reset the factories that may have been changed during the session,
+ * e.g. by {@link #execPROT(String)}
+ * @throws IOException If an error occurs while disconnecting.
+ * @since 3.0
+ */
+ @Override
+ public void disconnect() throws IOException
+ {
+ super.disconnect();
+ if (plainSocket != null) {
+ plainSocket.close();
+ }
+ setSocketFactory(null);
+ setServerSocketFactory(null);
+ }
+
+ /**
+ * Send the ADAT command with the specified authentication data.
+ * @param data The data to send with the command.
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @since 3.0
+ */
+ public int execADAT(final byte[] data) throws IOException
+ {
+ if (data != null)
+ {
+ return sendCommand(CMD_ADAT,
Base64.encodeBase64StringUnChunked(data));
+ }
+ return sendCommand(CMD_ADAT);
+ }
+
+ /**
+ * AUTH command.
+ * @throws SSLException If it server reply code not equal "234" and "334".
+ * @throws IOException If an I/O error occurs while either sending
+ * the command.
+ */
+ protected void execAUTH() throws SSLException, IOException {
+ final int replyCode = sendCommand(CMD_AUTH, auth);
+ if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) {
+ // replyCode = 334
+ // I carry out an ADAT command.
+ } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) {
+ throw new SSLException(getReplyString());
+ }
+ }
+
+ /**
+ * Send the AUTH command with the specified mechanism.
+ * @param mechanism The mechanism name to send with the command.
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @since 3.0
+ */
+ public int execAUTH(final String mechanism) throws IOException
+ {
+ return sendCommand(CMD_AUTH, mechanism);
+ }
+
+ /**
+ * Send the CCC command to the server.
+ * The CCC (Clear Command Channel) command causes the underlying {@link
SSLSocket} instance to be assigned
+ * to a plain {@link Socket} instances
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @since 3.0
+ */
+ public int execCCC() throws IOException
+ {
+ final int repCode = sendCommand(CMD_CCC);
+// This will be performed by sendCommand(String, String)
+// if (FTPReply.isPositiveCompletion(repCode)) {
+// _socket_.close();
+// _socket_ = plainSocket;
+// _controlInput_ = new BufferedReader(
+// new InputStreamReader(
+// _socket_.getInputStream(), getControlEncoding()));
+// _controlOutput_ = new BufferedWriter(
+// new OutputStreamWriter(
+// _socket_.getOutputStream(), getControlEncoding()));
+// }
+ return repCode;
+ }
+
+ /**
+ * Send the CONF command with the specified data.
+ * @param data The data to send with the command.
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @since 3.0
+ */
+ public int execCONF(final byte[] data) throws IOException
+ {
+ if (data != null)
+ {
+ return sendCommand(CMD_CONF,
Base64.encodeBase64StringUnChunked(data));
+ }
+ return sendCommand(CMD_CONF, ""); // perhaps "=" or just
sendCommand(String)?
+ }
+
+ /**
+ * Send the ENC command with the specified data.
+ * @param data The data to send with the command.
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @since 3.0
+ */
+ public int execENC(final byte[] data) throws IOException
+ {
+ if (data != null)
+ {
+ return sendCommand(CMD_ENC,
Base64.encodeBase64StringUnChunked(data));
+ }
+ return sendCommand(CMD_ENC, ""); // perhaps "=" or just
sendCommand(String)?
+ }
+
+ /**
+ * Send the MIC command with the specified data.
+ * @param data The data to send with the command.
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @since 3.0
+ */
+ public int execMIC(final byte[] data) throws IOException
+ {
+ if (data != null)
+ {
+ return sendCommand(CMD_MIC,
Base64.encodeBase64StringUnChunked(data));
+ }
+ return sendCommand(CMD_MIC, ""); // perhaps "=" or just
sendCommand(String)?
+ }
+
+ /**
+ * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
+ * @param pbsz Protection Buffer Size.
+ * @throws SSLException If the server reply code does not equal "200".
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @see #parsePBSZ(long)
+ */
+ public void execPBSZ(final long pbsz) throws SSLException, IOException {
+ if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
+ throw new IllegalArgumentException();
+ }
+ final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz));
+ if (FTPReply.COMMAND_OK != status) {
+ throw new SSLException(getReplyString());
+ }
+ }
+
+ /**
+ * PROT command.
+ * <ul>
+ * <li>C - Clear</li>
+ * <li>S - Safe(SSL protocol only)</li>
+ * <li>E - Confidential(SSL protocol only)</li>
+ * <li>P - Private</li>
+ * </ul>
+ * <b>N.B.</b> the method calls
+ * {@link #setSocketFactory(javax.net.SocketFactory)} and
+ * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)}
+ *
+ * @param prot Data Channel Protection Level, if {@code null}, use {@link
#DEFAULT_PROT}.
+ * @throws SSLException If the server reply code does not equal {@code
200}.
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ */
+ public void execPROT(String prot) throws SSLException, IOException {
+ if (prot == null) {
+ prot = DEFAULT_PROT;
+ }
+ if (!checkPROTValue(prot)) {
+ throw new IllegalArgumentException();
+ }
+ if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
+ throw new SSLException(getReplyString());
+ }
+ if (DEFAULT_PROT.equals(prot)) {
+ setSocketFactory(null);
+ setServerSocketFactory(null);
+ } else {
+ setSocketFactory(new FTPSSocketFactory(context));
+ setServerSocketFactory(new FTPSServerSocketFactory(context));
+ initSslContext();
+ }
+ }
+
+ /**
+ * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
+ * @param prefix the prefix to find
+ * @param reply where to find the prefix
+ * @return the remainder of the string after the prefix, or null if the
prefix was not present.
+ */
+ private String extractPrefixedData(final String prefix, final String
reply) {
+ final int idx = reply.indexOf(prefix);
+ if (idx == -1) {
+ return null;
+ }
+ // N.B. Cannot use trim before substring as leading space would affect
the offset.
+ return reply.substring(idx+prefix.length()).trim();
+ }
+
+ /**
+ * Return AUTH command use value.
+ * @return AUTH command use value.
+ */
+ public String getAuthValue() {
+ return this.auth;
+ }
+
+ /**
+ * Returns the names of the cipher suites which could be enabled
+ * for use on this connection.
+ * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns null.
+ * @return An array of cipher suite names, or <code>null</code>
+ */
+ public String[] getEnabledCipherSuites() {
+ if (_socket_ instanceof SSLSocket) {
+ return ((SSLSocket)_socket_).getEnabledCipherSuites();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the names of the protocol versions which are currently
+ * enabled for use on this connection.
+ * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns null.
+ * @return An array of protocols, or <code>null</code>
+ */
+ public String[] getEnabledProtocols() {
+ if (_socket_ instanceof SSLSocket) {
+ return ((SSLSocket)_socket_).getEnabledProtocols();
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if new SSL sessions may be established by this socket.
+ * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an
+ * instance of {@link SSLSocket} with {@link SSLSocket}{@link
#getEnableSessionCreation()}) enabled,
+ * this returns False.
+ * @return true - Indicates that sessions may be created;
+ * this is the default.
+ * false - indicates that an existing session must be resumed.
+ */
+ public boolean getEnableSessionCreation() {
+ if (_socket_ instanceof SSLSocket) {
+ return ((SSLSocket)_socket_).getEnableSessionCreation();
+ }
+ return false;
+ }
+
+ /**
+ * Get the currently configured {@link HostnameVerifier}.
+ * The verifier is only used on client mode connections.
+ * @return A HostnameVerifier instance.
+ * @since 3.4
+ */
+ public HostnameVerifier getHostnameVerifier()
+ {
+ return hostnameVerifier;
+ }
+
+ /**
+ * Gets the {@link KeyManager} instance.
+ *
+ * @return The {@link KeyManager} instance
+ */
+ private KeyManager getKeyManager() {
+ return keyManager;
+ }
+
+ /**
+ * Returns true if the socket will require client authentication.
+ * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns false.
+ * @return true - If the server mode socket should request
+ * that the client authenticate itself.
+ */
+ public boolean getNeedClientAuth() {
+ if (_socket_ instanceof SSLSocket) {
+ return ((SSLSocket)_socket_).getNeedClientAuth();
+ }
+ return false;
+ }
+
+ /**
+ * Get the currently configured {@link TrustManager}.
+ *
+ * @return A TrustManager instance.
+ */
+ public TrustManager getTrustManager() {
+ return trustManager;
+ }
+
+ /**
+ * Returns true if the socket is set to use client mode
+ * in its first handshake.
+ * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns false.
+ * @return true - If the socket should start its first handshake
+ * in "client" mode.
+ */
+ public boolean getUseClientMode() {
+ if (_socket_ instanceof SSLSocket) {
+ return ((SSLSocket)_socket_).getUseClientMode();
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the socket will request client authentication.
+ * When the underlying {@link Socket} is not an {@link SSLSocket}
instance, returns false.
+ * @return true - If the server mode socket should request
+ * that the client authenticate itself.
+ */
+ public boolean getWantClientAuth() {
+ if (_socket_ instanceof SSLSocket) {
+ return ((SSLSocket)_socket_).getWantClientAuth();
+ }
+ return false;
+ }
+
+ /**
+ * Performs a lazy init of the SSL context
+ * @throws IOException
+ */
+ private void initSslContext() throws IOException {
+ if (context == null) {
+ context = SSLContextUtils.createSSLContext(protocol,
getKeyManager(), getTrustManager());
+ }
+ }
+
+ /**
+ * Return whether or not endpoint identification using the HTTPS algorithm
+ * on Java 1.7+ is enabled. The default behavior is for this to be
disabled.
+ *
+ * This check is only performed on client mode connections.
+ *
+ * @return True if enabled, false if not.
+ * @since 3.4
+ */
+ public boolean isEndpointCheckingEnabled()
+ {
+ return tlsEndpointChecking;
+ }
+
+ /**
+ * Parses the given ADAT response line and base64-decodes the data.
+ * @param reply The ADAT reply to parse.
+ * @return the data in the reply, base64-decoded.
+ * @since 3.0
+ */
+ public byte[] parseADATReply(final String reply)
+ {
+ if (reply == null) {
+ return null;
+ }
+ return Base64.decodeBase64(extractPrefixedData("ADAT=", reply));
+ }
+
+ /**
+ * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
+ * Issues the command and parses the response to return the negotiated
value.
+ *
+ * @param pbsz Protection Buffer Size.
+ * @throws SSLException If the server reply code does not equal "200".
+ * @throws IOException If an I/O error occurs while sending
+ * the command.
+ * @return the negotiated value.
+ * @see #execPBSZ(long)
+ * @since 3.0
+ */
+ public long parsePBSZ(final long pbsz) throws SSLException, IOException {
+ execPBSZ(pbsz);
+ long minvalue = pbsz;
+ final String remainder = extractPrefixedData("PBSZ=",
getReplyString());
+ if (remainder != null) {
+ final long replysz = Long.parseLong(remainder);
+ if (replysz < minvalue) {
+ minvalue = replysz;
+ }
+ }
+ return minvalue;
+ }
+
+ /**
+ * Send an FTP command.
+ * A successful CCC (Clear Command Channel) command causes the underlying
{@link SSLSocket}
+ * instance to be assigned to a plain {@link Socket}
+ * @param command The FTP command.
+ * @return server reply.
+ * @throws IOException If an I/O error occurs while sending the command.
+ * @throws SSLException if a CCC command fails
+ * @see org.apache.commons.net.ftp.FTP#sendCommand(String)
+ */
+ // Would like to remove this method, but that will break any existing
clients that are using CCC
+ @Override
+ public int sendCommand(final String command, final String args) throws
IOException {
+ final int repCode = super.sendCommand(command, args);
+ /* If CCC is issued, restore socket i/o streams to unsecured versions
*/
+ if (CMD_CCC.equals(command)) {
+ if (FTPReply.COMMAND_OK != repCode) {
+ throw new SSLException(getReplyString());
+ }
+ _socket_.close();
+ _socket_ = plainSocket;
+ _controlInput_ = new BufferedReader(
+ new InputStreamReader(
+ _socket_ .getInputStream(), getControlEncoding()));
+ _controlOutput_ = new BufferedWriter(
+ new OutputStreamWriter(
+ _socket_.getOutputStream(), getControlEncoding()));
+ }
+ return repCode;
+ }
+
+ /**
+ * Set AUTH command use value.
+ * This processing is done before connected processing.
+ * @param auth AUTH command use value.
+ */
+ public void setAuthValue(final String auth) {
+ this.auth = auth;
+ }
+
+ /**
+ * Controls which particular cipher suites are enabled for use on this
+ * connection. Called before server negotiation.
+ * @param cipherSuites The cipher suites.
+ */
+ public void setEnabledCipherSuites(final String[] cipherSuites) {
+ suites = cipherSuites.clone();
+ }
+
+ /**
+ * Controls which particular protocol versions are enabled for use on this
+ * connection. I perform setting before a server negotiation.
+ * @param protocolVersions The protocol versions.
+ */
+ public void setEnabledProtocols(final String[] protocolVersions) {
+ protocols = protocolVersions.clone();
+ }
+
+ /**
+ * Controls whether a new SSL session may be established by this socket.
+ * @param isCreation The established socket flag.
+ */
+ public void setEnabledSessionCreation(final boolean isCreation) {
+ this.isCreation = isCreation;
+ }
+
+ /**
+ * Automatic endpoint identification checking using the HTTPS algorithm
+ * is supported on Java 1.7+. The default behavior is for this to be
disabled.
+ *
+ * This check is only performed on client mode connections.
+ *
+ * @param enable Enable automatic endpoint identification checking using
the HTTPS algorithm on Java 1.7+.
+ * @since 3.4
+ */
+ public void setEndpointCheckingEnabled(final boolean enable)
+ {
+ tlsEndpointChecking = enable;
+ }
+
+ /**
+ * Override the default {@link HostnameVerifier} to use.
+ * The verifier is only used on client mode connections.
+ * @param newHostnameVerifier The HostnameVerifier implementation to set
or <code>null</code> to disable.
+ * @since 3.4
+ */
+ public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier)
+ {
+ hostnameVerifier = newHostnameVerifier;
+ }
+
+ /**
+ * Set a {@link KeyManager} to use
+ *
+ * @param keyManager The KeyManager implementation to set.
+ * @see org.apache.commons.net.util.KeyManagerUtils
+ */
+ public void setKeyManager(final KeyManager keyManager) {
+ this.keyManager = keyManager;
+ }
+
+ /**
+ * Configures the socket to require client authentication.
+ * @param isNeedClientAuth The need client auth flag.
+ */
+ public void setNeedClientAuth(final boolean isNeedClientAuth) {
+ this.isNeedClientAuth = isNeedClientAuth;
+ }
+
+ // DEPRECATED - for API compatibility only - DO NOT USE
+
+ /**
+ * Override the default {@link TrustManager} to use; if set to {@code
null},
+ * the default TrustManager from the JVM will be used.
+ *
+ * @param trustManager The TrustManager implementation to set, may be
{@code null}
+ * @see org.apache.commons.net.util.TrustManagerUtils
+ */
+ public void setTrustManager(final TrustManager trustManager) {
+ this.trustManager = trustManager;
+ }
+
+ /**
+ * Configures the socket to use client (or server) mode in its first
+ * handshake.
+ * @param isClientMode The use client mode flag.
+ */
+ public void setUseClientMode(final boolean isClientMode) {
+ this.isClientMode = isClientMode;
+ }
+
+ /**
+ * Configures the socket to request client authentication,
+ * but only if such a request is appropriate to the cipher
+ * suite negotiated.
+ * @param isWantClientAuth The want client auth flag.
+ */
+ public void setWantClientAuth(final boolean isWantClientAuth) {
+ this.isWantClientAuth = isWantClientAuth;
+ }
+
+ /**
+ * SSL/TLS negotiation. Acquires an SSL socket of a control
+ * connection and carries out handshake processing.
+ * @throws IOException If server negotiation fails
+ */
+ protected void sslNegotiation() throws IOException {
+ plainSocket = _socket_;
+ initSslContext();
+ final SSLSocket socket = createSSLSocket(_socket_);
+ socket.setEnableSessionCreation(isCreation);
+ socket.setUseClientMode(isClientMode);
+
+ // client mode
+ if (isClientMode) {
+ if (tlsEndpointChecking) {
+ SSLSocketUtils.enableEndpointNameVerification(socket);
+ }
+ } else { // server mode
+ socket.setNeedClientAuth(isNeedClientAuth);
+ socket.setWantClientAuth(isWantClientAuth);
+ }
+
+ if (protocols != null) {
+ socket.setEnabledProtocols(protocols);
+ }
+ if (suites != null) {
+ socket.setEnabledCipherSuites(suites);
+ }
+ socket.startHandshake();
+
+ // TODO the following setup appears to duplicate that in the super
class methods
+ _socket_ = socket;
+ _controlInput_ = new BufferedReader(new InputStreamReader(
+ socket .getInputStream(), getControlEncoding()));
+ _controlOutput_ = new BufferedWriter(new OutputStreamWriter(
+ socket.getOutputStream(), getControlEncoding()));
+
+ if (isClientMode && (hostnameVerifier != null &&
+ !hostnameVerifier.verify(_hostname_, socket.getSession()))) {
+ throw new SSLHandshakeException("Hostname doesn't match
certificate");
+ }
+ }
+
+}
+/* kate: indent-width 4; replace-tabs on; */
diff --git a/src/main/java/org/apache/commons/net/ntp/TimeStamp.java
b/src/main/java/org/apache/commons/net/ntp/TimeStamp.java
index 20a10755..f9aa8b95 100644
--- a/src/main/java/org/apache/commons/net/ntp/TimeStamp.java
+++ b/src/main/java/org/apache/commons/net/ntp/TimeStamp.java
@@ -1,468 +1,468 @@
-package org.apache.commons.net.ntp;
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * TimeStamp class represents the Network Time Protocol (NTP) timestamp
- * as defined in RFC-1305 and SNTP (RFC-2030). It is represented as a
- * 64-bit unsigned fixed-point number in seconds relative to 0-hour on
1-January-1900.
- * The 32-bit low-order bits are the fractional seconds whose precision is
- * about 200 picoseconds. Assumes overflow date when date passes MAX_LONG
- * and reverts back to 0 is 2036 and not 1900. Test for most significant
- * bit: if MSB=0 then 2036 basis is used otherwise 1900 if MSB=1.
- * <p>
- * Methods exist to convert NTP timestamps to and from the equivalent Java date
- * representation, which is the number of milliseconds since the standard base
- * time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
- * </p>
- *
- * @see java.util.Date
- */
-public class TimeStamp implements java.io.Serializable, Comparable<TimeStamp>
-{
- private static final long serialVersionUID = 8139806907588338737L;
-
- /**
- * Baseline NTP time if bit-0=0 is 7-Feb-2036 @ 06:28:16 UTC
- */
- protected static final long msb0baseTime = 2085978496000L;
-
- /**
- * Baseline NTP time if bit-0=1 is 1-Jan-1900 @ 01:00:00 UTC
- */
- protected static final long msb1baseTime = -2208988800000L;
-
- /**
- * Default NTP date string format. E.g. Fri, Sep 12 2003 21:06:23.860.
- * See <code>java.text.SimpleDateFormat</code> for code descriptions.
- */
- public static final String NTP_DATE_FORMAT = "EEE, MMM dd yyyy
HH:mm:ss.SSS";
-
- /**
- * Left-pad 8-character hex string with 0's
- *
- * @param buf - StringBuilder which is appended with leading 0's.
- * @param l - a long.
- */
- private static void appendHexString(final StringBuilder buf, final long l)
- {
- final String s = Long.toHexString(l);
- for (int i = s.length(); i < 8; i++) {
- buf.append('0');
- }
- buf.append(s);
- }
-
- /**
- * Convert NTP timestamp hexstring (e.g. "c1a089bd.fc904f6d") to the NTP
- * 64-bit unsigned fixed-point number.
- * @param hexString the string to convert
- *
- * @return NTP 64-bit timestamp value.
- * @throws NumberFormatException - if the string does not contain a
parsable timestamp.
- */
- protected static long decodeNtpHexString(final String hexString)
- throws NumberFormatException
- {
- if (hexString == null) {
- throw new NumberFormatException("null");
- }
- final int ind = hexString.indexOf('.');
- if (ind == -1) {
- if (hexString.isEmpty()) {
- return 0;
- }
- return Long.parseLong(hexString, 16) << 32; // no decimal
- }
-
- return Long.parseLong(hexString.substring(0, ind), 16) << 32 |
- Long.parseLong(hexString.substring(ind + 1), 16);
- }
- /**
- * Constructs a NTP timestamp object and initializes it so that
- * it represents the time at which it was allocated, measured to the
- * nearest millisecond.
- * @return NTP timestamp object set to the current time.
- * @see java.lang.System#currentTimeMillis()
- */
- public static TimeStamp getCurrentTime()
- {
- return getNtpTime(System.currentTimeMillis());
- }
-
- // initialization of static time bases
- /*
- static {
- TimeZone utcZone = TimeZone.getTimeZone("UTC");
- Calendar calendar = Calendar.getInstance(utcZone);
- calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
- calendar.set(Calendar.MILLISECOND, 0);
- msb1baseTime = calendar.getTime().getTime();
- calendar.set(2036, Calendar.FEBRUARY, 7, 6, 28, 16);
- calendar.set(Calendar.MILLISECOND, 0);
- msb0baseTime = calendar.getTime().getTime();
- }
- */
-
- /**
- * Helper method to convert Java time to NTP timestamp object.
- * Note that Java time (milliseconds) by definition has less precision
- * then NTP time (picoseconds) so converting Ntptime to Javatime and back
- * to Ntptime loses precision. For example, Tue, Dec 17 2002 09:07:24.810
- * is represented by a single Java-based time value of f22cd1fc8a, but its
- * NTP equivalent are all values from c1a9ae1c.cf5c28f5 to
c1a9ae1c.cf9db22c.
- * @param dateMillis the milliseconds since January 1, 1970, 00:00:00
GMT.
- * @return NTP timestamp object at the specified date.
- */
- public static TimeStamp getNtpTime(final long dateMillis)
- {
- return new TimeStamp(toNtpTime(dateMillis));
- }
-
- /**
- * Converts 64-bit NTP timestamp to Java standard time.
- *
- * Note that java time (milliseconds) by definition has less precision
- * then NTP time (picoseconds) so converting NTP timestamp to java time
and back
- * to NTP timestamp loses precision. For example, Tue, Dec 17 2002
09:07:24.810 EST
- * is represented by a single Java-based time value of f22cd1fc8a, but its
- * NTP equivalent are all values ranging from c1a9ae1c.cf5c28f5 to
c1a9ae1c.cf9db22c.
- *
- * @param ntpTimeValue the input time
- * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
- * represented by this NTP timestamp value.
- */
- public static long getTime(final long ntpTimeValue)
- {
- final long seconds = (ntpTimeValue >>> 32) & 0xffffffffL; //
high-order 32-bits
- long fraction = ntpTimeValue & 0xffffffffL; // low-order
32-bits
-
- // Use round-off on fractional part to preserve going to lower
precision
- fraction = Math.round(1000D * fraction / 0x100000000L);
-
- /*
- * If the most significant bit (MSB) on the seconds field is set we use
- * a different time base. The following text is a quote from RFC-2030
(SNTP v4):
- *
- * If bit 0 is set, the UTC time is in the range 1968-2036 and UTC
time
- * is reckoned from 0h 0m 0s UTC on 1 January 1900. If bit 0 is not
set,
- * the time is in the range 2036-2104 and UTC time is reckoned from
- * 6h 28m 16s UTC on 7 February 2036.
- */
- final long msb = seconds & 0x80000000L;
- if (msb == 0) {
- // use base: 7-Feb-2036 @ 06:28:16 UTC
- return msb0baseTime + (seconds * 1000) + fraction;
- }
- // use base: 1-Jan-1900 @ 01:00:00 UTC
- return msb1baseTime + (seconds * 1000) + fraction;
- }
-
- /**
- * Parses the string argument as a NTP hexidecimal timestamp
representation string
- * (e.g. "c1a089bd.fc904f6d").
- *
- * @param s - hexstring.
- * @return the Timestamp represented by the argument in hexidecimal.
- * @throws NumberFormatException - if the string does not contain a
parsable timestamp.
- */
- public static TimeStamp parseNtpString(final String s)
- throws NumberFormatException
- {
- return new TimeStamp(decodeNtpHexString(s));
- }
-
- /**
- * Converts Java time to 64-bit NTP time representation.
- *
- * @param millis Java time
- * @return NTP timestamp representation of Java time value.
- */
- protected static long toNtpTime(final long millis)
- {
- final boolean useBase1 = millis < msb0baseTime; // time < Feb-2036
- final long baseTimeMillis;
- if (useBase1) {
- baseTimeMillis = millis - msb1baseTime; // dates <= Feb-2036
- } else {
- // if base0 needed for dates >= Feb-2036
- baseTimeMillis = millis - msb0baseTime;
- }
-
- long seconds = baseTimeMillis / 1000;
- final long fraction = ((baseTimeMillis % 1000) * 0x100000000L) / 1000;
-
- if (useBase1) {
- seconds |= 0x80000000L; // set high-order bit if msb1baseTime 1900
used
- }
-
- return seconds << 32 | fraction;
- }
-
- /**
- * Converts 64-bit NTP timestamp value to a <code>String</code>.
- * The NTP timestamp value is represented as hex string with
- * seconds separated by fractional seconds by a decimal point;
- * e.g. c1a089bd.fc904f6d == Tue, Dec 10 2002 10:41:49.986
- * @param ntpTime the 64 bit timestamp
- *
- * @return NTP timestamp 64-bit long value as hex string with seconds
- * separated by fractional seconds.
- */
- public static String toString(final long ntpTime)
- {
- final StringBuilder buf = new StringBuilder();
- // high-order second bits (32..63) as hexstring
- appendHexString(buf, (ntpTime >>> 32) & 0xffffffffL);
-
- // low-order fractional seconds bits (0..31) as hexstring
- buf.append('.');
- appendHexString(buf, ntpTime & 0xffffffffL);
-
- return buf.toString();
- }
-
- /**
- * NTP timestamp value: 64-bit unsigned fixed-point number as defined in
RFC-1305
- * with high-order 32 bits the seconds field and the low-order 32-bits the
- * fractional field.
- */
- private final long ntpTime;
-
- private DateFormat simpleFormatter;
-
- private DateFormat utcFormatter;
-
- /**
- * Constructs a newly allocated NTP timestamp object
- * that represents the Java Date argument.
- *
- * @param d - the Date to be represented by the Timestamp object.
- */
- public TimeStamp(final Date d)
- {
- ntpTime = d == null ? 0 : toNtpTime(d.getTime());
- }
-
- /**
- * Constructs a newly allocated NTP timestamp object
- * that represents the native 64-bit long argument.
- * @param ntpTime the timestamp
- */
- public TimeStamp(final long ntpTime)
- {
- this.ntpTime = ntpTime;
- }
-
- /**
- * Constructs a newly allocated NTP timestamp object
- * that represents the value represented by the string
- * in hexdecimal form (e.g. "c1a089bd.fc904f6d").
- * @param hexStamp the hex timestamp
- *
- * @throws NumberFormatException - if the string does not contain a
parsable timestamp.
- */
- public TimeStamp(final String hexStamp) throws NumberFormatException
- {
- ntpTime = decodeNtpHexString(hexStamp);
- }
-
- /**
- * Compares two Timestamps numerically.
- *
- * @param anotherTimeStamp - the <code>TimeStamp</code> to be compared.
- * @return the value <code>0</code> if the argument TimeStamp is equal to
- * this TimeStamp; a value less than <code>0</code> if this
TimeStamp
- * is numerically less than the TimeStamp argument; and a
- * value greater than <code>0</code> if this TimeStamp is
- * numerically greater than the TimeStamp argument
- * (signed comparison).
- */
- @Override
- public int compareTo(final TimeStamp anotherTimeStamp)
- {
- final long thisVal = this.ntpTime;
- final long anotherVal = anotherTimeStamp.ntpTime;
- return (Long.compare(thisVal, anotherVal));
- }
-
- /**
- * Compares this object against the specified object.
- * The result is <code>true</code> if and only if the argument is
- * not <code>null</code> and is a <code>Long</code> object that
- * contains the same <code>long</code> value as this object.
- *
- * @param obj the object to compare with.
- * @return <code>true</code> if the objects are the same;
- * <code>false</code> otherwise.
- */
- @Override
- public boolean equals(final Object obj)
- {
- if (obj instanceof TimeStamp) {
- return ntpTime == ((TimeStamp) obj).ntpValue();
- }
- return false;
- }
-
- /**
- * Converts NTP timestamp to Java Date object.
- *
- * @return NTP Timestamp in Java Date
- */
- public Date getDate()
- {
- return new Date(getTime(ntpTime));
- }
-
- /**
- * Returns low-order 32-bits representing the fractional seconds.
- *
- * @return fractional seconds represented by this NTP timestamp.
- */
- public long getFraction()
- {
- return ntpTime & 0xffffffffL;
- }
-
- /**
- * Returns high-order 32-bits representing the seconds of this NTP
timestamp.
- *
- * @return seconds represented by this NTP timestamp.
- */
- public long getSeconds()
- {
- return (ntpTime >>> 32) & 0xffffffffL;
- }
-
- /**
- * Converts NTP timestamp to Java standard time.
- *
- * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
- * represented by this NTP timestamp value.
- */
- public long getTime()
- {
- return getTime(ntpTime);
- }
-
- /**
- * Computes a hashcode for this Timestamp. The result is the exclusive
- * OR of the two halves of the primitive <code>long</code> value
- * represented by this <code>TimeStamp</code> object. That is, the hashcode
- * is the value of the expression:
- * <blockquote><pre>
- * {@code (int)(this.ntpValue()^(this.ntpValue() >>> 32))}
- * </pre></blockquote>
- *
- * @return a hash code value for this object.
- */
- @Override
- public int hashCode()
- {
- return (int) (ntpTime ^ (ntpTime >>> 32));
- }
-
- /**
- * Returns the value of this Timestamp as a long value.
- *
- * @return the 64-bit long value represented by this object.
- */
- public long ntpValue()
- {
- return ntpTime;
- }
-
- /**
- * Converts this <code>TimeStamp</code> object to a <code>String</code>
- * of the form:
- * <blockquote><pre>
- * EEE, MMM dd yyyy HH:mm:ss.SSS</pre></blockquote>
- * See java.text.SimpleDataFormat for code descriptions.
- *
- * @return a string representation of this date.
- */
- public String toDateString()
- {
- if (simpleFormatter == null) {
- simpleFormatter = new SimpleDateFormat(NTP_DATE_FORMAT, Locale.US);
- simpleFormatter.setTimeZone(TimeZone.getDefault());
- }
- final Date ntpDate = getDate();
- return simpleFormatter.format(ntpDate);
- }
-
- /**
- * Converts this <code>TimeStamp</code> object to a <code>String</code>.
- * The NTP timestamp 64-bit long value is represented as hex string with
- * seconds separated by fractional seconds by a decimal point;
- * e.g. c1a089bd.fc904f6d == Tue, Dec 10 2002 10:41:49.986
- *
- * @return NTP timestamp 64-bit long value as hex string with seconds
- * separated by fractional seconds.
- */
- @Override
- public String toString()
- {
- return toString(ntpTime);
- }
-
- /**
- * Converts this <code>TimeStamp</code> object to a <code>String</code>
- * of the form:
- * <blockquote><pre>
- * EEE, MMM dd yyyy HH:mm:ss.SSS UTC</pre></blockquote>
- * See java.text.SimpleDataFormat for code descriptions.
- *
- * @return a string representation of this date in UTC.
- */
- public String toUTCString()
- {
- if (utcFormatter == null) {
- utcFormatter = new SimpleDateFormat(NTP_DATE_FORMAT + " 'UTC'",
- Locale.US);
- utcFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
- final Date ntpDate = getDate();
- return utcFormatter.format(ntpDate);
- }
-
- /*
- Serialization is unnecessary for this class.
- Reject attempts to do so until such time as the Serializable attribute
can be dropped.
- */
-
- private void writeObject(final java.io.ObjectOutputStream out) throws
IOException
- {
- throw new UnsupportedOperationException("Serialization is not
supported");
- }
-
- private void readObject(final java.io.ObjectInputStream in) throws
IOException, ClassNotFoundException
- {
- throw new UnsupportedOperationException("Serialization is not
supported");
- }
-
-}
+package org.apache.commons.net.ntp;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * TimeStamp class represents the Network Time Protocol (NTP) timestamp
+ * as defined in RFC-1305 and SNTP (RFC-2030). It is represented as a
+ * 64-bit unsigned fixed-point number in seconds relative to 0-hour on
1-January-1900.
+ * The 32-bit low-order bits are the fractional seconds whose precision is
+ * about 200 picoseconds. Assumes overflow date when date passes MAX_LONG
+ * and reverts back to 0 is 2036 and not 1900. Test for most significant
+ * bit: if MSB=0 then 2036 basis is used otherwise 1900 if MSB=1.
+ * <p>
+ * Methods exist to convert NTP timestamps to and from the equivalent Java date
+ * representation, which is the number of milliseconds since the standard base
+ * time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
+ * </p>
+ *
+ * @see java.util.Date
+ */
+public class TimeStamp implements java.io.Serializable, Comparable<TimeStamp>
+{
+ private static final long serialVersionUID = 8139806907588338737L;
+
+ /**
+ * Baseline NTP time if bit-0=0 is 7-Feb-2036 @ 06:28:16 UTC
+ */
+ protected static final long msb0baseTime = 2085978496000L;
+
+ /**
+ * Baseline NTP time if bit-0=1 is 1-Jan-1900 @ 01:00:00 UTC
+ */
+ protected static final long msb1baseTime = -2208988800000L;
+
+ /**
+ * Default NTP date string format. E.g. Fri, Sep 12 2003 21:06:23.860.
+ * See <code>java.text.SimpleDateFormat</code> for code descriptions.
+ */
+ public static final String NTP_DATE_FORMAT = "EEE, MMM dd yyyy
HH:mm:ss.SSS";
+
+ /**
+ * Left-pad 8-character hex string with 0's
+ *
+ * @param buf - StringBuilder which is appended with leading 0's.
+ * @param l - a long.
+ */
+ private static void appendHexString(final StringBuilder buf, final long l)
+ {
+ final String s = Long.toHexString(l);
+ for (int i = s.length(); i < 8; i++) {
+ buf.append('0');
+ }
+ buf.append(s);
+ }
+
+ /**
+ * Convert NTP timestamp hexstring (e.g. "c1a089bd.fc904f6d") to the NTP
+ * 64-bit unsigned fixed-point number.
+ * @param hexString the string to convert
+ *
+ * @return NTP 64-bit timestamp value.
+ * @throws NumberFormatException - if the string does not contain a
parsable timestamp.
+ */
+ protected static long decodeNtpHexString(final String hexString)
+ throws NumberFormatException
+ {
+ if (hexString == null) {
+ throw new NumberFormatException("null");
+ }
+ final int ind = hexString.indexOf('.');
+ if (ind == -1) {
+ if (hexString.isEmpty()) {
+ return 0;
+ }
+ return Long.parseLong(hexString, 16) << 32; // no decimal
+ }
+
+ return Long.parseLong(hexString.substring(0, ind), 16) << 32 |
+ Long.parseLong(hexString.substring(ind + 1), 16);
+ }
+ /**
+ * Constructs a NTP timestamp object and initializes it so that
+ * it represents the time at which it was allocated, measured to the
+ * nearest millisecond.
+ * @return NTP timestamp object set to the current time.
+ * @see System#currentTimeMillis()
+ */
+ public static TimeStamp getCurrentTime()
+ {
+ return getNtpTime(System.currentTimeMillis());
+ }
+
+ // initialization of static time bases
+ /*
+ static {
+ TimeZone utcZone = TimeZone.getTimeZone("UTC");
+ Calendar calendar = Calendar.getInstance(utcZone);
+ calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ msb1baseTime = calendar.getTime().getTime();
+ calendar.set(2036, Calendar.FEBRUARY, 7, 6, 28, 16);
+ calendar.set(Calendar.MILLISECOND, 0);
+ msb0baseTime = calendar.getTime().getTime();
+ }
+ */
+
+ /**
+ * Helper method to convert Java time to NTP timestamp object.
+ * Note that Java time (milliseconds) by definition has less precision
+ * then NTP time (picoseconds) so converting Ntptime to Javatime and back
+ * to Ntptime loses precision. For example, Tue, Dec 17 2002 09:07:24.810
+ * is represented by a single Java-based time value of f22cd1fc8a, but its
+ * NTP equivalent are all values from c1a9ae1c.cf5c28f5 to
c1a9ae1c.cf9db22c.
+ * @param dateMillis the milliseconds since January 1, 1970, 00:00:00
GMT.
+ * @return NTP timestamp object at the specified date.
+ */
+ public static TimeStamp getNtpTime(final long dateMillis)
+ {
+ return new TimeStamp(toNtpTime(dateMillis));
+ }
+
+ /**
+ * Converts 64-bit NTP timestamp to Java standard time.
+ *
+ * Note that java time (milliseconds) by definition has less precision
+ * then NTP time (picoseconds) so converting NTP timestamp to java time
and back
+ * to NTP timestamp loses precision. For example, Tue, Dec 17 2002
09:07:24.810 EST
+ * is represented by a single Java-based time value of f22cd1fc8a, but its
+ * NTP equivalent are all values ranging from c1a9ae1c.cf5c28f5 to
c1a9ae1c.cf9db22c.
+ *
+ * @param ntpTimeValue the input time
+ * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
+ * represented by this NTP timestamp value.
+ */
+ public static long getTime(final long ntpTimeValue)
+ {
+ final long seconds = (ntpTimeValue >>> 32) & 0xffffffffL; //
high-order 32-bits
+ long fraction = ntpTimeValue & 0xffffffffL; // low-order
32-bits
+
+ // Use round-off on fractional part to preserve going to lower
precision
+ fraction = Math.round(1000D * fraction / 0x100000000L);
+
+ /*
+ * If the most significant bit (MSB) on the seconds field is set we use
+ * a different time base. The following text is a quote from RFC-2030
(SNTP v4):
+ *
+ * If bit 0 is set, the UTC time is in the range 1968-2036 and UTC
time
+ * is reckoned from 0h 0m 0s UTC on 1 January 1900. If bit 0 is not
set,
+ * the time is in the range 2036-2104 and UTC time is reckoned from
+ * 6h 28m 16s UTC on 7 February 2036.
+ */
+ final long msb = seconds & 0x80000000L;
+ if (msb == 0) {
+ // use base: 7-Feb-2036 @ 06:28:16 UTC
+ return msb0baseTime + (seconds * 1000) + fraction;
+ }
+ // use base: 1-Jan-1900 @ 01:00:00 UTC
+ return msb1baseTime + (seconds * 1000) + fraction;
+ }
+
+ /**
+ * Parses the string argument as a NTP hexidecimal timestamp
representation string
+ * (e.g. "c1a089bd.fc904f6d").
+ *
+ * @param s - hexstring.
+ * @return the Timestamp represented by the argument in hexidecimal.
+ * @throws NumberFormatException - if the string does not contain a
parsable timestamp.
+ */
+ public static TimeStamp parseNtpString(final String s)
+ throws NumberFormatException
+ {
+ return new TimeStamp(decodeNtpHexString(s));
+ }
+
+ /**
+ * Converts Java time to 64-bit NTP time representation.
+ *
+ * @param millis Java time
+ * @return NTP timestamp representation of Java time value.
+ */
+ protected static long toNtpTime(final long millis)
+ {
+ final boolean useBase1 = millis < msb0baseTime; // time < Feb-2036
+ final long baseTimeMillis;
+ if (useBase1) {
+ baseTimeMillis = millis - msb1baseTime; // dates <= Feb-2036
+ } else {
+ // if base0 needed for dates >= Feb-2036
+ baseTimeMillis = millis - msb0baseTime;
+ }
+
+ long seconds = baseTimeMillis / 1000;
+ final long fraction = ((baseTimeMillis % 1000) * 0x100000000L) / 1000;
+
+ if (useBase1) {
+ seconds |= 0x80000000L; // set high-order bit if msb1baseTime 1900
used
+ }
+
+ return seconds << 32 | fraction;
+ }
+
+ /**
+ * Converts 64-bit NTP timestamp value to a <code>String</code>.
+ * The NTP timestamp value is represented as hex string with
+ * seconds separated by fractional seconds by a decimal point;
+ * e.g. c1a089bd.fc904f6d == Tue, Dec 10 2002 10:41:49.986
+ * @param ntpTime the 64 bit timestamp
+ *
+ * @return NTP timestamp 64-bit long value as hex string with seconds
+ * separated by fractional seconds.
+ */
+ public static String toString(final long ntpTime)
+ {
+ final StringBuilder buf = new StringBuilder();
+ // high-order second bits (32..63) as hexstring
+ appendHexString(buf, (ntpTime >>> 32) & 0xffffffffL);
+
+ // low-order fractional seconds bits (0..31) as hexstring
+ buf.append('.');
+ appendHexString(buf, ntpTime & 0xffffffffL);
+
+ return buf.toString();
+ }
+
+ /**
+ * NTP timestamp value: 64-bit unsigned fixed-point number as defined in
RFC-1305
+ * with high-order 32 bits the seconds field and the low-order 32-bits the
+ * fractional field.
+ */
+ private final long ntpTime;
+
+ private DateFormat simpleFormatter;
+
+ private DateFormat utcFormatter;
+
+ /**
+ * Constructs a newly allocated NTP timestamp object
+ * that represents the Java Date argument.
+ *
+ * @param d - the Date to be represented by the Timestamp object.
+ */
+ public TimeStamp(final Date d)
+ {
+ ntpTime = d == null ? 0 : toNtpTime(d.getTime());
+ }
+
+ /**
+ * Constructs a newly allocated NTP timestamp object
+ * that represents the native 64-bit long argument.
+ * @param ntpTime the timestamp
+ */
+ public TimeStamp(final long ntpTime)
+ {
+ this.ntpTime = ntpTime;
+ }
+
+ /**
+ * Constructs a newly allocated NTP timestamp object
+ * that represents the value represented by the string
+ * in hexdecimal form (e.g. "c1a089bd.fc904f6d").
+ * @param hexStamp the hex timestamp
+ *
+ * @throws NumberFormatException - if the string does not contain a
parsable timestamp.
+ */
+ public TimeStamp(final String hexStamp) throws NumberFormatException
+ {
+ ntpTime = decodeNtpHexString(hexStamp);
+ }
+
+ /**
+ * Compares two Timestamps numerically.
+ *
+ * @param anotherTimeStamp - the <code>TimeStamp</code> to be compared.
+ * @return the value <code>0</code> if the argument TimeStamp is equal to
+ * this TimeStamp; a value less than <code>0</code> if this
TimeStamp
+ * is numerically less than the TimeStamp argument; and a
+ * value greater than <code>0</code> if this TimeStamp is
+ * numerically greater than the TimeStamp argument
+ * (signed comparison).
+ */
+ @Override
+ public int compareTo(final TimeStamp anotherTimeStamp)
+ {
+ final long thisVal = this.ntpTime;
+ final long anotherVal = anotherTimeStamp.ntpTime;
+ return (Long.compare(thisVal, anotherVal));
+ }
+
+ /**
+ * Compares this object against the specified object.
+ * The result is <code>true</code> if and only if the argument is
+ * not <code>null</code> and is a <code>Long</code> object that
+ * contains the same <code>long</code> value as this object.
+ *
+ * @param obj the object to compare with.
+ * @return <code>true</code> if the objects are the same;
+ * <code>false</code> otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof TimeStamp) {
+ return ntpTime == ((TimeStamp) obj).ntpValue();
+ }
+ return false;
+ }
+
+ /**
+ * Converts NTP timestamp to Java Date object.
+ *
+ * @return NTP Timestamp in Java Date
+ */
+ public Date getDate()
+ {
+ return new Date(getTime(ntpTime));
+ }
+
+ /**
+ * Returns low-order 32-bits representing the fractional seconds.
+ *
+ * @return fractional seconds represented by this NTP timestamp.
+ */
+ public long getFraction()
+ {
+ return ntpTime & 0xffffffffL;
+ }
+
+ /**
+ * Returns high-order 32-bits representing the seconds of this NTP
timestamp.
+ *
+ * @return seconds represented by this NTP timestamp.
+ */
+ public long getSeconds()
+ {
+ return (ntpTime >>> 32) & 0xffffffffL;
+ }
+
+ /**
+ * Converts NTP timestamp to Java standard time.
+ *
+ * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
+ * represented by this NTP timestamp value.
+ */
+ public long getTime()
+ {
+ return getTime(ntpTime);
+ }
+
+ /**
+ * Computes a hashcode for this Timestamp. The result is the exclusive
+ * OR of the two halves of the primitive <code>long</code> value
+ * represented by this <code>TimeStamp</code> object. That is, the hashcode
+ * is the value of the expression:
+ * <blockquote><pre>
+ * {@code (int)(this.ntpValue()^(this.ntpValue() >>> 32))}
+ * </pre></blockquote>
+ *
+ * @return a hash code value for this object.
+ */
+ @Override
+ public int hashCode()
+ {
+ return (int) (ntpTime ^ (ntpTime >>> 32));
+ }
+
+ /**
+ * Returns the value of this Timestamp as a long value.
+ *
+ * @return the 64-bit long value represented by this object.
+ */
+ public long ntpValue()
+ {
+ return ntpTime;
+ }
+
+ /**
+ * Converts this <code>TimeStamp</code> object to a <code>String</code>
+ * of the form:
+ * <blockquote><pre>
+ * EEE, MMM dd yyyy HH:mm:ss.SSS</pre></blockquote>
+ * See java.text.SimpleDataFormat for code descriptions.
+ *
+ * @return a string representation of this date.
+ */
+ public String toDateString()
+ {
+ if (simpleFormatter == null) {
+ simpleFormatter = new SimpleDateFormat(NTP_DATE_FORMAT, Locale.US);
+ simpleFormatter.setTimeZone(TimeZone.getDefault());
+ }
+ final Date ntpDate = getDate();
+ return simpleFormatter.format(ntpDate);
+ }
+
+ /**
+ * Converts this <code>TimeStamp</code> object to a <code>String</code>.
+ * The NTP timestamp 64-bit long value is represented as hex string with
+ * seconds separated by fractional seconds by a decimal point;
+ * e.g. c1a089bd.fc904f6d == Tue, Dec 10 2002 10:41:49.986
+ *
+ * @return NTP timestamp 64-bit long value as hex string with seconds
+ * separated by fractional seconds.
+ */
+ @Override
+ public String toString()
+ {
+ return toString(ntpTime);
+ }
+
+ /**
+ * Converts this <code>TimeStamp</code> object to a <code>String</code>
+ * of the form:
+ * <blockquote><pre>
+ * EEE, MMM dd yyyy HH:mm:ss.SSS UTC</pre></blockquote>
+ * See java.text.SimpleDataFormat for code descriptions.
+ *
+ * @return a string representation of this date in UTC.
+ */
+ public String toUTCString()
+ {
+ if (utcFormatter == null) {
+ utcFormatter = new SimpleDateFormat(NTP_DATE_FORMAT + " 'UTC'",
+ Locale.US);
+ utcFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+ final Date ntpDate = getDate();
+ return utcFormatter.format(ntpDate);
+ }
+
+ /*
+ Serialization is unnecessary for this class.
+ Reject attempts to do so until such time as the Serializable attribute
can be dropped.
+ */
+
+ private void writeObject(final java.io.ObjectOutputStream out) throws
IOException
+ {
+ throw new UnsupportedOperationException("Serialization is not
supported");
+ }
+
+ private void readObject(final java.io.ObjectInputStream in) throws
IOException, ClassNotFoundException
+ {
+ throw new UnsupportedOperationException("Serialization is not
supported");
+ }
+
+}