- Buffer output
 - Separate methods for inbound and outbound, so we
   don't need to use PacketLocal for inbound
 - Cleanups after prop
 - Finals etc.
This commit is contained in:
zzz
2012-10-27 18:03:54 +00:00
parent 99e759a5be
commit 61ee957add
10 changed files with 101 additions and 65 deletions

View File

@ -195,7 +195,9 @@ class ConnectionHandler {
_manager.getPacketHandler().receivePacketDirect(packet, false); _manager.getPacketHandler().receivePacketDirect(packet, false);
} else { } else {
// log it here, just before we kill it - dest will be unknown // log it here, just before we kill it - dest will be unknown
((PacketLocal)packet).logTCPDump(true); if (I2PSocketManagerFull.pcapWriter != null &&
_context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
packet.logTCPDump(null);
// goodbye // goodbye
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))

View File

@ -267,8 +267,9 @@ class ConnectionManager {
con.setReceiveStreamId(receiveId); con.setReceiveStreamId(receiveId);
// finally, we know enough that we can log the packet with the conn filled in // finally, we know enough that we can log the packet with the conn filled in
((PacketLocal)synPacket).setConnection(con); if (I2PSocketManagerFull.pcapWriter != null &&
((PacketLocal)synPacket).logTCPDump(true); _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
synPacket.logTCPDump(con);
try { try {
// This validates the packet, and sets the con's SendStreamID and RemotePeer // This validates the packet, and sets the con's SendStreamID and RemotePeer
con.getPacketHandler().receivePacket(synPacket, con); con.getPacketHandler().receivePacket(synPacket, con);

View File

@ -315,6 +315,8 @@ public class I2PSocketManagerFull implements I2PSocketManager {
} catch (I2PSessionException ise) { } catch (I2PSessionException ise) {
_log.warn("Unable to destroy the session", ise); _log.warn("Unable to destroy the session", ise);
} }
if (pcapWriter != null)
pcapWriter.flush();
} }
} }
@ -351,7 +353,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
private static final String PCAP_FILE = "streaming.pcap"; private static final String PCAP_FILE = "streaming.pcap";
private static void debugInit(I2PAppContext ctx) { private static void debugInit(I2PAppContext ctx) {
if (!Boolean.valueOf(ctx.getProperty(PROP_PCAP)).booleanValue()) if (!ctx.getBooleanProperty(PROP_PCAP))
return; return;
synchronized(_pcapInitLock) { synchronized(_pcapInitLock) {
if (!_pcapInitialized) { if (!_pcapInitialized) {

View File

@ -59,9 +59,7 @@ class MessageHandler implements I2PSessionMuxedListener {
return; return;
} }
if (data == null) return; if (data == null) return;
//Packet packet = new Packet(); Packet packet = new Packet();
// for tcpdump
Packet packet = new PacketLocal(_context, null);
try { try {
packet.readPacket(data, 0, data.length); packet.readPacket(data, 0, data.length);
packet.setRemotePort(fromPort); packet.setRemotePort(fromPort);

View File

@ -1,5 +1,6 @@
package net.i2p.client.streaming; package net.i2p.client.streaming;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
@ -16,7 +17,8 @@ import net.i2p.util.Log;
* This contains solely the data that goes out on the wire, * This contains solely the data that goes out on the wire,
* including the local and remote port which is embedded in * including the local and remote port which is embedded in
* the I2CP overhead, not in the packet itself. * the I2CP overhead, not in the packet itself.
* For local state saved for outbound packets, see PacketLocal. * This is the class used for inbound packets.
* For local state saved for outbound packets, see the PacketLocal extension.
* *
* <p> * <p>
* *
@ -709,4 +711,14 @@ class Packet {
if (isFlagSet(FLAG_SYNCHRONIZE)) buf.append(" SYN"); if (isFlagSet(FLAG_SYNCHRONIZE)) buf.append(" SYN");
return buf.toString(); return buf.toString();
} }
/** Generate a pcap/tcpdump-compatible format,
* so we can use standard debugging tools.
*/
public void logTCPDump(Connection con) {
try {
I2PSocketManagerFull.pcapWriter.write(this, con);
} catch (IOException ioe) {
}
}
} }

View File

@ -131,8 +131,9 @@ class PacketHandler {
private void receiveKnownCon(Connection con, Packet packet) { private void receiveKnownCon(Connection con, Packet packet) {
// is this ok here or does it need to be below each packetHandler().receivePacket() ? // is this ok here or does it need to be below each packetHandler().receivePacket() ?
((PacketLocal)packet).setConnection(con); if (I2PSocketManagerFull.pcapWriter != null &&
((PacketLocal)packet).logTCPDump(true); _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
packet.logTCPDump(con);
if (packet.isFlagSet(Packet.FLAG_ECHO)) { if (packet.isFlagSet(Packet.FLAG_ECHO)) {
if (packet.getSendStreamId() > 0) { if (packet.getSendStreamId() > 0) {
if (con.getOptions().getAnswerPings()) if (con.getOptions().getAnswerPings())
@ -318,7 +319,9 @@ class PacketHandler {
_manager.getConnectionHandler().receiveNewSyn(packet); _manager.getConnectionHandler().receiveNewSyn(packet);
} else { } else {
// log it here, just before we kill it - dest will be unknown // log it here, just before we kill it - dest will be unknown
((PacketLocal)packet).logTCPDump(true); if (I2PSocketManagerFull.pcapWriter != null &&
_context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
packet.logTCPDump(null);
// don't queue again (infinite loop!) // don't queue again (infinite loop!)
sendReset(packet); sendReset(packet);
packet.releasePayload(); packet.releasePayload();

View File

@ -10,6 +10,8 @@ import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2; import net.i2p.util.SimpleTimer2;
/** /**
* This is the class used for outbound packets.
*
* coordinate local attributes about a packet - send time, ack time, number of * coordinate local attributes about a packet - send time, ack time, number of
* retries, etc. * retries, etc.
*/ */
@ -143,8 +145,6 @@ class PacketLocal extends Packet implements MessageOutputStream.WriteStatus {
/** @return null if not bound */ /** @return null if not bound */
public Connection getConnection() { return _connection; } public Connection getConnection() { return _connection; }
/** used to set the rcvd conn after the fact for incoming syn replies */
public void setConnection(Connection con) { _connection = con; }
/** /**
* Will force a fast restransmit on the 3rd call (FAST_RETRANSMIT_THRESHOLD) * Will force a fast restransmit on the 3rd call (FAST_RETRANSMIT_THRESHOLD)
@ -263,16 +263,11 @@ class PacketLocal extends Packet implements MessageOutputStream.WriteStatus {
/** Generate a pcap/tcpdump-compatible format, /** Generate a pcap/tcpdump-compatible format,
* so we can use standard debugging tools. * so we can use standard debugging tools.
*/ */
public void logTCPDump(boolean isInbound) { public void logTCPDump() {
if (_log.shouldLog(Log.INFO))
_log.info(toString());
if (I2PSocketManagerFull.pcapWriter != null &&
Boolean.valueOf(_context.getProperty(I2PSocketManagerFull.PROP_PCAP)).booleanValue()) {
try { try {
I2PSocketManagerFull.pcapWriter.write(this, isInbound); I2PSocketManagerFull.pcapWriter.write(this);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.warn("pcap write ioe: " + ioe); _log.warn("pcap write ioe: " + ioe);
} }
} }
}
} }

View File

@ -169,7 +169,9 @@ class PacketQueue {
Connection c = packet.getConnection(); Connection c = packet.getConnection();
String suffix = (c != null ? "wsize " + c.getOptions().getWindowSize() + " rto " + c.getOptions().getRTO() : null); String suffix = (c != null ? "wsize " + c.getOptions().getWindowSize() + " rto " + c.getOptions().getRTO() : null);
_connectionManager.getPacketHandler().displayPacket(packet, "SEND", suffix); _connectionManager.getPacketHandler().displayPacket(packet, "SEND", suffix);
((PacketLocal)packet).logTCPDump(false); if (I2PSocketManagerFull.pcapWriter != null &&
_context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP))
((PacketLocal)packet).logTCPDump();
} }
if ( (packet.getSequenceNum() == 0) && (!packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) ) { if ( (packet.getSequenceNum() == 0) && (!packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) ) {

View File

@ -1,8 +1,10 @@
package net.i2p.client.streaming; package net.i2p.client.streaming;
import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
@ -72,8 +74,8 @@ public class PcapWriter {
private static final byte OPTION_NACK = (byte) 0xac; private static final byte OPTION_NACK = (byte) 0xac;
private FileOutputStream _fos; private final OutputStream _fos;
private I2PAppContext _context; private final I2PAppContext _context;
public PcapWriter(I2PAppContext ctx, String file) throws IOException { public PcapWriter(I2PAppContext ctx, String file) throws IOException {
_context = ctx; _context = ctx;
@ -81,37 +83,52 @@ public class PcapWriter {
//if (f.exists()) { //if (f.exists()) {
// _fos = new FileOutputStream(f, true); // _fos = new FileOutputStream(f, true);
//} else { //} else {
_fos = new FileOutputStream(f); _fos = new BufferedOutputStream(new FileOutputStream(f), 64*1024);
_fos.write(FILE_HEADER); _fos.write(FILE_HEADER);
//} //}
} }
public void close() { public void close() {
FileOutputStream fos = _fos;
if (fos != null) {
try { try {
fos.close(); _fos.close();
} catch (IOException ioe) {} } catch (IOException ioe) {}
_fos = null;
}
} }
public void write(PacketLocal pkt, boolean isInbound) throws IOException { public void flush() {
try { try {
wrt(pkt, isInbound); _fos.flush();
} catch (IOException ioe) {}
}
/**
* For outbound packets
*/
public void write(PacketLocal pkt) throws IOException {
try {
wrt(pkt, pkt.getConnection(), false);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
dfe.printStackTrace(); dfe.printStackTrace();
throw new IOException(dfe.toString()); throw new IOException(dfe.toString());
} }
// remove me
_fos.flush();
} }
private synchronized void wrt(PacketLocal pkt, boolean isInbound) throws IOException, DataFormatException { /**
FileOutputStream fos = _fos; * For inbound packets
if (fos == null) * @param con may be null
throw new IOException("Not open or already closed"); */
Connection con = pkt.getConnection(); public void write(Packet pkt, Connection con) throws IOException {
try {
wrt(pkt, con, true);
} catch (DataFormatException dfe) {
dfe.printStackTrace();
throw new IOException(dfe.toString());
}
}
/**
* @param con may be null
*/
private synchronized void wrt(Packet pkt, Connection con, boolean isInbound) throws IOException, DataFormatException {
int includeLen = Math.min(MAX_PAYLOAD_BYTES, pkt.getPayloadSize()); int includeLen = Math.min(MAX_PAYLOAD_BYTES, pkt.getPayloadSize());
// option block // option block
@ -142,23 +159,23 @@ public class PcapWriter {
// PCAP Header // PCAP Header
long now; long now;
if (isInbound) if (isInbound)
now = pkt.getCreatedOn(); now = _context.clock().now();
else else
now = pkt.getLastSend(); now = ((PacketLocal)pkt).getLastSend();
DataHelper.writeLong(fos, 4, now / 1000); DataHelper.writeLong(_fos, 4, now / 1000);
DataHelper.writeLong(fos, 4, 1000 * (now % 1000)); DataHelper.writeLong(_fos, 4, 1000 * (now % 1000));
DataHelper.writeLong(fos, 4, 54 + optLen + includeLen); // 14 MAC + 20 IP + 20 TCP DataHelper.writeLong(_fos, 4, 54 + optLen + includeLen); // 14 MAC + 20 IP + 20 TCP
DataHelper.writeLong(fos, 4, 58 + optLen + pkt.getPayloadSize()); // 54 + MAC checksum DataHelper.writeLong(_fos, 4, 58 + optLen + pkt.getPayloadSize()); // 54 + MAC checksum
// MAC Header 14 bytes // MAC Header 14 bytes
fos.write(MAC_HEADER); _fos.write(MAC_HEADER);
// IP 20 bytes total // IP 20 bytes total
// IP Header 12 bytes // IP Header 12 bytes
int length = 20 + 20 + optLen + pkt.getPayloadSize(); int length = 20 + 20 + optLen + pkt.getPayloadSize();
fos.write(IP_HEADER_1); _fos.write(IP_HEADER_1);
DataHelper.writeLong(fos, 2, length); // total IP length DataHelper.writeLong(_fos, 2, length); // total IP length
fos.write(IP_HEADER_2); _fos.write(IP_HEADER_2);
// src and dst IP 8 bytes // src and dst IP 8 bytes
// make our side always start with 127.0.x.x // make our side always start with 127.0.x.x
@ -199,17 +216,17 @@ public class PcapWriter {
checksum = update(checksum, IP_HEADER_2); checksum = update(checksum, IP_HEADER_2);
checksum = update(checksum, srcAddr, 4); checksum = update(checksum, srcAddr, 4);
checksum = update(checksum, dstAddr, 4); checksum = update(checksum, dstAddr, 4);
DataHelper.writeLong(fos, 2, checksum ^ 0xffff); DataHelper.writeLong(_fos, 2, checksum ^ 0xffff);
// IPs // IPs
fos.write(srcAddr, 0, 4); _fos.write(srcAddr, 0, 4);
fos.write(dstAddr, 0, 4); _fos.write(dstAddr, 0, 4);
// TCP header 20 bytes total // TCP header 20 bytes total
// src and dst port 4 bytes // src and dst port 4 bytes
// the rcv ID is the source, and the send ID is the dest. // the rcv ID is the source, and the send ID is the dest.
DataHelper.writeLong(fos, 2, pkt.getReceiveStreamId() & 0xffff); DataHelper.writeLong(_fos, 2, pkt.getReceiveStreamId() & 0xffff);
DataHelper.writeLong(fos, 2, pkt.getSendStreamId() & 0xffff); DataHelper.writeLong(_fos, 2, pkt.getSendStreamId() & 0xffff);
// seq and acks 8 bytes // seq and acks 8 bytes
long seq; long seq;
@ -226,8 +243,8 @@ public class PcapWriter {
else else
acked = getLowestAckedThrough(pkt, con); acked = getLowestAckedThrough(pkt, con);
} }
DataHelper.writeLong(fos, 4, pkt.getSequenceNum()); DataHelper.writeLong(_fos, 4, pkt.getSequenceNum());
DataHelper.writeLong(fos, 4, acked); DataHelper.writeLong(_fos, 4, acked);
// offset and flags 2 bytes // offset and flags 2 bytes
int flags = 0; int flags = 0;
@ -241,8 +258,8 @@ public class PcapWriter {
flags |= 0x10; flags |= 0x10;
// offset byte // offset byte
int osb = (5 + (optLen / 4)) << 4; int osb = (5 + (optLen / 4)) << 4;
DataHelper.writeLong(fos, 1, osb); // 5 + optLen/4 32-byte words DataHelper.writeLong(_fos, 1, osb); // 5 + optLen/4 32-byte words
DataHelper.writeLong(fos, 1, flags); DataHelper.writeLong(_fos, 1, flags);
// window size 2 bytes // window size 2 bytes
long window = ConnectionOptions.INITIAL_WINDOW_SIZE; long window = ConnectionOptions.INITIAL_WINDOW_SIZE;
@ -268,18 +285,20 @@ public class PcapWriter {
// for now we don't spoof window scaling // for now we don't spoof window scaling
if (window > 65535) if (window > 65535)
window = 65535; window = 65535;
DataHelper.writeLong(fos, 2, window); DataHelper.writeLong(_fos, 2, window);
// checksum and urgent pointer 4 bytes // checksum and urgent pointer 4 bytes
DataHelper.writeLong(fos, 4, 0); DataHelper.writeLong(_fos, 4, 0);
// TCP option block // TCP option block
if (optLen > 0) if (optLen > 0)
fos.write(options, 0, optLen); _fos.write(options, 0, optLen);
// some data // some data
if (includeLen > 0) if (includeLen > 0)
fos.write(pkt.getPayload().getData(), 0, includeLen); _fos.write(pkt.getPayload().getData(), 0, includeLen);
if (pkt.isFlagSet(Packet.FLAG_CLOSE))
_fos.flush();
} }
/** /**
@ -294,7 +313,7 @@ public class PcapWriter {
* *
* To do: Add the SACK option to the TCP header. * To do: Add the SACK option to the TCP header.
*/ */
private static long getLowestAckedThrough(PacketLocal pkt, Connection con) { private static long getLowestAckedThrough(Packet pkt, Connection con) {
long nacks[] = pkt.getNacks(); long nacks[] = pkt.getNacks();
long lowest = pkt.getAckThrough(); // can return -1 but we increment below long lowest = pkt.getAckThrough(); // can return -1 but we increment below
if (nacks != null) { if (nacks != null) {
@ -311,14 +330,16 @@ public class PcapWriter {
} }
private static class Options { private static class Options {
byte[] _b; private final byte[] _b;
int _len; private int _len;
public Options() { public Options() {
_b = new byte[MAX_OPTION_LEN]; _b = new byte[MAX_OPTION_LEN];
} }
/** 40 bytes long, caller must use size() to get actual size */ /** 40 bytes long, caller must use size() to get actual size */
public byte[] getData() { return _b; } public byte[] getData() { return _b; }
/** rounded to next 4 bytes */ /** rounded to next 4 bytes */
public int size() { return ((_len + 3) / 4) * 4; } public int size() { return ((_len + 3) / 4) * 4; }

View File

@ -21,7 +21,7 @@ public class RouterVersion {
public final static long BUILD = 0; public final static long BUILD = 0;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = "-pcap"; public final static String EXTRA = "";
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + FULL_VERSION); System.out.println("I2P Router version: " + FULL_VERSION);