442 lines
17 KiB
Java
442 lines
17 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* javax.baja.xml.XElem
|
|
*/
|
|
package com.tridium.sys.license;
|
|
|
|
import com.tridium.sys.license.FlrConfig;
|
|
import com.tridium.sys.license.FlrException;
|
|
import com.tridium.sys.license.LicenseFile;
|
|
import com.tridium.sys.license.NLicenseManager;
|
|
import com.tridium.sys.license.XFlrMsg;
|
|
import java.math.BigInteger;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.URL;
|
|
import java.security.DigestException;
|
|
import java.security.MessageDigest;
|
|
import java.util.Random;
|
|
import java.util.StringTokenizer;
|
|
import javax.baja.license.LicenseDatabaseException;
|
|
import javax.baja.sys.BAbsTime;
|
|
import javax.baja.sys.BFacets;
|
|
import javax.baja.sys.BLong;
|
|
import javax.baja.sys.BRelTime;
|
|
import javax.baja.sys.Sys;
|
|
import javax.baja.util.Version;
|
|
import javax.baja.xml.XElem;
|
|
|
|
public class FloatingLicenseManager
|
|
extends NLicenseManager {
|
|
static final int MIN_HB_FREQ = 5;
|
|
static final int MAX_HB_FREQ;
|
|
static final int HB_MISS_LIMIT;
|
|
FlrClient client;
|
|
private Heartbeat heartbeat;
|
|
private ReleaseLicenseHook releaseHook;
|
|
private FlrConfig flrConfig;
|
|
private String licPack;
|
|
|
|
protected LicenseFile[] loadLicenses() {
|
|
try {
|
|
Runtime.getRuntime().removeShutdownHook(this.releaseHook);
|
|
LicenseFile[] licenseFileArray = this.client.getLicenses();
|
|
int n = 0;
|
|
while (n < licenseFileArray.length) {
|
|
licenseFileArray[n].load(this);
|
|
++n;
|
|
}
|
|
Runtime.getRuntime().addShutdownHook(this.releaseHook);
|
|
if (this.heartbeat == null) {
|
|
this.heartbeat = new Heartbeat(this);
|
|
this.heartbeat.start();
|
|
}
|
|
return licenseFileArray;
|
|
}
|
|
catch (LicenseDatabaseException licenseDatabaseException) {
|
|
this.setFatalLicenseFault(licenseDatabaseException.getMessage());
|
|
return new FloatingLicense[0];
|
|
}
|
|
}
|
|
|
|
public FlrConfig getConfig() {
|
|
return this.flrConfig;
|
|
}
|
|
|
|
public String getPack() {
|
|
return this.licPack;
|
|
}
|
|
|
|
boolean failover() {
|
|
log.error(this.lex.getText("flm.failover.notify", new Object[]{this.client.getBoundUrl()}));
|
|
this.reload();
|
|
if (this.isFatalLicenseFault()) {
|
|
log.error(this.lex.getText("flm.failover.fail"));
|
|
return false;
|
|
}
|
|
log.message(this.lex.getText("flm.failover.success", new Object[]{this.client.getBoundUrl()}));
|
|
return true;
|
|
}
|
|
|
|
public FloatingLicenseManager(FlrConfig flrConfig, String string) {
|
|
this.flrConfig = flrConfig;
|
|
this.licPack = string;
|
|
this.client = new FlrClient(this);
|
|
this.releaseHook = new ReleaseLicenseHook(this);
|
|
}
|
|
|
|
static {
|
|
int n = 3600;
|
|
try {
|
|
n = Integer.parseInt(System.getProperty("niagara.flm.hb.freq"));
|
|
if (n > 3600) {
|
|
n = 3600;
|
|
}
|
|
}
|
|
catch (Exception exception) {}
|
|
MAX_HB_FREQ = Math.max(5, n);
|
|
int n2 = 24;
|
|
try {
|
|
n2 = Integer.parseInt(System.getProperty("niagara.flm.hb.maxMiss"));
|
|
if (n2 > 24) {
|
|
n2 = 24;
|
|
}
|
|
}
|
|
catch (Exception exception) {}
|
|
HB_MISS_LIMIT = Math.max(1, n2);
|
|
}
|
|
|
|
/*
|
|
* Illegal identifiers - consider using --renameillegalidents true
|
|
*/
|
|
private static class FlrClient {
|
|
private static final String XML_CONTENT = "text/xml; charset=\"utf-8\"";
|
|
XFlrMsg reqMsg;
|
|
private FloatingLicenseManager mgr;
|
|
private FlrCksum flrCksum;
|
|
private int boundFlr;
|
|
|
|
public boolean isBound() {
|
|
boolean bl = false;
|
|
if (this.boundFlr >= 0) {
|
|
bl = true;
|
|
}
|
|
return bl;
|
|
}
|
|
|
|
public URL getBoundUrl() {
|
|
if (!this.isBound()) {
|
|
throw new IllegalStateException("FLR is not bound");
|
|
}
|
|
return this.mgr.flrConfig.flrs()[this.boundFlr].getURL();
|
|
}
|
|
|
|
public FloatingLicense[] getLicenses() throws LicenseDatabaseException {
|
|
FlrConfig.FlrDef[] flrDefArray = this.mgr.getConfig().flrs();
|
|
int n = this.isBound() ? this.boundFlr : (this.boundFlr = 0);
|
|
while (true) {
|
|
XElem[] xElemArray;
|
|
Object object;
|
|
try {
|
|
XFlrMsg xFlrMsg = new XFlrMsg("lease");
|
|
xFlrMsg.setPayload(new XElem("lease").addAttr("pack", this.mgr.getPack()));
|
|
xFlrMsg.setMetadata("autofree", BLong.make(this.calcAutoFree()));
|
|
object = this.post(flrDefArray[this.boundFlr].getURL(), xFlrMsg);
|
|
xElemArray = ((XFlrMsg)object).getPayload().elems("license");
|
|
FloatingLicense[] floatingLicenseArray = new FloatingLicense[xElemArray.length];
|
|
int n2 = 0;
|
|
while (n2 < xElemArray.length) {
|
|
floatingLicenseArray[n2] = new FloatingLicense(xElemArray[n2]);
|
|
++n2;
|
|
}
|
|
this.reqMsg = xFlrMsg;
|
|
log.message(this.mgr.lex.getText("flm.lease.success", new Object[]{this.mgr.getPack(), flrDefArray[this.boundFlr].getURL()}));
|
|
return floatingLicenseArray;
|
|
}
|
|
catch (Exception exception) {
|
|
object = log.isTraceOn() ? "" : " -- " + exception.getMessage();
|
|
xElemArray = this.mgr.lex.getText("flm.lease.fail", new Object[]{this.mgr.getPack(), flrDefArray[this.boundFlr].getURL(), object});
|
|
if (log.isTraceOn()) {
|
|
log.trace((String)xElemArray, exception);
|
|
} else {
|
|
log.error((String)xElemArray);
|
|
}
|
|
if (flrDefArray.length != 1) {
|
|
++this.boundFlr;
|
|
this.boundFlr %= flrDefArray.length;
|
|
if (n != this.boundFlr) continue;
|
|
}
|
|
throw new LicenseDatabaseException(this.mgr.lex.getText("flm.lease.fatal", new Object[]{this.mgr.getPack()}));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public XFlrMsg post(XFlrMsg xFlrMsg) {
|
|
return this.post(this.getBoundUrl(), xFlrMsg);
|
|
}
|
|
|
|
public XFlrMsg post(URL uRL, XFlrMsg xFlrMsg) {
|
|
try {
|
|
xFlrMsg.getChallenge().setCksum(this.flrCksum.calcCksum(xFlrMsg, true));
|
|
HttpURLConnection httpURLConnection = (HttpURLConnection)uRL.openConnection();
|
|
httpURLConnection.setDoOutput(true);
|
|
httpURLConnection.setRequestProperty("Content-Type", XML_CONTENT);
|
|
xFlrMsg.write(httpURLConnection.getOutputStream(), true);
|
|
XFlrMsg xFlrMsg2 = XFlrMsg.make(httpURLConnection.getInputStream());
|
|
xFlrMsg2.throwIfError();
|
|
try {
|
|
this.flrCksum.validate(xFlrMsg, xFlrMsg2);
|
|
}
|
|
catch (DigestException digestException) {
|
|
throw new SecurityException(digestException.getMessage());
|
|
}
|
|
return xFlrMsg2;
|
|
}
|
|
catch (FlrException flrException) {
|
|
throw flrException;
|
|
}
|
|
catch (Exception exception) {
|
|
throw new FlrException("Message to FLR failed: " + exception);
|
|
}
|
|
}
|
|
|
|
private final long calcAutoFree() {
|
|
return BRelTime.makeSeconds(MAX_HB_FREQ).getMillis() * (long)HB_MISS_LIMIT;
|
|
}
|
|
|
|
private final /* synthetic */ void this() {
|
|
this.flrCksum = new CksumMagic();
|
|
}
|
|
|
|
public FlrClient(FloatingLicenseManager floatingLicenseManager) {
|
|
this.this();
|
|
this.mgr = floatingLicenseManager;
|
|
this.boundFlr = -1;
|
|
}
|
|
}
|
|
|
|
private static class Heartbeat
|
|
extends Thread {
|
|
private FloatingLicenseManager mgr;
|
|
private FlrClient client;
|
|
private int missedHeartbeats;
|
|
|
|
public boolean isFlatlined() {
|
|
boolean bl = false;
|
|
if (this.missedHeartbeats >= HB_MISS_LIMIT) {
|
|
bl = true;
|
|
}
|
|
return bl;
|
|
}
|
|
|
|
private final void forceFlatline() {
|
|
this.missedHeartbeats = HB_MISS_LIMIT;
|
|
}
|
|
|
|
private final long nextHbTime() {
|
|
return BRelTime.makeSeconds((int)(Math.random() * (double)(MAX_HB_FREQ - 5 + 1)) + 5).getMillis();
|
|
}
|
|
|
|
public void run() {
|
|
while (true) {
|
|
block11: {
|
|
try {
|
|
Object object;
|
|
long l = this.nextHbTime();
|
|
if (log.isTraceOn()) {
|
|
object = BAbsTime.now().add(BRelTime.make(l)).toString(BFacets.make("showSeconds", true));
|
|
log.trace(this.mgr.lex.getText("flm.hb.next", new Object[]{object}));
|
|
}
|
|
Thread.sleep(l);
|
|
object = new XFlrMsg("heartbeat");
|
|
((XFlrMsg)object).setPayload(this.client.reqMsg.asXML());
|
|
XFlrMsg xFlrMsg = this.client.post((XFlrMsg)object);
|
|
XElem xElem = xFlrMsg.getPayload();
|
|
if (xElem.name().equals("reject")) {
|
|
log.error(this.mgr.lex.getText("flm.hb.rejected"));
|
|
this.forceFlatline();
|
|
break block11;
|
|
}
|
|
if (xElem.name().equals("licenses")) break block11;
|
|
if (xElem.name().equals("success")) {
|
|
if (this.missedHeartbeats > 0) {
|
|
log.message(this.mgr.lex.getText("flm.hb.alive"));
|
|
}
|
|
this.missedHeartbeats = 0;
|
|
break block11;
|
|
}
|
|
throw new IllegalStateException("Invalid heartbeat response: " + xElem.name());
|
|
}
|
|
catch (InterruptedException interruptedException) {
|
|
}
|
|
catch (Exception exception) {
|
|
++this.missedHeartbeats;
|
|
Integer n = new Integer(HB_MISS_LIMIT - this.missedHeartbeats);
|
|
if (log.isTraceOn()) {
|
|
log.trace(this.mgr.lex.getText("flm.hb.missed", new Object[]{n, ""}), exception);
|
|
}
|
|
log.warning(this.mgr.lex.getText("flm.hb.missed", new Object[]{n, " -- " + exception.getMessage()}));
|
|
}
|
|
}
|
|
if (!this.isFlatlined()) continue;
|
|
if (!this.mgr.failover()) break;
|
|
this.missedHeartbeats = 0;
|
|
}
|
|
if (this.isFlatlined()) {
|
|
log.error(this.mgr.lex.getText("flm.exit"));
|
|
if (Sys.getStation() != null) {
|
|
Sys.getStation().save();
|
|
}
|
|
System.exit(1);
|
|
}
|
|
}
|
|
|
|
public Heartbeat(FloatingLicenseManager floatingLicenseManager) {
|
|
super(BAbsTime.now().toString());
|
|
this.mgr = floatingLicenseManager;
|
|
this.client = floatingLicenseManager.client;
|
|
this.missedHeartbeats = 0;
|
|
}
|
|
}
|
|
|
|
private static class FloatingLicense
|
|
extends LicenseFile {
|
|
XElem license;
|
|
|
|
protected String getLicenseName() {
|
|
return "Floating License";
|
|
}
|
|
|
|
protected XElem getRoot() throws Exception {
|
|
return this.license;
|
|
}
|
|
|
|
protected boolean isLicenseHostIdValid() {
|
|
return this.hostId.equals("FLOATING");
|
|
}
|
|
|
|
public FloatingLicense(XElem xElem) {
|
|
this.license = xElem;
|
|
}
|
|
}
|
|
|
|
private static final class ReleaseLicenseHook
|
|
extends Thread {
|
|
private FloatingLicenseManager mgr;
|
|
|
|
public final void run() {
|
|
try {
|
|
XFlrMsg xFlrMsg = new XFlrMsg("checkin");
|
|
xFlrMsg.setPayload(this.mgr.client.reqMsg.asXML());
|
|
log.message(this.mgr.lex.getText("flm.checkin.begin"));
|
|
this.mgr.client.post(xFlrMsg);
|
|
log.message(this.mgr.lex.getText("flm.checkin.end"));
|
|
}
|
|
catch (Exception exception) {
|
|
log.error(this.mgr.lex.getText("flm.checkin.failed", new Object[]{" -- " + exception.getMessage()}));
|
|
log.error("Failed to check-in leased license.", exception);
|
|
}
|
|
}
|
|
|
|
public ReleaseLicenseHook(FloatingLicenseManager floatingLicenseManager) {
|
|
this.mgr = floatingLicenseManager;
|
|
}
|
|
}
|
|
|
|
public static interface FlrCksum {
|
|
public Version version();
|
|
|
|
public String calcCksum(XFlrMsg var1, boolean var2) throws DigestException;
|
|
|
|
public void validate(XFlrMsg var1, XFlrMsg var2) throws DigestException;
|
|
|
|
public void validate(XFlrMsg var1, BRelTime var2) throws DigestException;
|
|
}
|
|
|
|
private static class CksumMagic
|
|
implements FlrCksum {
|
|
private Version version = new Version("1.0");
|
|
|
|
public Version version() {
|
|
return this.version;
|
|
}
|
|
|
|
public String calcCksum(XFlrMsg xFlrMsg, boolean bl) throws DigestException {
|
|
try {
|
|
MessageDigest messageDigest = MessageDigest.getInstance("md5");
|
|
XFlrMsg.XChallenge xChallenge = xFlrMsg.getChallenge();
|
|
xChallenge.setVersion(this.version);
|
|
long l = xChallenge.getTimestamp();
|
|
String string = xChallenge.getHostid();
|
|
int[] nArray = xChallenge.parseNonce();
|
|
Random random = new Random(l >>> 2 ^ -1L);
|
|
StringTokenizer stringTokenizer = new StringTokenizer(string, "-");
|
|
String[] stringArray = new String[stringTokenizer.countTokens()];
|
|
int n = 0;
|
|
while (n < stringArray.length) {
|
|
stringArray[n] = stringTokenizer.nextToken();
|
|
++n;
|
|
}
|
|
n = 0;
|
|
StringBuffer stringBuffer = new StringBuffer();
|
|
if (bl) {
|
|
stringBuffer.append(xFlrMsg.getType()).append(this.version.toString());
|
|
}
|
|
int n2 = 0;
|
|
while (n2 < 4) {
|
|
int n3 = 0;
|
|
while (n3 < nArray.length) {
|
|
boolean bl2 = random.nextBoolean();
|
|
if (bl && bl2) {
|
|
stringBuffer.append(nArray[n3]);
|
|
} else if (!bl && !bl2) {
|
|
stringBuffer.append(nArray[n3]);
|
|
} else {
|
|
stringBuffer.append(stringArray[n++ % stringArray.length]);
|
|
}
|
|
++n3;
|
|
}
|
|
++n2;
|
|
}
|
|
if (!bl) {
|
|
stringBuffer.append(xFlrMsg.getType()).append(this.version.toString());
|
|
}
|
|
return new BigInteger(1, messageDigest.digest(stringBuffer.toString().getBytes("UTF-16LE"))).toString(16);
|
|
}
|
|
catch (Exception exception) {
|
|
throw new DigestException(exception.getMessage());
|
|
}
|
|
}
|
|
|
|
public void validate(XFlrMsg xFlrMsg, XFlrMsg xFlrMsg2) throws DigestException {
|
|
XFlrMsg.XChallenge xChallenge = xFlrMsg2.getChallenge();
|
|
this.throwIfVersionMismatch(xChallenge);
|
|
String string = this.calcCksum(xFlrMsg, false);
|
|
String string2 = xChallenge.getCksum();
|
|
if (!string.equals(string2)) {
|
|
throw new DigestException("Invalid FLR cksum");
|
|
}
|
|
}
|
|
|
|
public void validate(XFlrMsg xFlrMsg, BRelTime bRelTime) throws DigestException {
|
|
XFlrMsg.XChallenge xChallenge = xFlrMsg.getChallenge();
|
|
this.throwIfVersionMismatch(xChallenge);
|
|
xChallenge.throwIfTooOld(bRelTime);
|
|
String string = xChallenge.getCksum();
|
|
String string2 = this.calcCksum(xFlrMsg, true);
|
|
if (!string.equals(string2)) {
|
|
throw new DigestException("Cksum mismatch");
|
|
}
|
|
}
|
|
|
|
private final void throwIfVersionMismatch(XFlrMsg.XChallenge xChallenge) throws DigestException {
|
|
if (!xChallenge.getVersion().equals(this.version)) {
|
|
throw new DigestException("FLR and client have different cksum methods.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|