/* * 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 org.krakenapps.pcap.util.Buffer; public class TcpSackHandler { private TcpStateUpdater stateUpdater; public TcpSackHandler() { stateUpdater = new TcpStateUpdater(); } public void handle(TcpSessionTable sessionTable, TcpSessionImpl session, TcpPacket packet) { session.setRelativeNumbers(packet); TcpState serverState = session.getServerState(); if (serverState.compareTo(TcpState.ESTABLISHED) < 0) session.doEstablish(sessionTable, session, packet, stateUpdater); else { TcpSackReassembler.insert(session, packet); cleanUpWindow(session, packet); TcpPacket reassembledPacket; while (true) { reassembledPacket = TcpSackReassembler.reassemble(session, packet, stateUpdater); if (reassembledPacket == null) break; slideWindow(session, reassembledPacket); stateUpdater.updateState(session, reassembledPacket); } if (session.getClientState() == TcpState.CLOSED && session.getServerState() == TcpState.CLOSED) session.close(sessionTable, session, reassembledPacket); } } private void cleanUpWindow(TcpSessionImpl session, TcpPacket packet) { TcpHost host; WaitQueue queue; if (packet.getDirection() == TcpDirection.ToServer) { host = session.getClient(); queue = session.getClientQueue(); } else { host = session.getServer(); queue = session.getServerQueue(); } /* apply window size */ host.setLastAcceptableFrame(packet.getWindow()); int end = host.getLastAcceptableFrame(); /* clear up receive window */ for (int i = 0; i < queue.size(); i++) { TcpPacket p = queue.dequeue(i); int seq = p.getRelativeSeq(); int lengthOfData = 0; if (p.getData() != null) lengthOfData = p.getData().readableBytes(); if (seq > end) queue.remove(i); else if (seq + lengthOfData > end) { /* cut garbage data */ int garbage = (seq + lengthOfData) - end; int remain = lengthOfData - garbage; Buffer data = p.getData(); data.skip(remain); data.flip(); } } } private void slideWindow(TcpSessionImpl session, TcpPacket packet) { if (packet == null || !packet.isAck()) return; TcpHost host; if (packet.getDirection() == TcpDirection.ToServer) host = session.getServer(); else host = session.getClient(); host.setLastFrameReceived(packet.getReassembledLength()); if(packet.isFin()) host.setLastFrameReceived(1); } }