On Wed, Dec 3, 2008 at 2:51 AM, <toad at freenetproject.org> wrote:
> Author: toad
> Date: 2008-12-02 18:51:25 +0000 (Tue, 02 Dec 2008)
> New Revision: 24014
>
> Modified:
> trunk/freenet/src/freenet/node/FNPPacketMangler.java
> trunk/freenet/src/freenet/node/PacketTracker.java
> trunk/freenet/src/freenet/node/PeerNode.java
> Log:
> New negotiation type 3. If we connect with neg type 3, we don't change the
> PacketTracker on rekeying.
> Should help a lot with bug #2692.
>
Will we remove type 2 any time soon?
>
> Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
> ===================================================================
> --- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2008-12-02
> 13:55:19 UTC (rev 24013)
> +++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2008-12-02
> 18:51:25 UTC (rev 24014)
> @@ -533,7 +533,7 @@
> Logger.error(this, "Decrypted auth packet but invalid
> version: "+version);
> return;
> }
> - if(negType != 2) {
> + if(!(negType == 2 || negType == 3)) {
> Logger.error(this, "Unknown neg type: "+negType);
> return;
> }
> @@ -549,10 +549,10 @@
>
> if(packetType == 0) {
> // Phase 1
> - processJFKMessage1(payload,4,null,replyTo, true,
> setupType);
> + processJFKMessage1(payload,4,null,replyTo, true,
> setupType, negType);
> } else if(packetType == 2) {
> // Phase 3
> - processJFKMessage3(payload, 4, null, replyTo, false,
> true, setupType);
> + processJFKMessage3(payload, 4, null, replyTo, false,
> true, setupType, negType);
> } else {
> Logger.error(this, "Invalid phase "+packetType+" for
> anonymous-initiator (we are the responder)");
> }
> @@ -577,7 +577,7 @@
> Logger.error(this, "Decrypted auth packet but invalid
> version: "+version);
> return;
> }
> - if(negType != 2) {
> + if(!(negType == 2 || negType == 3)) {
> Logger.error(this, "Unknown neg type: "+negType);
> return;
> }
> @@ -593,10 +593,10 @@
>
> if(packetType == 1) {
> // Phase 2
> - processJFKMessage2(payload, 4, pn, replyTo, true,
> setupType);
> + processJFKMessage2(payload, 4, pn, replyTo, true,
> setupType, negType);
> } else if(packetType == 3) {
> // Phase 4
> - processJFKMessage4(payload, 4, pn, replyTo, false,
> true, setupType);
> + processJFKMessage4(payload, 4, pn, replyTo, false,
> true, setupType, negType);
> } else {
> Logger.error(this, "Invalid phase "+packetType+" for
> anonymous-initiator (we are the responder)");
> }
> @@ -642,7 +642,7 @@
> } else if (negType == 1) {
> Logger.error(this, "Old StationToStation (negType 1)
> not supported.");
> return;
> - } else if (negType==2){
> + } else if (negType==2 || negType == 3){ // negType == 3 => no
> new PacketTracker when rekeying
> /*
> * We implement Just Fast Keying key management
> protocol with active identity protection
> * for the initiator and no identity protection for
> the responder
> @@ -673,7 +673,7 @@
> * session key will be different,can be used
> to differentiate between
> * parallel sessions
> */
> -
> processJFKMessage1(payload,3,pn,replyTo,false,-1);
> +
> processJFKMessage1(payload,3,pn,replyTo,false,-1,negType);
>
> }
> else if(packetType==1){
> @@ -682,7 +682,7 @@
> * nonce and an authenticator calculated from
> a transient hash key private
> * to the responder.
> */
> -
> processJFKMessage2(payload,3,pn,replyTo,false,-1);
> +
> processJFKMessage2(payload,3,pn,replyTo,false,-1,negType);
> }
> else if(packetType==2){
> /*
> @@ -690,7 +690,7 @@
> * cached by the Responder.Receiving a
> duplicate message simply causes
> * the responder to Re-transmit the
> corresponding message4
> */
> - processJFKMessage3(payload, 3, pn, replyTo,
> oldOpennetPeer, false, -1);
> + processJFKMessage3(payload, 3, pn, replyTo,
> oldOpennetPeer, false, -1, negType);
> }
> else if(packetType==3){
> /*
> @@ -698,7 +698,7 @@
> * using the same keys as in the previous
> message.
> * The signature is non-message recovering
> */
> - processJFKMessage4(payload, 3, pn, replyTo,
> oldOpennetPeer, false, -1);
> + processJFKMessage4(payload, 3, pn, replyTo,
> oldOpennetPeer, false, -1, negType);
> }
> } else {
> Logger.error(this, "Decrypted auth packet but unknown
> negotiation type "+negType+" from "+replyTo+" possibly from "+pn);
> @@ -729,7 +729,7 @@
> * ACM Transactions on Information and System Security, Vol 7 No 2,
> May 2004, Pages 1-30.
> *
> */
> - private void processJFKMessage1(byte[] payload,int offset,PeerNode
> pn,Peer replyTo, boolean unknownInitiator, int setupType)
> + private void processJFKMessage1(byte[] payload,int offset,PeerNode
> pn,Peer replyTo, boolean unknownInitiator, int setupType, int negType)
> {
> long t1=System.currentTimeMillis();
> if(logMINOR) Logger.minor(this, "Got a JFK(1) message,
> processing it - "+pn);
> @@ -760,7 +760,7 @@
>
> NativeBigInteger _hisExponential = new
> NativeBigInteger(1,hisExponential);
> if(DiffieHellman.checkDHExponentialValidity(this.getClass(),
> _hisExponential)) {
> - sendJFKMessage2(nonceInitiator, hisExponential, pn,
> replyTo, unknownInitiator, setupType);
> + sendJFKMessage2(nonceInitiator, hisExponential, pn,
> replyTo, unknownInitiator, setupType, negType);
> }else
> Logger.error(this, "We can't accept the exponential
> "+pn+" sent us!! REDFLAG: IT CAN'T HAPPEN UNLESS AGAINST AN ACTIVE
> ATTACKER!!");
>
> @@ -777,7 +777,7 @@
> * know the responder in all cases.
> * @param replyTo The peer to send the actual packet to.
> */
> - private void sendJFKMessage1(PeerNode pn, Peer replyTo, boolean
> unknownInitiator, int setupType) {
> + private void sendJFKMessage1(PeerNode pn, Peer replyTo, boolean
> unknownInitiator, int setupType, int negType) {
> if(logMINOR) Logger.minor(this, "Sending a JFK(1) message to
> "+replyTo+" for "+pn.getPeer());
> final long now = System.currentTimeMillis();
> DiffieHellmanLightContext ctx = (DiffieHellmanLightContext)
> pn.getKeyAgreementSchemeContext();
> @@ -804,9 +804,9 @@
> if(unknownInitiator) {
> offset += modulusLength;
> System.arraycopy(pn.identityHash, 0, message1, offset,
> pn.identityHash.length);
> -
> sendAnonAuthPacket(1,2,0,setupType,message1,pn,replyTo,pn.anonymousInitiatorSetupCipher);
> +
> sendAnonAuthPacket(1,negType,0,setupType,message1,pn,replyTo,pn.anonymousInitiatorSetupCipher);
> } else {
> - sendAuthPacket(1,2,0,message1,pn,replyTo);
> + sendAuthPacket(1,negType,0,message1,pn,replyTo);
> }
> long t2=System.currentTimeMillis();
> if((t2-now)>500)
> @@ -824,7 +824,7 @@
> * @param pn The node to encrypt the message for. CAN BE NULL if
> anonymous-initiator.
> * @param replyTo The peer to send the packet to.
> */
> - private void sendJFKMessage2(byte[] nonceInitator, byte[]
> hisExponential, PeerNode pn, Peer replyTo, boolean unknownInitiator, int
> setupType) {
> + private void sendJFKMessage2(byte[] nonceInitator, byte[]
> hisExponential, PeerNode pn, Peer replyTo, boolean unknownInitiator, int
> setupType, int negType) {
> if(logMINOR) Logger.minor(this, "Sending a JFK(2) message to
> "+pn);
> DiffieHellmanLightContext ctx = getLightDiffieHellmanContext();
> // g^r
> @@ -857,9 +857,9 @@
> System.arraycopy(authenticator, 0, message2, offset,
> HASH_LENGTH);
>
> if(unknownInitiator)
> -
> sendAnonAuthPacket(1,2,1,setupType,message2,pn,replyTo,crypto.anonSetupCipher);
> +
> sendAnonAuthPacket(1,negType,1,setupType,message2,pn,replyTo,crypto.anonSetupCipher);
> else
> - sendAuthPacket(1,2,1,message2,pn,replyTo);
> + sendAuthPacket(1,negType,1,message2,pn,replyTo);
> }
>
> /*
> @@ -896,7 +896,7 @@
> * @param pn The peerNode we are talking to. Cannot be null as we are
> the initiator.
> */
>
> - private void processJFKMessage2(byte[] payload,int
> inputOffset,PeerNode pn,Peer replyTo, boolean unknownInitiator, int setupType)
> + private void processJFKMessage2(byte[] payload,int
> inputOffset,PeerNode pn,Peer replyTo, boolean unknownInitiator, int
> setupType, int negType)
> {
> long t1=System.currentTimeMillis();
> if(logMINOR) Logger.minor(this, "Got a JFK(2) message,
> processing it - "+pn.getPeer());
> @@ -939,7 +939,7 @@
> }
> if(message3 != null) {
> Logger.normal(this, "We replayed a message from the
> cache (shouldn't happen often) - "+pn.getPeer());
> - sendAuthPacket(1, 2, 3, (byte[]) message3, pn,
> replyTo);
> + sendAuthPacket(1, negType, 3, (byte[]) message3, pn,
> replyTo);
> return;
> }
>
> @@ -977,7 +977,7 @@
> // At this point we know it's from the peer, so we can report
> a packet received.
> pn.receivedPacket(true, false);
>
> - sendJFKMessage3(1, 2, 3, nonceInitiator, nonceResponder,
> hisExponential, authenticator, pn, replyTo, unknownInitiator, setupType);
> + sendJFKMessage3(1, negType, 3, nonceInitiator,
> nonceResponder, hisExponential, authenticator, pn, replyTo, unknownInitiator,
> setupType);
>
> long t2=System.currentTimeMillis();
> if((t2-t1)>500)
> @@ -1008,7 +1008,7 @@
> * responder.
> * @return byte Message3
> */
> - private void processJFKMessage3(byte[] payload, int inputOffset,
> PeerNode pn,Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator,
> int setupType)
> + private void processJFKMessage3(byte[] payload, int inputOffset,
> PeerNode pn,Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator,
> int setupType, int negType)
> {
> final long t1 = System.currentTimeMillis();
> if(logMINOR) Logger.minor(this, "Got a JFK(3) message,
> processing it - "+pn);
> @@ -1071,9 +1071,9 @@
> // We are replaying a JFK(4).
> // Therefore if it is anon-initiator it is encrypted
> with our setup key.
> if(unknownInitiator)
> - sendAnonAuthPacket(1,2,3,setupType, (byte[])
> message4, null, replyTo, crypto.anonSetupCipher);
> + sendAnonAuthPacket(1,negType,3,setupType,
> (byte[]) message4, null, replyTo, crypto.anonSetupCipher);
> else
> - sendAuthPacket(1, 2, 3, (byte[]) message4,
> pn, replyTo);
> + sendAuthPacket(1, negType, 3, (byte[])
> message4, pn, replyTo);
> return;
> } else {
> if(logDEBUG) Logger.debug(this, "No message4 found for
> "+HexUtil.bytesToHex(authenticator)+" responderExponential
> "+Fields.hashCode(responderExponential)+" initiatorExponential
> "+Fields.hashCode(initiatorExponential)+" nonceResponder
> "+Fields.hashCode(nonceResponder)+" nonceInitiator
> "+Fields.hashCode(nonceInitiator)+" address
> "+HexUtil.bytesToHex(replyTo.getAddress().getAddress()));
> @@ -1155,7 +1155,7 @@
> pn.receivedPacket(true, false);
>
> // Send reply
> - sendJFKMessage4(1, 2, 3, nonceInitiator,
> nonceResponder,initiatorExponential, responderExponential,
> + sendJFKMessage4(1, negType, 3, nonceInitiator,
> nonceResponder,initiatorExponential, responderExponential,
> c, Ke, Ka, authenticator, hisRef, pn, replyTo,
> unknownInitiator, setupType);
>
> c.initialize(Ks);
> @@ -1175,7 +1175,7 @@
> // wantPeer will call node.peers.addPeer(), we don't
> have to.
> }
>
> - if(pn.completedHandshake(bootID, hisRef, 0, hisRef.length, c,
> Ks, replyTo, true)) {
> + if(pn.completedHandshake(bootID, hisRef, 0, hisRef.length, c,
> Ks, replyTo, true, negType)) {
> if(dontWant)
> node.peers.disconnect(pn, true, false);
> else
> @@ -1240,7 +1240,7 @@
> * @param pn The PeerNode we are talking to. Cannot be null as we are
> the initiator.
> * @param replyTo The Peer we are replying to.
> */
> - private boolean processJFKMessage4(byte[] payload, int inputOffset,
> PeerNode pn, Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator,
> int setupType)
> + private boolean processJFKMessage4(byte[] payload, int inputOffset,
> PeerNode pn, Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator,
> int setupType, int negType)
> {
> final long t1 = System.currentTimeMillis();
> if(logMINOR) Logger.minor(this, "Got a JFK(4) message,
> processing it - "+pn.getPeer());
> @@ -1370,7 +1370,7 @@
>
> // We change the key
> c.initialize(pn.jfkKs);
> - if(pn.completedHandshake(bootID, data, 8, data.length - 8, c,
> pn.jfkKs, replyTo, false)) {
> + if(pn.completedHandshake(bootID, data, 8, data.length - 8, c,
> pn.jfkKs, replyTo, false, negType)) {
> if(dontWant)
> node.peers.disconnect(pn, true, false);
> else
> @@ -1411,7 +1411,7 @@
> * @param replyTo The Peer to send the packet to.
> */
>
> - private void sendJFKMessage3(int version,int negType,int phase,byte[]
> nonceInitiator,byte[] nonceResponder,byte[] hisExponential, byte[]
> authenticator, final PeerNode pn, final Peer replyTo, final boolean
> unknownInitiator, final int setupType)
> + private void sendJFKMessage3(int version,final int negType,int
> phase,byte[] nonceInitiator,byte[] nonceResponder,byte[] hisExponential,
> byte[] authenticator, final PeerNode pn, final Peer replyTo, final boolean
> unknownInitiator, final int setupType)
> {
> if(logMINOR) Logger.minor(this, "Sending a JFK(3) message to
> "+pn.getPeer());
> long t1=System.currentTimeMillis();
> @@ -1503,18 +1503,18 @@
> authenticatorCache.put(new
> ByteArrayWrapper(authenticator),message3);
> }
> if(unknownInitiator)
> - sendAnonAuthPacket(1, 2, 2, setupType, message3, pn,
> replyTo, pn.anonymousInitiatorSetupCipher);
> + sendAnonAuthPacket(1, negType, 2, setupType,
> message3, pn, replyTo, pn.anonymousInitiatorSetupCipher);
> else
> - sendAuthPacket(1, 2, 2, message3, pn, replyTo);
> + sendAuthPacket(1, negType, 2, message3, pn, replyTo);
>
> /* Re-send the packet after 5sec if we don't get any reply */
> node.getTicker().queueTimedJob(new Runnable() {
> public void run() {
> if(pn.timeLastConnected() >=
> pn.lastReceivedPacketTime()) {
> if(unknownInitiator)
> - sendAnonAuthPacket(1, 2, 2,
> setupType, message3, pn, replyTo, pn.anonymousInitiatorSetupCipher);
> + sendAnonAuthPacket(1,
> negType, 2, setupType, message3, pn, replyTo,
> pn.anonymousInitiatorSetupCipher);
> else
> - sendAuthPacket(1, 2, 2,
> message3, pn, replyTo);
> + sendAuthPacket(1, negType, 2,
> message3, pn, replyTo);
> }
> }
> }, 5*1000);
> @@ -1599,9 +1599,9 @@
> }
>
> if(unknownInitiator)
> - sendAnonAuthPacket(1, 2, 3, setupType, message4, pn,
> replyTo, crypto.anonSetupCipher);
> + sendAnonAuthPacket(1, negType, 3, setupType,
> message4, pn, replyTo, crypto.anonSetupCipher);
> else
> - sendAuthPacket(1, 2, 3, message4, pn, replyTo);
> + sendAuthPacket(1, negType, 3, message4, pn, replyTo);
> long t2=System.currentTimeMillis();
> if((t2-t1)>500)
> Logger.error(this,"Message4 timeout error:Sending
> packet for"+pn.getPeer());
> @@ -2774,7 +2774,7 @@
> pn.couldNotSendHandshake();
> return;
> }
> - sendJFKMessage1(pn, peer, pn.handshakeUnknownInitiator(),
> pn.handshakeSetupType());
> + sendJFKMessage1(pn, peer, pn.handshakeUnknownInitiator(),
> pn.handshakeSetupType(), negType);
> if(logMINOR)
> Logger.minor(this, "Sending handshake to "+peer+" for
> "+pn);
> pn.sentHandshake();
> @@ -2794,7 +2794,7 @@
> }
>
> public int[] supportedNegTypes() {
> - return new int[] { 2 };
> + return new int[] { 2, 3 };
> }
>
> public int fullHeadersLengthOneMessage() {
>
> Modified: trunk/freenet/src/freenet/node/PacketTracker.java
> ===================================================================
> --- trunk/freenet/src/freenet/node/PacketTracker.java 2008-12-02 13:55:19
> UTC (rev 24013)
> +++ trunk/freenet/src/freenet/node/PacketTracker.java 2008-12-02 18:51:25
> UTC (rev 24014)
> @@ -107,6 +107,7 @@
> */
> public void deprecated() {
> logMINOR = Logger.shouldLog(Logger.MINOR, this);
> + if(logMINOR) Logger.minor(this, "Deprecated: "+this);
> isDeprecated = true;
> sentPacketsContents.interrupt();
> }
> @@ -1009,6 +1010,10 @@
> * *** Must only be called if the KeyTracker is not to be kept.
> Otherwise, we may receive some packets twice. ***
> */
> public void completelyDeprecated(KeyTracker newTracker) {
> + if(newTracker.packets == this) {
> + Logger.error(this, "Completely deprecated in favour
> of self!");
> + return;
> + }
> if(logMINOR)
> Logger.minor(this, "Completely deprecated: " + this +
> " in favour of " + newTracker);
> LimitedRangeIntByteArrayMapElement[] elements = clear();
>
> Modified: trunk/freenet/src/freenet/node/PeerNode.java
> ===================================================================
> --- trunk/freenet/src/freenet/node/PeerNode.java 2008-12-02 13:55:19
> UTC (rev 24013)
> +++ trunk/freenet/src/freenet/node/PeerNode.java 2008-12-02 18:51:25
> UTC (rev 24014)
> @@ -1805,7 +1805,7 @@
> * @param replyTo The IP the handshake came in on.
> * @return True unless we rejected the handshake, or it failed to parse.
> */
> - public boolean completedHandshake(long thisBootID, byte[] data, int
> offset, int length, BlockCipher encCipher, byte[] encKey, Peer replyTo,
> boolean unverified) {
> + public boolean completedHandshake(long thisBootID, byte[] data, int
> offset, int length, BlockCipher encCipher, byte[] encKey, Peer replyTo,
> boolean unverified, int negType) {
> logMINOR = Logger.shouldLog(Logger.MINOR, PeerNode.class);
> long now = System.currentTimeMillis();
>
> @@ -1852,15 +1852,13 @@
> routable = false;
> } else
> older = false;
> - PacketTracker packets = new PacketTracker(this);
> - KeyTracker newTracker = new KeyTracker(this, packets,
> encCipher, encKey);
> - if(logMINOR) Logger.minor(this, "New key tracker in
> completedHandshake: "+newTracker+" for "+shortToString());
> changedIP(replyTo);
> boolean bootIDChanged = false;
> boolean wasARekey = false;
> KeyTracker oldPrev = null;
> KeyTracker oldCur = null;
> KeyTracker prev = null;
> + KeyTracker newTracker;
> MessageItem[] messagesTellDisconnected = null;
> synchronized(this) {
> handshakeCount = 0;
> @@ -1887,7 +1885,11 @@
> } else if(bootIDChanged && logMINOR)
> Logger.minor(this, "Changed boot ID from " +
> bootID + " to " + thisBootID + " for " + getPeer());
> this.bootID = thisBootID;
> + PacketTracker packets;
> + boolean newPacketTracker = false;
> if(bootIDChanged) {
> + packets = new PacketTracker(this);
> + newPacketTracker = true;
> oldPrev = previousTracker;
> oldCur = currentTracker;
> previousTracker = null;
> @@ -1897,7 +1899,22 @@
> // connection initial messages by
> maybeOnConnect().
> messagesTellDisconnected =
> grabQueuedMessageItems();
> this.offeredMainJarVersion = 0;
> - } // else it's a rekey
> + } else {
> + // else it's a rekey
> + if(currentTracker != null &&
> currentTracker.packets.isDeprecated()) {
> + packets = new PacketTracker(this);
> + newPacketTracker = true;
> + } else if(currentTracker != null && negType
> >= 3)
> + packets = currentTracker.packets;
> + else if(previousTracker != null && negType >=
> 3)
> + packets = previousTracker.packets;
> + else {
> + packets = new PacketTracker(this);
> + newPacketTracker = true;
> + }
> + }
> + newTracker = new KeyTracker(this, packets, encCipher,
> encKey);
> + if(logMINOR) Logger.minor(this, "New key tracker in
> completedHandshake: "+newTracker+" for "+shortToString()+" neg type
> "+negType+" new packet tracker: "+newPacketTracker);
> if(unverified) {
> if(unverifiedTracker != null) {
> // Keep the old unverified tracker if
> possible.
> @@ -1941,11 +1958,11 @@
> node.lm.lostOrRestartedNode(this);
> node.usm.onRestart(this);
> }
> - if(oldPrev != null)
> + if(oldPrev != null && oldPrev.packets != newTracker.packets)
> oldPrev.packets.completelyDeprecated(newTracker);
> - if(oldCur != null)
> + if(oldCur != null && oldCur.packets != newTracker.packets)
> oldCur.packets.completelyDeprecated(newTracker);
> - if(prev != null)
> + if(prev != null && prev.packets != newTracker.packets)
> prev.packets.deprecated();
> PacketThrottle throttle;
> synchronized(this) {
> @@ -1979,6 +1996,7 @@
> */
> private synchronized void maybeSwapTrackers() {
> if(currentTracker == null || previousTracker == null) return;
> + if(currentTracker.packets == previousTracker.packets) return;
> long delta = Math.abs(currentTracker.packets.createdTime -
> previousTracker.packets.createdTime);
> if(previousTracker != null &&
> (!previousTracker.packets.isDeprecated()) &&
> delta < CHECK_FOR_SWAPPED_TRACKERS_INTERVAL) {
> @@ -2006,9 +2024,9 @@
> KeyTracker temp = previousTracker;
> previousTracker = currentTracker;
> currentTracker = temp;
> - if(logMINOR) Logger.minor(this, "Swapped
> KeyTracker's on "+this+" cur "+currentTracker+" prev "+previousTracker);
> + if(logMINOR) Logger.minor(this, "Swapped
> KeyTracker's on "+this+" cur "+currentTracker+" prev "+previousTracker+"
> delta "+delta+" cur.deprecated="+currentTracker.packets.isDeprecated()+"
> prev.deprecated="+previousTracker.packets.isDeprecated());
> } else {
> - if(logMINOR) Logger.minor(this, "Not swapping
> KeyTracker's on "+this+" cur "+currentTracker+" prev "+previousTracker);
> + if(logMINOR) Logger.minor(this, "Not swapping
> KeyTracker's on "+this+" cur "+currentTracker+" prev "+previousTracker+"
> delta "+delta+" cur.deprecated="+currentTracker.packets.isDeprecated()+"
> prev.deprecated="+previousTracker.packets.isDeprecated());
> }
> } else {
> if (logMINOR)
> @@ -2160,7 +2178,7 @@
> peerAddedTime = 0; // don't store anymore
> ctx = null;
> maybeSwapTrackers();
> - if(previousTracker != null)
> + if(previousTracker != null &&
> previousTracker.packets != currentTracker.packets)
> previousTracker.packets.deprecated();
> } else
> return;
>
> _______________________________________________
> cvs mailing list
> cvs at freenetproject.org
> http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs
>