/** * Copyright 2007-2015, Kaazing Corporation. All rights reserved. * * 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.kaazing.k3po.pcap.converter.internal.author.script; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.logging.Logger; import org.kaazing.k3po.pcap.converter.internal.author.emitter.Emitter; import org.kaazing.k3po.pcap.converter.internal.packet.Packet; /** * TcpRptScriptWriter extends RptScriptWriter with specific knowledge of how Tcp works * */ public abstract class TcpScript extends AbstractScript{ private ScriptState state; private final HashMap<Long, Integer> seqNumbers = new HashMap<>(); private final static Logger LOG = Logger.getLogger(TcpScript.class.getName()); private Long closingReadAck = null; private Long closingWriteAck = null; public TcpScript(Emitter emitter) { super(emitter); this.setState(ScriptState.NOT_INITED); } public final boolean recordSeqNumAndReturnTrueOnNewEntry(long seqNum, int length){ if(length == 0) return true; if(seqNumbers.containsKey(seqNum) && seqNumbers.get(seqNum) == length) return false; else seqNumbers.put(seqNum, length); return true; } public final ScriptState getState() { return state; } public final void setState(ScriptState state) { this.state = state; } public final void readPayloadOfTcpPacket(Packet packet) { logPayload(packet.getTcpPayload()); if ( packet.isHttp() && !packet.getHttpFieldPositionsAndSize().isEmpty() ) { writeWaitAndSwapDate(packet.getTimeInMicroSecondsFromEpoch()); int payloadLength = packet.getTcpPayloadSize(); byte[] payload = packet.getTcpPayload(); Map<Integer, Integer> httpFields = new TreeMap<>(packet.getHttpFieldPositionsAndSize()); int currentPos = 0; Iterator<Entry<Integer, Integer>> iter = httpFields.entrySet().iterator(); Map.Entry<Integer, Integer> entry = iter.next(); while (currentPos < (payloadLength) && iter != null) { if ( entry.getKey() > currentPos ) { byte[] toWrite = new byte[entry.getKey()]; System.arraycopy(payload, currentPos, toWrite, 0, entry.getKey()); currentPos += writeReadBytes(toWrite); } else if(entry.getValue() == 0 || entry.getKey() < currentPos) { if ( iter.hasNext() ) { entry = (Map.Entry<Integer, Integer>) iter.next(); }else { break; } }else if(currentPos + entry.getValue() > payload.length){ break; }else{ byte[] toWrite = new byte[entry.getValue()]; System.arraycopy(payload, currentPos, toWrite, 0, entry.getValue()); currentPos += writeReadBytesInStringFormat(toWrite); if ( iter.hasNext() ) { entry = iter.next(); } else { break; } } } if ( payload.length > currentPos ) { byte[] toWrite = new byte[payload.length - currentPos]; System.arraycopy(payload, currentPos, toWrite, 0, payload.length - currentPos); currentPos += writeReadBytes(toWrite); } } else { writeReadBytes(packet.getTcpPayload(), packet.getTimeInMicroSecondsFromEpoch()); } } public final void writePayloadOfTcpPacket(Packet packet) { logPayload(packet.getTcpPayload()); if ( packet.isHttp() && !packet.getHttpFieldPositionsAndSize().isEmpty() ) { writeWaitAndSwapDate(packet.getTimeInMicroSecondsFromEpoch()); int payloadLength = packet.getTcpPayloadSize(); byte[] payload = packet.getTcpPayload(); Map<Integer, Integer> httpFields = new TreeMap<>(packet.getHttpFieldPositionsAndSize()); int currentPos = 0; Iterator<Entry<Integer, Integer>> iter = httpFields.entrySet().iterator(); Map.Entry<Integer, Integer> entry = iter.next(); while (currentPos < (payloadLength) && iter != null) { if ( entry.getKey() > currentPos ) { byte[] toWrite = new byte[entry.getKey()]; System.arraycopy(payload, currentPos, toWrite, 0, entry.getKey()); currentPos += writeWriteBytes(toWrite); } else if(entry.getValue() == 0 || entry.getKey() < currentPos) { if ( iter.hasNext() ) { entry = iter.next(); }else { break; } }else if(currentPos + entry.getValue() > payload.length){ break; }else{ byte[] toWrite = new byte[entry.getValue()]; System.arraycopy(payload, currentPos, toWrite, 0, entry.getValue()); currentPos += writeWriteBytesInStringFormat(toWrite); if ( iter.hasNext() ) { entry = iter.next(); } else { break; } } } if ( payload.length > currentPos ) { byte[] toWrite = new byte[payload.length - currentPos]; System.arraycopy(payload, currentPos, toWrite, 0, payload.length - currentPos); currentPos += writeWriteBytes(toWrite); } } else { writeWriteBytes(packet.getTcpPayload(), packet.getTimeInMicroSecondsFromEpoch()); } } @Override public final void writeClosed(){ super.writeClosed(); state = ScriptState.CLOSED; } @Override public final void writeBufferToFile(){ if(this.state == ScriptState.NOT_INITED) return; if(this.state != ScriptState.CLOSED) LOG.warning("Writing script to file that did not complete lifecycle: (ie not in closed state)"); super.writeBufferToFile(); } public final void writeCloseWrite(double d){ if(this.state == ScriptState.CLOSE_WRITE) //Repeat Packet return; writeWaitAndSwapDate(d); writeln("# close-write"); if ( this.state == ScriptState.CLOSE_READ ){ if(closingScript){ writeln("close"); } writeClosed(); } else{ this.state = ScriptState.CLOSE_WRITE; } } public final void writeCloseRead(double date){ if(this.state == ScriptState.CLOSE_READ) //Repeat Packet return; writeWaitAndSwapDate(date); writeln("# close-read"); if ( this.state == ScriptState.CLOSE_WRITE ){ if(closingScript){ writeln("close"); } writeClosed(); }else{ this.state = ScriptState.CLOSE_READ; } } public final boolean isClosingWriteAck(long ack) { if(closingWriteAck == null) return false; else if(closingWriteAck == ack){ return true; } return false; } public final boolean isClosingReadAck(long ack) { if(closingReadAck == null) return false; else if(closingReadAck == ack){ closedRead = true; return true; } return false; } public final void setClosingWriteAck(long closingAck) { if(closingWriteAck != null){ return; } if(!closedRead){ closingScript = true; } closingWriteAck = closingAck + 1L; } public final void setClosingReadAck(long closingAck) { if(closingReadAck != null){ return; } closingReadAck = closingAck + 1L; } @Override public final void writeConnected(double date){ state = ScriptState.CONNECTED; super.writeConnected(date); } private boolean closingScript = false; private boolean closedRead = false; }