diff options
author | Benoit Foucher <benoit@zeroc.com> | 2009-10-13 13:49:34 +0200 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2009-10-13 13:49:34 +0200 |
commit | 50b781e9afffd5f2df09efb0a414c877afc74e95 (patch) | |
tree | f81ee8f7738dba72fc54edf636eeabbb5deb47b7 | |
parent | Fixed bug 4266 - stringified proxy issues, other minor issues (diff) | |
download | ice-50b781e9afffd5f2df09efb0a414c877afc74e95.tar.bz2 ice-50b781e9afffd5f2df09efb0a414c877afc74e95.tar.xz ice-50b781e9afffd5f2df09efb0a414c877afc74e95.zip |
Fixed bug 860 - close timeouts
-rw-r--r-- | CHANGES | 8 | ||||
-rw-r--r-- | config/PropertyNames.xml | 1 | ||||
-rw-r--r-- | cpp/src/Ice/ConnectionI.cpp | 96 | ||||
-rw-r--r-- | cpp/src/Ice/ConnectionI.h | 1 | ||||
-rw-r--r-- | cpp/src/Ice/DefaultsAndOverrides.cpp | 9 | ||||
-rw-r--r-- | cpp/src/Ice/DefaultsAndOverrides.h | 3 | ||||
-rw-r--r-- | cpp/src/Ice/PropertyNames.cpp | 3 | ||||
-rw-r--r-- | cpp/src/Ice/PropertyNames.h | 2 | ||||
-rw-r--r-- | cpp/test/Ice/timeout/AllTests.cpp | 42 | ||||
-rw-r--r-- | cs/src/Ice/ConnectionI.cs | 95 | ||||
-rw-r--r-- | cs/src/Ice/DefaultsAndOverrides.cs | 14 | ||||
-rw-r--r-- | cs/src/Ice/PropertyNames.cs | 3 | ||||
-rw-r--r-- | cs/test/Ice/timeout/AllTests.cs | 44 | ||||
-rw-r--r-- | java/src/Ice/ConnectionI.java | 106 | ||||
-rw-r--r-- | java/src/IceInternal/DefaultsAndOverrides.java | 14 | ||||
-rw-r--r-- | java/src/IceInternal/PropertyNames.java | 3 | ||||
-rw-r--r-- | java/test/Ice/timeout/AllTests.java | 49 |
17 files changed, 326 insertions, 167 deletions
@@ -33,6 +33,14 @@ General Changes These entries apply to all relevant language mappings unless otherwise noted. +- Added Ice.Override.CloseTimeout property. This property overrides + timeout settings used to close connections. + +- Ice connections are now forcefully closed after sending a close + connection message and once the connection timeout + expires. Previously, the connection would only be closed when the + object adapter or communicator was destroyed. + - The new Ice::ThreadHookPlugin class allows you to install thread notification hooks during communicator initialization via plugins. diff --git a/config/PropertyNames.xml b/config/PropertyNames.xml index dc800f1f6cb..93d67a49c1c 100644 --- a/config/PropertyNames.xml +++ b/config/PropertyNames.xml @@ -329,6 +329,7 @@ generated from the section label. <property name="MonitorConnections" /> <property name="Nohup" /> <property name="NullHandleAbort" /> + <property name="Override.CloseTimeout" /> <property name="Override.Compress" /> <property name="Override.ConnectTimeout" /> <property name="Override.Timeout" /> diff --git a/cpp/src/Ice/ConnectionI.cpp b/cpp/src/Ice/ConnectionI.cpp index 94303438497..7ae7476e306 100644 --- a/cpp/src/Ice/ConnectionI.cpp +++ b/cpp/src/Ice/ConnectionI.cpp @@ -356,59 +356,16 @@ Ice::ConnectionI::waitUntilFinished() IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); // - // We wait indefinitely until connection closing has been - // initiated. We also wait indefinitely until all outstanding - // requests are completed. Otherwise we couldn't guarantee - // that there are no outstanding calls when deactivate() is - // called on the servant locators. + // We wait indefinitely until the connection is finished and all + // outstanding requests are completed. Otherwise we couldn't + // guarantee that there are no outstanding calls when deactivate() + // is called on the servant locators. // - while(_state < StateClosing || _dispatchCount > 0) + while(_state < StateFinished || _dispatchCount > 0) { wait(); } - // - // Now we must wait until close() has been called on the - // transceiver. - // - while(_state != StateFinished) - { - if(_state < StateClosed && _endpoint->timeout() >= 0) - { - IceUtil::Time timeout = IceUtil::Time::milliSeconds(_endpoint->timeout()); - IceUtil::Time waitTime = _stateTime + timeout - IceUtil::Time::now(IceUtil::Time::Monotonic); - - if(waitTime > IceUtil::Time()) - { - // - // We must wait a bit longer until we close this - // connection. - // - if(!timedWait(waitTime)) - { - setState(StateClosed, CloseTimeoutException(__FILE__, __LINE__)); - } - } - else - { - // - // We already waited long enough, so let's close this - // connection! - // - setState(StateClosed, CloseTimeoutException(__FILE__, __LINE__)); - } - - // - // No return here, we must still wait until close() is - // called on the _transceiver. - // - } - else - { - wait(); - } - } - assert(_state == StateFinished); // @@ -1447,10 +1404,14 @@ Ice::ConnectionI::timedOut() { setState(StateClosed, ConnectTimeoutException(__FILE__, __LINE__)); } - else if(_state <= StateClosing) + else if(_state < StateClosing) { setState(StateClosed, TimeoutException(__FILE__, __LINE__)); } + else if(_state == StateClosing) + { + setState(StateClosed, CloseTimeoutException(__FILE__, __LINE__)); + } } string @@ -1469,7 +1430,7 @@ ConnectionInfoPtr Ice::ConnectionI::getInfo() const { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); - if(_exception.get()) + if(_state >= StateClosed) { _exception->ice_throw(); } @@ -1867,8 +1828,16 @@ Ice::ConnectionI::initiateShutdown() os.write(headerSize); // Message size. OutgoingMessage message(&os, false); - sendMessage(message); - + if(sendMessage(message)) + { + // + // Schedule the close timeout to wait for the peer to close the connection. If + // the message was queued for sending, sendNextMessage will schedule the timeout + // once all messages were sent. + // + scheduleTimeout(SocketOperationWrite, closeTimeout()); + } + // // The CloseConnection message should be sufficient. Closing the write // end of the socket is probably an artifact of how things were done @@ -2123,6 +2092,15 @@ Ice::ConnectionI::sendNextMessage(vector<OutgoingAsyncMessageCallbackPtr>& callb assert(_writeStream.b.empty()); _threadPool->unregister(this, SocketOperationWrite); + + // + // If all the messages were sent and we are in the closing state, we schedule + // the close timeout to wait for the peer to close the connection. + // + if(_state == StateClosing) + { + scheduleTimeout(SocketOperationWrite, closeTimeout()); + } } bool @@ -2660,3 +2638,17 @@ Ice::ConnectionI::connectTimeout() return _endpoint->timeout(); } } + +int +Ice::ConnectionI::closeTimeout() +{ + DefaultsAndOverridesPtr defaultsAndOverrides = _instance->defaultsAndOverrides(); + if(defaultsAndOverrides->overrideCloseTimeout) + { + return defaultsAndOverrides->overrideCloseTimeoutValue; + } + else + { + return _endpoint->timeout(); + } +} diff --git a/cpp/src/Ice/ConnectionI.h b/cpp/src/Ice/ConnectionI.h index c13ae288561..a023767a63f 100644 --- a/cpp/src/Ice/ConnectionI.h +++ b/cpp/src/Ice/ConnectionI.h @@ -251,6 +251,7 @@ private: } int connectTimeout(); + int closeTimeout(); const IceInternal::TransceiverPtr _transceiver; const IceInternal::InstancePtr _instance; diff --git a/cpp/src/Ice/DefaultsAndOverrides.cpp b/cpp/src/Ice/DefaultsAndOverrides.cpp index b14686121da..81572b0ec68 100644 --- a/cpp/src/Ice/DefaultsAndOverrides.cpp +++ b/cpp/src/Ice/DefaultsAndOverrides.cpp @@ -23,6 +23,8 @@ IceInternal::DefaultsAndOverrides::DefaultsAndOverrides(const PropertiesPtr& pro overrideTimeoutValue(-1), overrideConnectTimeout(false), overrideConnectTimeoutValue(-1), + overrideCloseTimeout(false), + overrideCloseTimeoutValue(-1), overrideCompress(false), overrideCompressValue(false), overrideSecure(false), @@ -48,6 +50,13 @@ IceInternal::DefaultsAndOverrides::DefaultsAndOverrides(const PropertiesPtr& pro const_cast<Int&>(overrideConnectTimeoutValue) = properties->getPropertyAsInt("Ice.Override.ConnectTimeout"); } + value = properties->getProperty("Ice.Override.CloseTimeout"); + if(!value.empty()) + { + const_cast<bool&>(overrideCloseTimeout) = true; + const_cast<Int&>(overrideCloseTimeoutValue) = properties->getPropertyAsInt("Ice.Override.CloseTimeout"); + } + value = properties->getProperty("Ice.Override.Compress"); if(!value.empty()) { diff --git a/cpp/src/Ice/DefaultsAndOverrides.h b/cpp/src/Ice/DefaultsAndOverrides.h index 1ee79794569..fb6b5d0bda7 100644 --- a/cpp/src/Ice/DefaultsAndOverrides.h +++ b/cpp/src/Ice/DefaultsAndOverrides.h @@ -1,3 +1,4 @@ + // ********************************************************************** // // Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved. @@ -35,6 +36,8 @@ public: Ice::Int overrideTimeoutValue; bool overrideConnectTimeout; Ice::Int overrideConnectTimeoutValue; + bool overrideCloseTimeout; + Ice::Int overrideCloseTimeoutValue; bool overrideCompress; bool overrideCompressValue; bool overrideSecure; diff --git a/cpp/src/Ice/PropertyNames.cpp b/cpp/src/Ice/PropertyNames.cpp index 1bd4149202e..e0b3f489e07 100644 --- a/cpp/src/Ice/PropertyNames.cpp +++ b/cpp/src/Ice/PropertyNames.cpp @@ -8,7 +8,7 @@ // ********************************************************************** // -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 7 14:30:37 2009 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Mon Oct 12 16:01:09 2009 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -80,6 +80,7 @@ const IceInternal::Property IcePropsData[] = IceInternal::Property("Ice.MonitorConnections", false, 0), IceInternal::Property("Ice.Nohup", false, 0), IceInternal::Property("Ice.NullHandleAbort", false, 0), + IceInternal::Property("Ice.Override.CloseTimeout", false, 0), IceInternal::Property("Ice.Override.Compress", false, 0), IceInternal::Property("Ice.Override.ConnectTimeout", false, 0), IceInternal::Property("Ice.Override.Timeout", false, 0), diff --git a/cpp/src/Ice/PropertyNames.h b/cpp/src/Ice/PropertyNames.h index 0c461df437a..1cd38a5c35e 100644 --- a/cpp/src/Ice/PropertyNames.h +++ b/cpp/src/Ice/PropertyNames.h @@ -8,7 +8,7 @@ // ********************************************************************** // -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 7 14:30:37 2009 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Mon Oct 12 16:01:09 2009 // IMPORTANT: Do not edit this file -- any edits made here will be lost! diff --git a/cpp/test/Ice/timeout/AllTests.cpp b/cpp/test/Ice/timeout/AllTests.cpp index 698ddd3f24f..a0cf7a83178 100644 --- a/cpp/test/Ice/timeout/AllTests.cpp +++ b/cpp/test/Ice/timeout/AllTests.cpp @@ -283,6 +283,34 @@ allTests(const Ice::CommunicatorPtr& communicator) } cout << "ok" << endl; + cout << "testing close timeout... " << flush; + { + TimeoutPrx to = TimeoutPrx::checkedCast(obj->ice_timeout(250)); + Ice::ConnectionPtr connection = to->ice_getConnection(); + timeout->holdAdapter(750); + connection->close(false); + try + { + connection->getInfo(); // getInfo() doesn't throw in the closing state. + } + catch(const Ice::LocalException&) + { + test(false); + } + IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(300)); + try + { + connection->getInfo(); + test(false); + } + catch(const Ice::CloseConnectionException&) + { + // Expected. + } + timeout->op(); // Ensure adapter is active. + } + cout << "ok" << endl; + cout << "testing timeout overrides... " << flush; { // @@ -368,6 +396,20 @@ allTests(const Ice::CommunicatorPtr& communicator) } comm->destroy(); } + { + // + // Test Ice.Override.CloseTimeout. + // + Ice::InitializationData initData; + initData.properties = communicator->getProperties()->clone(); + initData.properties->setProperty("Ice.Override.CloseTimeout", "200"); + Ice::CommunicatorPtr comm = Ice::initialize(initData); + Ice::ConnectionPtr connection = comm->stringToProxy(sref)->ice_getConnection(); + timeout->holdAdapter(750); + IceUtil::Time now = IceUtil::Time::now(); + comm->destroy(); + test(IceUtil::Time::now() - now < IceUtil::Time::milliSeconds(500)); + } cout << "ok" << endl; return timeout; diff --git a/cs/src/Ice/ConnectionI.cs b/cs/src/Ice/ConnectionI.cs index 1219bb28080..37db3c80f1a 100644 --- a/cs/src/Ice/ConnectionI.cs +++ b/cs/src/Ice/ConnectionI.cs @@ -250,60 +250,16 @@ namespace Ice lock(this) { // - // We wait indefinitely until connection closing has been - // initiated. We also wait indefinitely until all outstanding - // requests are completed. Otherwise we couldn't guarantee - // that there are no outstanding calls when deactivate() is - // called on the servant locators. + // We wait indefinitely until the connection is finished and all + // outstanding requests are completed. Otherwise we couldn't + // guarantee that there are no outstanding calls when deactivate() + // is called on the servant locators. // - while(_state < StateClosing || _dispatchCount > 0) + while(_state < StateFinished || _dispatchCount > 0) { Monitor.Wait(this); } - // - // Now we must wait until close() has been called on the - // transceiver. - // - while(_state != StateFinished) - { - if(_state != StateClosed && _endpoint.timeout() >= 0) - { - long absoluteWaitTime = _stateTime + _endpoint.timeout(); - int waitTime = (int)(absoluteWaitTime - IceInternal.Time.currentMonotonicTimeMillis()); - - if(waitTime > 0) - { - // - // We must wait a bit longer until we close this - // connection. - // - Monitor.Wait(this, waitTime); - if(IceInternal.Time.currentMonotonicTimeMillis() >= absoluteWaitTime) - { - setState(StateClosed, new CloseTimeoutException()); - } - } - else - { - // - // We already waited long enough, so let's close this - // connection! - // - setState(StateClosed, new CloseTimeoutException()); - } - - // - // No return here, we must still wait until close() is - // called on the _transceiver. - // - } - else - { - Monitor.Wait(this); - } - } - Debug.Assert(_state == StateFinished && _dispatchCount == 0); // @@ -1354,10 +1310,14 @@ namespace Ice { setState(StateClosed, new ConnectTimeoutException()); } - else if(_state <= StateClosing) + else if(_state < StateClosing) { setState(StateClosed, new TimeoutException()); } + else if(_state == StateClosing) + { + setState(StateClosed, new CloseTimeoutException()); + } } } @@ -1376,7 +1336,7 @@ namespace Ice { lock(this) { - if(_exception != null) + if(_state >= StateClosed) { throw _exception; } @@ -1763,7 +1723,15 @@ namespace Ice os.writeByte(_compressionSupported ? (byte)1 : (byte)0); os.writeInt(IceInternal.Protocol.headerSize); // Message size. - sendMessage(new OutgoingMessage(os, false, false)); + if(sendMessage(new OutgoingMessage(os, false, false))) + { + // + // Schedule the close timeout to wait for the peer to close the connection. If + // the message was queued for sending, sendNextMessage will schedule the timeout + // once all messages were sent. + // + scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout()); + } // // The CloseConnection message should be sufficient. Closing the write @@ -1967,6 +1935,16 @@ namespace Ice Debug.Assert(_writeStream.isEmpty()); _threadPool.unregister(this, IceInternal.SocketOperation.Write); + + // + // If all the messages were sent and we are in the closing state, we schedule + // the close timeout to wait for the peer to close the connection. + // + if(_state == StateClosing) + { + scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout()); + } + return callbacks; } @@ -2344,6 +2322,19 @@ namespace Ice } } + private int closeTimeout() + { + IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideCloseTimeout) + { + return defaultsAndOverrides.overrideCloseTimeoutValue; + } + else + { + return _endpoint.timeout(); + } + } + private void warning(string msg, System.Exception ex) { _logger.warning(msg + ":\n" + ex + "\n" + _transceiver.ToString()); diff --git a/cs/src/Ice/DefaultsAndOverrides.cs b/cs/src/Ice/DefaultsAndOverrides.cs index 3a99e355859..a74c4746e78 100644 --- a/cs/src/Ice/DefaultsAndOverrides.cs +++ b/cs/src/Ice/DefaultsAndOverrides.cs @@ -54,6 +54,18 @@ namespace IceInternal overrideConnectTimeoutValue = -1; } + val = properties.getProperty("Ice.Override.CloseTimeout"); + if(val.Length > 0) + { + overrideCloseTimeout = true; + overrideCloseTimeoutValue = properties.getPropertyAsInt("Ice.Override.CloseTimeout"); + } + else + { + overrideCloseTimeout = false; + overrideCloseTimeoutValue = -1; + } + val = properties.getProperty("Ice.Override.Compress"); if(val.Length > 0) { @@ -119,6 +131,8 @@ namespace IceInternal public int overrideTimeoutValue; public bool overrideConnectTimeout; public int overrideConnectTimeoutValue; + public bool overrideCloseTimeout; + public int overrideCloseTimeoutValue; public bool overrideCompress; public bool overrideCompressValue; public bool overrideSecure; diff --git a/cs/src/Ice/PropertyNames.cs b/cs/src/Ice/PropertyNames.cs index 03d39d2f743..43ad3c4a319 100644 --- a/cs/src/Ice/PropertyNames.cs +++ b/cs/src/Ice/PropertyNames.cs @@ -8,7 +8,7 @@ // ********************************************************************** // -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 7 14:30:37 2009 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Mon Oct 12 16:01:09 2009 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -82,6 +82,7 @@ namespace IceInternal new Property(@"^Ice\.MonitorConnections$", false, null), new Property(@"^Ice\.Nohup$", false, null), new Property(@"^Ice\.NullHandleAbort$", false, null), + new Property(@"^Ice\.Override\.CloseTimeout$", false, null), new Property(@"^Ice\.Override\.Compress$", false, null), new Property(@"^Ice\.Override\.ConnectTimeout$", false, null), new Property(@"^Ice\.Override\.Timeout$", false, null), diff --git a/cs/test/Ice/timeout/AllTests.cs b/cs/test/Ice/timeout/AllTests.cs index e50e4850db3..fd275d1b3d8 100644 --- a/cs/test/Ice/timeout/AllTests.cs +++ b/cs/test/Ice/timeout/AllTests.cs @@ -305,6 +305,35 @@ public class AllTests } Console.Out.WriteLine("ok"); + Console.Out.Write("testing close timeout... "); + Console.Out.Flush(); + { + Test.TimeoutPrx to = Test.TimeoutPrxHelper.checkedCast(obj.ice_timeout(250)); + Ice.Connection connection = to.ice_getConnection(); + timeout.holdAdapter(750); + connection.close(false); + try + { + connection.getInfo(); // getInfo() doesn't throw in the closing state. + } + catch(Ice.LocalException) + { + test(false); + } + Thread.Sleep(300); + try + { + connection.getInfo(); + test(false); + } + catch(Ice.CloseConnectionException) + { + // Expected. + } + timeout.op(); // Ensure adapter is active. + } + Console.Out.WriteLine("ok"); + Console.Out.Write("testing timeout overrides... "); Console.Out.Flush(); { @@ -393,6 +422,21 @@ public class AllTests } comm.destroy(); } + { + // + // Test Ice.Override.CloseTimeout. + // + Ice.InitializationData initData = new Ice.InitializationData(); + initData.properties = communicator.getProperties().ice_clone_(); + initData.properties.setProperty("Ice.Override.CloseTimeout", "200"); + Ice.Communicator comm = Ice.Util.initialize(initData); + comm.stringToProxy(sref).ice_getConnection(); + timeout.holdAdapter(750); + Stopwatch stopwatch = new Stopwatch(); + long now = stopwatch.ElapsedMilliseconds; + comm.destroy(); + test(stopwatch.ElapsedMilliseconds - now < 500); + } Console.Out.WriteLine("ok"); return timeout; diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java index 88ff87fa40b..c91ff3a44e0 100644 --- a/java/src/Ice/ConnectionI.java +++ b/java/src/Ice/ConnectionI.java @@ -223,13 +223,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne waitUntilFinished() { // - // We wait indefinitely until connection closing has been - // initiated. We also wait indefinitely until all outstanding - // requests are completed. Otherwise we couldn't guarantee - // that there are no outstanding calls when deactivate() is - // called on the servant locators. + // We wait indefinitely until the connection is finished and all + // outstanding requests are completed. Otherwise we couldn't + // guarantee that there are no outstanding calls when deactivate() + // is called on the servant locators. // - while(_state < StateClosing || _dispatchCount > 0) + while(_state < StateFinished || _dispatchCount > 0) { try { @@ -240,55 +239,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } } - // - // Now we must wait until close() has been called on the - // transceiver. - // - while(_state != StateFinished) - { - try - { - if(_state != StateClosed && _endpoint.timeout() >= 0) - { - long absoluteWaitTime = _stateTime + _endpoint.timeout(); - long waitTime = absoluteWaitTime - IceInternal.Time.currentMonotonicTimeMillis(); - - if(waitTime > 0) - { - // - // We must wait a bit longer until we close this - // connection. - // - wait(waitTime); - if(IceInternal.Time.currentMonotonicTimeMillis() >= absoluteWaitTime) - { - setState(StateClosed, new CloseTimeoutException()); - } - } - else - { - // - // We already waited long enough, so let's close this - // connection! - // - setState(StateClosed, new CloseTimeoutException()); - } - - // - // No return here, we must still wait until - // close() is called on the _transceiver. - // - } - else - { - wait(); - } - } - catch(InterruptedException ex) - { - } - } - assert(_state == StateFinished); // @@ -1145,7 +1095,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne synchronized(this) { assert(_state == StateClosed); - unscheduleTimeout(IceInternal.SocketOperation.Read | IceInternal.SocketOperation.Write); + unscheduleTimeout(IceInternal.SocketOperation.Read | + IceInternal.SocketOperation.Write | + IceInternal.SocketOperation.Connect); } // @@ -1221,10 +1173,14 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { setState(StateClosed, new ConnectTimeoutException()); } - else if(_state <= StateClosing) + else if(_state < StateClosing) { setState(StateClosed, new TimeoutException()); } + else if(_state == StateClosing) + { + setState(StateClosed, new CloseTimeoutException()); + } } public String @@ -1242,7 +1198,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne public synchronized ConnectionInfo getInfo() { - if(_exception != null) + if(_state >= StateClosed) { throw (Ice.LocalException)_exception.fillInStackTrace(); } @@ -1647,7 +1603,15 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne os.writeByte(_compressionSupported ? (byte)1 : (byte)0); os.writeInt(IceInternal.Protocol.headerSize); // Message size. - sendMessage(new OutgoingMessage(os, false, false)); + if(sendMessage(new OutgoingMessage(os, false, false))) + { + // + // Schedule the close timeout to wait for the peer to close the connection. If + // the message was queued for sending, sendNextMessage will schedule the timeout + // once all messages were sent. + // + scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout()); + } // // The CloseConnection message should be sufficient. Closing the write @@ -1850,6 +1814,16 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne assert(_writeStream.isEmpty()); _threadPool.unregister(this, IceInternal.SocketOperation.Write); + + // + // If all the messages were sent and we are in the closing state, we schedule + // the close timeout to wait for the peer to close the connection. + // + if(_state == StateClosing) + { + scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout()); + } + return callbacks; } @@ -2268,6 +2242,20 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } } + private int + closeTimeout() + { + IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideCloseTimeout) + { + return defaultsAndOverrides.overrideCloseTimeoutValue; + } + else + { + return _endpoint.timeout(); + } + } + private void warning(String msg, Exception ex) { diff --git a/java/src/IceInternal/DefaultsAndOverrides.java b/java/src/IceInternal/DefaultsAndOverrides.java index 026279274d1..c0ca6124917 100644 --- a/java/src/IceInternal/DefaultsAndOverrides.java +++ b/java/src/IceInternal/DefaultsAndOverrides.java @@ -51,6 +51,18 @@ public final class DefaultsAndOverrides overrideConnectTimeoutValue = -1; } + value = properties.getProperty("Ice.Override.CloseTimeout"); + if(value.length() > 0) + { + overrideCloseTimeout = true; + overrideCloseTimeoutValue = properties.getPropertyAsInt("Ice.Override.CloseTimeout"); + } + else + { + overrideCloseTimeout = false; + overrideCloseTimeoutValue = -1; + } + value = properties.getProperty("Ice.Override.Compress"); if(value.length() > 0) { @@ -116,6 +128,8 @@ public final class DefaultsAndOverrides final public int overrideTimeoutValue; final public boolean overrideConnectTimeout; final public int overrideConnectTimeoutValue; + final public boolean overrideCloseTimeout; + final public int overrideCloseTimeoutValue; final public boolean overrideCompress; final public boolean overrideCompressValue; final public boolean overrideSecure; diff --git a/java/src/IceInternal/PropertyNames.java b/java/src/IceInternal/PropertyNames.java index 6a9ee4ce94d..be7a8d07239 100644 --- a/java/src/IceInternal/PropertyNames.java +++ b/java/src/IceInternal/PropertyNames.java @@ -8,7 +8,7 @@ // ********************************************************************** // -// Generated by makeprops.py from file ../config/PropertyNames.xml, Wed Oct 7 14:30:37 2009 +// Generated by makeprops.py from file ../config/PropertyNames.xml, Mon Oct 12 16:01:09 2009 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -82,6 +82,7 @@ public final class PropertyNames new Property("Ice\\.MonitorConnections", false, null), new Property("Ice\\.Nohup", false, null), new Property("Ice\\.NullHandleAbort", false, null), + new Property("Ice\\.Override\\.CloseTimeout", false, null), new Property("Ice\\.Override\\.Compress", false, null), new Property("Ice\\.Override\\.ConnectTimeout", false, null), new Property("Ice\\.Override\\.Timeout", false, null), diff --git a/java/test/Ice/timeout/AllTests.java b/java/test/Ice/timeout/AllTests.java index 924067cb4c9..db6ffac8790 100644 --- a/java/test/Ice/timeout/AllTests.java +++ b/java/test/Ice/timeout/AllTests.java @@ -358,6 +358,41 @@ public class AllTests } out.println("ok"); + out.print("testing close timeout... "); + out.flush(); + { + TimeoutPrx to = TimeoutPrxHelper.checkedCast(obj.ice_timeout(250)); + Ice.Connection connection = to.ice_getConnection(); + timeout.holdAdapter(750); + connection.close(false); + try + { + connection.getInfo(); // getInfo() doesn't throw in the closing state. + } + catch(Ice.LocalException ex) + { + test(false); + } + try + { + Thread.sleep(300); + } + catch(java.lang.InterruptedException ex) + { + } + try + { + connection.getInfo(); + test(false); + } + catch(Ice.CloseConnectionException ex) + { + // Expected. + } + timeout.op(); // Ensure adapter is active. + } + out.println("ok"); + out.print("testing timeout overrides... "); out.flush(); { @@ -462,6 +497,20 @@ public class AllTests } comm.destroy(); } + { + // + // Test Ice.Override.CloseTimeout. + // + Ice.InitializationData initData = new Ice.InitializationData(); + initData.properties = communicator.getProperties()._clone(); + initData.properties.setProperty("Ice.Override.CloseTimeout", "200"); + Ice.Communicator comm = Ice.Util.initialize(initData); + Ice.Connection connection = comm.stringToProxy(sref).ice_getConnection(); + timeout.holdAdapter(750); + long now = System.nanoTime(); + comm.destroy(); + test(System.nanoTime() - now < 500 * 1000000); + } out.println("ok"); return timeout; |