| /* |
| * 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); |
| } |
| } |