summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2009-10-13 13:49:34 +0200
committerBenoit Foucher <benoit@zeroc.com>2009-10-13 13:49:34 +0200
commit50b781e9afffd5f2df09efb0a414c877afc74e95 (patch)
treef81ee8f7738dba72fc54edf636eeabbb5deb47b7
parentFixed bug 4266 - stringified proxy issues, other minor issues (diff)
downloadice-50b781e9afffd5f2df09efb0a414c877afc74e95.tar.bz2
ice-50b781e9afffd5f2df09efb0a414c877afc74e95.tar.xz
ice-50b781e9afffd5f2df09efb0a414c877afc74e95.zip
Fixed bug 860 - close timeouts
-rw-r--r--CHANGES8
-rw-r--r--config/PropertyNames.xml1
-rw-r--r--cpp/src/Ice/ConnectionI.cpp96
-rw-r--r--cpp/src/Ice/ConnectionI.h1
-rw-r--r--cpp/src/Ice/DefaultsAndOverrides.cpp9
-rw-r--r--cpp/src/Ice/DefaultsAndOverrides.h3
-rw-r--r--cpp/src/Ice/PropertyNames.cpp3
-rw-r--r--cpp/src/Ice/PropertyNames.h2
-rw-r--r--cpp/test/Ice/timeout/AllTests.cpp42
-rw-r--r--cs/src/Ice/ConnectionI.cs95
-rw-r--r--cs/src/Ice/DefaultsAndOverrides.cs14
-rw-r--r--cs/src/Ice/PropertyNames.cs3
-rw-r--r--cs/test/Ice/timeout/AllTests.cs44
-rw-r--r--java/src/Ice/ConnectionI.java106
-rw-r--r--java/src/IceInternal/DefaultsAndOverrides.java14
-rw-r--r--java/src/IceInternal/PropertyNames.java3
-rw-r--r--java/test/Ice/timeout/AllTests.java49
17 files changed, 326 insertions, 167 deletions
diff --git a/CHANGES b/CHANGES
index 2a8e5006105..0a1a6c65762 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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;