package edu.uw.zookeeper.server;
import static com.google.common.base.Preconditions.checkArgument;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.base.MoreObjects;
import edu.uw.zookeeper.ConfigurableTimeout;
import edu.uw.zookeeper.common.Configurable;
import edu.uw.zookeeper.common.Configuration;
import edu.uw.zookeeper.common.Hex;
import edu.uw.zookeeper.common.TimeValue;
import edu.uw.zookeeper.protocol.Session;
public class DefaultSessionParametersPolicy implements SessionParametersPolicy {
public static DefaultSessionParametersPolicy fromConfiguration(short id, Configuration configuration) {
TimeValue minTimeout = ConfigurableMinTimeout.get(configuration);
TimeValue maxTimeout = ConfigurableMaxTimeout.get(configuration);
if (maxTimeout.value() != Session.Parameters.noTimeout()) {
checkArgument(minTimeout.value() <= maxTimeout.value());
}
return defaults(id, minTimeout, maxTimeout);
}
@Configurable(path="sessions", arg="minTimeout", value="0 seconds", help="time")
public static class ConfigurableMinTimeout extends ConfigurableTimeout {
public static TimeValue get(Configuration configuration) {
return new ConfigurableMinTimeout().apply(configuration);
}
}
@Configurable(path="sessions", arg="maxTimeout", value="0 seconds", help="time")
public static class ConfigurableMaxTimeout extends ConfigurableTimeout {
public static TimeValue get(Configuration configuration) {
return new ConfigurableMaxTimeout().apply(configuration);
}
}
public static DefaultSessionParametersPolicy defaults(
short id,
TimeValue minTimeout,
TimeValue maxTimeout) {
Random random = new Random();
return create(id, 0, random.nextLong(), random, minTimeout, maxTimeout);
}
public static DefaultSessionParametersPolicy create(
short id,
int counter,
long secret,
Random random,
TimeValue minTimeout,
TimeValue maxTimeout) {
DefaultSessionParametersPolicy instance = new DefaultSessionParametersPolicy(
id, new AtomicInteger(counter), secret, random, minTimeout, maxTimeout, LogManager.getLogger(DefaultSessionParametersPolicy.class));
return instance;
}
protected static final int PASSWORD_LENGTH = 16;
protected final Logger logger;
protected final Random random;
protected final long secret;
protected final short id;
protected final AtomicInteger counter;
protected final TimeValue minTimeout;
protected final TimeValue maxTimeout;
protected DefaultSessionParametersPolicy(
short id,
AtomicInteger counter,
long secret,
Random random,
TimeValue minTimeout,
TimeValue maxTimeout,
Logger logger) {
this.random = random;
this.id = id;
this.secret = secret;
this.counter = counter;
this.minTimeout = minTimeout;
this.maxTimeout = maxTimeout;
this.logger = logger;
logger.info("{}", this);
}
@Override
public byte[] newPassword(long seed) {
Random r = new Random(seed ^ secret);
byte p[] = new byte[PASSWORD_LENGTH];
r.nextBytes(p);
return p;
}
@Override
public boolean validatePassword(long sessionId, byte[] passwd) {
return (sessionId != Session.uninitialized().id())
&& Arrays.equals(passwd, newPassword(sessionId));
}
@Override
public long newSessionId() {
int count = counter.incrementAndGet();
byte[] nonce = new byte[1];
random.nextBytes(nonce);
ByteBuffer bb = ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN);
bb.put((byte)0).putShort(id).put(nonce).putInt(count).flip();
return bb.getLong();
}
@Override
public TimeValue boundTimeout(TimeValue timeOut) {
TimeValue maxTimeout = maxTimeout();
if ((maxTimeout.value() != Session.Parameters.noTimeout())
&& (maxTimeout.value() < timeOut.value(maxTimeout.unit()))) {
timeOut = maxTimeout;
} else {
TimeValue minTimeout = minTimeout();
if (minTimeout.value() > timeOut.value(minTimeout.unit())) {
timeOut = minTimeout;
}
}
return timeOut;
}
@Override
public TimeValue maxTimeout() {
return maxTimeout;
}
@Override
public TimeValue minTimeout() {
return minTimeout;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("id", String.format("0x%s", Hex.toPaddedHexString(id))).add("secret", String.format("0x%8s", Long.toHexString(secret)).replace(' ', '0')).add("counter", counter).add("minTimeout", minTimeout).add("maxTimeout", maxTimeout).toString();
}
}