/*
* Copyright 2010 NCHOVY
*
* 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.krakenapps.pcap.decoder.tcp;
import java.util.HashMap;
import java.util.Map;
/**
* @author mindori
*/
enum Action {
SEND_SYN, RECV_SYN, RECV_SYNACKED, RECV_RST, SEND_FIN, RECV_FIN, RECV_FINACKED, RECV_ACKED
}
public class TcpTransitionMapper {
private final Map<TcpState, Map<Action, TcpState>> fsm;
public TcpTransitionMapper() {
fsm = new HashMap<TcpState, Map<Action, TcpState>>();
buildFsm(fsm);
}
private void buildFsm(Map<TcpState, Map<Action, TcpState>> fsm) {
connect(fsm, TcpState.LISTEN, Action.SEND_SYN, TcpState.SYN_SENT);
connect(fsm, TcpState.LISTEN, Action.RECV_SYN, TcpState.SYN_RCVD);
connect(fsm, TcpState.SYN_SENT, Action.RECV_SYNACKED, TcpState.ESTABLISHED);
connect(fsm, TcpState.SYN_RCVD, Action.RECV_SYNACKED, TcpState.ESTABLISHED);
connect(fsm, TcpState.ESTABLISHED, Action.SEND_FIN, TcpState.FIN_WAIT_1);
connect(fsm, TcpState.ESTABLISHED, Action.RECV_FIN, TcpState.CLOSE_WAIT);
// Normal close.
connect(fsm, TcpState.FIN_WAIT_1, Action.RECV_ACKED, TcpState.FIN_WAIT_2);
connect(fsm, TcpState.FIN_WAIT_1, Action.RECV_FINACKED, TcpState.CLOSED);
// Simultaneous close.
connect(fsm, TcpState.FIN_WAIT_1, Action.RECV_FIN, TcpState.CLOSING);
// TIME_WAIT -> CLOSED.
connect(fsm, TcpState.FIN_WAIT_2, Action.RECV_FIN, TcpState.CLOSED);
// TIME_WAIT -> CLOSED.
connect(fsm, TcpState.CLOSING, Action.RECV_FINACKED, TcpState.CLOSED);
connect(fsm, TcpState.CLOSE_WAIT, Action.SEND_FIN, TcpState.LAST_ACK);
connect(fsm, TcpState.LAST_ACK, Action.RECV_FINACKED, TcpState.CLOSED);
}
private void connect(Map<TcpState, Map<Action, TcpState>> fsm, TcpState state1, Action action,
TcpState state2) {
Map<Action, TcpState> m = fsm.get(state1);
if (m == null) {
m = new HashMap<Action, TcpState>();
fsm.put(state1, m);
}
m.put(action, state2);
}
public TcpState map(TcpPacket segment, TcpState state, Action action) {
try {
if (fsm == null || fsm.get(state).get(action) == null)
return TcpState.CLOSED;
return fsm.get(state).get(action);
} catch(NullPointerException e) {
return TcpState.CLOSED;
}
}
}