/*
|
* CDDL HEADER START
|
*
|
* The contents of this file are subject to the terms of the
|
* Common Development and Distribution License, Version 1.0 only
|
* (the "License"). You may not use this file except in compliance
|
* with the License.
|
*
|
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
|
* or http://forgerock.org/license/CDDLv1.0.html.
|
* See the License for the specific language governing permissions
|
* and limitations under the License.
|
*
|
* When distributing Covered Code, include this CDDL HEADER in each
|
* file and include the License file at legal-notices/CDDLv1_0.txt.
|
* If applicable, add the following below this CDDL HEADER, with the
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
* information:
|
* Portions Copyright [yyyy] [name of copyright owner]
|
*
|
* CDDL HEADER END
|
*
|
*
|
* Copyright 2008 Sun Microsystems, Inc.
|
* Portions Copyright 2014-2015 ForgeRock AS
|
*/
|
package org.opends.server.protocols.internal;
|
|
|
|
import java.io.IOException;
|
import java.net.InetAddress;
|
import java.net.InetSocketAddress;
|
import java.net.Socket;
|
import java.net.SocketAddress;
|
import java.nio.channels.SocketChannel;
|
|
import org.opends.server.types.DN;
|
|
|
|
/**
|
* This class provides an implementation of a {@code java.net.Socket}
|
* object that can be used to facilitate internal communication with
|
* the Directory Server through third-party LDAP APIs that provide the
|
* ability to use a custom socket factory when creating connections.
|
* Whenever data is written over the socket, it is decoded as LDAP
|
* communication and converted to an appropriate internal operation,
|
* which the server then processes and converts the response back to
|
* an LDAP encoding.
|
* <BR><BR>
|
* Note that this implementation only supports those operations which
|
* can be performed in the Directory Server via internal operations.
|
* This includes add, compare, delete, modify, modify DN, and search
|
* operations, and some types of extended operations. Special support
|
* has been added for simple bind operations to function properly, but
|
* SASL binds are not supported. Abandon and unbind operations are
|
* not supported, nor are the cancel or StartTLS extended operations.
|
* Only clear-text LDAP communication may be used.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
|
mayInstantiate=true,
|
mayExtend=false,
|
mayInvoke=true)
|
public final class InternalLDAPSocket
|
extends Socket
|
{
|
/** Indicates whether this socket is closed. */
|
private boolean closed;
|
|
/** The value that the client has requested for SO_KEEPALIVE. */
|
private boolean keepAlive;
|
|
/** The value that the client has requested for OOBINLINE. */
|
private boolean oobInline;
|
|
/** The value that the client has requested for SO_REUSEADDR. */
|
private boolean reuseAddress;
|
|
/** The value that the client has requested for TCP_NODELAY. */
|
private boolean tcpNoDelay;
|
|
/** The value that the client has requested for SO_LINGER. */
|
private int lingerDuration;
|
|
/** The value that the client has requested for SO_RCVBUF. */
|
private int receiveBufferSize;
|
|
/** The value that the client has requested for SO_SNDBUF. */
|
private int sendBufferSize;
|
|
/** The value that the client has requested for SO_TIMEOUT. */
|
private int timeout;
|
|
/** The value that the client has requested for the traffic class. */
|
private int trafficClass;
|
|
/**
|
* The internal client connection used to perform the internal
|
* operations. It will be null until it is first used.
|
*/
|
private InternalClientConnection conn;
|
|
/** The input stream associated with this internal LDAP socket. */
|
private InternalLDAPInputStream inputStream;
|
|
/** The output stream associated with this internal LDAP socket. */
|
private InternalLDAPOutputStream outputStream;
|
|
|
|
/**
|
* Creates a new internal LDAP socket.
|
*/
|
public InternalLDAPSocket()
|
{
|
closed = false;
|
keepAlive = true;
|
oobInline = true;
|
reuseAddress = true;
|
tcpNoDelay = true;
|
lingerDuration = 0;
|
receiveBufferSize = 1024;
|
sendBufferSize = 1024;
|
timeout = 0;
|
trafficClass = 0;
|
conn = null;
|
inputStream = new InternalLDAPInputStream(this);
|
outputStream = new InternalLDAPOutputStream(this);
|
}
|
|
|
|
/**
|
* Retrieves the internal client connection used to back this
|
* internal LDAP socket.
|
*
|
* @return The internal client connection used to back this
|
* internal LDAP socket.
|
*
|
* @throws IOException If there is a problem obtaining the
|
* connection.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.PRIVATE,
|
mayInstantiate=false,
|
mayExtend=false,
|
mayInvoke=false)
|
synchronized InternalClientConnection getConnection()
|
throws IOException
|
{
|
if (conn == null)
|
{
|
try
|
{
|
conn = new InternalClientConnection(DN.rootDN());
|
}
|
catch (Exception e)
|
{
|
// This should never happen.
|
throw new IOException(e.getMessage());
|
}
|
}
|
|
return conn;
|
}
|
|
|
|
/**
|
* Sets the internal client connection used to back this internal
|
* LDAP socket.
|
*
|
* @param conn The internal client connection used to back this
|
* internal LDAP socket.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.PRIVATE,
|
mayInstantiate=false,
|
mayExtend=false,
|
mayInvoke=false)
|
synchronized void setConnection(InternalClientConnection conn)
|
{
|
this.conn = conn;
|
}
|
|
|
|
/**
|
* Binds the socket to a local address. This does nothing, since
|
* there is no actual network communication performed by this
|
* socket implementation.
|
*
|
* @param bindpoint The socket address to which to bind.
|
*/
|
@Override
|
public void bind(SocketAddress bindpoint)
|
{
|
// No implementation is required.
|
}
|
|
|
|
/**
|
* Closes this socket. This will make it unavailable for use.
|
*/
|
@Override
|
public synchronized void close()
|
{
|
try
|
{
|
inputStream.closeInternal();
|
} catch (Exception e) {}
|
|
try
|
{
|
outputStream.closeInternal();
|
} catch (Exception e) {}
|
|
closed = true;
|
inputStream = null;
|
outputStream = null;
|
}
|
|
|
|
/**
|
* Connects this socket to the specified remote endpoint. This will
|
* make the connection available again if it has been previously
|
* closed. The provided address is irrelevant, as it will always be
|
* an internal connection.
|
*
|
* @param endpoint The address of the remote endpoint.
|
*/
|
@Override
|
public synchronized void connect(SocketAddress endpoint)
|
{
|
closed = false;
|
inputStream = new InternalLDAPInputStream(this);
|
outputStream = new InternalLDAPOutputStream(this);
|
}
|
|
|
|
/**
|
* Connects this socket to the specified remote endpoint. This does
|
* nothing, since there is no actual network communication performed
|
* by this socket implementation.
|
*
|
* @param endpoint The address of the remote endpoint.
|
* @param timeout The maximum length of time in milliseconds to
|
* wait for the connection to be established.
|
*/
|
@Override
|
public void connect(SocketAddress endpoint, int timeout)
|
{
|
closed = false;
|
inputStream = new InternalLDAPInputStream(this);
|
outputStream = new InternalLDAPOutputStream(this);
|
}
|
|
|
|
/**
|
* Retrieves the socket channel associated with this socket. This
|
* method always returns {@code null} since this implementation does
|
* not support use with NIO channels.
|
*
|
* @return {@code null} because this implementation does not
|
* support use with NIO channels.
|
*/
|
@Override
|
public SocketChannel getChannel()
|
{
|
// This implementation does not support use with NIO channels.
|
return null;
|
}
|
|
|
|
/**
|
* Retrieves the address to which this socket is connected. The
|
* address returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The address to which this socket is connected.
|
*/
|
@Override
|
public InetAddress getInetAddress()
|
{
|
try
|
{
|
return InetAddress.getLocalHost();
|
}
|
catch (Exception e)
|
{
|
// This should not happen.
|
return null;
|
}
|
}
|
|
|
|
/**
|
* Retrieves the input stream for this socket.
|
*
|
* @return The input stream for this socket.
|
*/
|
@Override
|
public InternalLDAPInputStream getInputStream()
|
{
|
return inputStream;
|
}
|
|
|
|
/**
|
* Indicates whether SO_KEEPALIVE is enabled. This implementation
|
* will return {@code true} by default, but if its value is changed
|
* using {@code setKeepalive} then that value will be returned.
|
* This setting has no effect in this socket implementation.
|
*
|
* @return {@code true} if SO_KEEPALIVE is enabled, or
|
* {@code false} if not.
|
*/
|
@Override
|
public boolean getKeepAlive()
|
{
|
return keepAlive;
|
}
|
|
|
|
/**
|
* Retrieves the local address to which this socket is bound. The
|
* address returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The local address to which this socket is bound.
|
*/
|
@Override
|
public InetAddress getLocalAddress()
|
{
|
try
|
{
|
return InetAddress.getLocalHost();
|
}
|
catch (Exception e)
|
{
|
// This should not happen.
|
return null;
|
}
|
}
|
|
|
|
/**
|
* Retrieves the local port to which this socket is bound. The
|
* value returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The local port to which this socket is bound.
|
*/
|
@Override
|
public int getLocalPort()
|
{
|
return 389;
|
}
|
|
|
|
/**
|
* Retrieves the local socket address to which this socket is bound.
|
* The value returned is meaningless, since there is no actual
|
* network communication performed by this socket implementation.
|
*
|
* @return The local socket address to which this socket is bound.
|
*/
|
@Override
|
public SocketAddress getLocalSocketAddress()
|
{
|
try
|
{
|
return new InetSocketAddress(getLocalAddress(), getLocalPort());
|
}
|
catch (Exception e)
|
{
|
// This should not happen.
|
return null;
|
}
|
}
|
|
|
|
/**
|
* Indicates whether OOBINLINE is enabled. This implementation will
|
* return {@code true} by default, but if its value is changed
|
* using {@code setOOBInline} then that value will be returned.
|
* This setting has no effect in this socket implementation.
|
*
|
* @return {@code true} if OOBINLINE is enabled, or {@code false}
|
* if it is not.
|
*/
|
@Override
|
public boolean getOOBInline()
|
{
|
return oobInline;
|
}
|
|
|
|
/**
|
* Retrieves the output stream for this socket.
|
*
|
* @return The output stream for this socket.
|
*/
|
@Override
|
public InternalLDAPOutputStream getOutputStream()
|
{
|
return outputStream;
|
}
|
|
|
|
/**
|
* Retrieves the remote port to which this socket is connected. The
|
* value returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The remote port to which this socket is connected.
|
*/
|
@Override
|
public int getPort()
|
{
|
return 389;
|
}
|
|
|
|
/**
|
* Retrieves the value of the SO_RCVBUF option for this socket. The
|
* value returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The value of the SO_RCVBUF option for this socket.
|
*/
|
@Override
|
public int getReceiveBufferSize()
|
{
|
return receiveBufferSize;
|
}
|
|
|
|
/**
|
* Retrieves the remote socket address to which this socket is
|
* connected. The value returned is meaningless, since there is no
|
* actual network communication performed by this socket
|
* implementation.
|
*
|
* @return The remote socket address to which this socket is
|
* connected.
|
*/
|
@Override
|
public SocketAddress getRemoteSocketAddress()
|
{
|
try
|
{
|
return new InetSocketAddress(getInetAddress(), getPort());
|
}
|
catch (Exception e)
|
{
|
// This should not happen.
|
return null;
|
}
|
}
|
|
|
|
/**
|
* Indicates whether SO_REUSEADDR is enabled. This implementation
|
* will return {@code true} by default, but if its value is changed
|
* using {@code setReuseAddress} then that value will be returned.
|
* This setting has no effect in this socket implementation.
|
*
|
* @return {@code true} if SO_REUSEADDR is enabled, or
|
* {@code false} if it is not.
|
*/
|
@Override
|
public boolean getReuseAddress()
|
{
|
return reuseAddress;
|
}
|
|
|
|
/**
|
* Retrieves the value of the SO_SNDBUF option for this socket. The
|
* value returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The value of the SO_SNDBUF option for this socket.
|
*/
|
@Override
|
public int getSendBufferSize()
|
{
|
return sendBufferSize;
|
}
|
|
|
|
/**
|
* Retrieves the value of the SO_LINGER option for this socket. The
|
* value returned is meaningless, since there is no actual network
|
* communication performed by this socket implementation.
|
*
|
* @return The value of the SO_LINGER option for this socket.
|
*/
|
@Override
|
public int getSoLinger()
|
{
|
return lingerDuration;
|
}
|
|
|
|
/**
|
* Retrieves the value of the SO_TIMEOUT option for this socket.
|
* The value returned is meaningless, since there is no actual
|
* network communication performed by this socket implementation.
|
*
|
* @return The value of the SO_TIMEOUT option for this socket.
|
*/
|
@Override
|
public int getSoTimeout()
|
{
|
return timeout;
|
}
|
|
|
|
/**
|
* Indicates whether TCP_NODELAY is enabled. This implementation
|
* will return {@code true} by default, but if its value is changed
|
* using {@code setTcpNoDelay} then that value will be returned.
|
* This setting has no effect in this socket implementation.
|
*
|
* @return {@code true} if TCP_NODELAY is enabled, or {@code false}
|
* if it is not.
|
*/
|
@Override
|
public boolean getTcpNoDelay()
|
{
|
return tcpNoDelay;
|
}
|
|
|
|
/**
|
* Retrieves the traffic class for this socket. The value returned
|
* will be meaningless, since there is no actual network
|
* communication performed by this socket.
|
*
|
* @return The traffic class for this socket.
|
*/
|
@Override
|
public int getTrafficClass()
|
{
|
return trafficClass;
|
}
|
|
|
|
/**
|
* Indicates whether this socket is bound to a local address. This
|
* method will always return {@code true} to indicate that it is
|
* bound.
|
*
|
* @return {@code true} to indicate that the socket is bound to a
|
* local address.
|
*/
|
@Override
|
public boolean isBound()
|
{
|
return true;
|
}
|
|
|
|
/**
|
* Indicates whether this socket is closed. This method will always
|
* return {@code false} to indicate that it is not closed.
|
*
|
* @return {@code false} to indicate that the socket is not closed.
|
*/
|
@Override
|
public boolean isClosed()
|
{
|
return closed;
|
}
|
|
|
|
/**
|
* Indicates whether this socket is connected to both local and
|
* remote endpoints. This method will always return {@code true} to
|
* indicate that it is connected.
|
*
|
* @return {@code true} to indicate that the socket is connected.
|
*/
|
@Override
|
public boolean isConnected()
|
{
|
return !closed;
|
}
|
|
|
|
/**
|
* Indicates whether the input side of this socket has been closed.
|
* This method will always return {@code false} to indicate that it
|
* is not closed.
|
*
|
* @return {@code false} to indicate that the input side of this
|
* socket is not closed.
|
*/
|
@Override
|
public boolean isInputShutdown()
|
{
|
return closed;
|
}
|
|
|
|
/**
|
* Indicates whether the output side of this socket has been closed.
|
* This method will always return {@code false} to indicate that it
|
* is not closed.
|
*
|
* @return {@code false} to indicate that the output side of this
|
* socket is not closed.
|
*/
|
@Override
|
public boolean isOutputShutdown()
|
{
|
return closed;
|
}
|
|
|
|
/**
|
* Sends a single byte of urgent data over this socket.
|
*
|
* @param data The data to be sent.
|
*
|
* @throws IOException If a problem occurs while trying to write
|
* the provided data over this socket.
|
*/
|
@Override
|
public void sendUrgentData(int data)
|
throws IOException
|
{
|
getOutputStream().write(data);
|
}
|
|
|
|
/**
|
* Sets the value of SO_KEEPALIVE for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param on The value to use for the SO_KEEPALIVE option.
|
*/
|
@Override
|
public void setKeepAlive(boolean on)
|
{
|
keepAlive = on;
|
}
|
|
|
|
/**
|
* Sets the value of OOBINLINE for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param on The value to use for the OOBINLINE option.
|
*/
|
@Override
|
public void setOOBInline(boolean on)
|
{
|
oobInline = on;
|
}
|
|
|
|
/**
|
* Sets the provided performance preferences for this socket. This
|
* will not affect anything, since there is no actual network
|
* communication performed by this socket.
|
*
|
* @param connectionTime An {@code int} expressing the relative
|
* importance of a short connection time.
|
* @param latency An {@code int} expressing the relative
|
* importance of low latency.
|
* @param bandwidth An {@code int} expressing the relative
|
* importance of high bandwidth.
|
*/
|
@Override
|
public void setPerformancePreferences(int connectionTime,
|
int latency, int bandwidth)
|
{
|
// No implementation is required.
|
}
|
|
|
|
/**
|
* Sets the value of SO_RCVBUF for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param size The value to use for the SO_RCVBUF option.
|
*/
|
@Override
|
public void setReceiveBufferSize(int size)
|
{
|
receiveBufferSize = size;
|
}
|
|
|
|
/**
|
* Sets the value of SO_REUSEADDR for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param on The value to use for the SO_REUSEADDR option.
|
*/
|
@Override
|
public void setReuseAddress(boolean on)
|
{
|
reuseAddress = on;
|
}
|
|
|
|
/**
|
* Sets the value of SO_SNDBUF for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param size The value to use for the SO_SNDBUF option.
|
*/
|
@Override
|
public void setSendBufferSize(int size)
|
{
|
sendBufferSize = size;
|
}
|
|
|
|
/**
|
* Sets the value of SO_LINGER for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param on Indicates whether to enable the linger option.
|
* @param linger The length of time in milliseconds to allow the
|
* connection to linger.
|
*/
|
@Override
|
public void setSoLinger(boolean on, int linger)
|
{
|
lingerDuration = linger;
|
}
|
|
|
|
/**
|
* Sets the value of SO_TIMEOUT for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param timeout The value to use for the SO_TIMEOUT option.
|
*/
|
@Override
|
public void setSoTimeout(int timeout)
|
{
|
this.timeout = timeout;
|
}
|
|
|
|
/**
|
* Sets the value of TCP_NODELAY for this socket. This will not
|
* affect anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param on The value to use for the TCP_NODELAY option.
|
*/
|
@Override
|
public void setTcpNoDelay(boolean on)
|
{
|
tcpNoDelay = on;
|
}
|
|
|
|
/**
|
* Sets the traffic class for this socket. This will not affect
|
* anything, since there is no actual network communication
|
* performed by this socket.
|
*
|
* @param tc The value to use for the traffic class.
|
*/
|
@Override
|
public void setTrafficClass(int tc)
|
{
|
trafficClass = tc;
|
}
|
|
|
|
/**
|
* Shuts down the input side of this socket. This will have the
|
* effect of closing the entire socket.
|
*/
|
@Override
|
public void shutdownInput()
|
{
|
close();
|
}
|
|
|
|
/**
|
* Shuts down the output side of this socket. This will have the
|
* effect of closing the entire socket.
|
*/
|
@Override
|
public void shutdownOutput()
|
{
|
close();
|
}
|
|
|
|
/**
|
* Retrieves a string representation of this internal LDAP socket.
|
*
|
* @return A string representation of this internal LDAP socket.
|
*/
|
@Override
|
public String toString()
|
{
|
return "InternalLDAPSocket";
|
}
|
}
|