Author: toad
Date: 2008-12-17 14:42:10 +0000 (Wed, 17 Dec 2008)
New Revision: 24442

Modified:
   
branches/db4o/freenet/src/freenet/clients/http/staticfiles/themes/clean/theme.css
   branches/db4o/freenet/src/freenet/io/NetworkInterface.java
   branches/db4o/freenet/src/freenet/io/comm/PeerContext.java
   branches/db4o/freenet/src/freenet/io/xfer/BlockTransmitter.java
   branches/db4o/freenet/src/freenet/io/xfer/BulkTransmitter.java
   branches/db4o/freenet/src/freenet/io/xfer/PacketThrottle.java
   branches/db4o/freenet/src/freenet/l10n/freenet.l10n.fi.properties
   branches/db4o/freenet/src/freenet/node/FailureTable.java
   branches/db4o/freenet/src/freenet/node/OpennetManager.java
   branches/db4o/freenet/src/freenet/node/OpennetPeerNode.java
   branches/db4o/freenet/src/freenet/node/PacketSender.java
   branches/db4o/freenet/src/freenet/node/PeerNode.java
   branches/db4o/freenet/src/freenet/node/PeerNodeStatus.java
   branches/db4o/freenet/src/freenet/node/RequestHandler.java
   branches/db4o/freenet/src/freenet/node/SSKInsertSender.java
   branches/db4o/freenet/src/freenet/node/Version.java
   branches/db4o/freenet/src/freenet/node/updater/NodeUpdateManager.java
   branches/db4o/freenet/src/freenet/node/updater/NodeUpdater.java
   
branches/db4o/freenet/src/freenet/node/updater/UpdateOverMandatoryManager.java
   branches/db4o/freenet/src/freenet/pluginmanager/PluginManager.java
   branches/db4o/freenet/src/freenet/support/TransferThread.java
Log:
Merge all the M's


Modified: 
branches/db4o/freenet/src/freenet/clients/http/staticfiles/themes/clean/theme.css
===================================================================
--- 
branches/db4o/freenet/src/freenet/clients/http/staticfiles/themes/clean/theme.css
   2008-12-17 14:41:55 UTC (rev 24441)
+++ 
branches/db4o/freenet/src/freenet/clients/http/staticfiles/themes/clean/theme.css
   2008-12-17 14:42:10 UTC (rev 24442)
@@ -206,6 +206,7 @@
        padding: 0;
        position: absolute;
        left: 177px;
+       right: 0px;
 }

 a {

Modified: branches/db4o/freenet/src/freenet/io/NetworkInterface.java
===================================================================
--- branches/db4o/freenet/src/freenet/io/NetworkInterface.java  2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/io/NetworkInterface.java  2008-12-17 
14:42:10 UTC (rev 24442)
@@ -174,6 +174,7 @@
                for (Acceptor acceptor : acceptors) {
                        acceptor.setSoTimeout(timeout);
                }
+               this.timeout = timeout;
        }

        /**
@@ -190,6 +191,9 @@
        public Socket accept() throws SocketTimeoutException {
                synchronized (syncObject) {
                        while (acceptedSockets.size() == 0) {
+                               if (acceptors.size() == 0) {
+                                       throw new SocketTimeoutException();
+                               }
                                try {
                                        syncObject.wait(timeout);
                                } catch (InterruptedException ie1) {

Modified: branches/db4o/freenet/src/freenet/io/comm/PeerContext.java
===================================================================
--- branches/db4o/freenet/src/freenet/io/comm/PeerContext.java  2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/io/comm/PeerContext.java  2008-12-17 
14:42:10 UTC (rev 24442)
@@ -38,7 +38,7 @@

        /** Send a throttled message to the node (may block for a long time). 
         * @throws SyncSendWaitedTooLongException */
-       public void sendThrottledMessage(Message msg, int packetSize, 
ByteCounter ctr, int timeout, boolean waitForSent) throws 
NotConnectedException, WaitedTooLongException, SyncSendWaitedTooLongException;
+       public void sendThrottledMessage(Message msg, int packetSize, 
ByteCounter ctr, int timeout, boolean waitForSent, AsyncMessageCallback 
callback) throws NotConnectedException, WaitedTooLongException, 
SyncSendWaitedTooLongException;

        /** Get the current boot ID. This is a random number that changes every 
time the node starts up. */
        public long getBootID();

Modified: branches/db4o/freenet/src/freenet/io/xfer/BlockTransmitter.java
===================================================================
--- branches/db4o/freenet/src/freenet/io/xfer/BlockTransmitter.java     
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/io/xfer/BlockTransmitter.java     
2008-12-17 14:42:10 UTC (rev 24442)
@@ -98,7 +98,7 @@
                                        }
                                        int totalPackets;
                                        try {
-                                               
_destination.sendThrottledMessage(DMT.createPacketTransmit(_uid, packetNo, 
_sentPackets, _prb.getPacket(packetNo)), _prb._packetSize, _ctr, SEND_TIMEOUT, 
false);
+                                               
_destination.sendThrottledMessage(DMT.createPacketTransmit(_uid, packetNo, 
_sentPackets, _prb.getPacket(packetNo)), _prb._packetSize, _ctr, SEND_TIMEOUT, 
false, null);
                                                
totalPackets=_prb.getNumPackets();
                                        } catch (NotConnectedException e) {
                                                Logger.normal(this, 
"Terminating send: "+e);

Modified: branches/db4o/freenet/src/freenet/io/xfer/BulkTransmitter.java
===================================================================
--- branches/db4o/freenet/src/freenet/io/xfer/BulkTransmitter.java      
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/io/xfer/BulkTransmitter.java      
2008-12-17 14:42:10 UTC (rev 24442)
@@ -3,6 +3,7 @@
  * http://www.gnu.org/ for further details of the GPL. */
 package freenet.io.xfer;

+import freenet.io.comm.AsyncMessageCallback;
 import freenet.io.comm.AsyncMessageFilterCallback;
 import freenet.io.comm.ByteCounter;
 import freenet.io.comm.DMT;
@@ -190,7 +191,7 @@
        public boolean send() {
                boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
                long lastSentPacket = System.currentTimeMillis();
-               while(true) {
+outer: while(true) {
                        if(prb.isAborted()) {
                                if(logMINOR)
                                        Logger.minor(this, "Aborted "+this);
@@ -217,8 +218,30 @@
                                        completed();
                                        return true;
                                }
-                               // Wait for a packet, BulkReceivedAll or 
BulkReceiveAborted
                                synchronized(this) {
+                                       // Wait for all packets to complete
+                                       while(true) {
+                                               if(failedPacket) {
+                                                       cancel("Packet send 
failed");
+                                                       return false;
+                                               }
+                                               
if(Logger.shouldLog(Logger.MINOR, this))
+                                                       Logger.minor(this, 
"Waiting for packets: remaining: "+inFlightPackets);
+                                               if(inFlightPackets == 0) break;
+                                               try {
+                                                       wait();
+                                                       if(failedPacket) {
+                                                               cancel("Packet 
send failed");
+                                                               return false;
+                                                       }
+                                                       if(inFlightPackets == 
0) break;
+                                                       continue outer; // 
Might be a packet...
+                                               } catch (InterruptedException 
e) {
+                                                       // Ignore
+                                               }
+                                       }
+                                       
+                                       // Wait for a packet to come in, 
BulkReceivedAll or BulkReceiveAborted
                                        try {
                                                wait(60*1000);
                                        } catch (InterruptedException e) {
@@ -229,7 +252,7 @@
                                long end = System.currentTimeMillis();
                                if(end - lastSentPacket > TIMEOUT) {
                                        Logger.error(this, "Send timed out on 
"+this);
-                                       cancel("Timeout");
+                                       cancel("Timeout awaiting 
BulkReceivedAll");
                                        return false;
                                }
                                continue;
@@ -245,7 +268,8 @@

                        // Congestion control and bandwidth limiting
                        try {
-                               
peer.sendThrottledMessage(DMT.createFNPBulkPacketSend(uid, blockNo, buf), 
buf.length, ctr, BulkReceiver.TIMEOUT, false);
+                               if(logMINOR) Logger.minor(this, "Sending packet 
"+blockNo);
+                               
peer.sendThrottledMessage(DMT.createFNPBulkPacketSend(uid, blockNo, buf), 
buf.length, ctr, BulkReceiver.TIMEOUT, false, new UnsentPacketTag());
                                synchronized(this) {
                                        blocksNotSentButPresent.setBit(blockNo, 
false);
                                }
@@ -266,6 +290,56 @@
                }
        }

+       private int inFlightPackets = 0;
+       private boolean failedPacket = false;
+       
+       private class UnsentPacketTag implements AsyncMessageCallback {
+
+               private boolean finished;
+               
+               private UnsentPacketTag() {
+                       synchronized(BulkTransmitter.this) {
+                               inFlightPackets++;
+                       }
+               }
+               
+               public void acknowledged() {
+                       complete(false);
+               }
+
+               private void complete(boolean failed) {
+                       synchronized(this) {
+                               if(finished) return;
+                               finished = true;
+                       }
+                       synchronized(BulkTransmitter.this) {
+                               if(failed) {
+                                       failedPacket = true;
+                                       BulkTransmitter.this.notifyAll();
+                                       if(Logger.shouldLog(Logger.MINOR, 
this)) Logger.minor(this, "Packet failed for "+BulkTransmitter.this);
+                               } else {
+                                       inFlightPackets--;
+                                       if(inFlightPackets <= 0)
+                                               
BulkTransmitter.this.notifyAll();
+                                       if(Logger.shouldLog(Logger.MINOR, 
this)) Logger.minor(this, "Packet sent "+BulkTransmitter.this+" remaining in 
flight: "+inFlightPackets);
+                               }
+                       }
+               }
+
+               public void disconnected() {
+                       complete(true);
+               }
+
+               public void fatalError() {
+                       complete(true);
+               }
+
+               public void sent() {
+                       // Wait for acknowledgment
+               }
+               
+       }
+       
        @Override
        public String toString() {
                return "BulkTransmitter:"+uid+":"+peer.shortToString();

Modified: branches/db4o/freenet/src/freenet/io/xfer/PacketThrottle.java
===================================================================
--- branches/db4o/freenet/src/freenet/io/xfer/PacketThrottle.java       
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/io/xfer/PacketThrottle.java       
2008-12-17 14:42:10 UTC (rev 24442)
@@ -146,7 +146,7 @@
                return ((PACKET_SIZE * 1000.0 / getDelay()));
        }

-       public void sendThrottledMessage(Message msg, PeerContext peer, int 
packetSize, ByteCounter ctr, long deadline, boolean blockForSend) throws 
NotConnectedException, ThrottleDeprecatedException, WaitedTooLongException, 
SyncSendWaitedTooLongException {
+       public void sendThrottledMessage(Message msg, PeerContext peer, int 
packetSize, ByteCounter ctr, long deadline, boolean blockForSend, 
AsyncMessageCallback cbForAsyncSend) throws NotConnectedException, 
ThrottleDeprecatedException, WaitedTooLongException, 
SyncSendWaitedTooLongException {
                long start = System.currentTimeMillis();
                long bootID = peer.getBootID();
                synchronized(this) {
@@ -226,7 +226,7 @@
                        Logger.error(this, "Congestion control wait time: 
"+waitTime+" for "+this);
                else if(logMINOR)
                        Logger.minor(this, "Congestion control wait time: 
"+waitTime+" for "+this);
-               MyCallback callback = new MyCallback();
+               MyCallback callback = new MyCallback(cbForAsyncSend);
                try {
                        peer.sendAsync(msg, callback, ctr);
                        ctr.sentPayload(packetSize);
@@ -266,6 +266,12 @@

                private boolean finished = false;

+               private AsyncMessageCallback chainCallback;
+               
+               public MyCallback(AsyncMessageCallback cbForAsyncSend) {
+                       this.chainCallback = cbForAsyncSend;
+               }
+
                public void acknowledged() {
                        synchronized(PacketThrottle.this) {
                                if(finished) {
@@ -277,6 +283,7 @@
                                PacketThrottle.this.notifyAll();
                        }
                        if(logMINOR) Logger.minor(this, "Removed packet: acked 
for "+this);
+                       if(chainCallback != null) chainCallback.acknowledged();
                }

                public void disconnected() {
@@ -287,6 +294,7 @@
                                PacketThrottle.this.notifyAll();
                        }
                        if(logMINOR) Logger.minor(this, "Removed packet: 
disconnected for "+this);
+                       if(chainCallback != null) chainCallback.disconnected();
                }

                public void fatalError() {
@@ -297,10 +305,12 @@
                                PacketThrottle.this.notifyAll();
                        }
                        if(logMINOR) Logger.minor(this, "Removed packet: error 
for "+this);
+                       if(chainCallback != null) chainCallback.fatalError();
                }

                public void sent() {
                        // Ignore
+                       if(chainCallback != null) chainCallback.sent();
                }

                @Override

Modified: branches/db4o/freenet/src/freenet/l10n/freenet.l10n.fi.properties
===================================================================
--- branches/db4o/freenet/src/freenet/l10n/freenet.l10n.fi.properties   
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/l10n/freenet.l10n.fi.properties   
2008-12-17 14:42:10 UTC (rev 24442)
@@ -1,3 +1,8 @@
+Announcer.announceAlertShort=Solmu yritt?? yhdist?? verkkoon, se on eritt?in 
hidas jonkin aikaa.
+Announcer.announceDisabledTooOld=Solmu n?ytt?isi olevan liian vanha 
yhdist??kseen Freenettiin. Solmu otti pois k?yt?st? itsens? ilmoittamisen, 
sill? se olisi turhaa. Sinun kannattaa p?ivitt?? solmusi mahdollisimman 
nopeasti (automaattip?ivitys voi odottaa sy?tett? tai se voi olla poi k?yt?st?).
+Announcer.announceLoading=Freenet yritt?? parhaillaan ladata 
l?hdesolmutiedostoa, jotta se voi yritt?? ilmoittaa itsest??n muulle verkolle. 
Ilmoittaminen voi ottaa muutamia minuutteja.
+Announcer.coolingOff=Seuraavien ${time] sekuntien aikana solmu odottaa muita 
solmuja, joille se ilmoitti yhdist?v?ns?. Jos sill? ei ole tarpeeksi solmuja, 
se yritt?? toista solmua.
+Announcer.dontKnowAddress=Freenet ei viel? ole kyennyt tunnistamaan 
IP-osoitettaan. Solmu ei kykene ilmoittamaan itsest??n ennen t?t? tietoa.
 BookmarkEditorToadlet.addBookmark=Lis?? kirjanmerkki
 BookmarkEditorToadlet.addCategory=Lis?? kategoria
 BookmarkEditorToadlet.addDefaultBookmarks=Uudelleenlis?? alkuper?iset 
kirjanmerkit
@@ -190,7 +195,7 @@
 DarknetConnectionsToadlet.urlReference=Referenssin osoite:
 DarknetConnectionsToadlet.versionTitle=Versio
 ExtOldAgeUserAlert.extTooOldTitle=Freenet-ext on liian vanha
-FNPPacketMangler.somePeersDisconnectedStillNotAcked=Mahdollisesti virhe: 
${count} vertaista pakotettu sulkemaan yhteys hyv?ksym?tt?mien pakettien takia.
+FNPPacketMangler.somePeersDisconnectedStillNotAcked=Mahdollinen ohjelmavirhe: 
${count} vertaista pakotettu sulkemaan yhteys hyv?ksym?tt?mien pakettien takia.
 FNPPacketMangler.somePeersDisconnectedStillNotAckedDetail=${count}:lla 
vertaisistasi on vakavia ongelmia (eiv?t ole hyv?ksyneet pakettejasi kymmenen 
minuutin kuluessa). T?m? on luultavasti koodivirhe. Toivomme sinun ilmoittavan 
t?m?n virheen Freenetin vianseurantaan osoitteessa 
${link}https://bugs.freenetproject.org/${/link} tai s?hk?postiosoitteeseen 
support at freenetproject.org. Muista lis?t? t?m? viesti ja tieto py?ritt?m?si 
solmun versiosta. Ongelman vaivaamat vertaiset (et varmaankaan halua lis?t? 
niit? virheilmoitukseen, jos ne ovat sinun darknet-vertaisiasi) ovat:
 FProxyToadlet.abortToHomepage=Peru ja siirry FProxyn etusivulle.
 FProxyToadlet.alertsTitle=H?lytykset
@@ -321,8 +326,15 @@
 KnownUnsafeContentTypeException.knownUnsafe=T?m? on mahdollisesti vaarallinen 
MIME-tyyppi. Jos solmu p??st?? sen l?pi, selaimesi saattaa tehd? pahoja 
asioita, jotka vaarantavat yksityisyytesi, ja sivustosi saattaa n?ky? 
yhteydesss? t?h?n sivuun. Erityisesti:
 KnownUnsafeContentTypeException.noFilter=Koska t?lle datalle ei ole 
sis??nrakennettua filtteri?, sinun kannattaa olla erityisen varovainen!
 KnownUnsafeContentTypeException.title=Tunnettu vaarallinen tyyppi: ${type}
+LocalFileInsertToadlet.checkPathExist=Tarkista, ett? m??ritetty polku on 
olemassa.
+LocalFileInsertToadlet.checkPathIsDir=Tarkista, ett? m??ritelty polku on 
hakemisto.
+LocalFileInsertToadlet.checkPathReadable=Tarkista, ett? m??r?tty polku voidaan 
lukea solmua py?ritt?v?n tunnuksen toimesta.
+LocalFileInsertToadlet.dirAccessDenied=Et voi selata t?t? hakemistoa
+LocalFileInsertToadlet.dirCannotBeRead=Hakemistoa "${path}" ei voida lukea.
 LocalFileInsertToadlet.fileHeader=Tiedosto
 LocalFileInsertToadlet.insert=Lis??
+LocalFileInsertToadlet.listing=Hakemistolistaus: ${path}
+LocalFileInsertToadlet.listingTitle=Hakemiston ${path} hakemistolistaus
 LocalFileInsertToadlet.sizeHeader=Koko
 LogConfigHandler.minLoggingPriority=Pienin prioriteetti lokiviesteille
 LogConfigHandler.minLoggingPriorityLong=Pienin prioriteetti, jolla viestit 
kirjoitetaan lokiin. Vaihtoehdot ovat debug(testaus), minor(v?h?inen), 
normal(vakio), error(virheet), ??nekk?imm?st? hiljaisimpaan.
@@ -358,24 +370,38 @@
 Node.outBWLimitLong=Kova rajoitus l?hetysnopeudelle (tavua / sekunti). solmun 
ei pit?isi k?yt?nn?ss? koskaan ylitt?? t?t?.
 Node.storeSize=Varaston koko tavuissa
 Node.storeSizeLong=Varaston koko tavuissa
+NodeClientCore.couldNotFindOrCreateDir=Hakemistoa ei l?ytynyt tai sit? ei 
voinut luoda.
+NodeClientCore.downloadAllowedDirs=Hakemistot, joihin lataaminen on sallittua
+NodeClientCore.downloadAllowedDirsLong=Puolipisteell? eroteltu lista 
hakemistoista, joista lataaminen on sallittua. "downloads" tarkoittaa 
downloadDir:?, tyhj? tarkoittaa, ettei levylle tallentaminen ole sallittua, 
"all" sallii lataukset kaikkialle. VAROITUS! Jos t?m? on asetettu "all":ksi, 
jokainen k?ytt?j?, jolla on FCP-oikeudet, voi ladata mink? tahansa tiedoston 
koneeltasi!
+NodeClientCore.downloadDir=Ensisijainen lataushakemisto
 NodeClientCore.downloadDirLong=Ladattavien tiedostojen oletustallennuspaikka
 NodeClientCore.encryptPersistentTempBuckets=Kryptaa sinnikk?iden 
v?liaikaistiedostot? ?L? KOSKE T?H?N!
+NodeClientCore.encryptPersistentTempBucketsLong=Salaa sinnikk?t v?liaikaiset 
s?ili?t? Joissakin tapauksissa (jos k?yt?t kiintolevy- ja 
sivutustiedostosalausta) v?liaikaisten s?ili?iden salaaminen voi olla t?ysin 
turhaa. ?L? KOSKE T?H?N ELLET TIED?, MIT? OLET TEKEM?SS?!
 NodeClientCore.encryptTempBuckets=Kryptaa v?liaikaiset s?ili?t? ?L? KOSKE 
T?H?N!
 NodeClientCore.encryptTempBucketsLong=Kryptaa v?liaikaiset s?ili?t? Joissakin 
tapauksissa (jos k?yt?t kiintolevy- ja swap-kryptausta) ei kenties ole mit??n 
j?rke? kryptata v?liaikaisia s?ili?it?. ?L? KOSKE T?H?N JOS ET TIED?, MIT? OLET 
TKEM?SS?!
 NodeClientCore.fileForClientStats=Tiedosto, johon tallennetaan asiakasohjelman 
statistiikat
+NodeClientCore.fileForClientStatsLong=Tiedosto, johon tallennetaan klientin 
kuristusstatistiikka (k?ytet??n pyynt?jen l?hetysm??r?n m??rittelemiseen)
+NodeClientCore.lazyResume=T?ydellinen sinnikk?iden pyynt?jen lataus 
k?ynnistyksen j?lkeen? (kuluttaa enemm?n muistia)
+NodeClientCore.lazyResumeLong=Solmu voi ladata sinnikk??t jonossa olevat 
pyynn?t k?ynnistyksen yhteydess?, tai se voi lukea datan muistiin ja sitten 
viimeistell? pyynt?jen jatkmasisprosessin solmun k?ynnistytty?. Lyhent?? 
k?ynnistysaikoja, mutta k?ytt?? enemm?n muistia.
 NodeClientCore.maxArchiveSize=Maksimikoko arkistoille.
 NodeClientCore.maxArchiveSizeLong=Suurin sallittu koko mille tahansa arkistolle
 NodeClientCore.maxRAMBucketSize=Suurin sallittu koko k?ytt?muistis?ili?lle.
+NodeClientCore.maxRAMBucketSizeLong=Suurin mahdollinen koko 
v?limuistis?ili?lle (suuremmat s?ili?t pidet??n kiintolevyll?)
+NodeClientCore.maxUSKFetchers=Suurin sallittu USK-hakijoiden m??r?
+NodeClientCore.maxUSKFetchersLong=Suurin USK-hakijoiden sallittu m??r?
 NodeClientCore.maxUSKFetchersMustBeGreaterThanZero=T?ytyy olla suurempi kuin 
nolla
+NodeClientCore.movingTempDirOnTheFlyNotSupported=V?liaikaishakemiston siirtoa 
lennosta ei tueta t?ll? hetkell?.
 NodeClientCore.persistentTempDir=Sinnikk?iden v?liaikaistiedostojen hakemisto
 NodeClientCore.persistentTempDirLong=Sinnikk?iden v?liaikaistiedostojen 
hakemiston nimi
 NodeClientCore.ramBucketPoolSize=V?liaikaistiedostoille varattu k?ytt?muisti
 NodeClientCore.ramBucketPoolSizeLong=V?liaikaisille s?ili?ille varattu RAM. 
Enemm?n muistia tarkoittaa pienemp?? levynk?ytt??.
+NodeClientCore.startingUp=Salli Freenetille muutama hetki viimeistell? 
k?ynnistysprosessi. Voit k?ytt?? solmua, mutta jotkin asiat saattavat olla 
toimimatta, ja solmu voi toimia hitaammin kuin normaalisti.
 NodeClientCore.startingUpShort=Freenet on k?ynnistym?ss?, jotkin toiminnot 
eiv?t v?ltt?m?tt? toimi, ja solmu voi toimia hitaasti.
 NodeClientCore.startingUpTitle=Freenet on k?ynnistym?ss?
 NodeClientCore.tempDir=V?liaikaistiedostojen hakemisto
 NodeClientCore.tempDirLong=V?liaikaistiedostojen hakemiston nimi
 NodeClientCore.uploadAllowedDirs=Hakemistot, joista l?hett?minen on sallittu
+NodeClientCore.uploadAllowedDirsLong=Puolipisteell? eroteltu lista 
hakemistoista, joista l?hett?minen on sallittua. Tyhj? tarkoittaa, ettei 
l?hetykset ole sallittuja, "all" sallii l?hetykset kaikkialle. VAROITUS! Jos 
t?m? on asetettu "all":ksi, jokainen k?ytt?j?, jolla on FCP-oikeudet, voi 
l?hett?? mink? tahansa tiedoston k?ytt?en konettasi.
 NodeIPDectector.inclLocalAddress=Sis?llyt? paikalliset osoitteet 
solmuviitteeseen
 NodeIPDectector.inclLocalAddressLong=M??ritt??, sis?llytet??nk? paikalliset 
osoitteet(LAN ja localhost) solmun viitteisiin. T?m? ei ole hy?dyllist?, 
elleiv?t molemmat puolet aseta kohtaa allowLocalAddresses=true toistensa 
referensseihin.
 NodeIPDectector.ipOverride=IP-osoitteen korvaus
@@ -386,8 +412,24 @@
 NodeIPDetector.maybeSymmetricShort=Yhteysongelmia: saatat olla symmetrisen 
NATin takana.
 NodeIPDetector.maybeSymmetricTitle=Yhteysongelmia
 NodeIPDetector.unknownHostErrorInIPOverride=Tuntematon is?nt?: ${error}
+NodeUpdateManager.enabled=Lataa uudet Freenet-versiot
+NodeUpdateManager.enabledLong=Solmusi etsii uusia versioita Freenetist? 
automaattisesti? Jos etsii, uudet versiot tunnistetaan ja ladataan 
automaattisesti, mutta ei v?ltt?m?tt? asenneta. T?m? asetus muuttuu takaisin 
ep?todeksi, ellei solmua ajeta wrapper:lla.
+NodeUpdateManager.extURI=Mist? solmun pit?isi etsi? p?ivityksi? 
freenet-ext.jar:a varten?
+NodeUpdateManager.extURILong=Mist? solmun pit?isi etsi? p?ivityksi? 
freenet-ext.jar:a varten?
 NodeUpdateManager.installNewVersions=Asenna automaattisesti uudet versiot.
 NodeUpdateManager.installNewVersionsLong=M??ritt??, asentaako solmu 
p?ivitykset automaattisesti, kysym?tt? sinulta.
+NodeUpdateManager.invalidExtURI=Ep?kelpo ext-URI: ${error}
+NodeUpdateManager.invalidRevocationURI=Ep?kelpo mullistus-URI: ${error}
+NodeUpdateManager.invalidUpdateURI=Ep?kelpo p?ivitys-URI: ${error}
+NodeUpdateManager.noUpdateWithoutWrapper=Ei voida p?ivitt??, koska solmu ei 
py?ri wrapperin alla.
+NodeUpdateManager.revocationURI=Mist? solmun pit?isi etsi? mullistusavainta?
+NodeUpdateManager.revocationURILong=Mullistusavaimen URI. Jos t?m? l?ydet??n, 
solmu n?ytt?? sen sis?ll?n ja ottaa automaattip?ivitt?j?n pois k?yt?st?.
+NodeUpdateManager.updateCatastropheTitle=Katastrofaalinen p?ivitysvirhe!
+NodeUpdateManager.updateFailed=P?ivitys ep?onnistui: ${reason}
+NodeUpdateManager.updateFailedShort=P?ivitys ep?onnistui: ${reason}
+NodeUpdateManager.updateFailedTitle=P?ivitys ep?onnistui.
+NodeUpdateManager.updateURI=Mist? solmun pit?isi etsi? p?ivityksi??
+NodeUpdateManager.updateURILong=Mist? solmun pit?isi etsi? p?ivityksi??
 NotEnoughNiceLevelsUserAlert.content=Solmusi on huomannut, ett? se py?rii 
tavallista korkeammalla ?nice?-arvolla. Se ei voi suoriutua kunnolla, ellei 
sill? ole tarpeeksi tasoja j?ljell?. (Katso PRIORITY run.sh-tiedostosta ja 
alenna t?t? arvoa)! T?ll? hetkell? solmulla on ${available} tasoa j?ljell? kun 
se tarvitsisi ${required} tasoa.
 NotEnoughNiceLevelsUserAlert.short=Ei tarpeeksi ?nice?-tasoja j?ljell?! Aja 
Freenetti? alemmalla ?nice?-tasolla korjaaksesi ongelman.
 NotEnoughNiceLevelsUserAlert.title=Ei tarpeeksi ?nice?-tasoja j?ljell?!
@@ -396,7 +438,7 @@
 OpennetUserAlert.warning=Freenet py?rii parhaillaan turvattomassa tilassa. On 
helppoa saada selville, ett? sin? py?rit?t Freenetti?, ja yhdist?? solmu 
solmuusi hy?k?t?kseen sinua vastaan. Yrit? saada joitakin yhteyksi? 
luottamiltasi henkil?ilt? ja lis?? heid?t Yst?v?t-sivulle mahdollisimman pian. 
N?in olet paljon v?hemm?n haavoittuvainen. Kun olet lis?nnyt v?hint??n kymmenen 
yst?v?? (henkil?iden lis??minen, joita et tunne, ei lis?? turvallisuuttasi), 
kytke turvaton tila pois ja Freenet-yhteytesi on n?kym?t?n ulkomaailmalle.
 OpennetUserAlert.warningShort=Turvaton tila on k?yt?ss?.
 OpennetUserAlert.warningTitle=Varoitus: turvaton tila on k?yt?ss?. Solmusi 
yhdist?? muukalaisiin.
-PacketSender.somePeersDisconnectedBlockedTooLong=Mahdollisesti virhe, raportoi 
se: ${count} vertaista pakotettu sulkemaan yhteys yli 10 minuuttia jatkuneen 
pakettien torjumisen takia.
+PacketSender.somePeersDisconnectedBlockedTooLong=Mahdollinen ohjelmavirhe: 
${count} vertaista pakotettu sulkemaan yhteys yli 10 minuuttia jatkuneen 
pakettien torjumisen takia.
 PacketSender.somePeersDisconnectedBlockedTooLongDetail=${count}:lla 
vertaisistasi on vakavia ongelmia (pakettien allokointi on ep?onnistunut 
viimeisten 10 minuutin aikana). T?m? on luultavimmin kooodivirheen syyt?. 
Toivomme sinun ilmoittavan t?m?n virheen virheenseurantaan osoitteessa 
${link}https://bugs.freenetproject.org/${/link} tai s?hk?postiosoitteeseen 
support at freenetproject.org. Sis?llyt? t?m? viesti ja tieto t?m?nhetkisest? 
solmusi Freenet-versiosta. Ongelman vaivaamat vertaiset (et luultavasti halua 
sis?llytt?? n?it? ilmoitukseen, mik?li n?m? ovat darknet-vertaisia) ovat:
 PageMaker.modeAdvanced=Kehittynyt rajapinta
 PageMaker.modeAdvancedTooltip=Kehittynyt rajapinta, jota vain kokeneet 
k?ytt?j?t ja kehitt?j?t tarvitsevat
@@ -683,6 +725,12 @@
 TranslationToadlet.translationUpdatedTitle=K??nn?s p?ivitetty!
 UnknownContentTypeException.explanation=Freenettisi ei tied? mit??n t?st? 
MIME-tyypist?. T?m? tarkoittaa, ett? selaimesi saattaa tehd? jotain vaarallista 
t?m?n latauksen takia. Esimerkiksi, monet tiedostomuodot voivat sis?lt?? 
sis?llytettyj? kuvia tai videoita, jotka ladataan www-sivulta; t?m? ei miss??n 
tapauksessa ole vaaratonta, sill? ne voivat tuhota anonyymiteettisi ja 
paljastaa IP-osoitteesi (jos hy?kk??j? py?ritt?? www-sivua tai p??see sen 
lokeihin). Linkit www-sivuille voi olla my?s uhka, melko pitk?lti samasta 
syyst?, kuten my?s erilaiset skriptit.
 UnknownContentTypeException.title=Tuntematon ja mahdollisesti vaarallinen 
sis?lt?tyyppi: ${type}
+UpdateDeployContext.cannotUpdateNoExtJar=freenet-ext.jar:a ei kyetty l?yt?m??n 
wrapper.conf:sta (freenet.jar l?ydettiin: ${mainFilename})
+UpdateDeployContext.cannotUpdateNoJars=Freenetin jar-tiedostoja ei kyet? 
l?yt?m??n wrapper.conf:sta
+UpdateDeployContext.cannotUpdateNoMainJar=freenet.jar:ia ei kyetty l?yt?m??n 
wrapper.conf:sta (freenet-ext.jar l?ydettiin: ${extFilename})
+UpdateDeployContext.updateCatastrophe=KATASTROFAALINEN VIRHE: ${old} 
poistettu, mutta ${new}:? ei voida uudelleennimet? ${old}:ksi. Siisp? SOLMU EI 
TULE K?YNNISTYM??N! Korjaa ongelma siirt?m?ll? ${new} ${old}:ksi k?sin.
+UpdateDeployContext.updateFailedCannotDeleteOldConfig=${old}:ia ei voida 
poistaa, joten ei voi uudelleennimet? sen p??lle. P?ivitys ep?onnistui.
+UpdateDeployContext.updateFailedNonStandardConfig=Ei voida p?ivitt?? 
ep?standardin asetusten takia: written main=${main} ext=${ext} - t?t? ei 
pit?isi tapahtua! Raportoi t?m? kehitt?jille ja liit? mukaan solmusi 
wrapper.conf.
 UpdatedVersionAvailableUserAlert.clickToUpdateNow=Klikkaa t?st? p?ivitt??ksesi 
solmusi heti.
 UpdatedVersionAvailableUserAlert.title=Uusi vakaa versio Freenetist? on 
julkaista, sinun kannattaisi p?ivitt?? mahdollisimman nopeasti
 UpdatedVersionAvailableUserAlert.updateASAPButton=P?ivit? mahdollisimman 
nopeasti

Modified: branches/db4o/freenet/src/freenet/node/FailureTable.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/FailureTable.java    2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/FailureTable.java    2008-12-17 
14:42:10 UTC (rev 24442)
@@ -425,7 +425,7 @@

                                public void run() {
                                        try {
-                                               
source.sendThrottledMessage(data, dataLength, senderCounter, 60*1000, false);
+                                               
source.sendThrottledMessage(data, dataLength, senderCounter, 60*1000, false, 
null);
                                        } catch (NotConnectedException e) {
                                                // :(
                                        } catch (WaitedTooLongException e) {

Modified: branches/db4o/freenet/src/freenet/node/OpennetManager.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/OpennetManager.java  2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/OpennetManager.java  2008-12-17 
14:42:10 UTC (rev 24442)
@@ -14,6 +14,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Enumeration;

 import freenet.io.comm.ByteCounter;
 import freenet.io.comm.DMT;
@@ -301,7 +302,7 @@
                                        Logger.minor(this, "Opennet peer 
already present in LRU: "+nodeToAddNow);
                                return true;
                        }
-                       if(peersLRU.size() < getNumberOfConnectedPeersToAim()) {
+                       if(getSize() < getNumberOfConnectedPeersToAim()) {
                                if(nodeToAddNow != null) {
                                        if(logMINOR) Logger.minor(this, "Added 
opennet peer "+nodeToAddNow+" as opennet peers list not full");
                                        if(addAtLRU)
@@ -332,11 +333,11 @@
                        int maxPeers = getNumberOfConnectedPeersToAim();
                        // If we have dropped a disconnected peer, then the 
inter-peer offer cooldown doesn't apply: we can accept immediately.
                        boolean hasDisconnected = false;
-                       if(peersLRU.size() == maxPeers && nodeToAddNow == null) 
{
+                       if(getSize() == maxPeers && nodeToAddNow == null) {
                                PeerNode toDrop = peerToDrop(true, false);
                                if(toDrop != null)
                                        hasDisconnected = !toDrop.isConnected();
-                       } else while(peersLRU.size() > maxPeers - (nodeToAddNow 
== null ? 0 : 1)) {
+                       } else while(getSize() > maxPeers - (nodeToAddNow == 
null ? 0 : 1)) {
                                OpennetPeerNode toDrop;
                                // can drop peers which are over the limit
                                toDrop = peerToDrop(noDisconnect || 
nodeToAddNow == null, false);
@@ -347,7 +348,7 @@
                                        break;
                                }
                                if(logMINOR)
-                                       Logger.minor(this, "Drop opennet peer: 
"+toDrop+" (connected="+toDrop.isConnected()+") of "+peersLRU.size());
+                                       Logger.minor(this, "Drop opennet peer: 
"+toDrop+" (connected="+toDrop.isConnected()+") of 
"+peersLRU.size()+":"+getSize());
                                if(!toDrop.isConnected())
                                        hasDisconnected = true;
                                peersLRU.remove(toDrop);
@@ -403,7 +404,7 @@
        }

        void dropExcessPeers() {
-               while(peersLRU.size() > getNumberOfConnectedPeersToAim()) {
+               while(getSize() > getNumberOfConnectedPeersToAim()) {
                        if(logMINOR)
                                Logger.minor(this, "Dropping opennet peers: 
currently "+peersLRU.size());
                        PeerNode toDrop;
@@ -417,8 +418,23 @@
                }
        }

+       /**
+        * How many opennet peers do we have?
+        * Connected but out of date nodes don't count towards the connection 
limit. Let them connect for
+        * long enough to auto-update. They will be disconnected eventually, 
and then removed: 
+        * @see OpennetPeerNode.shouldDisconnectAndRemoveNow()
+        */
+       synchronized public int getSize() {
+               int x = 0;
+               for(Enumeration e = peersLRU.elements();e.hasMoreElements();) {
+                       PeerNode pn = (PeerNode) e.nextElement();
+                       if(!(pn.isConnected() && 
pn.isUnroutableOlderVersion())) x++;
+               }
+               return x;
+       }
+
        synchronized OpennetPeerNode peerToDrop(boolean noDisconnect, boolean 
force) {
-               if(peersLRU.size() < getNumberOfConnectedPeersToAim()) {
+               if(getSize() < getNumberOfConnectedPeersToAim()) {
                        // Don't drop any peers
                        return null;
                } else {
@@ -426,6 +442,10 @@
                        OpennetPeerNode[] peers = (OpennetPeerNode[]) 
peersLRU.toArrayOrdered(new OpennetPeerNode[peersLRU.size()]);
                        for(int i=0;i<peers.length;i++) {
                                OpennetPeerNode pn = peers[i];
+                               if(pn.isConnected() && 
pn.isUnroutableOlderVersion()) {
+                                       // Doesn't count anyway.
+                                       continue;
+                               }
                                if(pn == null) continue;
                                if((!pn.isDroppable(false)) && !force) continue;
                                // LOCKING: Always take the OpennetManager lock 
first
@@ -442,6 +462,10 @@
                        for(int i=0;i<peers.length;i++) {
                                OpennetPeerNode pn = peers[i];
                                if(pn == null) continue;
+                               if(pn.isConnected() && 
pn.isUnroutableOlderVersion()) {
+                                       // Doesn't count anyway.
+                                       continue;
+                               }
                                if((!pn.isDroppable(false)) && !force) continue;
                                if(Logger.shouldLog(Logger.MINOR, this))
                                        Logger.minor(this, "Possibly dropping 
opennet peer "+pn+" "+
@@ -480,7 +504,7 @@
                        }
                }
        }
-
+       
        synchronized PeerNode[] getOldPeers() {
                return (PeerNode[]) oldPeers.toArrayOrdered(new 
PeerNode[oldPeers.size()]);
        }

Modified: branches/db4o/freenet/src/freenet/node/OpennetPeerNode.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/OpennetPeerNode.java 2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/OpennetPeerNode.java 2008-12-17 
14:42:10 UTC (rev 24442)
@@ -113,6 +113,9 @@

        @Override
        public final boolean shouldDisconnectAndRemoveNow() {
+               // Allow announced peers 15 minutes to download the auto-update.
+               if(isConnected() && isUnroutableOlderVersion() && 
System.currentTimeMillis() - timeLastConnectionCompleted() > 60*60*1000)
+                       return true;
                return false;
        }


Modified: branches/db4o/freenet/src/freenet/node/PacketSender.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/PacketSender.java    2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/PacketSender.java    2008-12-17 
14:42:10 UTC (rev 24442)
@@ -227,7 +227,7 @@
                        nextActionTime = Math.min(nextActionTime, now + 
canSendAt);
                }

-               int newBrokeAt = 0;
+               int newBrokeAt = brokeAt;
                for(int i = 0; i < nodes.length; i++) {
                        int idx = (i + brokeAt + 1) % nodes.length;
                        PeerNode pn = nodes[idx];
@@ -238,10 +238,12 @@
                                // Might as well do it properly.
                                node.peers.disconnect(pn, true, true, false);
                        }
-                       if(pn.shouldThrottle() && !canSendThrottled)
-                               continue;

                        if(pn.isConnected()) {
+                               
+                               if(pn.shouldThrottle() && !canSendThrottled)
+                                       continue;
+                               
                                // Is the node dead?
                                if(now - pn.lastReceivedPacketTime() > 
pn.maxTimeBetweenReceivedPackets()) {
                                        Logger.normal(this, "Disconnecting from 
" + pn + " - haven't received packets recently");
@@ -256,12 +258,12 @@
                                         */
                                        pn.invalidate();
                                        pn.setPeerNodeStatus(now);
-                                       Logger.normal(this, 
"shouldDisconnectNow has returned true : marking the peer as incompatible");
+                                       Logger.normal(this, 
"shouldDisconnectNow has returned true : marking the peer as incompatible: 
"+pn);
                                        continue;
                                }

                                try {
-                               if(canSendThrottled && pn.maybeSendPacket(now, 
rpiTemp, rpiIntTemp)) {
+                               if((canSendThrottled || !pn.shouldThrottle()) 
&& pn.maybeSendPacket(now, rpiTemp, rpiIntTemp)) {
                                        canSendThrottled = false;
                                        count = node.outputThrottle.getCount();
                                        if(count > MAX_PACKET_SIZE)

Modified: branches/db4o/freenet/src/freenet/node/PeerNode.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/PeerNode.java        2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/PeerNode.java        2008-12-17 
14:42:10 UTC (rev 24442)
@@ -1896,6 +1896,7 @@
                        isRoutable = routable;
                        unroutableNewerVersion = newer;
                        unroutableOlderVersion = older;
+                       boolean notReusingTracker = false;
                        bootIDChanged = (thisBootID != this.bootID);
                        if(bootIDChanged && wasARekey) {
                                Logger.error(this, "Changed boot ID while 
rekeying! from " + bootID + " to " + thisBootID + " for " + getPeer());
@@ -1923,6 +1924,7 @@
                        } else if(trackerID == -1) {
                                // Create a new tracker unconditionally
                                packets = new PacketTracker(this);
+                               notReusingTracker = true;
                                if(logMINOR) Logger.minor(this, "Creating new 
PacketTracker as instructed for "+this);
                        } else if(trackerID == -2 && !bootIDChanged) {
                                // Reuse if not deprecated and not boot ID 
changed
@@ -1934,19 +1936,26 @@
                                        if(logMINOR) Logger.minor(this, 
"Re-using packet tracker (not given an ID): "+packets.trackerID+" on "+this+" 
from prev "+previousTracker);
                                } else {
                                        packets = new PacketTracker(this);
+                                       notReusingTracker = true;
                                        if(logMINOR) Logger.minor(this, "Cannot 
reuse trackers (not given an ID) on "+this);
                                }
                        } else {
                                if(isJFK4 && negType >= 4 && trackerID < 0)
                                        Logger.error(this, "JFK(4) packet with 
neg type "+negType+" has negative tracker ID: "+trackerID);

+                               notReusingTracker = true;
                                if(isJFK4/* && !jfk4SameAsOld implied */ && 
trackerID >= 0) {
                                        packets = new PacketTracker(this, 
trackerID);
                                } else
                                        packets = new PacketTracker(this);
                                if(logMINOR) Logger.minor(this, "Creating new 
tracker (last resort) on "+this);
                        }
-                       if(bootIDChanged) {
+                       if(bootIDChanged || notReusingTracker) {
+                               if((!bootIDChanged) && notReusingTracker)
+                                       // FIXME is this a real problem? 
Clearly the other side has changed trackers for some reason...
+                                       // Normally that shouldn't happen 
except when a connection times out ... it is probably possible
+                                       // for that to timeout on one side and 
not the other ...
+                                       Logger.error(this, "Not reusing 
tracker, so wiping old trackers for "+this);
                                oldPrev = previousTracker;
                                oldCur = currentTracker;
                                previousTracker = null;
@@ -1993,6 +2002,7 @@
                        if(previousTracker != null && unverifiedTracker != null 
&& 
                                        
Arrays.equals(previousTracker.sessionKey, unverifiedTracker.sessionKey))
                                Logger.error(this, "previousTracker key equals 
unverifiedTracker key: prev "+previousTracker+" unv "+unverifiedTracker);
+                       timeLastSentPacket = now;
                }
                if(messagesTellDisconnected != null) {
                        for(int i=0;i<messagesTellDisconnected.length;i++) {
@@ -4034,12 +4044,12 @@
                return resendBytesSent;
        }

-       public void sendThrottledMessage(Message msg, int packetSize, 
ByteCounter ctr, int timeout, boolean blockForSend) throws 
NotConnectedException, WaitedTooLongException, SyncSendWaitedTooLongException {
+       public void sendThrottledMessage(Message msg, int packetSize, 
ByteCounter ctr, int timeout, boolean blockForSend, AsyncMessageCallback 
callback) throws NotConnectedException, WaitedTooLongException, 
SyncSendWaitedTooLongException {
                long deadline = System.currentTimeMillis() + timeout;
                if(logMINOR) Logger.minor(this, "Sending throttled message with 
timeout "+timeout+" packet size "+packetSize+" to "+shortToString());
                for(int i=0;i<100;i++) {
                        try {
-                               getThrottle().sendThrottledMessage(msg, this, 
packetSize, ctr, deadline, blockForSend);
+                               getThrottle().sendThrottledMessage(msg, this, 
packetSize, ctr, deadline, blockForSend, callback);
                                return;
                        } catch (ThrottleDeprecatedException e) {
                                // Try with the new throttle. We don't need it, 
we'll get it from getThrottle().
@@ -4048,6 +4058,7 @@
                }
                Logger.error(this, "Peer constantly changes its IP address!!: 
"+shortToString());
                forceDisconnect(true);
+               throw new NotConnectedException();
        }

        /**
@@ -4117,6 +4128,7 @@
         */
        public boolean maybeSendPacket(long now, Vector<ResendPacketItem> 
rpiTemp, int[] rpiIntTemp) throws BlockedTooLongException {
                // If there are any urgent notifications, we must send a packet.
+               if(logMINOR) Logger.minor(this, "maybeSendPacket: "+this);
                boolean mustSend = false;
                boolean mustSendPacket = false;
                if(mustSendNotificationsNow(now)) {
@@ -4172,9 +4184,12 @@
                // If it's a keepalive, we must add an FNPVoid to ensure it has 
a packet number.
                boolean keepalive = false;

-               if(now - lastSentPacketTime() > Node.KEEPALIVE_INTERVAL) {
+               long lastSent = lastSentPacketTime();
+               if(now - lastSent > Node.KEEPALIVE_INTERVAL) {
                        if(logMINOR)
                                Logger.minor(this, "Sending keepalive");
+                       if(now - lastSent > Node.KEEPALIVE_INTERVAL * 10 && 
lastSent > -1)
+                               Logger.error(this, "Long gap between sending 
packets: "+(now - lastSent)+" for "+this);
                        keepalive = true;
                        mustSend = true;
                        mustSendPacket = true;

Modified: branches/db4o/freenet/src/freenet/node/PeerNodeStatus.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/PeerNodeStatus.java  2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/PeerNodeStatus.java  2008-12-17 
14:42:10 UTC (rev 24442)
@@ -98,9 +98,6 @@
        private final double selectionRate;

        PeerNodeStatus(PeerNode peerNode, boolean noHeavy) {
-               if(Logger.shouldLog(Logger.MINOR, this)) {
-                       Logger.minor(this, "Creating peer node status for 
"+peerNode+" noHeavy="+noHeavy);
-               }
                Peer p = peerNode.getPeer();
                if(p == null) {
                        peerAddress = null;

Modified: branches/db4o/freenet/src/freenet/node/RequestHandler.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/RequestHandler.java  2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/RequestHandler.java  2008-12-17 
14:42:10 UTC (rev 24442)
@@ -349,7 +349,7 @@

                        public void run() {
                                try {
-                                       source.sendThrottledMessage(dataMsg, 
data.length, RequestHandler.this, 60 * 1000, true);
+                                       source.sendThrottledMessage(dataMsg, 
data.length, RequestHandler.this, 60 * 1000, true, null);
                                        applyByteCounts();
                                } catch(NotConnectedException e) {
                                        // Okay
@@ -383,7 +383,7 @@
                source.sendAsync(headersMsg, null, ctr);
                final Message dataMsg = DMT.createFNPSSKDataFoundData(uid, 
data);
                try {
-                       source.sendThrottledMessage(dataMsg, data.length, ctr, 
60 * 1000, false);
+                       source.sendThrottledMessage(dataMsg, data.length, ctr, 
60 * 1000, false, null);
                } catch(SyncSendWaitedTooLongException e) {
                        // Impossible
                        throw new Error(e);

Modified: branches/db4o/freenet/src/freenet/node/SSKInsertSender.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/SSKInsertSender.java 2008-12-17 
14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/SSKInsertSender.java 2008-12-17 
14:42:10 UTC (rev 24442)
@@ -249,7 +249,7 @@

             try {
                                next.sendAsync(headersMsg, null, this);
-                               next.sendThrottledMessage(dataMsg, data.length, 
this, SSKInsertHandler.DATA_INSERT_TIMEOUT, false);
+                               next.sendThrottledMessage(dataMsg, data.length, 
this, SSKInsertHandler.DATA_INSERT_TIMEOUT, false, null);
                        } catch (NotConnectedException e1) {
                                if(logMINOR) Logger.minor(this, "Not connected 
to "+next);
                                continue;

Modified: branches/db4o/freenet/src/freenet/node/Version.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/Version.java 2008-12-17 14:41:55 UTC 
(rev 24441)
+++ branches/db4o/freenet/src/freenet/node/Version.java 2008-12-17 14:42:10 UTC 
(rev 24442)
@@ -24,17 +24,17 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       private static final int buildNumber = 1193;
+       private static final int buildNumber = 1194;

        /** Oldest build of Fred we will talk to */
-       private static final int oldLastGoodBuild = 1192;
-       private static final int newLastGoodBuild = 1193;
+       private static final int oldLastGoodBuild = 1193;
+       private static final int newLastGoodBuild = 1194;
        static final long transitionTime;

        static {
                final Calendar _cal = 
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
                // year, month - 1 (or constant), day, hour, minute, second
-               _cal.set( 2008, Calendar.DECEMBER, 16, 0, 0, 0 );
+               _cal.set( 2008, Calendar.DECEMBER, 19, 0, 0, 0 );
                transitionTime = _cal.getTimeInMillis();
        }


Modified: branches/db4o/freenet/src/freenet/node/updater/NodeUpdateManager.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/updater/NodeUpdateManager.java       
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/updater/NodeUpdateManager.java       
2008-12-17 14:42:10 UTC (rev 24442)
@@ -80,6 +80,9 @@
        private long startedFetchingNextExtJar;
        private long gotJarTime;

+       private int minExtVersion;
+       private int maxExtVersion;
+       
        // Revocation alert
        private RevocationKeyFoundUserAlert revocationAlert;
        // Update alert
@@ -155,6 +158,9 @@

         this.uom = new UpdateOverMandatoryManager(this);
         this.uom.removeOldTempFiles();
+        
+        maxExtVersion = NodeStarter.RECOMMENDED_EXT_BUILD_NUMBER;
+        minExtVersion = NodeStarter.REQUIRED_EXT_BUILD_NUMBER;
        }

        public void start() throws InvalidConfigValueException {
@@ -235,8 +241,8 @@
                                        throw new 
InvalidConfigValueException(l10n("noUpdateWithoutWrapper"));
                                }
                                // Start it
-                               mainUpdater = new NodeUpdater(this, updateURI, 
false, Version.buildNumber(), Integer.MAX_VALUE, "main-jar-");
-                               extUpdater = new NodeUpdater(this, extURI, 
true, NodeStarter.extBuildNumber, NodeStarter.RECOMMENDED_EXT_BUILD_NUMBER, 
"ext-jar-");
+                               mainUpdater = new NodeUpdater(this, updateURI, 
false, Version.buildNumber(), -1, Integer.MAX_VALUE, "main-jar-");
+                               extUpdater = new NodeUpdater(this, extURI, 
true, NodeStarter.extBuildNumber, NodeStarter.REQUIRED_EXT_BUILD_NUMBER, 
NodeStarter.RECOMMENDED_EXT_BUILD_NUMBER, "ext-jar-");
                        }
                }
                if(!enable) {
@@ -357,6 +363,11 @@
                                if(logMINOR) Logger.minor(this, "Not ready: 
Still fetching");
                                return false; // Wait for running fetch to 
complete
                        }
+                       int extVer = getReadyExt();
+                       if(extVer < minExtVersion || extVer > maxExtVersion) {
+                               if(logMINOR) Logger.minor(this, "Invalid ext: 
current "+extVer+" must be between "+minExtVersion+" and "+maxExtVersion);
+                               return false;
+                       }
                        if(!ignoreRevocation) {
                                if(now - revocationChecker.lastSucceeded() < 
RECENT_REVOCATION_INTERVAL)
                                        return true;
@@ -411,6 +422,11 @@
                                        if(logMINOR) Logger.minor(this, "Not 
ready to deploy update");
                                        return;
                                }
+                               int extVer = getReadyExt();
+                               if(extVer < minExtVersion || extVer > 
maxExtVersion) {
+                                       if(logMINOR) Logger.minor(this, 
"Invalid ext: current "+extVer+" must be between "+minExtVersion+" and 
"+maxExtVersion);
+                                       return;
+                               }
                                if(isDeployingUpdate) {
                                        if(logMINOR) Logger.minor(this, 
"Already deploying update");
                                        return;
@@ -600,8 +616,12 @@
        /**
         * Called when a new jar has been downloaded.
         * @param isExt If true, the new jar is the ext jar; if false, it is 
the main jar.
+        * @param recommendedExt If isExt is false, the recommended ext version 
(upper bound)
+        * for the new jar, or -1 if it was not specified or the parse failed.
+        * @param requiredExt If isExt is false, the required ext version 
(lower bound) for the
+        * new jar, or -1 if it was not specified or the parse failed. 
         */
-       void onDownloadedNewJar(boolean isExt) {
+       void onDownloadedNewJar(boolean isExt, int requiredExt, int 
recommendedExt) {
                synchronized(this) {
                        if(isExt) {
                                if(extUpdater.getFetchedVersion() > 
NodeStarter.extBuildNumber) {
@@ -620,12 +640,28 @@
                                                Logger.minor(this, "Got main 
jar: "+mainUpdater.getFetchedVersion());
                                }
                        }
+                       if(!isExt) {
+                               if(requiredExt > -1)
+                                       minExtVersion = requiredExt;
+                               if(recommendedExt > -1)
+                                       maxExtVersion = recommendedExt;
+                       }
                }
+               if(!isExt && (requiredExt > -1 || recommendedExt > -1)) {
+                       extUpdater.setMinMax(requiredExt, recommendedExt);
+               }
                revocationChecker.start(true);
                deployOffThread(REVOCATION_FETCH_TIMEOUT);
                if(!isAutoUpdateAllowed)
                        broadcastUOMAnnounces();
        }
+       
+       private int getReadyExt() {
+               int ver = NodeStarter.extBuildNumber;
+               int fetched = extUpdater.getFetchedVersion();
+               if(fetched > 0) ver = fetched;
+               return ver;
+       }

        /**
         * Called when the NodeUpdater starts to fetch a new version of the jar.

Modified: branches/db4o/freenet/src/freenet/node/updater/NodeUpdater.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/updater/NodeUpdater.java     
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/node/updater/NodeUpdater.java     
2008-12-17 14:42:10 UTC (rev 24442)
@@ -1,9 +1,16 @@
 package freenet.node.updater;

+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.MalformedURLException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;

 import com.db4o.ObjectContainer;

@@ -27,6 +34,7 @@
 import freenet.support.Logger;
 import freenet.support.api.Bucket;
 import freenet.support.io.BucketTools;
+import freenet.support.io.Closer;
 import freenet.support.io.FileBucket;

 public class NodeUpdater implements ClientCallback, USKCallback, RequestClient 
{
@@ -41,18 +49,20 @@
        private final Node node;
        public final NodeUpdateManager manager;
        private final int currentVersion;
+       private int realAvailableVersion;
        private int availableVersion;
        private int fetchingVersion;
        private int fetchedVersion;
        private int writtenVersion;
        private int maxDeployVersion;
+       private int minDeployVersion;
        private boolean isRunning;
        private boolean isFetching;
        public final boolean extUpdate;
        private final String blobFilenamePrefix;
        private File tempBlobFile;

-       NodeUpdater(NodeUpdateManager manager, FreenetURI URI, boolean 
extUpdate, int current, int max, String blobFilenamePrefix) {
+       NodeUpdater(NodeUpdateManager manager, FreenetURI URI, boolean 
extUpdate, int current, int min, int max, String blobFilenamePrefix) {
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
                this.manager = manager;
                this.node = manager.node;
@@ -67,6 +77,7 @@
                this.extUpdate = extUpdate;
                this.blobFilenamePrefix = blobFilenamePrefix;
                this.maxDeployVersion = max;
+               this.minDeployVersion = min;

                FetchContext tempContext = core.makeClient((short) 0, 
true).getFetchContext();
                tempContext.allowSplitfiles = true;
@@ -90,20 +101,28 @@
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
                if(logMINOR)
                        Logger.minor(this, "Found edition " + l);
-               System.err.println("Found " + (extUpdate ? "freenet-ext.jar " : 
"") + "update edition " + l);
                int found;
                synchronized(this) {
                        if(!isRunning)
                                return;
                        found = (int) key.suggestedEdition;

-                       if(found > maxDeployVersion) found = maxDeployVersion;
+                       realAvailableVersion = found;
+                       if(found > maxDeployVersion) {
+                               System.err.println("Ignoring "+(extUpdate ? 
"freenet-ext.jar " : "") + "update edition "+l);
+                               found = maxDeployVersion;
+                       }

                        if(found <= availableVersion)
                                return;
+                       System.err.println("Found " + (extUpdate ? 
"freenet-ext.jar " : "") + "update edition " + found);
                        Logger.minor(this, "Updating availableVersion from " + 
availableVersion + " to " + found + " and queueing an update");
                        this.availableVersion = found;
                }
+               finishOnFoundEdition(found);
+       }
+
+       private void finishOnFoundEdition(int found) {
                ticker.queueTimedJob(new Runnable() {

                        public void run() {
@@ -121,6 +140,7 @@
                        return;
                if(manager.isBlown())
                        return;
+               ClientGetter cancelled = null;
                synchronized(this) {
                        if(logMINOR)
                                Logger.minor(this, "maybeUpdate: isFetching=" + 
isFetching + ", isRunning=" + isRunning + ", availableVersion=" + 
availableVersion);
@@ -130,6 +150,11 @@
                                return;
                        if(availableVersion <= fetchedVersion)
                                return;
+                       if(fetchingVersion < minDeployVersion || 
fetchingVersion == currentVersion) {
+                               Logger.normal(this, "Cancelling previous 
fetch");
+                               cancelled = cg;
+                               cg = null;
+                       }
                        fetchingVersion = availableVersion;

                        if(availableVersion > currentVersion) {
@@ -153,6 +178,8 @@
                                                uri, ctx, 
RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS,
                                                this, null, new 
FileBucket(tempBlobFile, false, false, false, false, false));
                                        toStart = cg;
+                               } else {
+                                       System.err.println("Already fetching 
"+(extUpdate ? "freenet-ext.jar " : "") + "fetch for " + fetchingVersion + " 
want "+availableVersion);
                                }
                                isFetching = true;
                        } catch(Exception e) {
@@ -169,6 +196,8 @@
                                        isFetching = false;
                                }
                        }
+               if(cancelled != null)
+                       cancelled.cancel(null, core.clientContext);
        }

        File getBlobFile(int availableVersion) {
@@ -206,6 +235,8 @@

        void onSuccess(FetchResult result, ClientGetter state, File 
tempBlobFile, int fetchedVersion) {
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
+               int requiredExt = -1;
+               int recommendedExt = -1;
                synchronized(this) {
                        if(fetchedVersion <= this.fetchedVersion) {
                                tempBlobFile.delete();
@@ -244,13 +275,73 @@
                        System.out.println("Found " + (extUpdate ? "ext " : "") 
+ fetchedVersion);
                        if(fetchedVersion > currentVersion)
                                Logger.normal(this, "Found version " + 
fetchedVersion + ", setting up a new UpdatedVersionAvailableUserAlert");
+                       if(!extUpdate) {
+                               InputStream is = null;
+                               try {
+                                       is = result.asBucket().getInputStream();
+                                       ZipInputStream zis = new 
ZipInputStream(is);
+                                       ZipEntry ze;
+                                       while(true) {
+                                               ze = zis.getNextEntry();
+                                               if(ze == null) break;
+                                               if(ze.isDirectory()) continue;
+                                               String name = ze.getName();
+                                               
+                                               
if(name.equals("META-INF/MANIFEST.MF")) {
+                                                       if(logMINOR) 
Logger.minor(this, "Found manifest");
+                                                       long size = 
ze.getSize();
+                                                       if(logMINOR) 
Logger.minor(this, "Manifest size: "+size);
+                                                       if(size > 
MAX_MANIFEST_SIZE) {
+                                                               
Logger.error(this, "Manifest is too big: "+size+" bytes, limit is 
"+MAX_MANIFEST_SIZE);
+                                                               break;
+                                                       }
+                                                       byte[] buf = new 
byte[(int) size];
+                                                       DataInputStream dis = 
new DataInputStream(zis);
+                                                       dis.readFully(buf);
+                                                       ByteArrayInputStream 
bais = new ByteArrayInputStream(buf);
+                                                       InputStreamReader isr = 
new InputStreamReader(bais, "UTF-8");
+                                                       BufferedReader br = new 
BufferedReader(isr);
+                                                       String line;
+                                                       while((line = 
br.readLine()) != null) {
+                                                               
if(line.startsWith(REQUIRED_EXT_PREFIX)) {
+                                                                       
requiredExt = Integer.parseInt(line.substring(REQUIRED_EXT_PREFIX.length()));
+                                                               } else 
if(line.startsWith(RECOMMENDED_EXT_PREFIX)) {
+                                                                       
recommendedExt = 
Integer.parseInt(line.substring(RECOMMENDED_EXT_PREFIX.length()));
+                                                               }
+                                                       }
+                                               } else {
+                                                       zis.closeEntry();
+                                               }
+                                       }
+                               } catch (IOException e) {
+                                       Logger.error(this, "IOException trying 
to read manifest on update");
+                               } catch (Throwable t) {
+                                       Logger.error(this, "Failed to parse 
update manifest: "+t, t);
+                                       requiredExt = recommendedExt = -1;
+                               } finally {
+                                       Closer.close(is);
+                               }
+                               if(requiredExt != -1) {
+                                       System.err.println("Required ext 
version: "+requiredExt);
+                                       Logger.normal(this, "Required ext 
version: "+requiredExt);
+                               }
+                               if(recommendedExt != -1) {
+                                       System.err.println("Recommended ext 
version: "+recommendedExt);
+                                       Logger.normal(this, "Recommended ext 
version: "+recommendedExt);
+                               }
+                               
+                       }
                        this.cg = null;
                        if(this.result != null)
                                this.result.asBucket().free();
                        this.result = result;
                }
-               manager.onDownloadedNewJar(extUpdate);
+               manager.onDownloadedNewJar(extUpdate, requiredExt, 
recommendedExt);
        }
+       
+       private static final String REQUIRED_EXT_PREFIX = 
"Required-Ext-Version: ";
+       private static final String RECOMMENDED_EXT_PREFIX = 
"Recommended-Ext-Version: ";
+       private static final int MAX_MANIFEST_SIZE = 1024*1024;

        public void onFailure(FetchException e, ClientGetter state, 
ObjectContainer container) {
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
@@ -385,4 +476,27 @@
        public boolean persistent() {
                return false;
        }
+
+       public void setMinMax(int requiredExt, int recommendedExt) {
+               int callFinishedFound = -1;
+               synchronized(this) {
+                       if(recommendedExt > -1) {
+                               maxDeployVersion = recommendedExt;
+                       }
+                       if(requiredExt > -1) {
+                               minDeployVersion = requiredExt;
+                               if(realAvailableVersion != availableVersion && 
availableVersion < requiredExt && realAvailableVersion >= requiredExt) {
+                                       // We found a revision but didn't fetch 
it because it was after the old range.
+                                       System.err.println("Have found edition 
"+realAvailableVersion+" but ignored it because out of range, fetching as 
required by new jar");
+                                       callFinishedFound = availableVersion = 
realAvailableVersion;
+                               } else if(availableVersion < requiredExt) { // 
Including if it hasn't been found at all
+                                       // Just try it ...
+                                       callFinishedFound = availableVersion = 
requiredExt;
+                                       System.err.println("Need minimum 
edition "+requiredExt+" for new jar, fetching...");
+                               }
+                       }
+               }
+               if(callFinishedFound > -1)
+                       finishOnFoundEdition(callFinishedFound);
+       }
 }

Modified: 
branches/db4o/freenet/src/freenet/node/updater/UpdateOverMandatoryManager.java
===================================================================
--- 
branches/db4o/freenet/src/freenet/node/updater/UpdateOverMandatoryManager.java  
    2008-12-17 14:41:55 UTC (rev 24441)
+++ 
branches/db4o/freenet/src/freenet/node/updater/UpdateOverMandatoryManager.java  
    2008-12-17 14:42:10 UTC (rev 24442)
@@ -248,7 +248,7 @@
                        whenToTakeOverTheNormalUpdater = 
System.currentTimeMillis() + GRACE_TIME;
                boolean isOutdated = updateManager.node.isOudated();
                // if the new build is self-mandatory or if the "normal" 
updater has been trying to update for more than one hour
-               Logger.normal(this, "We received a valid UOMAnnounce : 
(isOutdated=" + isOutdated + " version=" + mainJarVersion + " 
whenToTakeOverTheNormalUpdater=" + 
TimeUtil.formatTime(whenToTakeOverTheNormalUpdater - now) + ") file length " + 
mainJarFileLength + " updateManager version " + 
updateManager.newMainJarVersion());
+               Logger.normal(this, "We received a valid UOMAnnounce (main) : 
(isOutdated=" + isOutdated + " version=" + mainJarVersion + " 
whenToTakeOverTheNormalUpdater=" + 
TimeUtil.formatTime(whenToTakeOverTheNormalUpdater - now) + ") file length " + 
mainJarFileLength + " updateManager version " + 
updateManager.newMainJarVersion());
                if(mainJarVersion > Version.buildNumber() && mainJarFileLength 
> 0 &&
                        mainJarVersion > updateManager.newMainJarVersion()) {
                        source.setMainJarOfferedVersion(mainJarVersion);
@@ -314,7 +314,7 @@
                        whenToTakeOverTheNormalUpdater = 
System.currentTimeMillis() + GRACE_TIME;
                boolean isOutdated = updateManager.node.isOudated();
                // if the new build is self-mandatory or if the "normal" 
updater has been trying to update for more than one hour
-               Logger.normal(this, "We received a valid UOMAnnounce : 
(isOutdated=" + isOutdated + " version=" + extJarVersion + " 
whenToTakeOverTheNormalUpdater=" + 
TimeUtil.formatTime(whenToTakeOverTheNormalUpdater - now) + ") file length " + 
extJarFileLength + " updateManager version " + 
updateManager.newExtJarVersion());
+               Logger.normal(this, "We received a valid UOMAnnounce (ext) : 
(isOutdated=" + isOutdated + " version=" + extJarVersion + " 
whenToTakeOverTheNormalUpdater=" + 
TimeUtil.formatTime(whenToTakeOverTheNormalUpdater - now) + ") file length " + 
extJarFileLength + " updateManager version " + 
updateManager.newExtJarVersion());
                if(extJarVersion > NodeStarter.extBuildNumber && 
extJarFileLength > 0 &&
                        extJarVersion > updateManager.newExtJarVersion()) {
                        source.setExtJarOfferedVersion(extJarVersion);
@@ -371,8 +371,8 @@
        }

        private void sendUOMRequest(final PeerNode source, boolean addOnFail, 
final boolean isExt) {
-               final String name = isExt ? "Main" : "Extra";
-               String lname = isExt ? "main" : "ext";
+               final String name = isExt ? "Extra" : "Main";
+               String lname = isExt ? "ext" : "main";
                if(logMINOR)
                        Logger.minor(this, "sendUOMRequest"+name+"(" + source + 
"," + addOnFail + ")");
                if(!source.isConnected())

Modified: branches/db4o/freenet/src/freenet/pluginmanager/PluginManager.java
===================================================================
--- branches/db4o/freenet/src/freenet/pluginmanager/PluginManager.java  
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/pluginmanager/PluginManager.java  
2008-12-17 14:42:10 UTC (rev 24442)
@@ -751,6 +751,9 @@
                                pluginFile.delete();
                                throw new PluginNotFoundException("plugin main 
class is not a plugin");
                        }
+                       if(object instanceof FredPluginWithClassLoader) {
+                               
((FredPluginWithClassLoader)object).setClassLoader(jarClassLoader);
+                       }
                        return (FredPlugin) object;
                } catch(IOException ioe1) {
                        Logger.error(this, "could not load plugin", ioe1);

Modified: branches/db4o/freenet/src/freenet/support/TransferThread.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/TransferThread.java       
2008-12-17 14:41:55 UTC (rev 24441)
+++ branches/db4o/freenet/src/freenet/support/TransferThread.java       
2008-12-17 14:42:10 UTC (rev 24442)
@@ -28,6 +28,7 @@
        private Thread mThread;

        private volatile boolean isRunning = false;
+       private volatile boolean shutdownFinished = false;

        private final Collection<ClientGetter> mFetches = createFetchStorage();
        private final Collection<BaseClientPutter> mInserts = 
createInsertStorage();
@@ -56,6 +57,7 @@
                        mThread.interrupt();
                }

+               try {
                while(isRunning) {
                        Thread.interrupted();

@@ -67,8 +69,15 @@
                                mThread.interrupt();
                        }
                }
+               }

-               abortAllTransfers();
+               finally {
+                       abortAllTransfers();
+                       synchronized (this) {
+                               shutdownFinished = true;
+                               notify();
+                       }
+               }
        }

        protected void abortAllTransfers() {
@@ -122,13 +131,17 @@
        public void terminate() {
                isRunning = false;
                mThread.interrupt();
-               try {
-                       mThread.join();
+               
+               synchronized(this) {
+                       while(!shutdownFinished) {
+                               try {
+                                       wait();
+                               }
+                               catch (InterruptedException e) {
+                                       Thread.interrupted();
+                               }
+                       }
                }
-               catch(InterruptedException e)
-               {
-                       Thread.currentThread().interrupt();
-               }
        }




Reply via email to