fr.dyade.aaa.agent.StreamNetwork Maven / Gradle / Ivy
Show all versions of a3-rt Show documentation
/*
* Copyright (C) 2001 - 2023 ScalAgent Distributed Technologies
* Copyright (C) 2004 - France Telecom R&D
* Copyright (C) 1996 - 2000 BULL
* Copyright (C) 1996 - 2000 INRIA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Initial developer(s): Dyade
* Contributor(s): ScalAgent Distributed Technologies
*/
package fr.dyade.aaa.agent;
import java.io.IOException;
import java.net.BindException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import org.objectweb.util.monolog.api.BasicLevel;
import fr.dyade.aaa.common.net.ServerSocketFactory;
import fr.dyade.aaa.common.net.ServerSocketFactory13;
import fr.dyade.aaa.common.net.SocketAddress;
import fr.dyade.aaa.common.net.SocketFactory;
/**
* StreamNetwork
is a base implementation of Network
* class for TCP sockets.
*/
public abstract class StreamNetwork extends Network {
/**
* Numbers of attempt to bind the server's socket before aborting,
* default value is 3.
* This value can be adjusted for all network components by setting
* CnxRetry
global property or for a particular network
* by setting <DomainName>.CnxRetry
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
int CnxRetry = 3;
/**
* The maximum queue length for incoming connection indications,
* default value is 5.
* This value can be adjusted for all network components by setting
* backlog
global property or for a particular network
* by setting <DomainName>.backlog
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
int backlog = 5;
/**
* Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm),
* default value is false.
* This value can be adjusted for all network components by setting
* TcpNoDelay
global property or for a particular network
* by setting <DomainName>.TcpNoDelay
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
boolean TcpNoDelay = false;
/**
* Enable SO_LINGER with the specified linger time in seconds, if the
* value is less than 0 then it disables SO_LINGER. Default value is -1.
* This value can be adjusted for all network components by setting
* SoLinger
global property or for a particular network
* by setting <DomainName>.SoLinger
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
int SoLinger = -1;
/**
* Enable/disable SO_TIMEOUT with the specified timeout in milliseconds.
* The timeout must be > 0. A timeout of zero is interpreted as an infinite
* timeout. Default value is 0.
* This value can be adjusted for all network components by setting
* SoTimeout
global property or for a particular network
* by setting <DomainName>.SoTimeout
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
int SoTimeout = 0;
/**
* Defines in milliseconds the timeout used during socket connection.
* The timeout must be > 0. A timeout of zero is interpreted as an infinite
* timeout. Default value is 0.
* This value can be adjusted for all network components by setting
* ConnectTimeout
global property or for a particular network
* by setting <DomainName>.ConnectTimeout
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
int ConnectTimeout = 0;
/**
* The local address the listen ServerSocket is bound to. A null address
* will assign the wildcard address. Default value is null.
* This value can be adjusted for all network components by setting
* InLocalAddress
global property or for a particular network
* by setting <DomainName>.InLocalAddress
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
InetAddress inLocalAddr = null;
/**
* The local port the sockets are bound to. A valid port value is between 0
* and 65535. A port number of zero will let the system pick up an ephemeral
* port in a bind operation. Default value is 0.
* This value can be adjusted for all network components by setting
* OutLocalPort
global property or for a particular network
* by setting <DomainName>.OutLocalPort
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
int outLocalPort = 0;
/**
* The local address the sockets are bound to. A null address will assign
* the wildcard address. Default value is null.
* This value can be adjusted for all network components by setting
* OutLocalAddress
global property or for a particular network
* by setting <DomainName>.OutLocalAddress
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
InetAddress outLocalAddr = null;
/**
* Allows to define a specific factory for ServerSocket in order to by-pass
* compatibility problem between JDK version.
* Currently there is two factories, The default factory for JDK
* since 1.4, and {@link ServerSocketFactory13} for JDK prior
* to 1.4.
* This value can be adjusted for all network components by setting
* ServerSocketFactory
global property or for a particular
* network by setting <DomainName>.ServerSocketFactory
* specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
ServerSocketFactory serverSocketFactory = null;
/**
* Allows to define a specific factory for Socket in order to by-pass
* compatibility problem between JDK version.
* Currently there is two factories, The default factory one for JDK
* since 1.4, and SocketFactory13 for JDK prior to 1.4.
* This value can be adjusted for all network components by setting
* SocketFactory
global property or for a particular network
* by setting <DomainName>.SocketFactory
specific property.
*
* Theses properties can be fixed either from java
launching
* command, or in a3servers.xml
configuration file.
*/
SocketFactory socketFactory = null;
/** Creates a new Network component */
protected StreamNetwork() {
super();
}
/**
* Initializes a new StreamNetwork component.
*
* @param name The domain name.
* @param port The listen port.
* @param servers The list of servers directly accessible from this
* network interface.
*
* @see Network
*/
@Override
public void init(String name, int port, short[] servers) throws Exception {
super.init(name, port, servers);
}
/**
* Set the properties of the network.
* Inherited from Network class, can be extended by subclasses.
*/
@Override
public void setProperties() throws Exception {
if (logmon.isLoggable(BasicLevel.DEBUG))
logmon.log(BasicLevel.DEBUG, domain + ", StreamNetwork.setProperties()");
super.setProperties();
CnxRetry = AgentServer.getInteger("CnxRetry", CnxRetry).intValue();
CnxRetry = AgentServer.getInteger(domain + ".CnxRetry", CnxRetry).intValue();
backlog = AgentServer.getInteger("backlog", backlog).intValue();
backlog = AgentServer.getInteger(domain + ".backlog", backlog).intValue();
TcpNoDelay = AgentServer.getBoolean(domain + ".TcpNoDelay");
if (!TcpNoDelay)
TcpNoDelay = AgentServer.getBoolean("TcpNoDelay");
SoLinger = AgentServer.getInteger("SoLinger", SoLinger).intValue();
SoLinger = AgentServer.getInteger(domain + ".SoLinger", SoLinger).intValue();
SoTimeout = AgentServer.getInteger("SoTimeout", SoTimeout).intValue();
SoTimeout = AgentServer.getInteger(domain + ".SoTimeout", SoTimeout).intValue();
ConnectTimeout = AgentServer.getInteger("ConnectTimeout", ConnectTimeout).intValue();
ConnectTimeout = AgentServer.getInteger(domain + ".ConnectTimeout", ConnectTimeout).intValue();
String inLocalAddressStr = null;
inLocalAddressStr = AgentServer.getProperty("InLocalAddress", inLocalAddressStr);
inLocalAddressStr = AgentServer.getProperty(domain + ".InLocalAddress", inLocalAddressStr);
if (inLocalAddressStr != null)
inLocalAddr = InetAddress.getByName(inLocalAddressStr);
String outLocalAddressStr = null;
outLocalAddressStr = AgentServer.getProperty("OutLocalAddress", outLocalAddressStr);
outLocalAddressStr = AgentServer.getProperty(domain + ".OutLocalAddress", outLocalAddressStr);
if (outLocalAddressStr != null)
outLocalAddr = InetAddress.getByName(outLocalAddressStr);
outLocalPort = AgentServer.getInteger("OutLocalPort", outLocalPort).intValue();
outLocalPort = AgentServer.getInteger(domain + ".OutLocalPort", outLocalPort).intValue();
String sfcn = AgentServer.getProperty("SocketFactory", SocketFactory.DefaultFactory);
sfcn = AgentServer.getProperty(domain + ".SocketFactory", sfcn);
socketFactory = SocketFactory.getFactory(sfcn);
String ssfcn = AgentServer.getProperty("ServerSocketFactory", ServerSocketFactory.DefaultFactory);
ssfcn = AgentServer.getProperty(domain + ".ServerSocketFactory", ssfcn);
serverSocketFactory = ServerSocketFactory.getFactory(ssfcn);
if (logmon.isLoggable(BasicLevel.DEBUG)) {
StringBuilder strbuf = new StringBuilder();
strbuf.append(" setProperties(");
strbuf.append("CnxRetry=").append(CnxRetry);
strbuf.append(", backlog=").append(backlog);
strbuf.append(", TcpNoDelay=").append(TcpNoDelay);
strbuf.append(", SoLinger=").append(SoLinger);
strbuf.append(", SoTimeout=").append(SoTimeout);
strbuf.append(", ConnectTimeout=").append(ConnectTimeout);
strbuf.append(", inLocalAddressStr=").append(inLocalAddressStr);
strbuf.append(", outLocalAddressStr=").append(outLocalAddressStr);
strbuf.append(", outLocalPort=").append(outLocalPort);
strbuf.append(", ssfcn=").append(ssfcn);
strbuf.append(", sfcn=").append(sfcn);
strbuf.append(')');
logmon.log(BasicLevel.DEBUG, getName() + strbuf.toString());
}
}
/**
* This method creates and returns a socket connected to a
* specified server. It may be overloaded in subclass, in order
* to create particular subclasses of sockets.
*
* @param server the server descriptor.
* @return a socket connected to a ServerSocket at the specified
* network address and port.
*
* @exception IOException if the connection can't be established
*/
final Socket createSocket(ServerDesc server) throws IOException {
if (server == null)
throw new ConnectException("Cannot connect to null server");
for (Enumeration e = server.getSockAddrs(); e.hasMoreElements();) {
SocketAddress sa = e.nextElement();
if (this.logmon.isLoggable(BasicLevel.DEBUG))
this.logmon.log(BasicLevel.DEBUG,
this.getName() + ", try to connect server#" +
server.getServerId() +
", addr=" + sa.getHostname() +
", port=" + sa.getPort());
try {
Socket socket = createSocket(sa);
if (this.logmon.isLoggable(BasicLevel.DEBUG))
this.logmon.log(BasicLevel.DEBUG, this.getName() + ", connected");
// Memorize the right address for next try.
server.moveToFirst(sa);
return socket;
} catch (IOException exc) {
this.logmon.log(BasicLevel.DEBUG,
this.getName() + ", connection refused, try next element");
continue;
}
}
throw new ConnectException("Cannot connect to server#" + server.getServerId());
}
/**
* This method creates and returns a socket connected to a ServerSocket at
* the specified socket address. If it fails it resets the address in order
* to take in account dynamic DNS.
*
* @param addr the socket address.
* @return a socket connected to a ServerSocket at the specified
* network address and port.
*
* @exception IOException if the connection can't be established
*/
final Socket createSocket(SocketAddress addr) throws IOException {
try {
return createSocket(addr.getAddress(), addr.getPort());
} catch (IOException exc) {
this.logmon.log(BasicLevel.DEBUG,
this.getName() + ", connection refused, reset addr");
addr.resetAddr();
return createSocket(addr.getAddress(), addr.getPort());
}
}
/**
* This method creates and returns a socket connected to a ServerSocket
* at the specified network address and port. It may be overloaded in
* subclass, in order to use particular implementation of sockets.
*
* Due to polymorphism of both factories and sockets, different kinds of
* sockets can be used by the same application code. The sockets returned
* to the application can be subclasses of
* Socket, so that they can directly expose new APIs for features such
* as compression, security, or firewall tunneling.
*
* @param addr the server address.
* @param port the server port.
* @return a socket connected to a ServerSocket at the specified
* network address and port.
*
* @exception IOException if the connection can't be established
*/
Socket createSocket(InetAddress addr, int port) throws IOException {
if (addr == null) throw new UnknownHostException();
return socketFactory.createSocket(addr, port,
outLocalAddr, outLocalPort,
ConnectTimeout);
}
/**
* This method creates and returns a server socket which uses all network
* interfaces on the host, and is bound to the specified port.
*
* @return a server socket bound to the specified port.
*
* @exception IOException for networking errors
*/
final ServerSocket createServerSocket() throws IOException {
for (int i=0; ; i++) {
try {
return createServerSocket(port);
} catch (BindException exc) {
if (i > CnxRetry) throw exc;
try {
Thread.sleep(i * 200L);
} catch (InterruptedException e) {}
}
}
}
/**
* This method creates and returns a server socket which uses all network
* interfaces on the host, and is bound to the specified port. It may be
* overloaded in subclass, in order to create particular subclasses of
* server sockets.
*
* @param port the port to listen to.
* @return a server socket bound to the specified port.
*
* @exception IOException for networking errors
*/
ServerSocket createServerSocket(int port) throws IOException {
if (logmon.isLoggable(BasicLevel.DEBUG)) {
StringBuilder strbuf = new StringBuilder();
strbuf.append(" createServerSocket(");
strbuf.append(", backlog=").append(backlog);
strbuf.append(", inLocalAddr=").append(inLocalAddr);
strbuf.append(')');
logmon.log(BasicLevel.DEBUG, getName() + strbuf.toString());
}
return serverSocketFactory.createServerSocket(port, backlog, inLocalAddr);
}
/**
* Configures this socket using the socket options established for this
* factory. It may be overloaded in subclass, in order to handle particular
* subclasses of sockets
*
* @param sock the socket.
*
* @exception SocketException for networking errors
*/
void setSocketOption(Socket sock) throws SocketException {
if (logmon.isLoggable(BasicLevel.DEBUG)) {
StringBuffer strbuf = new StringBuffer();
strbuf.append(" setSocketOption(");
strbuf.append(", TcpNoDelay=").append(TcpNoDelay);
strbuf.append(", SoLinger=").append(SoLinger);
strbuf.append(", SoTimeout=").append(SoTimeout);
strbuf.append(')');
logmon.log(BasicLevel.DEBUG, getName() + strbuf.toString());
}
// TCP data coalescing - ie Nagle's algorithm
sock.setTcpNoDelay(TcpNoDelay);
// Read operation will block indefinitely until requested data arrives
sock.setSoTimeout(SoTimeout);
// Linger-on-Close timeout.
if (SoLinger >= 0)
sock.setSoLinger(true, SoLinger);
else
sock.setSoLinger(false, 0);
}
}