blob: 83f2ef2800d9861adb499938c7568f0efce3eb0b [file] [log] [blame]
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opencord.igmpproxy.impl;
import org.onlab.packet.Ip4Address;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.opencord.igmpproxy.impl.state.DelayMember;
import org.opencord.igmpproxy.impl.state.IdleMember;
import org.opencord.igmpproxy.impl.state.NonMember;
import org.opencord.igmpproxy.statemachine.StateMachine;
import org.opencord.igmpproxy.statemachine.State;
import org.opencord.igmpproxy.statemachine.StateMachineId;
import java.util.concurrent.atomic.AtomicInteger;
/**
* State machine implementation.
*/
public final class SingleStateMachine implements StateMachine {
public static final int DEFAULT_MAX_RESP = 0xfffffff;
private StateMachineId stateMachineId;
private int currentState;
private Ip4Address srcIp;
private PortNumber upLinkPort;
private AtomicInteger timeOut; // unit is 1 second
private State[] states;
private int[] nonTransition =
{State.STATE_DELAY, State.STATE_NON,
State.STATE_NON, State.STATE_NON};
private int[] delayTransition =
{State.STATE_DELAY, State.STATE_NON,
State.STATE_DELAY, State.STATE_IDLE};
private int[] idleTransition =
{State.STATE_IDLE, State.STATE_NON,
State.STATE_DELAY, State.STATE_IDLE};
//THE TRANSITION TABLE
private int[][] transition =
{nonTransition, delayTransition, idleTransition};
/**
* Constructor for serializer.
*/
private SingleStateMachine() {
this.stateMachineId = null;
this.srcIp = null;
this.upLinkPort = null;
this.timeOut = null;
this.states = null;
}
/**
* Constructor of single state machine.
*
* @param deviceId device id of state-machine
* @param groupIp group id of state-machine
* @param srcIp source ip of state-machine
* @param upLinkPort uplink port of state-machine
*/
public SingleStateMachine(DeviceId deviceId,
Ip4Address groupIp,
Ip4Address srcIp,
PortNumber upLinkPort) {
this.stateMachineId = StateMachineId.of(deviceId, groupIp);
this.srcIp = srcIp;
this.upLinkPort = upLinkPort;
this.currentState = State.STATE_NON;
this.timeOut = null;
this.states = new State[]{new NonMember(this), new DelayMember(this), new IdleMember(this)};
}
/**
* Constructor of single state machine.
*
* @param machineId id of state-machine
* @param srcIp source ip of state-machine
* @param upLinkPort uplink port of state-machine
* @param currentState current state of state-machine
* @param timeout timeout value of state-machine
*/
public SingleStateMachine(StateMachineId machineId,
Ip4Address srcIp,
PortNumber upLinkPort,
int currentState,
Integer timeout) {
this.stateMachineId = machineId;
this.srcIp = srcIp;
this.upLinkPort = upLinkPort;
this.currentState = currentState;
if (timeout != null) {
createTimeOut(timeout);
} else {
this.timeOut = null;
}
this.states = new State[]{new NonMember(this), new DelayMember(this), new IdleMember(this)};
}
@Override
public StateMachineId getStateMachineId() {
return this.stateMachineId;
}
@Override
public Ip4Address getGroupIp() {
return this.stateMachineId.getGroupIp();
}
@Override
public DeviceId getDeviceId() {
return this.stateMachineId.getDeviceId();
}
@Override
public Ip4Address getSrcIp() {
return srcIp;
}
public PortNumber getUpLinkPort() {
return upLinkPort;
}
@Override
public int currentState() {
return this.currentState;
}
public Integer getTimeOut() {
return timeOut == null ? null : timeOut.get();
}
@Override
public void increaseTimeOut() {
this.timeOut.getAndIncrement();
}
@Override
public void decreaseTimeOut() {
this.timeOut.getAndDecrement();
}
@Override
public void setMaxTimeout() {
this.timeOut.set(DEFAULT_MAX_RESP);
}
@Override
public void startTimer(int timeout) {
createTimeOut(timeout);
}
@Override
public void resetTimer(int timeout) {
setTimeOut(timeout);
}
@Override
public void destroyTimer() {
setTimeOut(null);
}
@Override
public void join(boolean messageOutAllowed) {
if (messageOutAllowed) {
State state = states[currentState];
state.join();
}
next(State.TRANSITION_JOIN);
}
@Override
public void leave(boolean messageOutAllowed) {
if (messageOutAllowed) {
State state = states[currentState];
state.leave();
}
next(State.TRANSITION_LEAVE);
}
@Override
public void query(int maxResp) {
State state = states[currentState];
state.query(maxResp);
next(State.TRANSITION_QUERY);
}
@Override
public void timeOut(boolean sendQuery) {
if (sendQuery) {
State state = states[currentState];
state.timeOut();
}
next(State.TRANSITION_TIMEOUT);
}
private void next(int msg) {
this.currentState = transition[currentState][msg];
}
private void setTimeOut(int timeout) {
timeOut.set(timeout);
}
private void setTimeOut(Integer timeout) {
if (timeout == null) {
timeOut = null;
} else {
timeOut.set(timeout);
}
}
private void createTimeOut(Integer timeout) {
timeOut = new AtomicInteger(timeout);
}
}