001: package org.jgroups.protocols;
002:
003: import org.jgroups.Event;
004: import org.jgroups.Global;
005: import org.jgroups.stack.IpAddress;
006: import org.jgroups.util.Util;
007:
008: import java.lang.reflect.Method;
009: import java.net.InetAddress;
010: import java.net.NetworkInterface;
011: import java.net.UnknownHostException;
012: import java.util.Map;
013: import java.util.Properties;
014:
015: /**
016: * Protocol which uses InetAddress.isReachable() to check whether a given host is up or not,
017: * taking 1 argument; the host name of the host to be pinged.
018: * <em>Note that this protocol only works with JDK 5 !</em>
019: * The implementation of this may or may not use ICMP ! An alternative is to create a TCP connection to port 7 (echo service)
020: * and see whether it works ! This is obviously done in JDK 5, so unless an echo service is configured to run, this
021: * won't work...
022: * @author Bela Ban
023: * @version $Id: FD_ICMP.java,v 1.5.2.1 2007/04/27 08:03:51 belaban Exp $
024: */
025: public class FD_ICMP extends FD {
026:
027: /** network interface to be used to send the ICMP packets */
028: private NetworkInterface intf = null;
029:
030: private InetAddress bind_addr;
031:
032: private Method is_reacheable;
033:
034: /** Time-to-live for InetAddress.isReachable() */
035: private int ttl = 32;
036:
037: public String getName() {
038: return "FD_ICMP";
039: }
040:
041: public boolean setProperties(Properties props) {
042: boolean ignore_systemprops = Util
043: .isBindAddressPropertyIgnored();
044: String str = Util.getProperty(new String[] { Global.BIND_ADDR,
045: Global.BIND_ADDR_OLD }, props, "bind_addr",
046: ignore_systemprops, null);
047: if (str != null) {
048: try {
049: bind_addr = InetAddress.getByName(str);
050: } catch (UnknownHostException unknown) {
051: if (log.isFatalEnabled())
052: log
053: .fatal("(bind_addr): host " + str
054: + " not known");
055: return false;
056: }
057: props.remove("bind_addr");
058: }
059:
060: str = props.getProperty("ttl");
061: if (str != null) {
062: ttl = Integer.parseInt(str);
063: props.remove("ttl");
064: }
065:
066: super .setProperties(props);
067:
068: try {
069: Class is_reacheable_class = Util.loadClass(
070: "java.net.InetAddress", this .getClass());
071: is_reacheable = is_reacheable_class.getMethod(
072: "isReachable", new Class[] {
073: NetworkInterface.class, int.class,
074: int.class });
075: } catch (ClassNotFoundException e) {
076: // log.error("failed checking for InetAddress.isReachable() method - requires JDK 5 or higher");
077: Error error = new NoClassDefFoundError(
078: "failed checking for InetAddress.isReachable() method - requires JDK 5 or higher");
079: error.initCause(e);
080: throw error;
081: } catch (NoSuchMethodException e) {
082: // log.error("didn't find InetAddress.isReachable() method - requires JDK 5 or higher");
083: Error error = new NoSuchMethodError(
084: "didn't find InetAddress.isReachable() method - requires JDK 5 or higher");
085: error.initCause(e);
086: throw error;
087: }
088:
089: if (props.size() > 0) {
090: log.error("the following properties are not recognized: "
091: + props);
092: return false;
093: }
094: return true;
095: }
096:
097: public void init() throws Exception {
098: super .init();
099: if (bind_addr != null)
100: intf = NetworkInterface.getByInetAddress(bind_addr);
101: }
102:
103: public void up(Event evt) {
104: switch (evt.getType()) {
105: case Event.CONFIG:
106: if (bind_addr == null) {
107: Map config = (Map) evt.getArg();
108: bind_addr = (InetAddress) config.get("bind_addr");
109: }
110: break;
111: }
112: super .up(evt);
113: }
114:
115: protected Monitor createMonitor() {
116: return new FD_ICMP.PingMonitor();
117: }
118:
119: /**
120: * Runs InetAddress.isReachable(). Each time the command fails, we increment num_tries. If num_tries > max_tries, we
121: * emit a SUSPECT message. If ping_dest changes, or we do receive traffic from ping_dest, we reset num_tries to 0.
122: */
123: protected class PingMonitor extends Monitor {
124: long start, stop;
125:
126: public void run() {
127: if (ping_dest == null) {
128: if (log.isWarnEnabled())
129: log.warn("ping_dest is null: members=" + members
130: + ", pingable_mbrs=" + pingable_mbrs
131: + ", local_addr=" + local_addr);
132: return;
133: }
134:
135: // 1. execute ping command
136: InetAddress host = ping_dest instanceof IpAddress ? ((IpAddress) ping_dest)
137: .getIpAddress()
138: : null;
139: if (host == null)
140: throw new IllegalArgumentException(
141: "ping_dest is not of type IpAddress - FD_ICMP only works with these");
142: try {
143: if (log.isTraceEnabled())
144: log.trace("pinging " + host + " (ping_dest="
145: + ping_dest + ") using interface " + intf);
146: start = System.currentTimeMillis();
147: Boolean rc = (Boolean) is_reacheable.invoke(host,
148: new Object[] { intf, new Integer(ttl),
149: new Integer((int) timeout) });
150: stop = System.currentTimeMillis();
151: num_heartbeats++;
152: if (rc.booleanValue()) { // success
153: num_tries = 0;
154: if (log.isTraceEnabled())
155: log
156: .trace("successfully received response from "
157: + host
158: + " (after "
159: + (stop - start) + "ms)");
160: } else { // failure
161: num_tries++;
162: if (log.isDebugEnabled())
163: log.debug("could not ping " + ping_dest
164: + " (tries=" + num_tries + ") after "
165: + (stop - start) + "ms)");
166: }
167:
168: if (num_tries >= max_tries) {
169: if (log.isDebugEnabled())
170: log.debug("[" + local_addr
171: + "]: could not ping " + ping_dest
172: + " for " + (num_tries + 1)
173: + " times ("
174: + ((num_tries + 1) * timeout)
175: + " milliseconds), suspecting it");
176: // broadcast a SUSPECT message to all members - loop until
177: // unsuspect or view change is received
178: bcast_task.addSuspectedMember(ping_dest);
179: num_tries = 0;
180: if (stats) {
181: num_suspect_events++;
182: suspect_history.add(ping_dest);
183: }
184: }
185: } catch (Exception ex) {
186: if (log.isErrorEnabled())
187: log.error("failed pinging " + ping_dest, ex);
188: }
189: }
190: }
191:
192: }
|