summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2017-01-30 13:45:21 -0800
committerMark Spruiell <mes@zeroc.com>2017-01-30 13:45:21 -0800
commit61270a10f980933cf582edb766f10c8ac6d86e8a (patch)
tree45ab4a7c2986954054fce613bc3c8f7967e7951e
parentFix slice2cpp build failure (diff)
downloadice-61270a10f980933cf582edb766f10c8ac6d86e8a.tar.bz2
ice-61270a10f980933cf582edb766f10c8ac6d86e8a.tar.xz
ice-61270a10f980933cf582edb766f10c8ac6d86e8a.zip
merging IceBridge into master
-rw-r--r--cpp/include/Ice/ConnectionAsync.h93
-rw-r--r--cpp/src/Glacier2/RoutingTable.cpp2
-rw-r--r--cpp/src/Glacier2/SessionRouterI.cpp10
-rw-r--r--cpp/src/Ice/ConnectionI.cpp211
-rw-r--r--cpp/src/Ice/ConnectionI.h20
-rw-r--r--cpp/src/Ice/Exception.cpp8
-rw-r--r--cpp/src/Ice/ProxyFactory.cpp7
-rw-r--r--cpp/src/IceBridge/IceBridge.cpp837
-rw-r--r--cpp/src/IceBridge/Makefile.mk15
-rw-r--r--cpp/src/IceGrid/SessionManager.cpp2
-rw-r--r--cpp/test/Ice/acm/AllTests.cpp32
-rw-r--r--cpp/test/Ice/acm/Test.ice3
-rw-r--r--cpp/test/Ice/acm/TestI.cpp50
-rw-r--r--cpp/test/Ice/acm/TestI.h46
-rw-r--r--cpp/test/Ice/ami/AllTests.cpp322
-rw-r--r--cpp/test/Ice/ami/Client.cpp1
-rw-r--r--cpp/test/Ice/ami/Test.ice10
-rw-r--r--cpp/test/Ice/ami/TestI.cpp11
-rw-r--r--cpp/test/Ice/ami/TestI.h3
-rw-r--r--cpp/test/Ice/background/AllTests.cpp42
-rw-r--r--cpp/test/Ice/binding/AllTests.cpp42
-rw-r--r--cpp/test/Ice/hold/AllTests.cpp4
-rw-r--r--cpp/test/Ice/location/AllTests.cpp2
-rw-r--r--cpp/test/Ice/metrics/AllTests.cpp18
-rw-r--r--cpp/test/Ice/metrics/TestAMDI.cpp4
-rw-r--r--cpp/test/Ice/metrics/TestI.cpp2
-rw-r--r--cpp/test/Ice/operations/BatchOneways.cpp4
-rw-r--r--cpp/test/Ice/operations/BatchOnewaysAMI.cpp8
-rw-r--r--cpp/test/Ice/retry/TestI.cpp2
-rw-r--r--cpp/test/Ice/timeout/AllTests.cpp5
-rw-r--r--cpp/test/Ice/udp/AllTests.cpp2
-rw-r--r--cpp/test/IceSSL/configuration/AllTests.cpp2
-rw-r--r--cpp/test/IceStorm/stress/Subscriber.cpp2
-rw-r--r--csharp/src/Ice/ConnectionI.cs186
-rw-r--r--csharp/test/Ice/acm/AllTests.cs54
-rw-r--r--csharp/test/Ice/acm/Test.ice3
-rw-r--r--csharp/test/Ice/acm/TestI.cs31
-rw-r--r--csharp/test/Ice/ami/AllTests.cs173
-rw-r--r--csharp/test/Ice/ami/Client.cs2
-rw-r--r--csharp/test/Ice/ami/Server.cs7
-rw-r--r--csharp/test/Ice/ami/Test.ice10
-rw-r--r--csharp/test/Ice/ami/TestI.cs10
-rw-r--r--csharp/test/Ice/background/AllTests.cs24
-rw-r--r--csharp/test/Ice/binding/AllTests.cs28
-rw-r--r--csharp/test/Ice/hold/AllTests.cs2
-rw-r--r--csharp/test/Ice/location/AllTests.cs2
-rw-r--r--csharp/test/Ice/metrics/AllTests.cs20
-rw-r--r--csharp/test/Ice/metrics/MetricsAMDI.cs2
-rw-r--r--csharp/test/Ice/metrics/MetricsI.cs2
-rw-r--r--csharp/test/Ice/operations/BatchOneways.cs4
-rw-r--r--csharp/test/Ice/operations/BatchOnewaysAMI.cs4
-rw-r--r--csharp/test/Ice/retry/RetryI.cs2
-rw-r--r--csharp/test/Ice/timeout/AllTests.cs5
-rw-r--r--csharp/test/Ice/udp/AllTests.cs2
-rw-r--r--csharp/test/IceSSL/configuration/AllTests.cs2
-rw-r--r--java-compat/src/Ice/src/main/java/Ice/Callback_Connection_heartbeat.java55
-rw-r--r--java-compat/src/Ice/src/main/java/Ice/ConnectionI.java204
-rw-r--r--java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java2
-rw-r--r--java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java2
-rw-r--r--java-compat/test/src/main/java/test/Ice/acm/AllTests.java29
-rw-r--r--java-compat/test/src/main/java/test/Ice/acm/Test.ice3
-rw-r--r--java-compat/test/src/main/java/test/Ice/acm/TestI.java27
-rw-r--r--java-compat/test/src/main/java/test/Ice/ami/AMI.java162
-rw-r--r--java-compat/test/src/main/java/test/Ice/ami/Client.java1
-rw-r--r--java-compat/test/src/main/java/test/Ice/ami/Server.java6
-rw-r--r--java-compat/test/src/main/java/test/Ice/ami/Test.ice10
-rw-r--r--java-compat/test/src/main/java/test/Ice/ami/TestI.java18
-rw-r--r--java-compat/test/src/main/java/test/Ice/ami/lambda/AMI.java12
-rw-r--r--java-compat/test/src/main/java/test/Ice/background/AllTests.java40
-rw-r--r--java-compat/test/src/main/java/test/Ice/binding/AllTests.java30
-rw-r--r--java-compat/test/src/main/java/test/Ice/hold/AllTests.java2
-rw-r--r--java-compat/test/src/main/java/test/Ice/interrupt/AllTests.java5
-rw-r--r--java-compat/test/src/main/java/test/Ice/location/AllTests.java2
-rw-r--r--java-compat/test/src/main/java/test/Ice/metrics/AMDMetricsI.java2
-rw-r--r--java-compat/test/src/main/java/test/Ice/metrics/AllTests.java18
-rw-r--r--java-compat/test/src/main/java/test/Ice/metrics/MetricsI.java2
-rw-r--r--java-compat/test/src/main/java/test/Ice/operations/BatchOneways.java4
-rw-r--r--java-compat/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java4
-rw-r--r--java-compat/test/src/main/java/test/Ice/retry/RetryI.java2
-rw-r--r--java-compat/test/src/main/java/test/Ice/timeout/AllTests.java5
-rw-r--r--java-compat/test/src/main/java/test/Ice/udp/AllTests.java2
-rw-r--r--java-compat/test/src/main/java/test/IceSSL/configuration/AllTests.java2
-rw-r--r--java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java170
-rw-r--r--java/src/Ice/src/main/java/com/zeroc/IceInternal/IncomingConnectionFactory.java2
-rw-r--r--java/src/Ice/src/main/java/com/zeroc/IceInternal/OutgoingConnectionFactory.java2
-rw-r--r--java/test/src/main/java/test/Ice/acm/AllTests.java29
-rw-r--r--java/test/src/main/java/test/Ice/acm/Test.ice3
-rw-r--r--java/test/src/main/java/test/Ice/acm/TestI.java37
-rw-r--r--java/test/src/main/java/test/Ice/ami/AMI.java135
-rw-r--r--java/test/src/main/java/test/Ice/ami/Client.java1
-rw-r--r--java/test/src/main/java/test/Ice/ami/Server.java6
-rw-r--r--java/test/src/main/java/test/Ice/ami/Test.ice10
-rw-r--r--java/test/src/main/java/test/Ice/ami/TestI.java18
-rw-r--r--java/test/src/main/java/test/Ice/background/AllTests.java40
-rw-r--r--java/test/src/main/java/test/Ice/binding/AllTests.java31
-rw-r--r--java/test/src/main/java/test/Ice/hold/AllTests.java2
-rw-r--r--java/test/src/main/java/test/Ice/interrupt/AllTests.java4
-rw-r--r--java/test/src/main/java/test/Ice/location/AllTests.java2
-rw-r--r--java/test/src/main/java/test/Ice/metrics/AMDMetricsI.java2
-rw-r--r--java/test/src/main/java/test/Ice/metrics/AllTests.java19
-rw-r--r--java/test/src/main/java/test/Ice/metrics/MetricsI.java2
-rw-r--r--java/test/src/main/java/test/Ice/operations/BatchOneways.java4
-rw-r--r--java/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java4
-rw-r--r--java/test/src/main/java/test/Ice/retry/RetryI.java2
-rw-r--r--java/test/src/main/java/test/Ice/timeout/AllTests.java5
-rw-r--r--java/test/src/main/java/test/Ice/udp/AllTests.java2
-rw-r--r--java/test/src/main/java/test/IceSSL/configuration/AllTests.java2
-rw-r--r--js/src/Ice/ConnectionI.js50
-rw-r--r--js/src/Ice/OutgoingAsync.js33
-rw-r--r--js/test/Ice/acm/Client.js34
-rw-r--r--js/test/Ice/acm/Test.ice3
-rw-r--r--js/test/Ice/ami/Client.js8
-rw-r--r--js/test/Ice/binding/Client.js12
-rw-r--r--js/test/Ice/hold/Client.js2
-rw-r--r--js/test/Ice/location/Client.js2
-rw-r--r--js/test/Ice/operations/BatchOneways.js2
-rw-r--r--js/test/Ice/timeout/Client.js4
-rw-r--r--objective-c/src/Ice/ConnectionI.mm50
-rw-r--r--objective-c/test/Ice/acm/ACMTest.ice3
-rw-r--r--objective-c/test/Ice/acm/AllTests.m38
-rw-r--r--objective-c/test/Ice/acm/TestI.h9
-rw-r--r--objective-c/test/Ice/acm/TestI.m19
-rw-r--r--php/src/php5/Connection.cpp35
-rw-r--r--php/src/php5/Util.cpp4
-rw-r--r--php/src/php7/Connection.cpp57
-rw-r--r--php/src/php7/Util.cpp4
-rw-r--r--php/test/Ice/acm/Client.php52
-rw-r--r--php/test/Ice/acm/Test.ice3
-rw-r--r--php/test/Ice/binding/Client.php23
-rw-r--r--python/modules/IcePy/Connection.cpp233
-rw-r--r--python/modules/IcePy/Util.cpp4
-rw-r--r--python/test/Ice/acm/AllTests.py23
-rw-r--r--python/test/Ice/acm/Test.ice3
-rw-r--r--python/test/Ice/acm/TestI.py42
-rw-r--r--python/test/Ice/ami/AllTests.py170
-rwxr-xr-xpython/test/Ice/ami/Client.py1
-rwxr-xr-xpython/test/Ice/ami/Server.py4
-rw-r--r--python/test/Ice/ami/Test.ice10
-rw-r--r--python/test/Ice/ami/TestI.py9
-rw-r--r--python/test/Ice/binding/AllTests.py26
-rw-r--r--python/test/Ice/location/AllTests.py74
-rw-r--r--python/test/Ice/operations/BatchOneways.py4
-rw-r--r--python/test/Ice/operations/BatchOnewaysAMI.py4
-rw-r--r--python/test/Ice/operations/BatchOnewaysFuture.py4
-rw-r--r--python/test/Ice/timeout/AllTests.py76
-rw-r--r--ruby/src/IceRuby/Connection.cpp46
-rw-r--r--ruby/src/IceRuby/Util.cpp4
-rw-r--r--ruby/test/Ice/acm/AllTests.rb46
-rw-r--r--ruby/test/Ice/acm/Test.ice3
-rw-r--r--ruby/test/Ice/binding/AllTests.rb20
-rw-r--r--ruby/test/Ice/operations/BatchOneways.rb4
-rw-r--r--ruby/test/Ice/timeout/AllTests.rb5
-rw-r--r--scripts/tests/Ice/ami.py2
-rw-r--r--slice/Ice/Connection.ice64
-rw-r--r--slice/Ice/LocalException.ice7
155 files changed, 4028 insertions, 889 deletions
diff --git a/cpp/include/Ice/ConnectionAsync.h b/cpp/include/Ice/ConnectionAsync.h
index bc3f6064525..58f54cc3492 100644
--- a/cpp/include/Ice/ConnectionAsync.h
+++ b/cpp/include/Ice/ConnectionAsync.h
@@ -112,6 +112,99 @@ newCallback_Connection_flushBatchRequests(T* instance, void (T::*excb)(const ::I
return new Callback_Connection_flushBatchRequests<T, CT>(instance, excb, sentcb);
}
+template<class T>
+class CallbackNC_Connection_heartbeat : public Callback_Connection_heartbeat_Base,
+ public ::IceInternal::OnewayCallbackNC<T>
+{
+public:
+
+ typedef IceUtil::Handle<T> TPtr;
+
+ typedef void (T::*Exception)(const ::Ice::Exception&);
+ typedef void (T::*Sent)(bool);
+
+ CallbackNC_Connection_heartbeat(const TPtr& obj, Exception excb, Sent sentcb)
+ : ::IceInternal::OnewayCallbackNC<T>(obj, 0, excb, sentcb)
+ {
+ }
+
+ virtual void completed(const ::Ice::AsyncResultPtr& __result) const
+ {
+ ::Ice::ConnectionPtr __con = __result->getConnection();
+ assert(__con);
+ try
+ {
+ __con->end_heartbeat(__result);
+ assert(false);
+ }
+ catch(const ::Ice::Exception& ex)
+ {
+ ::IceInternal::CallbackNC<T>::exception(__result, ex);
+ }
+ }
+};
+
+template<class T> Callback_Connection_heartbeatPtr
+newCallback_Connection_heartbeat(const IceUtil::Handle<T>& instance,
+ void (T::*excb)(const ::Ice::Exception&),
+ void (T::*sentcb)(bool) = 0)
+{
+ return new CallbackNC_Connection_heartbeat<T>(instance, excb, sentcb);
+}
+
+template<class T> Callback_Connection_heartbeatPtr
+newCallback_Connection_heartbeat(T* instance, void (T::*excb)(const ::Ice::Exception&), void (T::*sentcb)(bool) = 0)
+{
+ return new CallbackNC_Connection_heartbeat<T>(instance, excb, sentcb);
+}
+
+template<class T, typename CT>
+class Callback_Connection_heartbeat : public Callback_Connection_heartbeat_Base,
+ public ::IceInternal::OnewayCallback<T, CT>
+{
+public:
+
+ typedef IceUtil::Handle<T> TPtr;
+
+ typedef void (T::*Exception)(const ::Ice::Exception& , const CT&);
+ typedef void (T::*Sent)(bool , const CT&);
+
+ Callback_Connection_heartbeat(const TPtr& obj, Exception excb, Sent sentcb)
+ : ::IceInternal::OnewayCallback<T, CT>(obj, 0, excb, sentcb)
+ {
+ }
+
+ virtual void completed(const ::Ice::AsyncResultPtr& __result) const
+ {
+ ::Ice::ConnectionPtr __con = __result->getConnection();
+ assert(__con);
+ try
+ {
+ __con->end_heartbeat(__result);
+ assert(false);
+ }
+ catch(const ::Ice::Exception& ex)
+ {
+ ::IceInternal::Callback<T, CT>::exception(__result, ex);
+ }
+ }
+};
+
+template<class T, typename CT> Callback_Connection_heartbeatPtr
+newCallback_Connection_heartbeat(const IceUtil::Handle<T>& instance,
+ void (T::*excb)(const ::Ice::Exception&, const CT&),
+ void (T::*sentcb)(bool, const CT&) = 0)
+{
+ return new Callback_Connection_heartbeat<T, CT>(instance, excb, sentcb);
+}
+
+template<class T, typename CT> Callback_Connection_heartbeatPtr
+newCallback_Connection_heartbeat(T* instance, void (T::*excb)(const ::Ice::Exception&, const CT&),
+ void (T::*sentcb)(bool, const CT&) = 0)
+{
+ return new Callback_Connection_heartbeat<T, CT>(instance, excb, sentcb);
+}
+
}
#endif
diff --git a/cpp/src/Glacier2/RoutingTable.cpp b/cpp/src/Glacier2/RoutingTable.cpp
index fde938fba00..e6b090de4cb 100644
--- a/cpp/src/Glacier2/RoutingTable.cpp
+++ b/cpp/src/Glacier2/RoutingTable.cpp
@@ -65,7 +65,7 @@ Glacier2::RoutingTable::add(const ObjectProxySeq& unfiltered, const Current& cur
if(!_verifier->verify(*prx))
{
- current.con->close(true);
+ current.con->close(CloseForcefully);
throw ObjectNotExistException(__FILE__, __LINE__);
}
ObjectPrx proxy = (*prx)->ice_twoway()->ice_secure(false)->ice_facet(""); // We add proxies in default form.
diff --git a/cpp/src/Glacier2/SessionRouterI.cpp b/cpp/src/Glacier2/SessionRouterI.cpp
index 9f774b79a8e..512d371611f 100644
--- a/cpp/src/Glacier2/SessionRouterI.cpp
+++ b/cpp/src/Glacier2/SessionRouterI.cpp
@@ -80,7 +80,7 @@ public:
// Close the connection otherwise the peer has no way to know that
// the session has gone.
//
- _connection->close(true);
+ _connection->close(CloseForcefully);
_router->destroySession(_connection);
}
}
@@ -922,7 +922,7 @@ SessionRouterI::refreshSession(const Ice::ConnectionPtr& con)
// Close the connection otherwise the peer has no way to know that the
// session has gone.
//
- con->close(true);
+ con->close(CloseForcefully);
throw SessionNotExistException();
}
}
@@ -1149,10 +1149,10 @@ SessionRouterI::getRouterImpl(const ConnectionPtr& connection, const Ice::Identi
if(_rejectTraceLevel >= 1)
{
Trace out(_instance->logger(), "Glacier2");
- out << "rejecting request. no session is associated with the connection.\n";
- out << "identity: " << _instance->communicator()->identityToString(id);
+ out << "rejecting request, no session is associated with the connection.\n";
+ out << "identity: " << identityToString(id);
}
- connection->close(true);
+ connection->close(CloseForcefully);
throw ObjectNotExistException(__FILE__, __LINE__);
}
return 0;
diff --git a/cpp/src/Ice/ConnectionI.cpp b/cpp/src/Ice/ConnectionI.cpp
index 7845259855c..23388d399c6 100644
--- a/cpp/src/Ice/ConnectionI.cpp
+++ b/cpp/src/Ice/ConnectionI.cpp
@@ -409,29 +409,31 @@ Ice::ConnectionI::destroy(DestructionReason reason)
}
void
-Ice::ConnectionI::close(bool force)
+Ice::ConnectionI::close(ConnectionClose mode)
{
IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this);
- if(force)
+ if(mode == CloseForcefully)
{
- setState(StateClosed, ForcedCloseConnectionException(__FILE__, __LINE__));
+ setState(StateClosed, ConnectionManuallyClosedException(__FILE__, __LINE__, false));
+ }
+ else if(mode == CloseGracefully)
+ {
+ setState(StateClosing, ConnectionManuallyClosedException(__FILE__, __LINE__, true));
}
else
{
+ assert(mode == CloseGracefullyAndWait);
+
//
- // If we do a graceful shutdown, then we wait until all
- // outstanding requests have been completed. Otherwise, the
- // CloseConnectionException will cause all outstanding
- // requests to be retried, regardless of whether the server
- // has processed them or not.
+ // Wait until all outstanding requests have been completed.
//
while(!_asyncRequests.empty())
{
wait();
}
- setState(StateClosing, CloseConnectionException(__FILE__, __LINE__));
+ setState(StateClosing, ConnectionManuallyClosedException(__FILE__, __LINE__, true));
}
}
@@ -550,13 +552,13 @@ Ice::ConnectionI::monitor(const IceUtil::Time& now, const ACMConfig& acm)
//
// We send a heartbeat if there was no activity in the last
// (timeout / 4) period. Sending a heartbeat sooner than really
- // needed is safer to ensure that the receiver will receive in
- // time the heartbeat. Sending the heartbeat if there was no
+ // needed is safer to ensure that the receiver will receive the
+ // heartbeat in time. Sending the heartbeat if there was no
// activity in the last (timeout / 2) period isn't enough since
// monitor() is called only every (timeout / 2) period.
//
// Note that this doesn't imply that we are sending 4 heartbeats
- // per timeout period because the monitor() method is sill only
+ // per timeout period because the monitor() method is still only
// called every (timeout / 2) period.
//
if(acm.heartbeat == HeartbeatAlways ||
@@ -564,7 +566,7 @@ Ice::ConnectionI::monitor(const IceUtil::Time& now, const ACMConfig& acm)
{
if(acm.heartbeat != HeartbeatOnInvocation || _dispatchCount > 0)
{
- heartbeat();
+ sendHeartbeatNow();
}
}
@@ -802,6 +804,174 @@ Ice::ConnectionI::end_flushBatchRequests(const AsyncResultPtr& r)
}
#endif
+namespace
+{
+
+const ::std::string __heartbeat_name = "heartbeat";
+
+class HeartbeatAsync : public OutgoingAsyncBase
+{
+public:
+
+ HeartbeatAsync(const ConnectionIPtr& connection,
+ const CommunicatorPtr& communicator,
+ const InstancePtr& instance) :
+ OutgoingAsyncBase(instance),
+ _communicator(communicator),
+ _connection(connection)
+ {
+ }
+
+ virtual CommunicatorPtr getCommunicator() const
+ {
+ return _communicator;
+ }
+
+ virtual ConnectionPtr getConnection() const
+ {
+ return _connection;
+ }
+
+ virtual const string& getOperation() const
+ {
+ return __heartbeat_name;
+ }
+
+ void invoke()
+ {
+ _observer.attach(_instance.get(), __heartbeat_name);
+ try
+ {
+ _os.write(magic[0]);
+ _os.write(magic[1]);
+ _os.write(magic[2]);
+ _os.write(magic[3]);
+ _os.write(currentProtocol);
+ _os.write(currentProtocolEncoding);
+ _os.write(validateConnectionMsg);
+ _os.write(static_cast<Byte>(0)); // Compression status (always zero for validate connection).
+ _os.write(headerSize); // Message size.
+ _os.i = _os.b.begin();
+
+ AsyncStatus status = _connection->sendAsyncRequest(ICE_SHARED_FROM_THIS, false, false, 0);
+ if(status & AsyncStatusSent)
+ {
+ _sentSynchronously = true;
+ if(status & AsyncStatusInvokeSentCallback)
+ {
+ invokeSent();
+ }
+ }
+ }
+ catch(const RetryException& ex)
+ {
+ if(exception(*ex.get()))
+ {
+ invokeExceptionAsync();
+ }
+ }
+ catch(const Exception& ex)
+ {
+ if(exception(ex))
+ {
+ invokeExceptionAsync();
+ }
+ }
+ }
+
+private:
+
+ CommunicatorPtr _communicator;
+ ConnectionIPtr _connection;
+};
+typedef IceUtil::Handle<HeartbeatAsync> HeartbeatAsyncPtr;
+
+}
+
+#ifdef ICE_CPP11_MAPPING
+void
+Ice::ConnectionI::heartbeat()
+{
+ Connection::heartbeatAsync().get();
+}
+
+std::function<void()>
+Ice::ConnectionI::heartbeatAsync(::std::function<void(::std::exception_ptr)> ex, ::std::function<void(bool)> sent)
+{
+ class HeartbeatLambda : public HeartbeatAsync, public LambdaInvoke
+ {
+ public:
+
+ HeartbeatLambda(std::shared_ptr<Ice::ConnectionI>&& connection,
+ std::shared_ptr<Ice::Communicator>& communicator,
+ const InstancePtr& instance,
+ std::function<void(std::exception_ptr)> ex,
+ std::function<void(bool)> sent) :
+ HeartbeatAsync(connection, communicator, instance), LambdaInvoke(std::move(ex), std::move(sent))
+ {
+ }
+ };
+ auto outAsync = make_shared<HeartbeatLambda>(ICE_SHARED_FROM_THIS, _communicator, _instance, ex, sent);
+ outAsync->invoke();
+ return [outAsync]() { outAsync->cancel(); };
+}
+#else
+void
+Ice::ConnectionI::heartbeat()
+{
+ end_heartbeat(begin_heartbeat());
+}
+
+AsyncResultPtr
+Ice::ConnectionI::begin_heartbeat()
+{
+ return _iceI_begin_heartbeat(dummyCallback, 0);
+}
+
+AsyncResultPtr
+Ice::ConnectionI::begin_heartbeat(const CallbackPtr& cb, const LocalObjectPtr& cookie)
+{
+ return _iceI_begin_heartbeat(cb, cookie);
+}
+
+AsyncResultPtr
+Ice::ConnectionI::begin_heartbeat(const Callback_Connection_heartbeatPtr& cb, const LocalObjectPtr& cookie)
+{
+ return _iceI_begin_heartbeat(cb, cookie);
+}
+
+AsyncResultPtr
+Ice::ConnectionI::_iceI_begin_heartbeat(const CallbackBasePtr& cb, const LocalObjectPtr& cookie)
+{
+ class HeartbeatCallback : public HeartbeatAsync, public CallbackCompletion
+ {
+ public:
+
+ HeartbeatCallback(const ConnectionIPtr& connection,
+ const CommunicatorPtr& communicator,
+ const InstancePtr& instance,
+ const CallbackBasePtr& callback,
+ const LocalObjectPtr& cookie) :
+ HeartbeatAsync(connection, communicator, instance),
+ CallbackCompletion(callback, cookie)
+ {
+ _cookie = cookie;
+ }
+ };
+
+ HeartbeatAsyncPtr result = new HeartbeatCallback(this, _communicator, _instance, cb, cookie);
+ result->invoke();
+ return result;
+}
+
+void
+Ice::ConnectionI::end_heartbeat(const AsyncResultPtr& r)
+{
+ AsyncResult::check(r, this, __heartbeat_name);
+ r->waitForResponse();
+}
+#endif
+
void
Ice::ConnectionI::setHeartbeatCallback(ICE_IN(ICE_HEARTBEAT_CALLBACK) callback)
{
@@ -1755,7 +1925,7 @@ Ice::ConnectionI::finish(bool close)
out << "closed " << _endpoint->protocol() << " connection\n" << toString();
if(!(dynamic_cast<const CloseConnectionException*>(_exception.get()) ||
- dynamic_cast<const ForcedCloseConnectionException*>(_exception.get()) ||
+ dynamic_cast<const ConnectionManuallyClosedException*>(_exception.get()) ||
dynamic_cast<const ConnectionTimeoutException*>(_exception.get()) ||
dynamic_cast<const CommunicatorDestroyedException*>(_exception.get()) ||
dynamic_cast<const ObjectAdapterDeactivatedException*>(_exception.get())))
@@ -2076,7 +2246,7 @@ Ice::ConnectionI::setState(State state, const LocalException& ex)
// Don't warn about certain expected exceptions.
//
if(!(dynamic_cast<const CloseConnectionException*>(&ex) ||
- dynamic_cast<const ForcedCloseConnectionException*>(&ex) ||
+ dynamic_cast<const ConnectionManuallyClosedException*>(&ex) ||
dynamic_cast<const ConnectionTimeoutException*>(&ex) ||
dynamic_cast<const CommunicatorDestroyedException*>(&ex) ||
dynamic_cast<const ObjectAdapterDeactivatedException*>(&ex) ||
@@ -2255,7 +2425,7 @@ Ice::ConnectionI::setState(State state)
if(_observer && state == StateClosed && _exception)
{
if(!(dynamic_cast<const CloseConnectionException*>(_exception.get()) ||
- dynamic_cast<const ForcedCloseConnectionException*>(_exception.get()) ||
+ dynamic_cast<const ConnectionManuallyClosedException*>(_exception.get()) ||
dynamic_cast<const ConnectionTimeoutException*>(_exception.get()) ||
dynamic_cast<const CommunicatorDestroyedException*>(_exception.get()) ||
dynamic_cast<const ObjectAdapterDeactivatedException*>(_exception.get()) ||
@@ -2285,8 +2455,7 @@ Ice::ConnectionI::setState(State state)
void
Ice::ConnectionI::initiateShutdown()
{
- assert(_state == StateClosing);
- assert(_dispatchCount == 0);
+ assert(_state == StateClosing && _dispatchCount == 0);
if(_shutdownInitiated)
{
@@ -2316,7 +2485,7 @@ Ice::ConnectionI::initiateShutdown()
setState(StateClosingPending);
//
- // Notify the the transceiver of the graceful connection closure.
+ // Notify the transceiver of the graceful connection closure.
//
SocketOperation op = _transceiver->closing(true, *_exception);
if(op)
@@ -2329,7 +2498,7 @@ Ice::ConnectionI::initiateShutdown()
}
void
-Ice::ConnectionI::heartbeat()
+Ice::ConnectionI::sendHeartbeatNow()
{
assert(_state == StateActive);
@@ -3016,7 +3185,7 @@ Ice::ConnectionI::parseMessage(InputStream& stream, Int& invokeNum, Int& request
setState(StateClosingPending, CloseConnectionException(__FILE__, __LINE__));
//
- // Notify the the transceiver of the graceful connection closure.
+ // Notify the transceiver of the graceful connection closure.
//
SocketOperation op = _transceiver->closing(false, *_exception);
if(op)
diff --git a/cpp/src/Ice/ConnectionI.h b/cpp/src/Ice/ConnectionI.h
index 72652518b94..7fb3781e880 100644
--- a/cpp/src/Ice/ConnectionI.h
+++ b/cpp/src/Ice/ConnectionI.h
@@ -157,12 +157,12 @@ public:
void activate();
void hold();
void destroy(DestructionReason);
- virtual void close(bool); // From Connection.
+ virtual void close(ConnectionClose); // From Connection.
bool isActiveOrHolding() const;
bool isFinished() const;
- void throwException() const; // Throws the connection exception if destroyed.
+ virtual void throwException() const; // From Connection. Throws the connection exception if destroyed.
void waitUntilHolding() const;
void waitUntilFinished(); // Not const, as this might close the connection upon timeout.
@@ -193,6 +193,19 @@ public:
virtual void setCloseCallback(ICE_IN(ICE_CLOSE_CALLBACK));
virtual void setHeartbeatCallback(ICE_IN(ICE_HEARTBEAT_CALLBACK));
+ virtual void heartbeat();
+
+#ifdef ICE_CPP11_MAPPING
+ virtual std::function<void()>
+ heartbeatAsync(::std::function<void(::std::exception_ptr)>, ::std::function<void(bool)> = nullptr);
+#else
+ virtual AsyncResultPtr begin_heartbeat();
+ virtual AsyncResultPtr begin_heartbeat(const CallbackPtr&, const LocalObjectPtr& = 0);
+ virtual AsyncResultPtr begin_heartbeat(const Callback_Connection_heartbeatPtr&, const LocalObjectPtr& = 0);
+
+ virtual void end_heartbeat(const AsyncResultPtr&);
+#endif
+
virtual void setACM(const IceUtil::Optional<int>&,
const IceUtil::Optional<ACMClose>&,
const IceUtil::Optional<ACMHeartbeat>&);
@@ -276,7 +289,7 @@ private:
void setState(State);
void initiateShutdown();
- void heartbeat();
+ void sendHeartbeatNow();
bool initialize(IceInternal::SocketOperation = IceInternal::SocketOperationNone);
bool validate(IceInternal::SocketOperation = IceInternal::SocketOperationNone);
@@ -308,6 +321,7 @@ private:
#ifndef ICE_CPP11_MAPPING
AsyncResultPtr _iceI_begin_flushBatchRequests(const IceInternal::CallbackBasePtr&, const LocalObjectPtr&);
+ AsyncResultPtr _iceI_begin_heartbeat(const IceInternal::CallbackBasePtr&, const LocalObjectPtr&);
#endif
Ice::CommunicatorPtr _communicator;
diff --git a/cpp/src/Ice/Exception.cpp b/cpp/src/Ice/Exception.cpp
index 4ac7d66cdd3..a20c564101e 100644
--- a/cpp/src/Ice/Exception.cpp
+++ b/cpp/src/Ice/Exception.cpp
@@ -632,14 +632,10 @@ Ice::CloseConnectionException::ice_print(ostream& out) const
}
void
-Ice::ForcedCloseConnectionException::ice_print(ostream& out) const
+Ice::ConnectionManuallyClosedException::ice_print(ostream& out) const
{
Exception::ice_print(out);
- out << ":\nprotocol error: connection forcefully closed";
- if(!reason.empty())
- {
- out << ":\n" << reason;
- }
+ out << ":\nprotocol error: connection manually closed (" << (graceful ? "gracefully" : "forcefully") << ")";
}
void
diff --git a/cpp/src/Ice/ProxyFactory.cpp b/cpp/src/Ice/ProxyFactory.cpp
index eba949508b6..34503ec961b 100644
--- a/cpp/src/Ice/ProxyFactory.cpp
+++ b/cpp/src/Ice/ProxyFactory.cpp
@@ -201,11 +201,12 @@ IceInternal::ProxyFactory::checkRetryAfterException(const LocalException& ex, co
}
//
- // Don't retry if the communicator is destroyed or object adapter
- // deactivated.
+ // Don't retry if the communicator is destroyed, object adapter is deactivated,
+ // or connection is manually closed.
//
if(dynamic_cast<const CommunicatorDestroyedException*>(&ex) ||
- dynamic_cast<const ObjectAdapterDeactivatedException*>(&ex))
+ dynamic_cast<const ObjectAdapterDeactivatedException*>(&ex) ||
+ dynamic_cast<const ConnectionManuallyClosedException*>(&ex))
{
ex.ice_throw();
}
diff --git a/cpp/src/IceBridge/IceBridge.cpp b/cpp/src/IceBridge/IceBridge.cpp
new file mode 100644
index 00000000000..31ec58aae6c
--- /dev/null
+++ b/cpp/src/IceBridge/IceBridge.cpp
@@ -0,0 +1,837 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Ice/Connection.h>
+#include <Ice/ObjectAdapter.h>
+#include <Ice/Service.h>
+#include <Ice/UUID.h>
+#include <IceUtil/Options.h>
+
+using namespace std;
+using namespace Ice;
+
+namespace
+{
+
+//
+// Represents a pending twoway invocation.
+//
+class Invocation : public IceUtil::Shared
+{
+public:
+
+ Invocation(const AMD_Object_ice_invokePtr& cb) :
+ _cb(cb)
+ {
+ }
+
+ void success(bool ok, const pair<const Byte*, const Byte*>& results)
+ {
+ _cb->ice_response(ok, results);
+ }
+
+ void exception(const Exception& ex)
+ {
+ _cb->ice_exception(ex);
+ }
+
+private:
+
+ AMD_Object_ice_invokePtr _cb;
+};
+typedef IceUtil::Handle<Invocation> InvocationPtr;
+
+//
+// Represents a pending oneway invocation.
+//
+class OnewayInvocation : public IceUtil::Shared
+{
+public:
+
+ OnewayInvocation(const AMD_Object_ice_invokePtr& cb) :
+ _cb(cb)
+ {
+ }
+
+ void success(bool, const pair<const Byte*, const Byte*>&)
+ {
+ assert(false);
+ }
+
+ void exception(const Exception& ex)
+ {
+ _cb->ice_exception(ex);
+ }
+
+ void sent(bool sentSynchronously)
+ {
+ _cb->ice_response(true, vector<Byte>());
+ }
+
+private:
+
+ AMD_Object_ice_invokePtr _cb;
+};
+typedef IceUtil::Handle<OnewayInvocation> OnewayInvocationPtr;
+
+//
+// Holds information about an incoming invocation that's been queued until an outgoing connection has
+// been established.
+//
+struct QueuedInvocation : public IceUtil::Shared
+{
+ QueuedInvocation(const AMD_Object_ice_invokePtr& c, const pair<const Byte*, const Byte*>& p, const Current& curr) :
+ cb(c), current(curr)
+ {
+ if(p.first)
+ {
+ //
+ // The pointers in paramData refer to the Ice marshaling buffer and won't remain valid after
+ // ice_invoke_async completes, so we have to make a copy of the parameter data.
+ //
+ vector<Byte> tmp(p.first, p.second);
+ paramData.swap(tmp);
+ }
+ }
+
+ const AMD_Object_ice_invokePtr cb;
+ vector<Byte> paramData;
+ const Current current;
+};
+typedef IceUtil::Handle<QueuedInvocation> QueuedInvocationPtr;
+typedef vector<QueuedInvocationPtr> InvocationList;
+
+//
+// Relays heartbeat messages.
+//
+class HeartbeatCallbackI : public HeartbeatCallback
+{
+public:
+
+ HeartbeatCallbackI(const ConnectionPtr& con) :
+ _connection(con)
+ {
+ }
+
+ virtual void heartbeat(const ConnectionPtr&)
+ {
+ //
+ // When a connection receives a heartbeat message, we send one over its corresponding connection.
+ //
+ try
+ {
+ _connection->begin_heartbeat();
+ }
+ catch(...)
+ {
+ }
+ }
+
+private:
+
+ const ConnectionPtr _connection;
+};
+
+//
+// Represents a pair of bridged connections.
+//
+class BridgeConnection : public IceUtil::Shared
+{
+public:
+
+ BridgeConnection(const ObjectAdapterPtr& adapter, const ObjectPrx& target, const ConnectionPtr& incoming) :
+ _adapter(adapter), _target(target), _incoming(incoming), _closed(false)
+ {
+ }
+
+ void setOutgoing(const ConnectionPtr& outgoing)
+ {
+ if(outgoing)
+ {
+ InvocationList queuedInvocations;
+
+ {
+ IceUtil::Mutex::Lock lock(_lock);
+
+ assert(!_outgoing);
+
+ if(_closed)
+ {
+ //
+ // The incoming connection is already closed. There's no point in leaving the outgoing
+ // connection open.
+ //
+ outgoing->close(CloseGracefully);
+ }
+ else
+ {
+ _outgoing = outgoing;
+
+ //
+ // Save the queued invocations.
+ //
+ queuedInvocations.swap(_queue);
+
+ //
+ // Register hearbeat callbacks on both connections.
+ //
+ _incoming->setHeartbeatCallback(new HeartbeatCallbackI(_outgoing));
+ _outgoing->setHeartbeatCallback(new HeartbeatCallbackI(_incoming));
+
+ //
+ // Configure the outgoing connection for bidirectional requests.
+ //
+ _outgoing->setAdapter(_adapter);
+ }
+ }
+
+ //
+ // Flush any queued invocations.
+ //
+ flush(outgoing, queuedInvocations);
+ }
+ else
+ {
+ IceUtil::Mutex::Lock lock(_lock);
+
+ //
+ // The outgoing connection failed so we close the incoming connection. closed() will eventually
+ // be called for it.
+ //
+ if(_incoming)
+ {
+ _incoming->close(CloseGracefully);
+ }
+ }
+ }
+
+ void closed(const ConnectionPtr& con)
+ {
+ InvocationList queuedInvocations;
+ ConnectionPtr toBeClosed;
+
+ {
+ IceUtil::Mutex::Lock lock(_lock);
+
+ if(con == _incoming)
+ {
+ //
+ // The incoming connection was closed.
+ //
+ toBeClosed = _outgoing;
+ queuedInvocations.swap(_queue);
+ _closed = true;
+ _incoming = 0;
+ }
+ else
+ {
+ assert(con == _outgoing);
+
+ //
+ // An outgoing connection was closed.
+ //
+ toBeClosed = _incoming;
+ _outgoing = 0;
+ }
+ }
+
+ //
+ // Close the corresponding connection.
+ //
+ if(toBeClosed)
+ {
+ //
+ // Examine the exception that caused the connection to be closed. A CloseConnectionException
+ // indicates the connection was closed gracefully and we do the same. We also look for
+ // ConnectionManuallyClosedException, which indicates the connection was closed locally.
+ // We close forcefully for any other exception.
+ //
+ try
+ {
+ con->throwException();
+ }
+ catch(const Ice::CloseConnectionException&)
+ {
+ toBeClosed->close(CloseGracefully);
+ }
+ catch(const Ice::ConnectionManuallyClosedException& ex)
+ {
+ //
+ // Connection was manually closed by the bridge.
+ //
+ toBeClosed->close(ex.graceful ? CloseGracefully : CloseForcefully);
+ }
+ catch(...)
+ {
+ toBeClosed->close(CloseForcefully);
+ }
+ }
+
+ //
+ // Even though the connection is already closed, we still need to "complete" the pending invocations so
+ // that the connection's dispatch count is updated correctly.
+ //
+ for(InvocationList::iterator p = queuedInvocations.begin(); p != queuedInvocations.end(); ++p)
+ {
+ (*p)->cb->ice_exception(ConnectionLostException(__FILE__, __LINE__));
+ }
+ }
+
+ void dispatch(const AMD_Object_ice_invokePtr& cb, const pair<const Byte*, const Byte*>& paramData,
+ const Current& current)
+ {
+ //
+ // We've received an invocations, either from the client via the incoming connection, or from
+ // the server via the outgoing (bidirectional) connection. The current.con member tells us
+ // the connection over which the request arrived.
+ //
+
+ ConnectionPtr dest;
+
+ {
+ IceUtil::Mutex::Lock lock(_lock);
+
+ if(_closed)
+ {
+ //
+ // If the incoming connection has already closed, we're done.
+ //
+ cb->ice_exception(ConnectionLostException(__FILE__, __LINE__));
+ }
+ else if(!_outgoing)
+ {
+ //
+ // Queue the invocation until the outgoing connection is established.
+ //
+ _queue.push_back(new QueuedInvocation(cb, paramData, current));
+ }
+ else if(current.con == _incoming)
+ {
+ //
+ // Forward to the outgoing connection.
+ //
+ dest = _outgoing;
+ }
+ else
+ {
+ //
+ // Forward to the incoming connection.
+ //
+ assert(current.con == _outgoing);
+ dest = _incoming;
+ }
+ }
+
+ if(dest)
+ {
+ send(dest, cb, paramData, current);
+ }
+ }
+
+private:
+
+ void flush(const ConnectionPtr& outgoing, const InvocationList& invocations)
+ {
+ for(InvocationList::const_iterator p = invocations.begin(); p != invocations.end(); ++p)
+ {
+ QueuedInvocationPtr i = *p;
+
+ pair<const Byte*, const Byte*> paramData;
+ if(i->paramData.empty())
+ {
+ paramData.first = paramData.second = 0;
+ }
+ else
+ {
+ paramData.first = &i->paramData[0];
+ paramData.second = paramData.first + i->paramData.size();
+ }
+
+ send(outgoing, i->cb, paramData, i->current);
+ }
+ }
+
+ void send(const ConnectionPtr& dest, const AMD_Object_ice_invokePtr& cb,
+ const pair<const Byte*, const Byte*>& paramData, const Current& current)
+ {
+ try
+ {
+ //
+ // Create a proxy having the same identity as the request.
+ //
+ ObjectPrx prx = dest->createProxy(current.id);
+
+ //
+ // Examine the proxy and the request to determine whether it should be forwarded as a oneway or a twoway.
+ //
+ if(!prx->ice_isTwoway() || !current.requestId)
+ {
+ if(prx->ice_isTwoway())
+ {
+ prx = prx->ice_oneway();
+ }
+ OnewayInvocationPtr i = new OnewayInvocation(cb);
+ Callback_Object_ice_invokePtr d =
+ newCallback_Object_ice_invoke(i, &OnewayInvocation::success, &OnewayInvocation::exception,
+ &OnewayInvocation::sent);
+ prx->begin_ice_invoke(current.operation, current.mode, paramData, current.ctx, d);
+ }
+ else
+ {
+ InvocationPtr i = new Invocation(cb);
+ Callback_Object_ice_invokePtr d =
+ newCallback_Object_ice_invoke(i, &Invocation::success, &Invocation::exception);
+ prx->begin_ice_invoke(current.operation, current.mode, paramData, current.ctx, d);
+ }
+ }
+ catch(const std::exception& ex)
+ {
+ cb->ice_exception(ex);
+ }
+ }
+
+ const ObjectAdapterPtr _adapter;
+ const ObjectPrx _target;
+ ConnectionPtr _incoming;
+
+ IceUtil::Mutex _lock;
+
+ bool _closed;
+ ConnectionPtr _outgoing;
+
+ //
+ // We maintain our own queue for invocations that arrive on the incoming connection before the outgoing
+ // connection has been established. We don't want to forward these to proxies and let the proxies handle
+ // the queuing because then the invocations could be sent out of order (e.g., when invocations are split
+ // among twoway/oneway/datagram proxies).
+ //
+ InvocationList _queue;
+};
+typedef IceUtil::Handle<BridgeConnection> BridgeConnectionPtr;
+
+//
+// Allows the bridge to be used as an Ice router.
+//
+class RouterI : public Router
+{
+public:
+
+ virtual ObjectPrx getClientProxy(const Current&) const
+ {
+ return 0;
+ }
+
+ virtual ObjectPrx getServerProxy(const Current&) const
+ {
+ return 0;
+ }
+
+ virtual ObjectProxySeq addProxies(const ObjectProxySeq&, const Current&)
+ {
+ return ObjectProxySeq();
+ }
+};
+
+class FinderI : public RouterFinder
+{
+public:
+
+ FinderI(const RouterPrx& router) :
+ _router(router)
+ {
+ }
+
+ virtual RouterPrx getRouter(const Current&)
+ {
+ return _router;
+ }
+
+private:
+
+ const RouterPrx _router;
+};
+
+class BridgeI;
+typedef IceUtil::Handle<BridgeI> BridgeIPtr;
+
+class CloseCallbackI : public CloseCallback
+{
+public:
+
+ CloseCallbackI(const BridgeIPtr& bridge) :
+ _bridge(bridge)
+ {
+ }
+
+ virtual void closed(const ConnectionPtr&);
+
+private:
+
+ const BridgeIPtr _bridge;
+};
+
+class GetConnectionCallback : public IceUtil::Shared
+{
+public:
+
+ GetConnectionCallback(const BridgeIPtr& bridge, const BridgeConnectionPtr& bc) :
+ _bridge(bridge), _bc(bc)
+ {
+ }
+
+ void success(const ConnectionPtr&);
+ void exception(const Exception&);
+
+private:
+
+ const BridgeIPtr _bridge;
+ const BridgeConnectionPtr _bc;
+};
+typedef IceUtil::Handle<GetConnectionCallback> GetConnectionCallbackPtr;
+
+//
+// The main bridge servant.
+//
+class BridgeI : public Ice::BlobjectArrayAsync
+{
+public:
+
+ BridgeI(const ObjectAdapterPtr& adapter, const ObjectPrx& target) :
+ _adapter(adapter), _target(target)
+ {
+ }
+
+ virtual void ice_invoke_async(const AMD_Object_ice_invokePtr& cb,
+ const std::pair<const Byte*, const Byte*>& paramData,
+ const Current& current)
+ {
+ BridgeConnectionPtr bc;
+
+ {
+ IceUtil::Mutex::Lock lock(_lock);
+
+ ConnectionMap::iterator p = _connections.find(current.con);
+ if(p == _connections.end())
+ {
+ //
+ // The connection is unknown to us, it must be a new incoming connection.
+ //
+
+ EndpointInfoPtr info = current.con->getEndpoint()->getInfo();
+
+ //
+ // Create a target proxy that matches the configuration of the incoming connection.
+ //
+ ObjectPrx target;
+ if(info->datagram())
+ {
+ target = _target->ice_datagram();
+ }
+ else if(info->secure())
+ {
+ target = _target->ice_secure(true);
+ }
+ else
+ {
+ target = _target;
+ }
+
+ //
+ // Force the proxy to establish a new connection by using a unique connection ID.
+ //
+ target = target->ice_connectionId(Ice::generateUUID());
+
+ bc = new BridgeConnection(_adapter, target, current.con);
+ _connections.insert(make_pair(current.con, bc));
+ current.con->setCloseCallback(new CloseCallbackI(this));
+
+ //
+ // Try to establish the outgoing connection.
+ //
+ try
+ {
+ //
+ // Begin the connection establishment process asynchronously. This can take a while to complete,
+ // especially when using Bluetooth.
+ //
+ GetConnectionCallbackPtr gc = new GetConnectionCallback(this, bc);
+ Callback_Object_ice_getConnectionPtr d =
+ newCallback_Object_ice_getConnection(gc, &GetConnectionCallback::success,
+ &GetConnectionCallback::exception);
+ target->begin_ice_getConnection(d);
+ }
+ catch(const Exception& ex)
+ {
+ cb->ice_exception(ex);
+ return;
+ }
+ }
+ else
+ {
+ bc = p->second;
+ }
+ }
+
+ //
+ // Delegate the invocation to the BridgeConnection object.
+ //
+ bc->dispatch(cb, paramData, current);
+ }
+
+ void closed(const ConnectionPtr& con)
+ {
+ //
+ // Notify the BridgeConnection that a connection has closed. We also need to remove it from our map.
+ //
+
+ BridgeConnectionPtr bc;
+
+ {
+ IceUtil::Mutex::Lock lock(_lock);
+
+ ConnectionMap::iterator p = _connections.find(con);
+ assert(p != _connections.end());
+ bc = p->second;
+ _connections.erase(p);
+ }
+
+ bc->closed(con);
+ }
+
+ void outgoingSuccess(const BridgeConnectionPtr& bc, const ConnectionPtr& outgoing)
+ {
+ //
+ // An outgoing connection was established. Notify the BridgeConnection object.
+ //
+ IceUtil::Mutex::Lock lock(_lock);
+ _connections.insert(make_pair(outgoing, bc));
+ outgoing->setCloseCallback(new CloseCallbackI(this));
+ bc->setOutgoing(outgoing);
+ }
+
+ void outgoingException(const BridgeConnectionPtr& bc, const Exception& ex)
+ {
+ //
+ // An outgoing connection attempt failed. Notify the BridgeConnection object.
+ //
+ bc->setOutgoing(0);
+ }
+
+private:
+
+ const ObjectAdapterPtr _adapter;
+ const ObjectPrx _target;
+
+ IceUtil::Mutex _lock;
+
+ typedef map<ConnectionPtr, BridgeConnectionPtr> ConnectionMap;
+ ConnectionMap _connections;
+};
+
+void
+CloseCallbackI::closed(const ConnectionPtr& con)
+{
+ _bridge->closed(con);
+}
+
+void
+GetConnectionCallback::success(const ConnectionPtr& outgoing)
+{
+ _bridge->outgoingSuccess(_bc, outgoing);
+}
+
+void
+GetConnectionCallback::exception(const Exception& ex)
+{
+ _bridge->outgoingException(_bc, ex);
+}
+
+class BridgeService : public Service
+{
+public:
+
+ BridgeService();
+
+protected:
+
+ virtual bool start(int, char*[], int&);
+ virtual bool stop();
+ virtual CommunicatorPtr initializeCommunicator(int&, char*[], const InitializationData&);
+
+private:
+
+ void usage(const std::string&);
+};
+
+}
+
+BridgeService::BridgeService()
+{
+}
+
+bool
+BridgeService::start(int argc, char* argv[], int& status)
+{
+ IceUtilInternal::Options opts;
+ opts.addOpt("h", "help");
+ opts.addOpt("v", "version");
+
+ vector<string> args;
+ try
+ {
+ args = opts.parse(argc, const_cast<const char**>(argv));
+ }
+ catch(const IceUtilInternal::BadOptException& e)
+ {
+ error(e.reason);
+ usage(argv[0]);
+ return false;
+ }
+
+ if(opts.isSet("help"))
+ {
+ usage(argv[0]);
+ status = EXIT_SUCCESS;
+ return false;
+ }
+ if(opts.isSet("version"))
+ {
+ print(ICE_STRING_VERSION);
+ status = EXIT_SUCCESS;
+ return false;
+ }
+
+ if(!args.empty())
+ {
+ cerr << argv[0] << ": too many arguments" << endl;
+ usage(argv[0]);
+ return false;
+ }
+
+ PropertiesPtr properties = communicator()->getProperties();
+
+ const string targetProperty = "IceBridge.Target.Endpoints";
+ const string targetEndpoints = properties->getProperty(targetProperty);
+ if(targetEndpoints.empty())
+ {
+ error("property '" + targetProperty + "' is not set");
+ return false;
+ }
+
+ Ice::ObjectPrx target;
+
+ try
+ {
+ target = communicator()->stringToProxy("dummy:" + targetEndpoints);
+ }
+ catch(const std::exception& ex)
+ {
+ ServiceError err(this);
+ err << "setting for target endpoints '" << targetEndpoints << "' is invalid:\n" << ex;
+ return false;
+ }
+
+ //
+ // Initialize the object adapter.
+ //
+ const string endpointsProperty = "IceBridge.Source.Endpoints";
+ if(properties->getProperty(endpointsProperty).empty())
+ {
+ error("property '" + endpointsProperty + "' is not set");
+ return false;
+ }
+
+ ObjectAdapterPtr adapter = communicator()->createObjectAdapter("IceBridge.Source");
+
+ adapter->addDefaultServant(new BridgeI(adapter, target), "");
+
+ if(properties->getPropertyAsIntWithDefault("IceBridge.Router", 0) > 0)
+ {
+ RouterPrx router = RouterPrx::uncheckedCast(adapter->add(new RouterI, stringToIdentity("IceBridge/router")));
+ adapter->add(new FinderI(router), stringToIdentity("Ice/RouterFinder"));
+ }
+
+ try
+ {
+ adapter->activate();
+ }
+ catch(const std::exception& ex)
+ {
+ {
+ ServiceError err(this);
+ err << "caught exception activating object adapter\n" << ex;
+ }
+
+ stop();
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BridgeService::stop()
+{
+ return true;
+}
+
+CommunicatorPtr
+BridgeService::initializeCommunicator(int& argc, char* argv[], const InitializationData& initializationData)
+{
+ InitializationData initData = initializationData;
+ initData.properties = createProperties(argc, argv, initializationData.properties);
+
+ StringSeq args = argsToStringSeq(argc, argv);
+ args = initData.properties->parseCommandLineOptions("IceBridge", args);
+ stringSeqToArgs(args, argc, argv);
+
+ //
+ // Disable automatic retry by default.
+ //
+ if(initData.properties->getProperty("Ice.RetryIntervals").empty())
+ {
+ initData.properties->setProperty("Ice.RetryIntervals", "-1");
+ }
+
+ return Service::initializeCommunicator(argc, argv, initData);
+}
+
+void
+BridgeService::usage(const string& appName)
+{
+ string options =
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n";
+#ifndef _WIN32
+ options.append(
+ "--daemon Run as a daemon.\n"
+ "--pidfile FILE Write process ID into FILE.\n"
+ "--noclose Do not close open file descriptors.\n"
+ "--nochdir Do not change the current working directory.\n"
+ );
+#endif
+ print("Usage: " + appName + " [options]\n" + options);
+}
+
+#ifdef _WIN32
+
+int
+wmain(int argc, wchar_t* argv[])
+
+#else
+
+int
+main(int argc, char* argv[])
+
+#endif
+{
+ BridgeService svc;
+ return svc.main(argc, argv);
+}
diff --git a/cpp/src/IceBridge/Makefile.mk b/cpp/src/IceBridge/Makefile.mk
new file mode 100644
index 00000000000..b3c282b0c39
--- /dev/null
+++ b/cpp/src/IceBridge/Makefile.mk
@@ -0,0 +1,15 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+$(project)_programs := icebridge
+$(project)_dependencies := Ice
+
+icebridge_targetdir := $(bindir)
+
+projects += $(project)
diff --git a/cpp/src/IceGrid/SessionManager.cpp b/cpp/src/IceGrid/SessionManager.cpp
index 34caf1f9bd2..57ded43015f 100644
--- a/cpp/src/IceGrid/SessionManager.cpp
+++ b/cpp/src/IceGrid/SessionManager.cpp
@@ -58,7 +58,7 @@ SessionManager::findAllQueryObjects(bool cached)
{
try
{
- connection->close(false);
+ connection->close(Ice::CloseGracefullyAndWait);
}
catch(const Ice::LocalException&)
{
diff --git a/cpp/test/Ice/acm/AllTests.cpp b/cpp/test/Ice/acm/AllTests.cpp
index 52c4922d98b..8e6563ede85 100644
--- a/cpp/test/Ice/acm/AllTests.cpp
+++ b/cpp/test/Ice/acm/AllTests.cpp
@@ -535,6 +535,32 @@ public:
}
};
+class HeartbeatManualTest : public TestCase
+{
+public:
+
+ HeartbeatManualTest(const RemoteCommunicatorPrxPtr& com) : TestCase("manual heartbeats", com)
+ {
+ //
+ // Disable heartbeats.
+ //
+ setClientACM(10, -1, 0);
+ setServerACM(10, -1, 0);
+ }
+
+ virtual void runTestCase(const RemoteObjectAdapterPrxPtr& adapter, const TestIntfPrxPtr& proxy)
+ {
+ proxy->startHeartbeatCount();
+ Ice::ConnectionPtr con = proxy->ice_getConnection();
+ con->heartbeat();
+ con->heartbeat();
+ con->heartbeat();
+ con->heartbeat();
+ con->heartbeat();
+ proxy->waitForHeartbeatCount(5);
+ }
+};
+
class SetACMTest : public TestCase
{
public:
@@ -564,8 +590,9 @@ public:
test(acm.close == Ice::CloseOnInvocationAndIdle);
test(acm.heartbeat == Ice::HeartbeatAlways);
- // Make sure the client sends few heartbeats to the server
- proxy->waitForHeartbeat(2);
+ // Make sure the client sends a few heartbeats to the server.
+ proxy->startHeartbeatCount();
+ proxy->waitForHeartbeatCount(2);
}
};
@@ -591,6 +618,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
tests.push_back(ICE_MAKE_SHARED(HeartbeatOnIdleTest, com));
tests.push_back(ICE_MAKE_SHARED(HeartbeatAlwaysTest, com));
+ tests.push_back(ICE_MAKE_SHARED(HeartbeatManualTest, com));
tests.push_back(ICE_MAKE_SHARED(SetACMTest, com));
for(vector<TestCasePtr>::const_iterator p = tests.begin(); p != tests.end(); ++p)
diff --git a/cpp/test/Ice/acm/Test.ice b/cpp/test/Ice/acm/Test.ice
index 5ab98180dd3..d78abd6eb0f 100644
--- a/cpp/test/Ice/acm/Test.ice
+++ b/cpp/test/Ice/acm/Test.ice
@@ -17,7 +17,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/cpp/test/Ice/acm/TestI.cpp b/cpp/test/Ice/acm/TestI.cpp
index d7742680a70..f4987856421 100644
--- a/cpp/test/Ice/acm/TestI.cpp
+++ b/cpp/test/Ice/acm/TestI.cpp
@@ -26,41 +26,6 @@ toString(int value)
return os.str();
}
-class HeartbeatCallbackI :
-#ifdef ICE_CPP11_MAPPING
- public enable_shared_from_this<HeartbeatCallbackI>,
-#else
- public Ice::HeartbeatCallback,
-#endif
- private IceUtil::Monitor<IceUtil::Mutex>
-{
-public:
-
- void
- waitForCount(int count)
- {
- Lock sync(*this);
- _count = count;
- while(_count > 0)
- {
- wait();
- }
- }
-
- virtual void
- heartbeat(const Ice::ConnectionPtr&)
- {
- Lock sync(*this);
- --_count;
- notifyAll();
- }
-
-private:
-
- int _count;
-};
-ICE_DEFINE_PTR(HeartbeatCallbackIPtr, HeartbeatCallbackI);
-
}
RemoteObjectAdapterPrxPtr
@@ -162,16 +127,23 @@ TestI::interruptSleep(const Ice::Current& current)
}
void
-TestI::waitForHeartbeat(int count, const Ice::Current& current)
+TestI::startHeartbeatCount(const Ice::Current& current)
{
- HeartbeatCallbackIPtr callback = ICE_MAKE_SHARED(HeartbeatCallbackI);
+ _callback = ICE_MAKE_SHARED(HeartbeatCallbackI);
#ifdef ICE_CPP11_MAPPING
+ HeartbeatCallbackIPtr callback = _callback;
current.con->setHeartbeatCallback([callback](Ice::ConnectionPtr connection)
{
callback->heartbeat(move(connection));
});
#else
- current.con->setHeartbeatCallback(callback);
+ current.con->setHeartbeatCallback(_callback);
#endif
- callback->waitForCount(count);
+}
+
+void
+TestI::waitForHeartbeatCount(int count, const Ice::Current&)
+{
+ assert(_callback);
+ _callback->waitForCount(count);
}
diff --git a/cpp/test/Ice/acm/TestI.h b/cpp/test/Ice/acm/TestI.h
index be031e3799d..c45415022a6 100644
--- a/cpp/test/Ice/acm/TestI.h
+++ b/cpp/test/Ice/acm/TestI.h
@@ -44,7 +44,51 @@ public:
virtual void sleep(int, const Ice::Current&);
virtual void sleepAndHold(int, const Ice::Current&);
virtual void interruptSleep(const Ice::Current&);
- virtual void waitForHeartbeat(int, const Ice::Current&);
+ virtual void startHeartbeatCount(const Ice::Current&);
+ virtual void waitForHeartbeatCount(int, const Ice::Current&);
+
+private:
+
+ class HeartbeatCallbackI :
+#ifdef ICE_CPP11_MAPPING
+ public std::enable_shared_from_this<HeartbeatCallbackI>,
+#else
+ public Ice::HeartbeatCallback,
+#endif
+ private IceUtil::Monitor<IceUtil::Mutex>
+ {
+ public:
+
+ HeartbeatCallbackI() :
+ _count(0)
+ {
+ }
+
+ void
+ waitForCount(int count)
+ {
+ Lock sync(*this);
+ while(_count < count)
+ {
+ wait();
+ }
+ }
+
+ virtual void
+ heartbeat(const Ice::ConnectionPtr&)
+ {
+ Lock sync(*this);
+ ++_count;
+ notifyAll();
+ }
+
+ private:
+
+ int _count;
+ };
+ ICE_DEFINE_PTR(HeartbeatCallbackIPtr, HeartbeatCallbackI);
+
+ HeartbeatCallbackIPtr _callback;
};
#endif
diff --git a/cpp/test/Ice/ami/AllTests.cpp b/cpp/test/Ice/ami/AllTests.cpp
index 439f8a7792f..3366c4fdc7e 100644
--- a/cpp/test/Ice/ami/AllTests.cpp
+++ b/cpp/test/Ice/ami/AllTests.cpp
@@ -773,6 +773,21 @@ private:
};
typedef IceUtil::Handle<FlushExCallback> FlushExCallbackPtr;
+class CloseCallback : virtual public CallbackBase, virtual public Ice::CloseCallback
+{
+public:
+
+ CloseCallback()
+ {
+ }
+
+ virtual void closed(const Ice::ConnectionPtr& con)
+ {
+ called();
+ }
+};
+typedef IceUtil::Handle<CloseCallback> CloseCallbackPtr;
+
class Thrower : public CallbackBase
{
public:
@@ -1850,7 +1865,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
test(p->opBatchCount() == 0);
auto b1 = p->ice_batchOneway();
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
auto id = this_thread::get_id();
promise<void> promise;
@@ -1924,7 +1939,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
auto b1 = Ice::uncheckedCast<Test::TestIntfPrx>(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
promise<void> promise;
b1->ice_getConnection()->flushBatchRequestsAsync(
@@ -2002,7 +2017,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
auto b1 = Ice::uncheckedCast<Test::TestIntfPrx>(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
promise<void> promise;
auto id = this_thread::get_id();
@@ -2072,8 +2087,8 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
b2->ice_getConnection(); // Ensure connection is established.
b1->opBatch();
b2->opBatch();
- b1->ice_getConnection()->close(false);
- b2->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
+ b2->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
promise<void> promise;
auto id = this_thread::get_id();
@@ -2161,8 +2176,38 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
if(p->ice_getConnection() && protocol != "bt")
{
- cout << "testing close connection with sending queue... " << flush;
+ cout << "testing graceful close connection with wait... " << flush;
+ {
+ //
+ // Local case: begin several requests, close the connection gracefully, and make sure it waits
+ // for the requests to complete.
+ //
+ vector<future<void>> results;
+ for(int i = 0; i < 3; ++i)
+ {
+ auto s = make_shared<promise<void>>();
+ p->sleepAsync(50,
+ [s]() { s->set_value(); },
+ [s](exception_ptr ex) { s->set_exception(ex); });
+ results.push_back(s->get_future());
+ }
+ p->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
+ for(vector<future<void>>::iterator p = results.begin(); p != results.end(); ++p)
+ {
+ try
+ {
+ p->get();
+ }
+ catch(const Ice::LocalException&)
+ {
+ test(false);
+ }
+ }
+ }
{
+ //
+ // Remote case.
+ //
Ice::ByteSeq seq;
seq.resize(1024 * 10);
for(Ice::ByteSeq::iterator q = seq.begin(); q != seq.end(); ++q)
@@ -2191,7 +2236,8 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
results.push_back(s->get_future());
}
atomic_flag sent = ATOMIC_FLAG_INIT;
- p->closeAsync(false, nullptr, nullptr, [&sent](bool) { sent.test_and_set(); });
+ p->closeAsync(Test::CloseMode::CloseGracefullyAndWait, nullptr, nullptr,
+ [&sent](bool) { sent.test_and_set(); });
if(!sent.test_and_set())
{
for(int i = 0; i < maxQueue; i++)
@@ -2231,8 +2277,111 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
}
}
cout << "ok" << endl;
- }
+ cout << "testing graceful close connection without wait... " << flush;
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection gracefully on the client side
+ // without waiting for the pending invocation to complete. There will be no retry and we expect the
+ // invocation to fail with ConnectionManuallyClosedException.
+ //
+ // This test requires two threads in the server's thread pool: one will block in sleep() and the other
+ // will process the CloseConnection message.
+ //
+ p->ice_ping();
+ auto con = p->ice_getConnection();
+ auto s = make_shared<promise<void>>();
+ p->sleepAsync(100,
+ [s]() { s->set_value(); },
+ [s](exception_ptr ex) { s->set_exception(ex); });
+ future<void> f = s->get_future();
+ con->close(Ice::ConnectionClose::CloseGracefully);
+ try
+ {
+ f.get();
+ test(false);
+ }
+ catch(const Ice::ConnectionManuallyClosedException& ex)
+ {
+ test(ex.graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection gracefully. Our call to TestIntf::close()
+ // completes successfully and then the connection should be closed immediately afterward,
+ // despite the fact that there's a pending call to sleep(). The call to sleep() should be
+ // automatically retried and complete successfully with a new connection.
+ //
+ p->ice_ping();
+ con = p->ice_getConnection();
+ auto sc = make_shared<promise<void>>();
+ con->setCloseCallback(
+ [sc](Ice::ConnectionPtr connection)
+ {
+ sc->set_value();
+ });
+ future<void> fc = sc->get_future();
+ s = make_shared<promise<void>>();
+ p->sleepAsync(100,
+ [s]() { s->set_value(); },
+ [s](exception_ptr ex) { s->set_exception(ex); });
+ f = s->get_future();
+ p->close(Test::CloseMode::CloseGracefully);
+ fc.get();
+ try
+ {
+ f.get();
+ }
+ catch(const Ice::LocalException&)
+ {
+ test(false);
+ }
+ p->ice_ping();
+ test(p->ice_getConnection() != con);
+ }
+ cout << "ok" << endl;
+
+ cout << "testing forceful close connection... " << flush;
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection forcefully on the client side.
+ // There will be no retry and we expect the invocation to fail with ConnectionManuallyClosedException.
+ //
+ p->ice_ping();
+ auto con = p->ice_getConnection();
+ auto s = make_shared<promise<void>>();
+ p->sleepAsync(100,
+ [s]() { s->set_value(); },
+ [s](exception_ptr ex) { s->set_exception(ex); });
+ future<void> f = s->get_future();
+ con->close(Ice::ConnectionClose::CloseForcefully);
+ try
+ {
+ f.get();
+ test(false);
+ }
+ catch(const Ice::ConnectionManuallyClosedException& ex)
+ {
+ test(!ex.graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection forcefully. This causes the request to fail
+ // with a ConnectionLostException. Since the close() operation is not idempotent, the client
+ // will not retry.
+ //
+ try
+ {
+ p->close(Test::CloseMode::CloseForcefully);
+ test(false);
+ }
+ catch(const Ice::ConnectionLostException&)
+ {
+ // Expected.
+ }
+ }
+ cout << "ok" << endl;
+ }
}
p->shutdown();
@@ -2944,7 +3093,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
test(p->opBatchCount() == 0);
Test::TestIntfPrx b1 = p->ice_batchOneway();
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = b1->begin_ice_flushBatchRequests(
Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync));
@@ -2962,7 +3111,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
test(p->opBatchCount() == 0);
Test::TestIntfPrx b1 = p->ice_batchOneway();
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback(cookie);
b1->begin_ice_flushBatchRequests(
Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync), cookie);
@@ -3013,7 +3162,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
test(p->opBatchCount() == 0);
Test::TestIntfPrx b1 = p->ice_batchOneway();
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = b1->begin_ice_flushBatchRequests(
Ice::newCallback_Object_ice_flushBatchRequests(cb, &FlushCallback::exception,
@@ -3031,7 +3180,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
test(p->opBatchCount() == 0);
Test::TestIntfPrx b1 = p->ice_batchOneway();
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback(cookie);
b1->begin_ice_flushBatchRequests(
Ice::newCallback_Object_ice_flushBatchRequests(cb, &FlushCallback::exceptionWC,
@@ -3100,7 +3249,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushExCallbackPtr cb = new FlushExCallback();
Ice::AsyncResultPtr r = b1->ice_getConnection()->begin_flushBatchRequests(
Ice::newCallback(cb, &FlushExCallback::completedAsync, &FlushExCallback::sentAsync));
@@ -3119,7 +3268,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushExCallbackPtr cb = new FlushExCallback(cookie);
b1->ice_getConnection()->begin_flushBatchRequests(
Ice::newCallback(cb, &FlushExCallback::completedAsync, &FlushExCallback::sentAsync), cookie);
@@ -3171,7 +3320,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushExCallbackPtr cb = new FlushExCallback();
Ice::AsyncResultPtr r = b1->ice_getConnection()->begin_flushBatchRequests(
Ice::newCallback_Connection_flushBatchRequests(cb, &FlushExCallback::exception,
@@ -3191,7 +3340,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushExCallbackPtr cb = new FlushExCallback(cookie);
b1->ice_getConnection()->begin_flushBatchRequests(
Ice::newCallback_Connection_flushBatchRequests(cb, &FlushExCallback::exceptionWC,
@@ -3249,7 +3398,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = communicator->begin_flushBatchRequests(
Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync));
@@ -3268,7 +3417,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback(cookie);
communicator->begin_flushBatchRequests(
Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync), cookie);
@@ -3319,7 +3468,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
b2->ice_getConnection(); // Ensure connection is established.
b1->opBatch();
b2->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = communicator->begin_flushBatchRequests(
Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync));
@@ -3346,8 +3495,8 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
b2->ice_getConnection(); // Ensure connection is established.
b1->opBatch();
b2->opBatch();
- b1->ice_getConnection()->close(false);
- b2->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
+ b2->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = communicator->begin_flushBatchRequests(
Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync));
@@ -3402,7 +3551,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = communicator->begin_flushBatchRequests(
Ice::newCallback_Communicator_flushBatchRequests(cb, &FlushCallback::exception,
@@ -3422,7 +3571,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
Test::TestIntfPrx b1 = Test::TestIntfPrx::uncheckedCast(
p->ice_getConnection()->createProxy(p->ice_getIdentity())->ice_batchOneway());
b1->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback(cookie);
communicator->begin_flushBatchRequests(
Ice::newCallback_Communicator_flushBatchRequests(cb, &FlushCallback::exceptionWC,
@@ -3476,7 +3625,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
b2->ice_getConnection(); // Ensure connection is established.
b1->opBatch();
b2->opBatch();
- b1->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = communicator->begin_flushBatchRequests(
Ice::newCallback_Communicator_flushBatchRequests(cb, &FlushCallback::exception,
@@ -3504,8 +3653,8 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
b2->ice_getConnection(); // Ensure connection is established.
b1->opBatch();
b2->opBatch();
- b1->ice_getConnection()->close(false);
- b2->ice_getConnection()->close(false);
+ b1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
+ b2->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
FlushCallbackPtr cb = new FlushCallback();
Ice::AsyncResultPtr r = communicator->begin_flushBatchRequests(
Ice::newCallback_Communicator_flushBatchRequests(cb, &FlushCallback::exception,
@@ -3715,8 +3864,35 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
if(p->ice_getConnection() && protocol != "bt")
{
- cout << "testing close connection with sending queue... " << flush;
+ cout << "testing graceful close connection with wait... " << flush;
+ {
+ //
+ // Local case: begin several requests, close the connection gracefully, and make sure it waits
+ // for the requests to complete.
+ //
+ vector<Ice::AsyncResultPtr> results;
+ for(int i = 0; i < 3; ++i)
+ {
+ results.push_back(p->begin_sleep(50));
+ }
+ p->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
+ for(vector<Ice::AsyncResultPtr>::const_iterator q = results.begin(); q != results.end(); ++q)
+ {
+ (*q)->waitForCompleted();
+ try
+ {
+ (*q)->throwLocalException();
+ }
+ catch(const Ice::LocalException&)
+ {
+ test(false);
+ }
+ }
+ }
{
+ //
+ // Remote case.
+ //
Ice::ByteSeq seq;
seq.resize(1024 * 10);
for(Ice::ByteSeq::iterator q = seq.begin(); q != seq.end(); ++q)
@@ -3740,7 +3916,7 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
{
results.push_back(p->begin_opWithPayload(seq));
}
- if(!p->begin_close(false)->isSent())
+ if(!p->begin_close(Test::CloseGracefullyAndWait)->isSent())
{
for(int i = 0; i < maxQueue; i++)
{
@@ -3775,6 +3951,96 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated)
}
}
cout << "ok" << endl;
+
+ cout << "testing graceful close connection without wait... " << flush;
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection gracefully on the client side
+ // without waiting for the pending invocation to complete. There will be no retry and we expect the
+ // invocation to fail with ConnectionManuallyClosedException.
+ //
+ // This test requires two threads in the server's thread pool: one will block in sleep() and the other
+ // will process the CloseConnection message.
+ //
+ p->ice_ping();
+ Ice::ConnectionPtr con = p->ice_getConnection();
+ Ice::AsyncResultPtr r = p->begin_sleep(100);
+ con->close(Ice::CloseGracefully);
+ r->waitForCompleted();
+ try
+ {
+ r->throwLocalException();
+ test(false);
+ }
+ catch(const Ice::ConnectionManuallyClosedException& ex)
+ {
+ test(ex.graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection gracefully. Our call to TestIntf::close()
+ // completes successfully and then the connection should be closed immediately afterward,
+ // despite the fact that there's a pending call to sleep(). The call to sleep() should be
+ // automatically retried and complete successfully.
+ //
+ p->ice_ping();
+ con = p->ice_getConnection();
+ CloseCallbackPtr cb = new CloseCallback;
+ con->setCloseCallback(cb);
+ r = p->begin_sleep(100);
+ p->close(Test::CloseGracefully);
+ cb->check();
+ r->waitForCompleted();
+ try
+ {
+ r->throwLocalException();
+ }
+ catch(const Ice::LocalException&)
+ {
+ test(false);
+ }
+ p->ice_ping();
+ test(p->ice_getConnection() != con);
+ }
+ cout << "ok" << endl;
+
+ cout << "testing forceful close connection... " << flush;
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection forcefully on the client side.
+ // There will be no retry and we expect the invocation to fail with ConnectionManuallyClosedException.
+ //
+ p->ice_ping();
+ Ice::ConnectionPtr con = p->ice_getConnection();
+ Ice::AsyncResultPtr r = p->begin_sleep(100);
+ con->close(Ice::CloseForcefully);
+ r->waitForCompleted();
+ try
+ {
+ r->throwLocalException();
+ test(false);
+ }
+ catch(const Ice::ConnectionManuallyClosedException& ex)
+ {
+ test(!ex.graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection forcefully. This causes the request to fail
+ // with a ConnectionLostException. Since the close() operation is not idempotent, the client
+ // will not retry.
+ //
+ try
+ {
+ p->close(Test::CloseForcefully);
+ test(false);
+ }
+ catch(const Ice::ConnectionLostException&)
+ {
+ // Expected.
+ }
+ }
+ cout << "ok" << endl;
}
p->shutdown();
diff --git a/cpp/test/Ice/ami/Client.cpp b/cpp/test/Ice/ami/Client.cpp
index 18fb26c44bb..c6915bc2557 100644
--- a/cpp/test/Ice/ami/Client.cpp
+++ b/cpp/test/Ice/ami/Client.cpp
@@ -37,6 +37,7 @@ main(int argc, char* argv[])
{
Ice::InitializationData initData = getTestInitData(argc, argv);
initData.properties->setProperty("Ice.Warn.AMICallback", "0");
+ initData.properties->setProperty("Ice.Warn.Connections", "0");
//
// Limit the send buffer size, this test relies on the socket
diff --git a/cpp/test/Ice/ami/Test.ice b/cpp/test/Ice/ami/Test.ice
index 289750a3eb2..c82910e4620 100644
--- a/cpp/test/Ice/ami/Test.ice
+++ b/cpp/test/Ice/ami/Test.ice
@@ -19,6 +19,13 @@ exception TestIntfException
{
};
+enum CloseMode
+{
+ CloseForcefully,
+ CloseGracefully,
+ CloseGracefullyAndWait
+};
+
interface TestIntf
{
void op();
@@ -34,7 +41,8 @@ interface TestIntf
out int eight, out int nine, out int ten, out int eleven);
int opBatchCount();
bool waitForBatch(int count);
- void close(bool force);
+ void close(CloseMode mode);
+ void sleep(int ms);
void shutdown();
bool supportsFunctionalTests();
diff --git a/cpp/test/Ice/ami/TestI.cpp b/cpp/test/Ice/ami/TestI.cpp
index f2dab5afd70..d7aa1d44762 100644
--- a/cpp/test/Ice/ami/TestI.cpp
+++ b/cpp/test/Ice/ami/TestI.cpp
@@ -93,9 +93,16 @@ TestIntfI::waitForBatch(Ice::Int count, const Ice::Current&)
}
void
-TestIntfI::close(bool force, const Ice::Current& current)
+TestIntfI::close(Test::CloseMode mode, const Ice::Current& current)
{
- current.con->close(force);
+ current.con->close(static_cast<ConnectionClose>(mode));
+}
+
+void
+TestIntfI::sleep(Ice::Int ms, const Ice::Current& current)
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this);
+ timedWait(IceUtil::Time::milliSeconds(ms));
}
void
diff --git a/cpp/test/Ice/ami/TestI.h b/cpp/test/Ice/ami/TestI.h
index bee3571b74b..edde85f6008 100644
--- a/cpp/test/Ice/ami/TestI.h
+++ b/cpp/test/Ice/ami/TestI.h
@@ -32,7 +32,8 @@ public:
virtual void opWithArgs(Ice::Int&, Ice::Int&, Ice::Int&, Ice::Int&, Ice::Int&, Ice::Int&, Ice::Int&,
Ice::Int&, Ice::Int&, Ice::Int&, Ice::Int&, const Ice::Current&);
virtual bool waitForBatch(Ice::Int, const Ice::Current&);
- virtual void close(bool, const Ice::Current&);
+ virtual void close(Test::CloseMode, const Ice::Current&);
+ virtual void sleep(Ice::Int, const Ice::Current&);
virtual void shutdown(const Ice::Current&);
virtual bool supportsFunctionalTests(const Ice::Current&);
diff --git a/cpp/test/Ice/background/AllTests.cpp b/cpp/test/Ice/background/AllTests.cpp
index f5fdc059870..4d6b82904d6 100644
--- a/cpp/test/Ice/background/AllTests.cpp
+++ b/cpp/test/Ice/background/AllTests.cpp
@@ -379,7 +379,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
#ifdef ICE_CPP11_MAPPING
background->opAsync();
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
background->opAsync();
vector<future<void>> results;
@@ -407,7 +407,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
}
#else
background->begin_op();
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
background->begin_op();
vector<Ice::AsyncResultPtr> results;
@@ -452,7 +452,7 @@ connectTests(const ConfigurationPtr& configuration, const Test::BackgroundPrxPtr
{
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
int i;
for(i = 0; i < 4; ++i)
@@ -560,7 +560,7 @@ connectTests(const ConfigurationPtr& configuration, const Test::BackgroundPrxPtr
}
configuration->connectException(new Ice::SocketException(__FILE__, __LINE__));
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(10));
configuration->connectException(0);
try
@@ -592,7 +592,7 @@ initializeTests(const ConfigurationPtr& configuration,
{
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
int i;
for(i = 0; i < 4; i++)
@@ -682,7 +682,7 @@ initializeTests(const ConfigurationPtr& configuration,
cerr << ex << endl;
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
try
{
@@ -695,7 +695,7 @@ initializeTests(const ConfigurationPtr& configuration,
cerr << ex << endl;
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
#endif
//
@@ -728,7 +728,7 @@ initializeTests(const ConfigurationPtr& configuration,
{
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
try
{
@@ -764,7 +764,7 @@ initializeTests(const ConfigurationPtr& configuration,
}
configuration->initializeException(new Ice::SocketException(__FILE__, __LINE__));
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(10));
configuration->initializeException(0);
try
@@ -784,12 +784,12 @@ initializeTests(const ConfigurationPtr& configuration,
}
configuration->initializeSocketOperation(IceInternal::SocketOperationWrite);
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
background->ice_ping();
configuration->initializeSocketOperation(IceInternal::SocketOperationNone);
ctl->initializeException(true);
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(10));
ctl->initializeException(false);
try
@@ -812,11 +812,11 @@ initializeTests(const ConfigurationPtr& configuration,
{
#if !defined(ICE_USE_IOCP) && !defined(ICE_USE_CFSTREAM)
ctl->initializeSocketOperation(IceInternal::SocketOperationWrite);
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
background->op();
ctl->initializeSocketOperation(IceInternal::SocketOperationNone);
#else
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
background->op();
#endif
}
@@ -847,7 +847,7 @@ validationTests(const ConfigurationPtr& configuration,
{
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
try
{
@@ -921,7 +921,7 @@ validationTests(const ConfigurationPtr& configuration,
cerr << ex << endl;
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
try
{
@@ -1081,7 +1081,7 @@ validationTests(const ConfigurationPtr& configuration,
cerr << ex << endl;
test(false);
}
- background->ice_getConnection()->close(false);
+ background->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
try
{
@@ -1163,7 +1163,7 @@ validationTests(const ConfigurationPtr& configuration,
#else
backgroundBatchOneway->begin_ice_flushBatchRequests();
#endif
- backgroundBatchOneway->ice_getConnection()->close(false);
+ backgroundBatchOneway->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
ctl->holdAdapter();
backgroundBatchOneway->opWithPayload(seq);
@@ -1183,10 +1183,10 @@ validationTests(const ConfigurationPtr& configuration,
// in the flush to report a CloseConnectionException). Instead we
// wait for the first flush to complete.
//
- //backgroundBatchOneway->ice_getConnection()->close(false);
+ //backgroundBatchOneway->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
backgroundBatchOneway->end_ice_flushBatchRequests(r);
#endif
- backgroundBatchOneway->ice_getConnection()->close(false);
+ backgroundBatchOneway->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
void
@@ -1775,10 +1775,10 @@ readWriteTests(const ConfigurationPtr& configuration,
IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(10));
background->ice_ping();
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(10));
- background->ice_getCachedConnection()->close(true);
+ background->ice_getCachedConnection()->close(Ice::CloseForcefully);
}
thread1->destroy();
diff --git a/cpp/test/Ice/binding/AllTests.cpp b/cpp/test/Ice/binding/AllTests.cpp
index a8d5f454a74..26e7fa48aa6 100644
--- a/cpp/test/Ice/binding/AllTests.cpp
+++ b/cpp/test/Ice/binding/AllTests.cpp
@@ -170,7 +170,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
test(test2->ice_getConnection() == test3->ice_getConnection());
names.erase(test1->getAdapterName());
- test1->ice_getConnection()->close(false);
+ test1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
//
@@ -192,7 +192,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
for(vector<RemoteObjectAdapterPrxPtr>::const_iterator q = adapters.begin(); q != adapters.end(); ++q)
{
- (*q)->getTestIntf()->ice_getConnection()->close(false);
+ (*q)->getTestIntf()->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
}
@@ -217,7 +217,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
test(test2->ice_getConnection() == test3->ice_getConnection());
names.erase(test1->getAdapterName());
- test1->ice_getConnection()->close(false);
+ test1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
//
@@ -314,7 +314,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
{
try
{
- (*q)->getTestIntf()->ice_getConnection()->close(false);
+ (*q)->getTestIntf()->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
catch(const Ice::LocalException&)
{
@@ -354,7 +354,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
test(test2->ice_getConnection() == test3->ice_getConnection());
names.erase(getAdapterNameWithAMI(test1));
- test1->ice_getConnection()->close(false);
+ test1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
//
@@ -376,7 +376,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
for(vector<RemoteObjectAdapterPrxPtr>::const_iterator q = adapters.begin(); q != adapters.end(); ++q)
{
- (*q)->getTestIntf()->ice_getConnection()->close(false);
+ (*q)->getTestIntf()->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
}
@@ -401,7 +401,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
test(test2->ice_getConnection() == test3->ice_getConnection());
names.erase(test1->getAdapterName());
- test1->ice_getConnection()->close(false);
+ test1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
//
@@ -433,7 +433,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
while(!names.empty())
{
names.erase(test->getAdapterName());
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
test = ICE_UNCHECKED_CAST(TestIntfPrx, test->ice_endpointSelection(Ice::Random));
@@ -445,7 +445,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
while(!names.empty())
{
names.erase(test->getAdapterName());
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
deactivate(com, adapters);
@@ -473,7 +473,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
#if TARGET_OS_IPHONE > 0
if(i != nRetry)
{
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter31"; i++);
}
#endif
@@ -483,7 +483,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
#if TARGET_OS_IPHONE > 0
if(i != nRetry)
{
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter32"; i++);
}
#endif
@@ -493,7 +493,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
#if TARGET_OS_IPHONE > 0
if(i != nRetry)
{
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter33"; i++);
}
#endif
@@ -525,29 +525,29 @@ allTests(const Ice::CommunicatorPtr& communicator)
#if TARGET_OS_IPHONE > 0
if(i != nRetry)
{
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter36"; i++);
}
#endif
test(i == nRetry);
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
adapters.push_back(com->createObjectAdapter("Adapter35", endpoints[1]->toString()));
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter35"; i++);
#if TARGET_OS_IPHONE > 0
if(i != nRetry)
{
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter35"; i++);
}
#endif
test(i == nRetry);
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
adapters.push_back(com->createObjectAdapter("Adapter34", endpoints[0]->toString()));
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter34"; i++);
#if TARGET_OS_IPHONE > 0
if(i != nRetry)
{
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
for(i = 0; i < nRetry && test->getAdapterName() == "Adapter34"; i++);
}
#endif
@@ -865,7 +865,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
for(i = 0; i < 5; i++)
{
test(test->getAdapterName() == "Adapter82");
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
TestIntfPrxPtr testSecure = ICE_UNCHECKED_CAST(TestIntfPrx, test->ice_secure(true));
@@ -881,7 +881,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
for(i = 0; i < 5; i++)
{
test(test->getAdapterName() == "Adapter81");
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
com->createObjectAdapter("Adapter83", (test->ice_getEndpoints()[1])->toString()); // Reactive tcp OA.
@@ -889,7 +889,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
for(i = 0; i < 5; i++)
{
test(test->getAdapterName() == "Adapter83");
- test->ice_getConnection()->close(false);
+ test->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
com->deactivateObjectAdapter(adapters[0]);
@@ -1098,7 +1098,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
// Close the connection now to free a FD (it could be done after the sleep but
// there could be race condiutation since the connection might not be closed
// immediately due to threading).
- test->ice_connectionId("0")->ice_getConnection()->close(false);
+ test->ice_connectionId("0")->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
//
// The server closed the acceptor, wait one second and retry after freeing a FD.
diff --git a/cpp/test/Ice/hold/AllTests.cpp b/cpp/test/Ice/hold/AllTests.cpp
index d08764d57d8..7cb0e59a53c 100644
--- a/cpp/test/Ice/hold/AllTests.cpp
+++ b/cpp/test/Ice/hold/AllTests.cpp
@@ -290,7 +290,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
{
completed->get_future().get();
holdSerialized->ice_ping(); // Ensure everything's dispatched
- holdSerialized->ice_getConnection()->close(false);
+ holdSerialized->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
}
completed->get_future().get();
@@ -305,7 +305,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
{
result->waitForSent();
holdSerialized->ice_ping(); // Ensure everything's dispatched
- holdSerialized->ice_getConnection()->close(false);
+ holdSerialized->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
}
result->waitForCompleted();
diff --git a/cpp/test/Ice/location/AllTests.cpp b/cpp/test/Ice/location/AllTests.cpp
index 148230c9fbf..4e96a75a0d5 100644
--- a/cpp/test/Ice/location/AllTests.cpp
+++ b/cpp/test/Ice/location/AllTests.cpp
@@ -637,7 +637,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const string& ref)
cout << "testing object migration... " << flush;
hello = ICE_CHECKED_CAST(HelloPrx, communicator->stringToProxy("hello"));
obj->migrateHello();
- hello->ice_getConnection()->close(false);
+ hello->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
hello->sayHello();
obj->migrateHello();
hello->sayHello();
diff --git a/cpp/test/Ice/metrics/AllTests.cpp b/cpp/test/Ice/metrics/AllTests.cpp
index c880af199ce..8d30231b520 100644
--- a/cpp/test/Ice/metrics/AllTests.cpp
+++ b/cpp/test/Ice/metrics/AllTests.cpp
@@ -287,7 +287,7 @@ struct Connect
{
if(proxy->ice_getCachedConnection())
{
- proxy->ice_getCachedConnection()->close(false);
+ proxy->ice_getCachedConnection()->close(Ice::CloseGracefullyAndWait);
}
try
{
@@ -298,7 +298,7 @@ struct Connect
}
if(proxy->ice_getCachedConnection())
{
- proxy->ice_getCachedConnection()->close(false);
+ proxy->ice_getCachedConnection()->close(Ice::CloseGracefullyAndWait);
}
}
@@ -534,8 +534,8 @@ allTests(const Ice::CommunicatorPtr& communicator, const CommunicatorObserverIPt
if(!collocated)
{
- metrics->ice_getConnection()->close(false);
- metrics->ice_connectionId("Con1")->ice_getConnection()->close(false);
+ metrics->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
+ metrics->ice_connectionId("Con1")->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -645,7 +645,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const CommunicatorObserverIPt
map = toMap(serverMetrics->getMetricsView("View", timestamp)["Connection"]);
test(map["holding"]->current == 1);
- metrics->ice_getConnection()->close(false);
+ metrics->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
map = toMap(clientMetrics->getMetricsView("View", timestamp)["Connection"]);
test(map["closing"]->current == 1);
@@ -660,7 +660,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const CommunicatorObserverIPt
props["IceMX.Metrics.View.Map.Connection.GroupBy"] = "none";
updateProps(clientProps, serverProps, update.get(), props, "Connection");
- metrics->ice_getConnection()->close(false);
+ metrics->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
metrics->ice_timeout(500)->ice_ping();
controller->hold();
@@ -717,7 +717,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const CommunicatorObserverIPt
testAttribute(clientMetrics, clientProps, update.get(), "Connection", "mcastHost", "");
testAttribute(clientMetrics, clientProps, update.get(), "Connection", "mcastPort", "");
- m->ice_getConnection()->close(false);
+ m->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -736,7 +736,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const CommunicatorObserverIPt
IceMX::MetricsPtr m1 = clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"][0];
test(m1->current == 0 && m1->total == 1 && m1->id == hostAndPort);
- metrics->ice_getConnection()->close(false);
+ metrics->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
controller->hold();
try
{
@@ -788,7 +788,7 @@ allTests(const Ice::CommunicatorPtr& communicator, const CommunicatorObserverIPt
try
{
prx->ice_ping();
- prx->ice_getConnection()->close(false);
+ prx->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
}
catch(const Ice::LocalException&)
{
diff --git a/cpp/test/Ice/metrics/TestAMDI.cpp b/cpp/test/Ice/metrics/TestAMDI.cpp
index 621bc976c1d..d5173e4380b 100644
--- a/cpp/test/Ice/metrics/TestAMDI.cpp
+++ b/cpp/test/Ice/metrics/TestAMDI.cpp
@@ -22,7 +22,7 @@ MetricsI::opAsync(function<void()> response, function<void(exception_ptr)>, cons
void
MetricsI::failAsync(function<void()> response, function<void(exception_ptr)>, const Ice::Current& current)
{
- current.con->close(true);
+ current.con->close(Ice::CloseForcefully);
response();
}
@@ -87,7 +87,7 @@ MetricsI::op_async(const Test::AMD_Metrics_opPtr& cb, const Ice::Current&)
void
MetricsI::fail_async(const Test::AMD_Metrics_failPtr& cb, const Ice::Current& current)
{
- current.con->close(true);
+ current.con->close(Ice::CloseForcefully);
cb->ice_response();
}
diff --git a/cpp/test/Ice/metrics/TestI.cpp b/cpp/test/Ice/metrics/TestI.cpp
index 24e7b9b8ec3..30f7a98bf35 100644
--- a/cpp/test/Ice/metrics/TestI.cpp
+++ b/cpp/test/Ice/metrics/TestI.cpp
@@ -18,7 +18,7 @@ MetricsI::op(const Ice::Current&)
void
MetricsI::fail(const Ice::Current& current)
{
- current.con->close(true);
+ current.con->close(Ice::CloseForcefully);
}
void
diff --git a/cpp/test/Ice/operations/BatchOneways.cpp b/cpp/test/Ice/operations/BatchOneways.cpp
index cc86c14a951..e3d261cf7e3 100644
--- a/cpp/test/Ice/operations/BatchOneways.cpp
+++ b/cpp/test/Ice/operations/BatchOneways.cpp
@@ -121,7 +121,7 @@ batchOneways(const Test::MyClassPrxPtr& p)
batch1->ice_ping();
batch2->ice_ping();
batch1->ice_flushBatchRequests();
- batch1->ice_getConnection()->close(false);
+ batch1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
batch1->ice_ping();
batch2->ice_ping();
@@ -129,7 +129,7 @@ batchOneways(const Test::MyClassPrxPtr& p)
batch2->ice_getConnection();
batch1->ice_ping();
- batch1->ice_getConnection()->close(false);
+ batch1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
batch1->ice_ping();
batch2->ice_ping();
}
diff --git a/cpp/test/Ice/operations/BatchOnewaysAMI.cpp b/cpp/test/Ice/operations/BatchOnewaysAMI.cpp
index 9adb2be5c7b..4545d8581cf 100644
--- a/cpp/test/Ice/operations/BatchOnewaysAMI.cpp
+++ b/cpp/test/Ice/operations/BatchOnewaysAMI.cpp
@@ -127,7 +127,7 @@ batchOnewaysAMI(const Test::MyClassPrxPtr& p)
batch1->ice_pingAsync().get();
batch2->ice_pingAsync().get();
batch1->ice_flushBatchRequestsAsync().get();
- batch1->ice_getConnection()->close(false);
+ batch1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
batch1->ice_pingAsync().get();
batch2->ice_pingAsync().get();
@@ -135,7 +135,7 @@ batchOnewaysAMI(const Test::MyClassPrxPtr& p)
batch2->ice_getConnection();
batch1->ice_pingAsync().get();
- batch1->ice_getConnection()->close(false);
+ batch1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
batch1->ice_pingAsync().get();
batch2->ice_pingAsync().get();
@@ -182,7 +182,7 @@ batchOnewaysAMI(const Test::MyClassPrxPtr& p)
batch1->end_ice_ping(batch1->begin_ice_ping());
batch2->end_ice_ping(batch2->begin_ice_ping());
batch1->end_ice_flushBatchRequests(batch1->begin_ice_flushBatchRequests());
- batch1->ice_getConnection()->close(false);
+ batch1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
batch1->end_ice_ping(batch1->begin_ice_ping());
batch2->end_ice_ping(batch2->begin_ice_ping());
@@ -190,7 +190,7 @@ batchOnewaysAMI(const Test::MyClassPrxPtr& p)
batch2->ice_getConnection();
batch1->end_ice_ping(batch1->begin_ice_ping());
- batch1->ice_getConnection()->close(false);
+ batch1->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
batch1->end_ice_ping(batch1->begin_ice_ping());
batch2->end_ice_ping(batch2->begin_ice_ping());
diff --git a/cpp/test/Ice/retry/TestI.cpp b/cpp/test/Ice/retry/TestI.cpp
index f721a3b6ab7..7fd3c0d4dd4 100644
--- a/cpp/test/Ice/retry/TestI.cpp
+++ b/cpp/test/Ice/retry/TestI.cpp
@@ -22,7 +22,7 @@ RetryI::op(bool kill, const Ice::Current& current)
{
if(current.con)
{
- current.con->close(true);
+ current.con->close(Ice::CloseForcefully);
}
else
{
diff --git a/cpp/test/Ice/timeout/AllTests.cpp b/cpp/test/Ice/timeout/AllTests.cpp
index 6681a8f56df..1947f4e9aa1 100644
--- a/cpp/test/Ice/timeout/AllTests.cpp
+++ b/cpp/test/Ice/timeout/AllTests.cpp
@@ -294,7 +294,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
TimeoutPrxPtr to = ICE_CHECKED_CAST(TimeoutPrx, obj->ice_timeout(250));
Ice::ConnectionPtr connection = to->ice_getConnection();
timeout->holdAdapter(600);
- connection->close(false);
+ connection->close(Ice::CloseGracefullyAndWait);
try
{
connection->getInfo(); // getInfo() doesn't throw in the closing state.
@@ -309,9 +309,10 @@ allTests(const Ice::CommunicatorPtr& communicator)
connection->getInfo();
test(false);
}
- catch(const Ice::CloseConnectionException&)
+ catch(const Ice::ConnectionManuallyClosedException& ex)
{
// Expected.
+ test(ex.graceful);
}
timeout->op(); // Ensure adapter is active.
}
diff --git a/cpp/test/Ice/udp/AllTests.cpp b/cpp/test/Ice/udp/AllTests.cpp
index e2e00f19da2..f16b10baa70 100644
--- a/cpp/test/Ice/udp/AllTests.cpp
+++ b/cpp/test/Ice/udp/AllTests.cpp
@@ -116,7 +116,7 @@ allTests(const CommunicatorPtr& communicator)
{
test(seq.size() > 16384);
}
- obj->ice_getConnection()->close(false);
+ obj->ice_getConnection()->close(CloseGracefullyAndWait);
communicator->getProperties()->setProperty("Ice.UDP.SndSize", "64000");
seq.resize(50000);
try
diff --git a/cpp/test/IceSSL/configuration/AllTests.cpp b/cpp/test/IceSSL/configuration/AllTests.cpp
index 96d14174b36..96c1e527cb7 100644
--- a/cpp/test/IceSSL/configuration/AllTests.cpp
+++ b/cpp/test/IceSSL/configuration/AllTests.cpp
@@ -1585,7 +1585,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir, bool p12)
//
verifier->reset();
verifier->returnValue(false);
- server->ice_getConnection()->close(false);
+ server->ice_getConnection()->close(Ice::CloseGracefullyAndWait);
try
{
server->ice_ping();
diff --git a/cpp/test/IceStorm/stress/Subscriber.cpp b/cpp/test/IceStorm/stress/Subscriber.cpp
index d43c2469b28..4722fe93caf 100644
--- a/cpp/test/IceStorm/stress/Subscriber.cpp
+++ b/cpp/test/IceStorm/stress/Subscriber.cpp
@@ -163,7 +163,7 @@ public:
if(!_done && (IceUtilInternal::random(10) == 1 || ++_count == _total))
{
_done = true;
- current.con->close(true);
+ current.con->close(CloseForcefully);
// Deactivate the OA. This ensures that the subscribers
// that have subscribed with oneway QoS will be booted.
current.adapter->deactivate();
diff --git a/csharp/src/Ice/ConnectionI.cs b/csharp/src/Ice/ConnectionI.cs
index 8943a4d48bc..c851279b0db 100644
--- a/csharp/src/Ice/ConnectionI.cs
+++ b/csharp/src/Ice/ConnectionI.cs
@@ -181,29 +181,31 @@ namespace Ice
}
}
- public void close(bool force)
+ public void close(ConnectionClose mode)
{
lock(this)
{
- if(force)
+ if(mode == ConnectionClose.CloseForcefully)
{
- setState(StateClosed, new ForcedCloseConnectionException());
+ setState(StateClosed, new ConnectionManuallyClosedException(false));
+ }
+ else if(mode == ConnectionClose.CloseGracefully)
+ {
+ setState(StateClosing, new ConnectionManuallyClosedException(true));
}
else
{
+ Debug.Assert(mode == ConnectionClose.CloseGracefullyAndWait);
+
//
- // If we do a graceful shutdown, then we wait until all
- // outstanding requests have been completed. Otherwise,
- // the CloseConnectionException will cause all outstanding
- // requests to be retried, regardless of whether the
- // server has processed them or not.
+ // Wait until all outstanding requests have been completed.
//
while(_asyncRequests.Count != 0)
{
Monitor.Wait(this);
}
- setState(StateClosing, new CloseConnectionException());
+ setState(StateClosing, new ConnectionManuallyClosedException(true));
}
}
}
@@ -330,13 +332,13 @@ namespace Ice
// We send a heartbeat if there was no activity in the last
// (timeout / 4) period. Sending a heartbeat sooner than
// really needed is safer to ensure that the receiver will
- // receive in time the heartbeat. Sending the heartbeat if
+ // receive the heartbeat in time. Sending the heartbeat if
// there was no activity in the last (timeout / 2) period
// isn't enough since monitor() is called only every (timeout
// / 2) period.
//
// Note that this doesn't imply that we are sending 4 heartbeats
- // per timeout period because the monitor() method is sill only
+ // per timeout period because the monitor() method is still only
// called every (timeout / 2) period.
//
if(acm.heartbeat == ACMHeartbeat.HeartbeatAlways ||
@@ -345,7 +347,7 @@ namespace Ice
{
if(acm.heartbeat != ACMHeartbeat.HeartbeatOnInvocation || _dispatchCount > 0)
{
- heartbeat();
+ sendHeartbeatNow();
}
}
@@ -583,6 +585,149 @@ namespace Ice
}
}
+ public void heartbeat()
+ {
+ heartbeatAsync().Wait();
+ }
+
+ private class HeartbeatCompletionCallback : AsyncResultCompletionCallback
+ {
+ public HeartbeatCompletionCallback(Ice.Connection connection,
+ Ice.Communicator communicator,
+ Instance instance,
+ object cookie,
+ Ice.AsyncCallback callback)
+ : base(communicator, instance, "heartbeat", cookie, callback)
+ {
+ _connection = connection;
+ }
+
+ public override Ice.Connection getConnection()
+ {
+ return _connection;
+ }
+
+ protected override Ice.AsyncCallback getCompletedCallback()
+ {
+ return (Ice.AsyncResult result) =>
+ {
+ try
+ {
+ result.throwLocalException();
+ }
+ catch(Ice.Exception ex)
+ {
+ if(exceptionCallback_ != null)
+ {
+ exceptionCallback_.Invoke(ex);
+ }
+ }
+ };
+ }
+
+ private Ice.Connection _connection;
+ }
+
+ private class HeartbeatTaskCompletionCallback : TaskCompletionCallback<object>
+ {
+ public HeartbeatTaskCompletionCallback(System.IProgress<bool> progress,
+ CancellationToken cancellationToken) :
+ base(progress, cancellationToken)
+ {
+ }
+
+ public override bool handleResponse(bool ok, OutgoingAsyncBase og)
+ {
+ SetResult(null);
+ return false;
+ }
+ }
+
+ private class HeartbeatAsync : OutgoingAsyncBase
+ {
+ public HeartbeatAsync(Ice.ConnectionI connection,
+ Instance instance,
+ OutgoingAsyncCompletionCallback completionCallback) :
+ base(instance, completionCallback)
+ {
+ _connection = connection;
+ }
+
+ public void invoke()
+ {
+ try
+ {
+ os_.writeBlob(IceInternal.Protocol.magic);
+ Ice.Util.currentProtocol.write__(os_);
+ Ice.Util.currentProtocolEncoding.write__(os_);
+ os_.writeByte(IceInternal.Protocol.validateConnectionMsg);
+ os_.writeByte((byte)0);
+ os_.writeInt(IceInternal.Protocol.headerSize); // Message size.
+
+ int status = _connection.sendAsyncRequest(this, false, false, 0);
+
+ if((status & AsyncStatusSent) != 0)
+ {
+ sentSynchronously_ = true;
+ if((status & AsyncStatusInvokeSentCallback) != 0)
+ {
+ invokeSent();
+ }
+ }
+ }
+ catch(RetryException ex)
+ {
+ try
+ {
+ throw ex.get();
+ }
+ catch(Ice.LocalException ee)
+ {
+ if(exception(ee))
+ {
+ invokeExceptionAsync();
+ }
+ }
+ }
+ catch(Ice.Exception ex)
+ {
+ if(exception(ex))
+ {
+ invokeExceptionAsync();
+ }
+ }
+ }
+
+ private readonly Ice.ConnectionI _connection;
+ }
+
+ public Task heartbeatAsync(IProgress<bool> progress = null, CancellationToken cancel = new CancellationToken())
+ {
+ var completed = new HeartbeatTaskCompletionCallback(progress, cancel);
+ var outgoing = new HeartbeatAsync(this, _instance, completed);
+ outgoing.invoke();
+ return completed.Task;
+ }
+
+ public AsyncResult begin_heartbeat(AsyncCallback cb = null, object cookie = null)
+ {
+ var result = new HeartbeatCompletionCallback(this, _communicator, _instance, cookie, cb);
+ var outgoing = new HeartbeatAsync(this, _instance, result);
+ outgoing.invoke();
+ return result;
+ }
+
+ public void end_heartbeat(AsyncResult r)
+ {
+ if(r != null && r.getConnection() != this)
+ {
+ const string msg = "Connection for call to end_heartbeat does not match connection that was used " +
+ "to call corresponding begin_heartbeat method";
+ throw new ArgumentException(msg);
+ }
+ AsyncResultI.check(r, "heartbeat").wait();
+ }
+
public void setACM(Optional<int> timeout, Optional<ACMClose> close, Optional<ACMHeartbeat> heartbeat)
{
lock(this)
@@ -1415,7 +1560,7 @@ namespace Ice
// Trace the cause of unexpected connection closures
//
if(!(_exception is CloseConnectionException ||
- _exception is ForcedCloseConnectionException ||
+ _exception is ConnectionManuallyClosedException ||
_exception is ConnectionTimeoutException ||
_exception is CommunicatorDestroyedException ||
_exception is ObjectAdapterDeactivatedException))
@@ -1723,7 +1868,7 @@ namespace Ice
// Don't warn about certain expected exceptions.
//
if(!(_exception is CloseConnectionException ||
- _exception is ForcedCloseConnectionException ||
+ _exception is ConnectionManuallyClosedException ||
_exception is ConnectionTimeoutException ||
_exception is CommunicatorDestroyedException ||
_exception is ObjectAdapterDeactivatedException ||
@@ -1902,7 +2047,7 @@ namespace Ice
if(_observer != null && state == StateClosed && _exception != null)
{
if(!(_exception is CloseConnectionException ||
- _exception is ForcedCloseConnectionException ||
+ _exception is ConnectionManuallyClosedException ||
_exception is ConnectionTimeoutException ||
_exception is CommunicatorDestroyedException ||
_exception is ObjectAdapterDeactivatedException ||
@@ -1931,8 +2076,7 @@ namespace Ice
private void initiateShutdown()
{
- Debug.Assert(_state == StateClosing);
- Debug.Assert(_dispatchCount == 0);
+ Debug.Assert(_state == StateClosing && _dispatchCount == 0);
if(_shutdownInitiated)
{
@@ -1958,7 +2102,7 @@ namespace Ice
setState(StateClosingPending);
//
- // Notify the the transceiver of the graceful connection closure.
+ // Notify the transceiver of the graceful connection closure.
//
int op = _transceiver.closing(true, _exception);
if(op != 0)
@@ -1970,7 +2114,7 @@ namespace Ice
}
}
- private void heartbeat()
+ private void sendHeartbeatNow()
{
Debug.Assert(_state == StateActive);
@@ -2456,7 +2600,7 @@ namespace Ice
setState(StateClosingPending, new CloseConnectionException());
//
- // Notify the the transceiver of the graceful connection closure.
+ // Notify the transceiver of the graceful connection closure.
//
int op = _transceiver.closing(false, _exception);
if(op != 0)
@@ -2540,7 +2684,7 @@ namespace Ice
{
info.outAsync = null;
}
- Monitor.PulseAll(this); // Notify threads blocked in close(false)
+ Monitor.PulseAll(this); // Notify threads blocked in close()
}
break;
}
diff --git a/csharp/test/Ice/acm/AllTests.cs b/csharp/test/Ice/acm/AllTests.cs
index 4059809084d..4e553fe894f 100644
--- a/csharp/test/Ice/acm/AllTests.cs
+++ b/csharp/test/Ice/acm/AllTests.cs
@@ -93,7 +93,7 @@ class LoggerI : Ice.Logger
private bool _started;
private List<string> _messages = new List<string>();
-};
+}
abstract class TestCase
{
@@ -251,7 +251,7 @@ abstract class TestCase
protected int _heartbeat;
protected bool _closed;
-};
+}
public class AllTests : TestCommon.AllTests
{
@@ -270,7 +270,7 @@ public class AllTests : TestCommon.AllTests
test(_heartbeat >= 2);
}
}
- };
+ }
class InvocationHeartbeatOnHoldTest : TestCase
{
@@ -298,7 +298,7 @@ public class AllTests : TestCommon.AllTests
waitForClosed();
}
}
- };
+ }
class InvocationNoHeartbeatTest : TestCase
{
@@ -328,7 +328,7 @@ public class AllTests : TestCommon.AllTests
}
}
}
- };
+ }
class InvocationHeartbeatCloseOnIdleTest : TestCase
{
@@ -351,7 +351,7 @@ public class AllTests : TestCommon.AllTests
test(!_closed);
}
}
- };
+ }
class CloseOnIdleTest : TestCase
{
@@ -370,7 +370,7 @@ public class AllTests : TestCommon.AllTests
test(_heartbeat == 0);
}
}
- };
+ }
class CloseOnInvocationTest : TestCase
{
@@ -389,7 +389,7 @@ public class AllTests : TestCommon.AllTests
test(!_closed);
}
}
- };
+ }
class CloseOnIdleAndInvocationTest : TestCase
{
@@ -419,7 +419,7 @@ public class AllTests : TestCommon.AllTests
waitForClosed();
}
- };
+ }
class ForcefulCloseOnIdleAndInvocationTest : TestCase
{
@@ -440,7 +440,7 @@ public class AllTests : TestCommon.AllTests
test(_heartbeat == 0);
}
}
- };
+ }
class HeartbeatOnIdleTest : TestCase
{
@@ -458,7 +458,7 @@ public class AllTests : TestCommon.AllTests
test(_heartbeat >= 3);
}
}
- };
+ }
class HeartbeatAlwaysTest : TestCase
{
@@ -480,7 +480,31 @@ public class AllTests : TestCommon.AllTests
test(_heartbeat >= 3);
}
}
- };
+ }
+
+ class HeartbeatManualTest : TestCase
+ {
+ public HeartbeatManualTest(RemoteCommunicatorPrx com) : base("manual heartbeats", com)
+ {
+ //
+ // Disable heartbeats.
+ //
+ setClientACM(10, -1, 0);
+ setServerACM(10, -1, 0);
+ }
+
+ public override void runTestCase(RemoteObjectAdapterPrx adapter, TestIntfPrx proxy)
+ {
+ proxy.startHeartbeatCount();
+ Ice.Connection con = proxy.ice_getConnection();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ proxy.waitForHeartbeatCount(5);
+ }
+ }
class SetACMTest : TestCase
{
@@ -511,9 +535,10 @@ public class AllTests : TestCommon.AllTests
test(acm.close == Ice.ACMClose.CloseOnInvocationAndIdle);
test(acm.heartbeat == Ice.ACMHeartbeat.HeartbeatAlways);
- proxy.waitForHeartbeat(2);
+ proxy.startHeartbeatCount();
+ proxy.waitForHeartbeatCount(2);
}
- };
+ }
public static void allTests(TestCommon.Application app)
{
@@ -535,6 +560,7 @@ public class AllTests : TestCommon.AllTests
tests.Add(new HeartbeatOnIdleTest(com));
tests.Add(new HeartbeatAlwaysTest(com));
+ tests.Add(new HeartbeatManualTest(com));
tests.Add(new SetACMTest(com));
foreach(TestCase test in tests)
diff --git a/csharp/test/Ice/acm/Test.ice b/csharp/test/Ice/acm/Test.ice
index 5ab98180dd3..d78abd6eb0f 100644
--- a/csharp/test/Ice/acm/Test.ice
+++ b/csharp/test/Ice/acm/Test.ice
@@ -17,7 +17,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/csharp/test/Ice/acm/TestI.cs b/csharp/test/Ice/acm/TestI.cs
index 0dd3455daf7..970c1c22148 100644
--- a/csharp/test/Ice/acm/TestI.cs
+++ b/csharp/test/Ice/acm/TestI.cs
@@ -34,7 +34,8 @@ public class RemoteCommunicatorI : RemoteCommunicatorDisp_
}
properties.setProperty(name + ".ThreadPool.Size", "2");
Ice.ObjectAdapter adapter = com.createObjectAdapterWithEndpoints(name, protocol + " -h \"" + host + "\"");
- return RemoteObjectAdapterPrxHelper.uncheckedCast(current.adapter.addWithUUID(new RemoteObjectAdapterI(adapter)));
+ return RemoteObjectAdapterPrxHelper.uncheckedCast(
+ current.adapter.addWithUUID(new RemoteObjectAdapterI(adapter)));
}
public override void
@@ -42,7 +43,7 @@ public class RemoteCommunicatorI : RemoteCommunicatorDisp_
{
current.adapter.getCommunicator().shutdown();
}
-};
+}
public class RemoteObjectAdapterI : RemoteObjectAdapterDisp_
{
@@ -82,7 +83,7 @@ public class RemoteObjectAdapterI : RemoteObjectAdapterDisp_
private Ice.ObjectAdapter _adapter;
private TestIntfPrx _testIntf;
-};
+}
public class TestI : TestIntfDisp_
{
@@ -117,7 +118,7 @@ public class TestI : TestIntfDisp_
{
lock(this)
{
- --_count;
+ ++_count;
System.Threading.Monitor.PulseAll(this);
}
}
@@ -126,8 +127,7 @@ public class TestI : TestIntfDisp_
{
lock(this)
{
- _count = count;
- while(_count > 0)
+ while(_count < count)
{
System.Threading.Monitor.Wait(this);
}
@@ -135,14 +135,19 @@ public class TestI : TestIntfDisp_
}
private int _count = 0;
- };
+ }
- public override void waitForHeartbeat(int count, Ice.Current current)
+ public override void startHeartbeatCount(Ice.Current current)
{
+ _callback = new HeartbeatCallbackI();
+ current.con.setHeartbeatCallback(_callback.heartbeat);
+ }
-
- HeartbeatCallbackI callback = new HeartbeatCallbackI();
- current.con.setHeartbeatCallback(callback.heartbeat);
- callback.waitForCount(count);
+ public override void waitForHeartbeatCount(int count, Ice.Current current)
+ {
+ System.Diagnostics.Debug.Assert(_callback != null);
+ _callback.waitForCount(count);
}
-};
+
+ private HeartbeatCallbackI _callback;
+}
diff --git a/csharp/test/Ice/ami/AllTests.cs b/csharp/test/Ice/ami/AllTests.cs
index 20c936e1fbe..dd91682ff69 100644
--- a/csharp/test/Ice/ami/AllTests.cs
+++ b/csharp/test/Ice/ami/AllTests.cs
@@ -1904,7 +1904,7 @@ public class AllTests : TestCommon.AllTests
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests(cb.completedAsync, cookie);
r.whenSent(cb.sentAsync);
@@ -1940,7 +1940,7 @@ public class AllTests : TestCommon.AllTests
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests();
r.whenCompleted(cb.exception);
@@ -1974,9 +1974,9 @@ public class AllTests : TestCommon.AllTests
b1.opBatch();
FlushCallback cb = new FlushCallback();
System.Threading.Tasks.Task t = b1.ice_flushBatchRequestsAsync(
- progress: new Progress(sentSynchronoully =>
+ progress: new Progress(sentSynchronously =>
{
- cb.sent(sentSynchronoully);
+ cb.sent(sentSynchronously);
}));
cb.check();
@@ -1989,12 +1989,12 @@ public class AllTests : TestCommon.AllTests
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
System.Threading.Tasks.Task t = b1.ice_flushBatchRequestsAsync(
- progress:new Progress(sentSynchronoully =>
+ progress:new Progress(sentSynchronously =>
{
- cb.sent(sentSynchronoully);
+ cb.sent(sentSynchronously);
}));
cb.check();
t.Wait();
@@ -2058,7 +2058,7 @@ public class AllTests : TestCommon.AllTests
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests(
(Ice.AsyncResult result) =>
@@ -2110,7 +2110,7 @@ public class AllTests : TestCommon.AllTests
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests();
r.whenCompleted(
@@ -2166,7 +2166,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
Task t = b1.ice_getConnection().flushBatchRequestsAsync(
progress: new Progress(
sentSynchronously =>
@@ -2205,7 +2205,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushExCallback cb = new FlushExCallback(cookie);
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests(cb.completedAsync, cookie);
r.whenSent(cb.sentAsync);
@@ -2242,7 +2242,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushExCallback cb = new FlushExCallback();
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests();
r.whenCompleted(cb.exception);
@@ -2297,7 +2297,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushExCallback cb = new FlushExCallback(cookie);
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests(
(Ice.AsyncResult result) =>
@@ -2350,7 +2350,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushExCallback cb = new FlushExCallback();
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests();
r.whenCompleted(
@@ -2404,7 +2404,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
SentCallback cb = new SentCallback();
Task t = communicator.flushBatchRequestsAsync(
progress:new Progress(
@@ -2459,7 +2459,7 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
SentCallback cb = new SentCallback();
Task t = communicator.flushBatchRequestsAsync(
new Progress(
@@ -2486,8 +2486,8 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
SentCallback cb = new SentCallback();
Task t = communicator.flushBatchRequestsAsync(
new Progress(
@@ -2528,7 +2528,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = communicator.begin_flushBatchRequests(cb.completedAsync, cookie);
r.whenSent(cb.sentAsync);
@@ -2577,7 +2577,7 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = communicator.begin_flushBatchRequests(cb.completedAsync, cookie);
r.whenSent(cb.sentAsync);
@@ -2601,8 +2601,8 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = communicator.begin_flushBatchRequests(cb.completedAsync, cookie);
r.whenSent(cb.sentAsync);
@@ -2639,7 +2639,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests();
r.whenCompleted(cb.exception);
@@ -2689,7 +2689,7 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests();
r.whenCompleted(cb.exception);
@@ -2714,8 +2714,8 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests();
r.whenCompleted(cb.exception);
@@ -2767,7 +2767,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
(Ice.AsyncResult result) =>
@@ -2831,7 +2831,7 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
(Ice.AsyncResult result) =>
@@ -2863,8 +2863,8 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback(cookie);
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
(Ice.AsyncResult result) =>
@@ -2917,7 +2917,7 @@ public class AllTests : TestCommon.AllTests
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests();
r.whenCompleted(
@@ -2983,7 +2983,7 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests();
r.whenCompleted(
@@ -3016,8 +3016,8 @@ public class AllTests : TestCommon.AllTests
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests();
r.whenCompleted(
@@ -3356,9 +3356,28 @@ public class AllTests : TestCommon.AllTests
if(p.ice_getConnection() != null)
{
- Write("testing close connection with sending queue... ");
+ Write("testing graceful close connection with wait... ");
Flush();
{
+ //
+ // Local case: begin several requests, close the connection gracefully, and make sure it waits
+ // for the requests to complete.
+ //
+ List<Task> results = new List<Task>();
+ for(int i = 0; i < 3; ++i)
+ {
+ results.Add(p.sleepAsync(50));
+ }
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ foreach(Task t in results)
+ {
+ t.Wait();
+ }
+ }
+ {
+ //
+ // Remote case.
+ //
byte[] seq = new byte[1024 * 10];
//
@@ -3379,7 +3398,7 @@ public class AllTests : TestCommon.AllTests
}
ProgresCallback cb = new ProgresCallback();
- p.closeAsync(false, progress:cb);
+ p.closeAsync(CloseMode.CloseGracefullyAndWait, progress:cb);
if(!cb.SentSynchronously)
{
@@ -3408,6 +3427,88 @@ public class AllTests : TestCommon.AllTests
}
}
WriteLine("ok");
+
+ Write("testing graceful close connection without wait... ");
+ Flush();
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection gracefully on the client side
+ // without waiting for the pending invocation to complete. There will be no retry and we expect the
+ // invocation to fail with ConnectionManuallyClosedException.
+ //
+ // This test requires two threads in the server's thread pool: one will block in sleep() and the other
+ // will process the CloseConnection message.
+ //
+ Task t = p.sleepAsync(100);
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseGracefully);
+ try
+ {
+ t.Wait();
+ test(false);
+ }
+ catch(System.AggregateException ex)
+ {
+ test(ex.InnerException is Ice.ConnectionManuallyClosedException);
+ test((ex.InnerException as Ice.ConnectionManuallyClosedException).graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection gracefully. Our call to TestIntf::close()
+ // completes successfully and then the connection should be closed immediately afterward,
+ // despite the fact that there's a pending call to sleep(). The call to sleep() should be
+ // automatically retried and complete successfully.
+ //
+ Ice.Connection con = p.ice_getConnection();
+ CallbackBase cb = new CallbackBase();
+ con.setCloseCallback(_ =>
+ {
+ cb.called();
+ });
+ t = p.sleepAsync(100);
+ p.close(CloseMode.CloseGracefully);
+ cb.check();
+ t.Wait();
+ p.ice_ping();
+ test(p.ice_getConnection() != con);
+ }
+ WriteLine("ok");
+
+ Write("testing forceful close connection... ");
+ Flush();
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection forcefully on the client side.
+ // There will be no retry and we expect the invocation to fail with ConnectionManuallyClosedException.
+ //
+ Task t = p.sleepAsync(100);
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseForcefully);
+ try
+ {
+ t.Wait();
+ test(false);
+ }
+ catch(System.AggregateException ex)
+ {
+ test(ex.InnerException is Ice.ConnectionManuallyClosedException);
+ test(!(ex.InnerException as Ice.ConnectionManuallyClosedException).graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection forcefully. This causes the request to fail
+ // with a ConnectionLostException. Since the close() operation is not idempotent, the client
+ // will not retry.
+ //
+ try
+ {
+ p.close(CloseMode.CloseForcefully);
+ test(false);
+ }
+ catch(Ice.ConnectionLostException)
+ {
+ // Expected.
+ }
+ }
+ WriteLine("ok");
}
p.shutdown();
diff --git a/csharp/test/Ice/ami/Client.cs b/csharp/test/Ice/ami/Client.cs
index bc64d64276a..fe52f0320b0 100644
--- a/csharp/test/Ice/ami/Client.cs
+++ b/csharp/test/Ice/ami/Client.cs
@@ -28,6 +28,8 @@ public class Client : TestCommon.Application
{
Ice.InitializationData initData = base.getInitData(ref args);
initData.properties.setProperty("Ice.Warn.AMICallback", "0");
+ initData.properties.setProperty("Ice.Warn.Connections", "0");
+
//
// Limit the send buffer size, this test relies on the socket
// send() blocking after sending a given amount of data.
diff --git a/csharp/test/Ice/ami/Server.cs b/csharp/test/Ice/ami/Server.cs
index d07fb4e30bf..0202e74127c 100644
--- a/csharp/test/Ice/ami/Server.cs
+++ b/csharp/test/Ice/ami/Server.cs
@@ -47,11 +47,16 @@ public class Server : TestCommon.Application
initData.properties.setProperty("Ice.Default.CollocationOptimized", "0");
//
+ // This test kills connections, so we don't want warnings.
+ //
+ initData.properties.setProperty("Ice.Warn.Connections", "0");
+
+ //
// Limit the recv buffer size, this test relies on the socket
// send() blocking after sending a given amount of data.
//
initData.properties.setProperty("Ice.TCP.RcvSize", "50000");
- return initData;
+ return initData;
}
public static int Main(string[] args)
diff --git a/csharp/test/Ice/ami/Test.ice b/csharp/test/Ice/ami/Test.ice
index 1bd696fdcd1..b9f88916103 100644
--- a/csharp/test/Ice/ami/Test.ice
+++ b/csharp/test/Ice/ami/Test.ice
@@ -18,6 +18,13 @@ exception TestIntfException
{
};
+enum CloseMode
+{
+ CloseForcefully,
+ CloseGracefully,
+ CloseGracefullyAndWait
+};
+
interface TestIntf
{
void op();
@@ -28,7 +35,8 @@ interface TestIntf
void opBatch();
int opBatchCount();
bool waitForBatch(int count);
- void close(bool force);
+ void close(CloseMode mode);
+ void sleep(int ms);
void shutdown();
bool supportsFunctionalTests();
diff --git a/csharp/test/Ice/ami/TestI.cs b/csharp/test/Ice/ami/TestI.cs
index 0aabc62501a..a18fc738cbe 100644
--- a/csharp/test/Ice/ami/TestI.cs
+++ b/csharp/test/Ice/ami/TestI.cs
@@ -85,9 +85,15 @@ public class TestI : TestIntfDisp_
}
override public void
- close(bool force, Ice.Current current)
+ close(CloseMode mode, Ice.Current current)
{
- current.con.close(force);
+ current.con.close((Ice.ConnectionClose)((int)mode));
+ }
+
+ override public void
+ sleep(int ms, Ice.Current current)
+ {
+ Thread.Sleep(ms);
}
override public void
diff --git a/csharp/test/Ice/background/AllTests.cs b/csharp/test/Ice/background/AllTests.cs
index 0a81a8e6d7a..0594a541224 100644
--- a/csharp/test/Ice/background/AllTests.cs
+++ b/csharp/test/Ice/background/AllTests.cs
@@ -327,7 +327,7 @@ public class AllTests
configuration.buffered(true);
backgroundController.buffered(true);
background.begin_op();
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
background.begin_op();
OpAMICallback cb = new OpAMICallback();
@@ -367,7 +367,7 @@ public class AllTests
System.Console.Out.WriteLine(ex);
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
for(int i = 0; i < 4; ++i)
{
@@ -433,7 +433,7 @@ public class AllTests
}
configuration.connectException(new Ice.SocketException());
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
Thread.Sleep(10);
configuration.connectException(null);
try
@@ -463,7 +463,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
for(int i = 0; i < 4; ++i)
{
@@ -544,7 +544,7 @@ public class AllTests
}
configuration.initializeException(new Ice.SocketException());
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
Thread.Sleep(10);
configuration.initializeException(null);
try
@@ -563,11 +563,11 @@ public class AllTests
test(false);
}
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
background.ice_ping();
ctl.initializeException(true);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
Thread.Sleep(10);
ctl.initializeException(false);
try
@@ -588,7 +588,7 @@ public class AllTests
try
{
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
background.op();
}
catch(Ice.LocalException)
@@ -620,7 +620,7 @@ public class AllTests
{
CloseCallback cb = new CloseCallback();
prx.ice_getConnection().setCloseCallback(cb.closed);
- prx.ice_getConnection().close(false);
+ prx.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
cb.check();
}
@@ -823,7 +823,7 @@ public class AllTests
// in the flush to report a CloseConnectionException). Instead we flush a second time
// with the same callback to wait for the first flush to complete.
//
- //backgroundBatchOneway.ice_getConnection().close(false);
+ //backgroundBatchOneway.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
backgroundBatchOneway.end_ice_flushBatchRequests(r3);
closeConnection(backgroundBatchOneway);
}
@@ -1159,10 +1159,10 @@ public class AllTests
Thread.Sleep(10);
background.ice_ping();
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
Thread.Sleep(10);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
}
thread1.destroy();
diff --git a/csharp/test/Ice/binding/AllTests.cs b/csharp/test/Ice/binding/AllTests.cs
index 90bde85dd9b..949d6c12b19 100644
--- a/csharp/test/Ice/binding/AllTests.cs
+++ b/csharp/test/Ice/binding/AllTests.cs
@@ -159,7 +159,7 @@ public class AllTests : TestCommon.AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.Remove(test1.getAdapterName());
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -181,7 +181,7 @@ public class AllTests : TestCommon.AllTests
foreach(RemoteObjectAdapterPrx adpt in adapters)
{
- adpt.getTestIntf().ice_getConnection().close(false);
+ adpt.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -206,7 +206,7 @@ public class AllTests : TestCommon.AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.Remove(test1.getAdapterName());
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -290,7 +290,7 @@ public class AllTests : TestCommon.AllTests
{
try
{
- a.getTestIntf().ice_getConnection().close(false);
+ a.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
catch(Ice.LocalException)
{
@@ -331,7 +331,7 @@ public class AllTests : TestCommon.AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.Remove(getAdapterNameWithAMI(test1));
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -353,7 +353,7 @@ public class AllTests : TestCommon.AllTests
foreach(RemoteObjectAdapterPrx adpt in adapters)
{
- adpt.getTestIntf().ice_getConnection().close(false);
+ adpt.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -378,7 +378,7 @@ public class AllTests : TestCommon.AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.Remove(getAdapterNameWithAMI(test1));
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -411,7 +411,7 @@ public class AllTests : TestCommon.AllTests
while(names.Count > 0)
{
names.Remove(obj.getAdapterName());
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
obj = TestIntfPrxHelper.uncheckedCast(obj.ice_endpointSelection(Ice.EndpointSelectionType.Random));
@@ -423,7 +423,7 @@ public class AllTests : TestCommon.AllTests
while(names.Count > 0)
{
names.Remove(obj.getAdapterName());
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
deactivate(com, adapters);
@@ -480,11 +480,11 @@ public class AllTests : TestCommon.AllTests
adapters.Add(com.createObjectAdapter("Adapter36", endpoints[2].ToString()));
for(i = 0; i < nRetry && obj.getAdapterName().Equals("Adapter36"); i++);
test(i == nRetry);
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
adapters.Add(com.createObjectAdapter("Adapter35", endpoints[1].ToString()));
for(i = 0; i < nRetry && obj.getAdapterName().Equals("Adapter35"); i++);
test(i == nRetry);
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
adapters.Add(com.createObjectAdapter("Adapter34", endpoints[0].ToString()));
for(i = 0; i < nRetry && obj.getAdapterName().Equals("Adapter34"); i++);
test(i == nRetry);
@@ -761,7 +761,7 @@ public class AllTests : TestCommon.AllTests
for(i = 0; i < 5; i++)
{
test(obj.getAdapterName().Equals("Adapter82"));
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
TestIntfPrx testSecure = TestIntfPrxHelper.uncheckedCast(obj.ice_secure(true));
@@ -777,7 +777,7 @@ public class AllTests : TestCommon.AllTests
for(i = 0; i < 5; i++)
{
test(obj.getAdapterName().Equals("Adapter81"));
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
com.createObjectAdapter("Adapter83", (obj.ice_getEndpoints()[1]).ToString()); // Reactive tcp OA.
@@ -785,7 +785,7 @@ public class AllTests : TestCommon.AllTests
for(i = 0; i < 5; i++)
{
test(obj.getAdapterName().Equals("Adapter83"));
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
com.deactivateObjectAdapter((RemoteObjectAdapterPrx)adapters[0]);
diff --git a/csharp/test/Ice/hold/AllTests.cs b/csharp/test/Ice/hold/AllTests.cs
index 41c2aab173f..41773301b3c 100644
--- a/csharp/test/Ice/hold/AllTests.cs
+++ b/csharp/test/Ice/hold/AllTests.cs
@@ -187,7 +187,7 @@ public class AllTests : TestCommon.AllTests
{
result.waitForSent();
holdSerialized.ice_ping(); // Ensure everything's dispatched.
- holdSerialized.ice_getConnection().close(false);
+ holdSerialized.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
result.waitForCompleted();
diff --git a/csharp/test/Ice/location/AllTests.cs b/csharp/test/Ice/location/AllTests.cs
index adf84b5abda..aa4a23a3a22 100644
--- a/csharp/test/Ice/location/AllTests.cs
+++ b/csharp/test/Ice/location/AllTests.cs
@@ -533,7 +533,7 @@ public class AllTests : TestCommon.AllTests
Flush();
hello = HelloPrxHelper.checkedCast(communicator.stringToProxy("hello"));
obj.migrateHello();
- hello.ice_getConnection().close(false);
+ hello.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
hello.sayHello();
obj.migrateHello();
hello.sayHello();
diff --git a/csharp/test/Ice/metrics/AllTests.cs b/csharp/test/Ice/metrics/AllTests.cs
index e22d7b65c12..41cc8468930 100644
--- a/csharp/test/Ice/metrics/AllTests.cs
+++ b/csharp/test/Ice/metrics/AllTests.cs
@@ -271,7 +271,7 @@ public class AllTests : TestCommon.AllTests
{
if(proxy.ice_getCachedConnection() != null)
{
- proxy.ice_getCachedConnection().close(false);
+ proxy.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
try
@@ -284,7 +284,7 @@ public class AllTests : TestCommon.AllTests
if(proxy.ice_getCachedConnection() != null)
{
- proxy.ice_getCachedConnection().close(false);
+ proxy.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -486,8 +486,8 @@ public class AllTests : TestCommon.AllTests
if(!collocated)
{
- metrics.ice_getConnection().close(false);
- metrics.ice_connectionId("Con1").ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ metrics.ice_connectionId("Con1").ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -590,7 +590,7 @@ public class AllTests : TestCommon.AllTests
map = toMap(serverMetrics.getMetricsView("View", out timestamp)["Connection"]);
test(map["holding"].current == 1);
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
map = toMap(clientMetrics.getMetricsView("View", out timestamp)["Connection"]);
test(map["closing"].current == 1);
@@ -605,7 +605,7 @@ public class AllTests : TestCommon.AllTests
props["IceMX.Metrics.View.Map.Connection.GroupBy"] = "none";
updateProps(clientProps, serverProps, update, props, "Connection");
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
metrics.ice_timeout(500).ice_ping();
controller.hold();
@@ -661,7 +661,7 @@ public class AllTests : TestCommon.AllTests
testAttribute(clientMetrics, clientProps, update, "Connection", "mcastHost", "");
testAttribute(clientMetrics, clientProps, update, "Connection", "mcastPort", "");
- m.ice_getConnection().close(false);
+ m.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -681,7 +681,7 @@ public class AllTests : TestCommon.AllTests
IceMX.Metrics m1 = clientMetrics.getMetricsView("View", out timestamp)["ConnectionEstablishment"][0];
test(m1.current == 0 && m1.total == 1 && m1.id.Equals(hostAndPort));
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
controller.hold();
try
{
@@ -733,7 +733,7 @@ public class AllTests : TestCommon.AllTests
try
{
prx.ice_ping();
- prx.ice_getConnection().close(false);
+ prx.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
catch(Ice.LocalException)
{
@@ -743,8 +743,6 @@ public class AllTests : TestCommon.AllTests
m1 = clientMetrics.getMetricsView("View", out timestamp)["EndpointLookup"][0];
test(m1.current <= 1 && m1.total == 1);
- prx.ice_getConnection().close(false);
-
bool dnsException = false;
try
{
diff --git a/csharp/test/Ice/metrics/MetricsAMDI.cs b/csharp/test/Ice/metrics/MetricsAMDI.cs
index e208bddfd38..d85fa95c919 100644
--- a/csharp/test/Ice/metrics/MetricsAMDI.cs
+++ b/csharp/test/Ice/metrics/MetricsAMDI.cs
@@ -41,7 +41,7 @@ public sealed class MetricsI : MetricsDisp_
override public Task failAsync(Ice.Current current)
{
- current.con.close(true);
+ current.con.close(Ice.ConnectionClose.CloseForcefully);
return null;
}
diff --git a/csharp/test/Ice/metrics/MetricsI.cs b/csharp/test/Ice/metrics/MetricsI.cs
index 6df99c878a9..4139191de9e 100644
--- a/csharp/test/Ice/metrics/MetricsI.cs
+++ b/csharp/test/Ice/metrics/MetricsI.cs
@@ -40,7 +40,7 @@ public sealed class MetricsI : MetricsDisp_
override public void fail(Ice.Current current)
{
- current.con.close(true);
+ current.con.close(Ice.ConnectionClose.CloseForcefully);
}
override public void opWithUserException(Ice.Current current)
diff --git a/csharp/test/Ice/operations/BatchOneways.cs b/csharp/test/Ice/operations/BatchOneways.cs
index aae9fedbe09..ee21049b0c7 100644
--- a/csharp/test/Ice/operations/BatchOneways.cs
+++ b/csharp/test/Ice/operations/BatchOneways.cs
@@ -100,7 +100,7 @@ class BatchOneways
batch1.ice_ping();
batch2.ice_ping();
batch1.ice_flushBatchRequests();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.ice_ping();
batch2.ice_ping();
@@ -108,7 +108,7 @@ class BatchOneways
batch2.ice_getConnection();
batch1.ice_ping();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.ice_ping();
batch2.ice_ping();
}
diff --git a/csharp/test/Ice/operations/BatchOnewaysAMI.cs b/csharp/test/Ice/operations/BatchOnewaysAMI.cs
index 87615c540ae..e482b261eb1 100644
--- a/csharp/test/Ice/operations/BatchOnewaysAMI.cs
+++ b/csharp/test/Ice/operations/BatchOnewaysAMI.cs
@@ -91,7 +91,7 @@ class BatchOnewaysAMI
batch1.begin_ice_ping();
batch2.begin_ice_ping();
batch1.end_ice_flushBatchRequests(batch1.begin_ice_flushBatchRequests());
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.begin_ice_ping();
batch2.begin_ice_ping();
@@ -99,7 +99,7 @@ class BatchOnewaysAMI
batch2.ice_getConnection();
batch1.begin_ice_ping();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.begin_ice_ping();
batch2.begin_ice_ping();
diff --git a/csharp/test/Ice/retry/RetryI.cs b/csharp/test/Ice/retry/RetryI.cs
index d7370c7edaa..952527cf15d 100644
--- a/csharp/test/Ice/retry/RetryI.cs
+++ b/csharp/test/Ice/retry/RetryI.cs
@@ -19,7 +19,7 @@ public sealed class RetryI : Test.RetryDisp_
{
if(current.con != null)
{
- current.con.close(true);
+ current.con.close(Ice.ConnectionClose.CloseForcefully);
}
else
{
diff --git a/csharp/test/Ice/timeout/AllTests.cs b/csharp/test/Ice/timeout/AllTests.cs
index e466f5f64d9..7c405f5872b 100644
--- a/csharp/test/Ice/timeout/AllTests.cs
+++ b/csharp/test/Ice/timeout/AllTests.cs
@@ -248,7 +248,7 @@ public class AllTests : TestCommon.AllTests
Test.TimeoutPrx to = Test.TimeoutPrxHelper.checkedCast(obj.ice_timeout(100));
Ice.Connection connection = to.ice_getConnection();
timeout.holdAdapter(500);
- connection.close(false);
+ connection.close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
connection.getInfo(); // getInfo() doesn't throw in the closing state.
@@ -263,9 +263,10 @@ public class AllTests : TestCommon.AllTests
connection.getInfo();
test(false);
}
- catch(Ice.CloseConnectionException)
+ catch(Ice.ConnectionManuallyClosedException ex)
{
// Expected.
+ test(ex.graceful);
}
timeout.op(); // Ensure adapter is active.
}
diff --git a/csharp/test/Ice/udp/AllTests.cs b/csharp/test/Ice/udp/AllTests.cs
index da166bcafc3..710a0acb287 100644
--- a/csharp/test/Ice/udp/AllTests.cs
+++ b/csharp/test/Ice/udp/AllTests.cs
@@ -126,7 +126,7 @@ public class AllTests
//
test(seq.Length > 16384);
}
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
communicator.getProperties().setProperty("Ice.UDP.SndSize", "64000");
seq = new byte[50000];
try
diff --git a/csharp/test/IceSSL/configuration/AllTests.cs b/csharp/test/IceSSL/configuration/AllTests.cs
index 425d99f00f0..64ae2a9932c 100644
--- a/csharp/test/IceSSL/configuration/AllTests.cs
+++ b/csharp/test/IceSSL/configuration/AllTests.cs
@@ -948,7 +948,7 @@ public class AllTests
//
verifier.reset();
verifier.returnValue(false);
- server.ice_getConnection().close(false);
+ server.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
server.ice_ping();
diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Connection_heartbeat.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Connection_heartbeat.java
new file mode 100644
index 00000000000..e02ef2906c7
--- /dev/null
+++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Connection_heartbeat.java
@@ -0,0 +1,55 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package Ice;
+
+/**
+ * Asynchronous callback base class for Connection.begin_heartbeat.
+ **/
+public abstract class Callback_Connection_heartbeat extends IceInternal.CallbackBase
+{
+ /**
+ * Called when the invocation raises an Ice run-time exception.
+ *
+ * @param ex The Ice run-time exception raised by the operation.
+ **/
+ public abstract void exception(LocalException ex);
+
+ /**
+ * Called when a queued invocation is sent successfully.
+ **/
+ public void sent(boolean sentSynchronously)
+ {
+ }
+
+ @Override
+ public final void _iceCompleted(AsyncResult __result)
+ {
+ try
+ {
+ __result.getConnection().end_heartbeat(__result);
+ }
+ catch(LocalException __ex)
+ {
+ exception(__ex);
+ }
+ }
+
+ @Override
+ public final void _iceSent(AsyncResult __result)
+ {
+ sent(__result.sentSynchronously());
+ }
+
+ @Override
+ public final boolean _iceHasSentCallback()
+ {
+ return true;
+ }
+}
diff --git a/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java b/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java
index f4f1b32f4bf..84131a38cfc 100644
--- a/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java
+++ b/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java
@@ -155,25 +155,27 @@ public final class ConnectionI extends IceInternal.EventHandler
}
@Override
- synchronized public void close(boolean force)
+ synchronized public void close(ConnectionClose mode)
{
if(Thread.interrupted())
{
throw new Ice.OperationInterruptedException();
}
- if(force)
+ if(mode == ConnectionClose.CloseForcefully)
{
- setState(StateClosed, new ForcedCloseConnectionException());
+ setState(StateClosed, new ConnectionManuallyClosedException(false));
+ }
+ else if(mode == ConnectionClose.CloseGracefully)
+ {
+ setState(StateClosing, new ConnectionManuallyClosedException(true));
}
else
{
+ assert(mode == ConnectionClose.CloseGracefullyAndWait);
+
//
- // If we do a graceful shutdown, then we wait until all
- // outstanding requests have been completed. Otherwise,
- // the CloseConnectionException will cause all outstanding
- // requests to be retried, regardless of whether the
- // server has processed them or not.
+ // Wait until all outstanding requests have been completed.
//
while(!_asyncRequests.isEmpty())
{
@@ -187,7 +189,7 @@ public final class ConnectionI extends IceInternal.EventHandler
}
}
- setState(StateClosing, new CloseConnectionException());
+ setState(StateClosing, new ConnectionManuallyClosedException(true));
}
}
@@ -279,14 +281,14 @@ public final class ConnectionI extends IceInternal.EventHandler
// We send a heartbeat if there was no activity in the last
// (timeout / 4) period. Sending a heartbeat sooner than
// really needed is safer to ensure that the receiver will
- // receive in time the heartbeat. Sending the heartbeat if
+ // receive the heartbeat in time. Sending the heartbeat if
// there was no activity in the last (timeout / 2) period
// isn't enough since monitor() is called only every (timeout
// / 2) period.
//
// Note that this doesn't imply that we are sending 4
// heartbeats per timeout period because the monitor() method
- // is sill only called every (timeout / 2) period.
+ // is still only called every (timeout / 2) period.
//
if(acm.heartbeat == ACMHeartbeat.HeartbeatAlways ||
(acm.heartbeat != ACMHeartbeat.HeartbeatOff && _writeStream.isEmpty() &&
@@ -518,6 +520,155 @@ public final class ConnectionI extends IceInternal.EventHandler
}
@Override
+ public void heartbeat()
+ {
+ end_heartbeat(begin_heartbeat());
+ }
+
+ private static final String __heartbeat_name = "heartbeat";
+
+ @Override
+ public AsyncResult begin_heartbeat()
+ {
+ return begin_heartbeatInternal(null);
+ }
+
+ @Override
+ public AsyncResult begin_heartbeat(Callback cb)
+ {
+ return begin_heartbeatInternal(cb);
+ }
+
+ @Override
+ public AsyncResult begin_heartbeat(Callback_Connection_heartbeat cb)
+ {
+ return begin_heartbeatInternal(cb);
+ }
+
+ @Override
+ public AsyncResult begin_heartbeat(IceInternal.Functional_VoidCallback __responseCb,
+ final IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb,
+ IceInternal.Functional_BoolCallback __sentCb)
+ {
+ return begin_heartbeatInternal(new IceInternal.Functional_CallbackBase(false, __exceptionCb, __sentCb)
+ {
+ @Override
+ public final void _iceCompleted(AsyncResult __result)
+ {
+ try
+ {
+ __result.getConnection().end_heartbeat(__result);
+ }
+ catch(Exception __ex)
+ {
+ __exceptionCb.apply(__ex);
+ }
+ }
+ });
+ }
+
+ static class HeartbeatAsync extends IceInternal.OutgoingAsyncBase
+ {
+ public static HeartbeatAsync check(AsyncResult r, Connection con, String operation)
+ {
+ check(r, operation);
+ if(!(r instanceof HeartbeatAsync))
+ {
+ throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method");
+ }
+ if(r.getConnection() != con)
+ {
+ throw new IllegalArgumentException("Connection for call to end_" + operation +
+ " does not match connection that was used to call corresponding " +
+ "begin_" + operation + " method");
+ }
+ return (HeartbeatAsync)r;
+ }
+
+ public HeartbeatAsync(ConnectionI con, Communicator communicator, IceInternal.Instance instance,
+ String operation, IceInternal.CallbackBase callback)
+ {
+ super(communicator, instance, operation, callback);
+ _connection = con;
+ }
+
+ @Override
+ public Connection getConnection()
+ {
+ return _connection;
+ }
+
+ public void invoke()
+ {
+ try
+ {
+ _os.writeBlob(IceInternal.Protocol.magic);
+ ProtocolVersion.ice_write(_os, IceInternal.Protocol.currentProtocol);
+ EncodingVersion.ice_write(_os, IceInternal.Protocol.currentProtocolEncoding);
+ _os.writeByte(IceInternal.Protocol.validateConnectionMsg);
+ _os.writeByte((byte) 0);
+ _os.writeInt(IceInternal.Protocol.headerSize); // Message size.
+
+ int status;
+ if(_instance.queueRequests())
+ {
+ status = _instance.getQueueExecutor().execute(new Callable<Integer>()
+ {
+ @Override
+ public Integer call() throws IceInternal.RetryException
+ {
+ return _connection.sendAsyncRequest(HeartbeatAsync.this, false, false, 0);
+ }
+ });
+ }
+ else
+ {
+ status = _connection.sendAsyncRequest(this, false, false, 0);
+ }
+
+ if((status & IceInternal.AsyncStatus.Sent) > 0)
+ {
+ _sentSynchronously = true;
+ if((status & IceInternal.AsyncStatus.InvokeSentCallback) > 0)
+ {
+ invokeSent();
+ }
+ }
+ }
+ catch(IceInternal.RetryException ex)
+ {
+ if(completed(ex.get()))
+ {
+ invokeCompletedAsync();
+ }
+ }
+ catch(Ice.Exception ex)
+ {
+ if(completed(ex))
+ {
+ invokeCompletedAsync();
+ }
+ }
+ }
+
+ private Ice.ConnectionI _connection;
+ }
+
+ private AsyncResult begin_heartbeatInternal(IceInternal.CallbackBase cb)
+ {
+ HeartbeatAsync result = new HeartbeatAsync(this, _communicator, _instance, __heartbeat_name, cb);
+ result.invoke();
+ return result;
+ }
+
+ @Override
+ public void end_heartbeat(AsyncResult ir)
+ {
+ HeartbeatAsync r = HeartbeatAsync.check(ir, this, __heartbeat_name);
+ r.waitForResponseOrUserEx();
+ }
+
+ @Override
synchronized public void setACM(Ice.IntOptional timeout, Ice.Optional<ACMClose> close,
Ice.Optional<ACMHeartbeat> heartbeat)
{
@@ -703,8 +854,7 @@ public final class ConnectionI extends IceInternal.EventHandler
public synchronized void invokeException(int requestId, LocalException ex, int invokeNum, boolean amd)
{
//
- // Fatal exception while invoking a request. Since
- // sendResponse/sendNoResponse isn't
+ // Fatal exception while invoking a request. Since sendResponse/sendNoResponse isn't
// called in case of a fatal exception we decrement _dispatchCount here.
//
@@ -968,7 +1118,7 @@ public final class ConnectionI extends IceInternal.EventHandler
}
else
{
- assert (_state <= StateClosingPending);
+ assert(_state <= StateClosingPending);
//
// We parse messages first, if we receive a close
@@ -1144,7 +1294,8 @@ public final class ConnectionI extends IceInternal.EventHandler
//
if(info.invokeNum > 0)
{
- invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager, info.adapter);
+ invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager,
+ info.adapter);
//
// Don't increase dispatchedCount, the dispatch count is
@@ -1301,7 +1452,7 @@ public final class ConnectionI extends IceInternal.EventHandler
// Trace the cause of unexpected connection closures
//
if(!(_exception instanceof CloseConnectionException ||
- _exception instanceof ForcedCloseConnectionException ||
+ _exception instanceof ConnectionManuallyClosedException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException))
@@ -1650,7 +1801,7 @@ public final class ConnectionI extends IceInternal.EventHandler
// Don't warn about certain expected exceptions.
//
if(!(_exception instanceof CloseConnectionException ||
- _exception instanceof ForcedCloseConnectionException ||
+ _exception instanceof ConnectionManuallyClosedException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException ||
@@ -1840,7 +1991,7 @@ public final class ConnectionI extends IceInternal.EventHandler
if(_observer != null && state == StateClosed && _exception != null)
{
if(!(_exception instanceof CloseConnectionException ||
- _exception instanceof ForcedCloseConnectionException ||
+ _exception instanceof ConnectionManuallyClosedException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException ||
@@ -1869,8 +2020,7 @@ public final class ConnectionI extends IceInternal.EventHandler
private void initiateShutdown()
{
- assert (_state == StateClosing);
- assert (_dispatchCount == 0);
+ assert(_state == StateClosing && _dispatchCount == 0);
if(_shutdownInitiated)
{
@@ -1897,8 +2047,7 @@ public final class ConnectionI extends IceInternal.EventHandler
setState(StateClosingPending);
//
- // Notify the the transceiver of the graceful connection
- // closure.
+ // Notify the the transceiver of the graceful connection closure.
//
int op = _transceiver.closing(true, _exception);
if(op != 0)
@@ -1910,7 +2059,7 @@ public final class ConnectionI extends IceInternal.EventHandler
}
}
- private void heartbeat()
+ private void sendHeartbeatNow()
{
assert (_state == StateActive);
@@ -1948,8 +2097,7 @@ public final class ConnectionI extends IceInternal.EventHandler
}
//
- // Update the connection description once the transceiver is
- // initialized.
+ // Update the connection description once the transceiver is initialized.
//
_desc = _transceiver.toString();
_initialized = true;
@@ -2108,8 +2256,7 @@ public final class ConnectionI extends IceInternal.EventHandler
}
else if(_state == StateClosingPending && _writeStream.pos() == 0)
{
- // Message wasn't sent, empty the _writeStream, we're not going to
- // send more data.
+ // Message wasn't sent, empty the _writeStream, we're not going to send more data.
OutgoingMessage message = _sendStreams.getFirst();
_writeStream.swap(message.stream);
return IceInternal.SocketOperation.None;
@@ -2416,8 +2563,7 @@ public final class ConnectionI extends IceInternal.EventHandler
setState(StateClosingPending, new CloseConnectionException());
//
- // Notify the the transceiver of the graceful connection
- // closure.
+ // Notify the the transceiver of the graceful connection closure.
//
int op = _transceiver.closing(false, _exception);
if(op != 0)
diff --git a/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java
index 9405e3dcc17..108df4607e0 100644
--- a/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java
+++ b/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java
@@ -141,7 +141,7 @@ public final class IncomingConnectionFactory extends EventHandler implements Ice
//
for(Ice.ConnectionI c : connections)
{
- c.close(true);
+ c.close(Ice.ConnectionClose.CloseForcefully);
}
throw e;
}
diff --git a/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java
index 94b80c0e2fb..b51856cf3e6 100644
--- a/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java
+++ b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java
@@ -133,7 +133,7 @@ public final class OutgoingConnectionFactory
{
for(Ice.ConnectionI c : l)
{
- c.close(true);
+ c.close(Ice.ConnectionClose.CloseForcefully);
}
}
throw new Ice.OperationInterruptedException();
diff --git a/java-compat/test/src/main/java/test/Ice/acm/AllTests.java b/java-compat/test/src/main/java/test/Ice/acm/AllTests.java
index a4369b684b8..05465c8e3cb 100644
--- a/java-compat/test/src/main/java/test/Ice/acm/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/acm/AllTests.java
@@ -575,6 +575,31 @@ public class AllTests
}
}
+ static class HeartbeatManualTest extends TestCase
+ {
+ public HeartbeatManualTest(Application app, RemoteCommunicatorPrx com, java.io.PrintWriter out)
+ {
+ super(app, "manual heartbeats", com, out);
+ //
+ // Disable heartbeats.
+ //
+ setClientACM(10, -1, 0);
+ setServerACM(10, -1, 0);
+ }
+
+ public void runTestCase(RemoteObjectAdapterPrx adapter, TestIntfPrx proxy)
+ {
+ proxy.startHeartbeatCount();
+ Ice.Connection con = proxy.ice_getConnection();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ proxy.waitForHeartbeatCount(5);
+ }
+ }
+
static class SetACMTest extends TestCase
{
public SetACMTest(Application app, RemoteCommunicatorPrx com, java.io.PrintWriter out)
@@ -607,7 +632,8 @@ public class AllTests
test(acm.heartbeat == Ice.ACMHeartbeat.HeartbeatAlways);
// Make sure the client sends few heartbeats to the server
- proxy.waitForHeartbeat(2);
+ proxy.startHeartbeatCount();
+ proxy.waitForHeartbeatCount(2);
}
}
@@ -634,6 +660,7 @@ public class AllTests
tests.add(new HeartbeatOnIdleTest(app, com, out));
tests.add(new HeartbeatAlwaysTest(app, com, out));
+ tests.add(new HeartbeatManualTest(app, com, out));
tests.add(new SetACMTest(app, com, out));
for(TestCase test : tests)
diff --git a/java-compat/test/src/main/java/test/Ice/acm/Test.ice b/java-compat/test/src/main/java/test/Ice/acm/Test.ice
index 117192a2df8..7f71427c741 100644
--- a/java-compat/test/src/main/java/test/Ice/acm/Test.ice
+++ b/java-compat/test/src/main/java/test/Ice/acm/Test.ice
@@ -18,7 +18,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/java-compat/test/src/main/java/test/Ice/acm/TestI.java b/java-compat/test/src/main/java/test/Ice/acm/TestI.java
index 00620c07dd0..a83cb645525 100644
--- a/java-compat/test/src/main/java/test/Ice/acm/TestI.java
+++ b/java-compat/test/src/main/java/test/Ice/acm/TestI.java
@@ -49,27 +49,34 @@ public class TestI extends _TestIntfDisp
}
}
- public void waitForHeartbeat(int count, Ice.Current current)
+ public void startHeartbeatCount(Ice.Current current)
{
- final Ice.Holder<Integer> c = new Ice.Holder<Integer>(count);
+ _counter = new Ice.Holder<Integer>(0);
Ice.HeartbeatCallback callback = new Ice.HeartbeatCallback()
{
- synchronized public void heartbeat(Ice.Connection connection)
+ public void heartbeat(Ice.Connection connection)
{
- --c.value;
- notifyAll();
+ synchronized(_counter)
+ {
+ ++_counter.value;
+ _counter.notifyAll();
+ }
}
};
current.con.setHeartbeatCallback(callback);
+ }
- synchronized(callback)
+ public void waitForHeartbeatCount(int count, Ice.Current current)
+ {
+ assert(_counter != null);
+ synchronized(_counter)
{
- while(c.value > 0)
+ while(_counter.value < count)
{
try
{
- callback.wait();
+ _counter.wait();
}
catch(InterruptedException ex)
{
@@ -77,4 +84,6 @@ public class TestI extends _TestIntfDisp
}
}
}
-};
+
+ private Ice.Holder<Integer> _counter;
+}
diff --git a/java-compat/test/src/main/java/test/Ice/ami/AMI.java b/java-compat/test/src/main/java/test/Ice/ami/AMI.java
index c018ccb8c62..c707f20e6c7 100644
--- a/java-compat/test/src/main/java/test/Ice/ami/AMI.java
+++ b/java-compat/test/src/main/java/test/Ice/ami/AMI.java
@@ -19,6 +19,7 @@ import test.Ice.ami.Test.Callback_TestIntf_op;
import test.Ice.ami.Test.Callback_TestIntf_opWithResult;
import test.Ice.ami.Test.Callback_TestIntf_opWithUE;
import test.Ice.ami.Test.Callback_TestIntf_opWithPayload;
+import test.Ice.ami.Test.CloseMode;
import test.Util.Application;
public class AMI
@@ -546,6 +547,18 @@ public class AMI
}
}
+ static class CloseCallback extends CallbackBase implements Ice.CloseCallback
+ {
+ CloseCallback()
+ {
+ }
+
+ public void closed(Ice.Connection con)
+ {
+ called();
+ }
+ }
+
enum ThrowType { LocalException, OtherException };
static class Thrower extends CallbackBase
@@ -1817,7 +1830,7 @@ public class AMI
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests(
new Ice.Callback()
@@ -1879,7 +1892,7 @@ public class AMI
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.ice_getConnection();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests(
new Ice.Callback_Object_ice_flushBatchRequests()
@@ -1948,7 +1961,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushExCallback cb = new FlushExCallback();
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests(
new Ice.Callback()
@@ -2010,7 +2023,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushExCallback cb = new FlushExCallback();
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests(
new Ice.Callback_Connection_flushBatchRequests()
@@ -2077,7 +2090,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
new Ice.Callback()
@@ -2151,7 +2164,7 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
new Ice.Callback()
@@ -2188,8 +2201,8 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
new Ice.Callback()
@@ -2251,7 +2264,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(
p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
new Ice.Callback_Communicator_flushBatchRequests()
@@ -2325,7 +2338,7 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
new Ice.Callback_Communicator_flushBatchRequests()
@@ -2362,8 +2375,8 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
new Ice.Callback_Communicator_flushBatchRequests()
@@ -2588,9 +2601,36 @@ public class AMI
if(p.ice_getConnection() != null)
{
- out.print("testing close connection with sending queue... ");
+ out.print("testing graceful close connection with wait... ");
out.flush();
{
+ //
+ // Local case: begin several requests, close the connection gracefully, and make sure it waits
+ // for the requests to complete.
+ //
+ java.util.List<Ice.AsyncResult> results = new java.util.ArrayList<>();
+ for(int i = 0; i < 3; ++i)
+ {
+ results.add(p.begin_sleep(50));
+ }
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ for(Ice.AsyncResult r : results)
+ {
+ r.waitForCompleted();
+ try
+ {
+ r.throwLocalException();
+ }
+ catch(Throwable ex)
+ {
+ test(false);
+ }
+ }
+ }
+ {
+ //
+ // Remote case.
+ //
byte[] seq = new byte[1024 * 10];
//
@@ -2604,12 +2644,12 @@ public class AMI
{
done = true;
p.ice_ping();
- java.util.List<Ice.AsyncResult> results = new java.util.ArrayList<Ice.AsyncResult>();
+ java.util.List<Ice.AsyncResult> results = new java.util.ArrayList<>();
for(int i = 0; i < maxQueue; ++i)
{
results.add(p.begin_opWithPayload(seq));
}
- if(!p.begin_close(false).isSent())
+ if(!p.begin_close(CloseMode.CloseGracefullyAndWait).isSent())
{
for(int i = 0; i < maxQueue; i++)
{
@@ -2643,6 +2683,98 @@ public class AMI
}
}
out.println("ok");
+
+ out.print("testing graceful close connection without wait... ");
+ out.flush();
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection gracefully on the client side
+ // without waiting for the pending invocation to complete. There will be no retry and we expect the
+ // invocation to fail with ConnectionManuallyClosedException.
+ //
+ // This test requires two threads in the server's thread pool: one will block in sleep() and the other
+ // will process the CloseConnection message.
+ //
+ p.ice_ping();
+ Ice.Connection con = p.ice_getConnection();
+ Ice.AsyncResult r = p.begin_sleep(100);
+ con.close(Ice.ConnectionClose.CloseGracefully);
+ r.waitForCompleted();
+ try
+ {
+ r.throwLocalException();
+ test(false);
+ }
+ catch(Ice.ConnectionManuallyClosedException ex)
+ {
+ test(ex.graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection gracefully. Our call to TestIntf::close()
+ // completes successfully and then the connection should be closed immediately afterward,
+ // despite the fact that there's a pending call to sleep(). The call to sleep() should be
+ // automatically retried and complete successfully.
+ //
+ p.ice_ping();
+ con = p.ice_getConnection();
+ CloseCallback cb = new CloseCallback();
+ con.setCloseCallback(cb);
+ r = p.begin_sleep(100);
+ p.close(CloseMode.CloseGracefully);
+ cb.check();
+ r.waitForCompleted();
+ try
+ {
+ r.throwLocalException();
+ }
+ catch(Ice.LocalException ex)
+ {
+ test(false);
+ }
+ p.ice_ping();
+ test(p.ice_getConnection() != con);
+ }
+ out.println("ok");
+
+ out.print("testing forceful close connection... ");
+ out.flush();
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection forcefully on the client side.
+ // There will be no retry and we expect the invocation to fail with ConnectionManuallyClosedException.
+ //
+ p.ice_ping();
+ Ice.Connection con = p.ice_getConnection();
+ Ice.AsyncResult r = p.begin_sleep(100);
+ con.close(Ice.ConnectionClose.CloseForcefully);
+ r.waitForCompleted();
+ try
+ {
+ r.throwLocalException();
+ test(false);
+ }
+ catch(Ice.ConnectionManuallyClosedException ex)
+ {
+ test(!ex.graceful);
+ }
+
+ //
+ // Remote case: the server closes the connection forcefully. This causes the request to fail
+ // with a ConnectionLostException. Since the close() operation is not idempotent, the client
+ // will not retry.
+ //
+ try
+ {
+ p.close(CloseMode.CloseForcefully);
+ test(false);
+ }
+ catch(Ice.ConnectionLostException ex)
+ {
+ // Expected.
+ }
+ }
+ out.println("ok");
}
}
}
diff --git a/java-compat/test/src/main/java/test/Ice/ami/Client.java b/java-compat/test/src/main/java/test/Ice/ami/Client.java
index 097bb922ce6..b261e603777 100644
--- a/java-compat/test/src/main/java/test/Ice/ami/Client.java
+++ b/java-compat/test/src/main/java/test/Ice/ami/Client.java
@@ -24,6 +24,7 @@ public class Client extends test.Util.Application
Ice.InitializationData initData = super.getInitData(argsH);
initData.properties.setProperty("Ice.Package.Test", "test.Ice.ami");
initData.properties.setProperty("Ice.Warn.AMICallback", "0");
+ initData.properties.setProperty("Ice.Warn.Connections", "0");
//
// Limit the send buffer size, this test relies on the socket
diff --git a/java-compat/test/src/main/java/test/Ice/ami/Server.java b/java-compat/test/src/main/java/test/Ice/ami/Server.java
index 1b826ef52e9..62dfc59af45 100644
--- a/java-compat/test/src/main/java/test/Ice/ami/Server.java
+++ b/java-compat/test/src/main/java/test/Ice/ami/Server.java
@@ -34,6 +34,12 @@ public class Server extends test.Util.Application
initData.properties.setProperty("TestAdapter.Endpoints", getTestEndpoint(initData.properties, 0));
initData.properties.setProperty("ControllerAdapter.Endpoints", getTestEndpoint(initData.properties, 1));
initData.properties.setProperty("ControllerAdapter.ThreadPool.Size", "1");
+
+ //
+ // This test kills connections, so we don't want warnings.
+ //
+ initData.properties.setProperty("Ice.Warn.Connections", "0");
+
//
// Limit the recv buffer size, this test relies on the socket
// send() blocking after sending a given amount of data.
diff --git a/java-compat/test/src/main/java/test/Ice/ami/Test.ice b/java-compat/test/src/main/java/test/Ice/ami/Test.ice
index 82b3fe6d383..bbc4d908d65 100644
--- a/java-compat/test/src/main/java/test/Ice/ami/Test.ice
+++ b/java-compat/test/src/main/java/test/Ice/ami/Test.ice
@@ -20,6 +20,13 @@ exception TestIntfException
{
};
+enum CloseMode
+{
+ CloseForcefully,
+ CloseGracefully,
+ CloseGracefullyAndWait
+};
+
interface TestIntf
{
void op();
@@ -30,7 +37,8 @@ interface TestIntf
void opBatch();
int opBatchCount();
bool waitForBatch(int count);
- void close(bool force);
+ void close(CloseMode mode);
+ void sleep(int ms);
void shutdown();
bool supportsFunctionalTests();
diff --git a/java-compat/test/src/main/java/test/Ice/ami/TestI.java b/java-compat/test/src/main/java/test/Ice/ami/TestI.java
index b0c6df0cf4a..af4c50e5d33 100644
--- a/java-compat/test/src/main/java/test/Ice/ami/TestI.java
+++ b/java-compat/test/src/main/java/test/Ice/ami/TestI.java
@@ -10,6 +10,7 @@
package test.Ice.ami;
import test.Ice.ami.Test._TestIntfDisp;
+import test.Ice.ami.Test.CloseMode;
import test.Ice.ami.Test.TestIntfException;
public class TestI extends _TestIntfDisp
@@ -129,9 +130,22 @@ public class TestI extends _TestIntfDisp
@Override
public void
- close(boolean force, Ice.Current current)
+ close(CloseMode mode, Ice.Current current)
{
- current.con.close(force);
+ current.con.close(Ice.ConnectionClose.valueOf(mode.value()));
+ }
+
+ @Override
+ public void
+ sleep(int ms, Ice.Current current)
+ {
+ try
+ {
+ Thread.sleep(ms);
+ }
+ catch(InterruptedException ex)
+ {
+ }
}
@Override
diff --git a/java-compat/test/src/main/java/test/Ice/ami/lambda/AMI.java b/java-compat/test/src/main/java/test/Ice/ami/lambda/AMI.java
index eb572f481e2..8d886c20d78 100644
--- a/java-compat/test/src/main/java/test/Ice/ami/lambda/AMI.java
+++ b/java-compat/test/src/main/java/test/Ice/ami/lambda/AMI.java
@@ -845,7 +845,7 @@ public class AMI
test(p.opBatchCount() == 0);
TestIntfPrx b1 = (TestIntfPrx)p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = b1.begin_ice_flushBatchRequests(
null,
@@ -901,7 +901,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushExCallback cb = new FlushExCallback();
Ice.AsyncResult r = b1.ice_getConnection().begin_flushBatchRequests(
null,
@@ -946,7 +946,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrxHelper.uncheckedCast(p.ice_getConnection().createProxy(
p.ice_getIdentity()).ice_batchOneway());
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
null,
@@ -998,7 +998,7 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
null,
@@ -1024,8 +1024,8 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final FlushCallback cb = new FlushCallback();
Ice.AsyncResult r = communicator.begin_flushBatchRequests(
null,
diff --git a/java-compat/test/src/main/java/test/Ice/background/AllTests.java b/java-compat/test/src/main/java/test/Ice/background/AllTests.java
index 187c7bbf4f2..e3f92a9f4d9 100644
--- a/java-compat/test/src/main/java/test/Ice/background/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/background/AllTests.java
@@ -398,7 +398,7 @@ public class AllTests
configuration.buffered(true);
backgroundController.buffered(true);
background.begin_op();
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
background.begin_op();
OpAMICallbackNoOp cb = new OpAMICallbackNoOp();
@@ -439,7 +439,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
for(int i = 0; i < 4; ++i)
{
@@ -505,7 +505,7 @@ public class AllTests
}
configuration.connectException(new Ice.SocketException());
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -548,7 +548,7 @@ public class AllTests
ex.printStackTrace();
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
for(int i = 0; i < 4; i++)
{
@@ -611,7 +611,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -623,7 +623,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -667,7 +667,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -702,7 +702,7 @@ public class AllTests
}
configuration.initializeException(new Ice.SocketException());
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -728,7 +728,7 @@ public class AllTests
}
configuration.initializeSocketStatus(IceInternal.SocketOperation.Write);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
try
{
@@ -743,7 +743,7 @@ public class AllTests
configuration.initializeSocketStatus(IceInternal.SocketOperation.None);
ctl.initializeException(true);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -771,7 +771,7 @@ public class AllTests
try
{
ctl.initializeSocketStatus(IceInternal.SocketOperation.Write);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
background.op();
ctl.initializeSocketStatus(IceInternal.SocketOperation.None);
}
@@ -806,7 +806,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -852,7 +852,7 @@ public class AllTests
ex.printStackTrace();
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -922,7 +922,7 @@ public class AllTests
ex.printStackTrace();
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -952,7 +952,7 @@ public class AllTests
backgroundBatchOneway.op();
ctl.resumeAdapter();
backgroundBatchOneway.ice_flushBatchRequests();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
//
// Send bigger requests to test with auto-flushing.
@@ -964,7 +964,7 @@ public class AllTests
backgroundBatchOneway.opWithPayload(seq);
ctl.resumeAdapter();
backgroundBatchOneway.ice_flushBatchRequests();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
//
// Then try the same thing with async flush.
@@ -976,7 +976,7 @@ public class AllTests
backgroundBatchOneway.op();
ctl.resumeAdapter();
backgroundBatchOneway.begin_ice_flushBatchRequests();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
ctl.holdAdapter();
backgroundBatchOneway.opWithPayload(seq);
@@ -986,7 +986,7 @@ public class AllTests
ctl.resumeAdapter();
r = backgroundBatchOneway.begin_ice_flushBatchRequests();
backgroundBatchOneway.end_ice_flushBatchRequests(r);
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
private static void
@@ -1328,7 +1328,7 @@ public class AllTests
}
background.ice_ping();
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -1337,7 +1337,7 @@ public class AllTests
{
}
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(Ice.ConnectionClose.CloseForcefully);
}
thread1._destroy();
diff --git a/java-compat/test/src/main/java/test/Ice/binding/AllTests.java b/java-compat/test/src/main/java/test/Ice/binding/AllTests.java
index 4aadfe0c3ff..062a5c87393 100644
--- a/java-compat/test/src/main/java/test/Ice/binding/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/binding/AllTests.java
@@ -176,7 +176,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(test1.getAdapterName());
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -198,7 +198,7 @@ public class AllTests
for(RemoteObjectAdapterPrx p : adapters)
{
- p.getTestIntf().ice_getConnection().close(false);
+ p.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -224,7 +224,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(test1.getAdapterName());
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -332,7 +332,7 @@ public class AllTests
{
try
{
- a.getTestIntf().ice_getConnection().close(false);
+ a.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
catch(Ice.LocalException ex)
{
@@ -374,7 +374,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(getAdapterNameWithAMI(test1));
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -396,7 +396,7 @@ public class AllTests
for(RemoteObjectAdapterPrx p : adapters)
{
- p.getTestIntf().ice_getConnection().close(false);
+ p.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -422,7 +422,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(getAdapterNameWithAMI(test1));
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -455,7 +455,7 @@ public class AllTests
while(!names.isEmpty())
{
names.remove(test.getAdapterName());
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
test = TestIntfPrxHelper.uncheckedCast(test.ice_endpointSelection(Ice.EndpointSelectionType.Random));
@@ -467,7 +467,7 @@ public class AllTests
while(!names.isEmpty())
{
names.remove(test.getAdapterName());
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
deactivate(com, adapters);
@@ -531,11 +531,11 @@ public class AllTests
adapters.add(com.createObjectAdapter("Adapter36", endpoints[2].toString()));
for(i = 0; i < nRetry && test.getAdapterName().equals("Adapter36"); i++);
test(i == nRetry);
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
adapters.add(com.createObjectAdapter("Adapter35", endpoints[1].toString()));
for(i = 0; i < nRetry && test.getAdapterName().equals("Adapter35"); i++);
test(i == nRetry);
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
adapters.add(com.createObjectAdapter("Adapter34", endpoints[0].toString()));
for(i = 0; i < nRetry && test.getAdapterName().equals("Adapter34"); i++);
test(i == nRetry);
@@ -832,7 +832,7 @@ public class AllTests
for(i = 0; i < 5; i++)
{
test(test.getAdapterName().equals("Adapter82"));
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
TestIntfPrx testSecure = TestIntfPrxHelper.uncheckedCast(test.ice_secure(true));
@@ -848,7 +848,7 @@ public class AllTests
for(i = 0; i < 5; i++)
{
test(test.getAdapterName().equals("Adapter81"));
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
com.createObjectAdapter("Adapter83", (test.ice_getEndpoints()[1]).toString()); // Reactive tcp OA.
@@ -856,7 +856,7 @@ public class AllTests
for(i = 0; i < 5; i++)
{
test(test.getAdapterName().equals("Adapter83"));
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
com.deactivateObjectAdapter(adapters.get(0));
@@ -1051,7 +1051,7 @@ public class AllTests
// Close the connection now to free a FD (it could be done after the sleep but
// there could be race condiutation since the connection might not be closed
// immediately due to threading).
- test.ice_connectionId("0").ice_getConnection().close(false);
+ test.ice_connectionId("0").ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
//
// The server closed the acceptor, wait one second and retry after freeing a FD.
diff --git a/java-compat/test/src/main/java/test/Ice/hold/AllTests.java b/java-compat/test/src/main/java/test/Ice/hold/AllTests.java
index b27fbaf331c..bd642b9882f 100644
--- a/java-compat/test/src/main/java/test/Ice/hold/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/hold/AllTests.java
@@ -206,7 +206,7 @@ public class AllTests
{
result.waitForSent();
holdSerialized.ice_ping(); // Ensure everything's dispatched
- holdSerialized.ice_getConnection().close(false);
+ holdSerialized.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
result.waitForCompleted();
diff --git a/java-compat/test/src/main/java/test/Ice/interrupt/AllTests.java b/java-compat/test/src/main/java/test/Ice/interrupt/AllTests.java
index 8d954f051ec..ed523af5dbe 100644
--- a/java-compat/test/src/main/java/test/Ice/interrupt/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/interrupt/AllTests.java
@@ -379,8 +379,7 @@ public class AllTests
out.flush();
{
final Thread mainThread = Thread.currentThread();
-
- p.ice_getConnection().close(false);
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
AsyncResult r = p.begin_ice_getConnection();
mainThread.interrupt();
@@ -394,7 +393,7 @@ public class AllTests
// Expected
}
- p.ice_getConnection().close(false);
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
final CallbackBase cb = new CallbackBase();
mainThread.interrupt();
diff --git a/java-compat/test/src/main/java/test/Ice/location/AllTests.java b/java-compat/test/src/main/java/test/Ice/location/AllTests.java
index 8b6d3fb74ee..f8a3ab46d65 100644
--- a/java-compat/test/src/main/java/test/Ice/location/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/location/AllTests.java
@@ -611,7 +611,7 @@ public class AllTests
out.flush();
hello = HelloPrxHelper.checkedCast(communicator.stringToProxy("hello"));
obj.migrateHello();
- hello.ice_getConnection().close(false);
+ hello.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
hello.sayHello();
obj.migrateHello();
hello.sayHello();
diff --git a/java-compat/test/src/main/java/test/Ice/metrics/AMDMetricsI.java b/java-compat/test/src/main/java/test/Ice/metrics/AMDMetricsI.java
index 865db0c83ef..42bb7ee43d7 100644
--- a/java-compat/test/src/main/java/test/Ice/metrics/AMDMetricsI.java
+++ b/java-compat/test/src/main/java/test/Ice/metrics/AMDMetricsI.java
@@ -28,7 +28,7 @@ public final class AMDMetricsI extends _MetricsDisp
public void
fail_async(AMD_Metrics_fail cb, Ice.Current current)
{
- current.con.close(true);
+ current.con.close(Ice.ConnectionClose.CloseForcefully);
cb.ice_response();
}
diff --git a/java-compat/test/src/main/java/test/Ice/metrics/AllTests.java b/java-compat/test/src/main/java/test/Ice/metrics/AllTests.java
index ea00e4fc8dd..52de5aef9c1 100644
--- a/java-compat/test/src/main/java/test/Ice/metrics/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/metrics/AllTests.java
@@ -313,7 +313,7 @@ public class AllTests
{
if(proxy.ice_getCachedConnection() != null)
{
- proxy.ice_getCachedConnection().close(false);
+ proxy.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
try
@@ -326,7 +326,7 @@ public class AllTests
if(proxy.ice_getCachedConnection() != null)
{
- proxy.ice_getCachedConnection().close(false);
+ proxy.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -545,8 +545,8 @@ public class AllTests
if(!collocated)
{
- metrics.ice_getConnection().close(false);
- metrics.ice_connectionId("Con1").ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ metrics.ice_connectionId("Con1").ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -649,7 +649,7 @@ public class AllTests
map = toMap(serverMetrics.getMetricsView("View", timestamp).get("Connection"));
test(map.get("holding").current == 1);
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
map = toMap(clientMetrics.getMetricsView("View", timestamp).get("Connection"));
test(map.get("closing").current == 1);
@@ -664,7 +664,7 @@ public class AllTests
props.put("IceMX.Metrics.View.Map.Connection.GroupBy", "none");
updateProps(clientProps, serverProps, update, props, "Connection");
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
metrics.ice_timeout(500).ice_ping();
controller.hold();
@@ -726,7 +726,7 @@ public class AllTests
testAttribute(clientMetrics, clientProps, update, "Connection", "mcastHost", "", out);
testAttribute(clientMetrics, clientProps, update, "Connection", "mcastPort", "", out);
- m.ice_getConnection().close(false);
+ m.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -746,7 +746,7 @@ public class AllTests
IceMX.Metrics m1 = clientMetrics.getMetricsView("View", timestamp).get("ConnectionEstablishment")[0];
test(m1.current == 0 && m1.total == 1 && m1.id.equals(hostAndPort));
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
controller.hold();
try
{
@@ -806,7 +806,7 @@ public class AllTests
m1 = clientMetrics.getMetricsView("View", timestamp).get("EndpointLookup")[0];
test(m1.current <= 1 && m1.total == 1 && m1.id.equals(prx.ice_getConnection().getEndpoint().toString()));
- prx.ice_getConnection().close(false);
+ prx.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
boolean dnsException = false;
try
diff --git a/java-compat/test/src/main/java/test/Ice/metrics/MetricsI.java b/java-compat/test/src/main/java/test/Ice/metrics/MetricsI.java
index a7cf0f3dccf..37a3a440351 100644
--- a/java-compat/test/src/main/java/test/Ice/metrics/MetricsI.java
+++ b/java-compat/test/src/main/java/test/Ice/metrics/MetricsI.java
@@ -27,7 +27,7 @@ public final class MetricsI extends _MetricsDisp
public void
fail(Ice.Current current)
{
- current.con.close(true);
+ current.con.close(Ice.ConnectionClose.CloseForcefully);
}
@Override
diff --git a/java-compat/test/src/main/java/test/Ice/operations/BatchOneways.java b/java-compat/test/src/main/java/test/Ice/operations/BatchOneways.java
index 75ed24a392e..d3240fc5a06 100644
--- a/java-compat/test/src/main/java/test/Ice/operations/BatchOneways.java
+++ b/java-compat/test/src/main/java/test/Ice/operations/BatchOneways.java
@@ -115,7 +115,7 @@ class BatchOneways
batch1.ice_ping();
batch2.ice_ping();
batch1.ice_flushBatchRequests();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.ice_ping();
batch2.ice_ping();
@@ -123,7 +123,7 @@ class BatchOneways
batch2.ice_getConnection();
batch1.ice_ping();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.ice_ping();
batch2.ice_ping();
}
diff --git a/java-compat/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java b/java-compat/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java
index 34d0cc00a43..985abb4e945 100644
--- a/java-compat/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java
+++ b/java-compat/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java
@@ -107,7 +107,7 @@ class BatchOnewaysAMI
batch.begin_ice_ping();
batch2.begin_ice_ping();
batch.end_ice_flushBatchRequests(batch.begin_ice_flushBatchRequests());
- batch.ice_getConnection().close(false);
+ batch.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch.begin_ice_ping();
batch2.begin_ice_ping();
@@ -115,7 +115,7 @@ class BatchOnewaysAMI
batch2.ice_getConnection();
batch.begin_ice_ping();
- batch.ice_getConnection().close(false);
+ batch.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
batch.begin_ice_ping().throwLocalException();
batch2.begin_ice_ping().throwLocalException();
}
diff --git a/java-compat/test/src/main/java/test/Ice/retry/RetryI.java b/java-compat/test/src/main/java/test/Ice/retry/RetryI.java
index 453b1ddd2c7..ab0d3ec70f7 100644
--- a/java-compat/test/src/main/java/test/Ice/retry/RetryI.java
+++ b/java-compat/test/src/main/java/test/Ice/retry/RetryI.java
@@ -25,7 +25,7 @@ public final class RetryI extends _RetryDisp
{
if(current.con != null)
{
- current.con.close(true);
+ current.con.close(Ice.ConnectionClose.CloseForcefully);
}
else
{
diff --git a/java-compat/test/src/main/java/test/Ice/timeout/AllTests.java b/java-compat/test/src/main/java/test/Ice/timeout/AllTests.java
index 4c92ee8885b..28172f950c3 100644
--- a/java-compat/test/src/main/java/test/Ice/timeout/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/timeout/AllTests.java
@@ -329,7 +329,7 @@ public class AllTests
TimeoutPrx to = TimeoutPrxHelper.checkedCast(obj.ice_timeout(100 * mult));
Ice.Connection connection = to.ice_getConnection();
timeout.holdAdapter(500);
- connection.close(false);
+ connection.close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
connection.getInfo(); // getInfo() doesn't throw in the closing state.
@@ -350,9 +350,10 @@ public class AllTests
connection.getInfo();
test(false);
}
- catch(Ice.CloseConnectionException ex)
+ catch(Ice.ConnectionManuallyClosedException ex)
{
// Expected.
+ test(ex.graceful);
}
timeout.op(); // Ensure adapter is active.
}
diff --git a/java-compat/test/src/main/java/test/Ice/udp/AllTests.java b/java-compat/test/src/main/java/test/Ice/udp/AllTests.java
index 22e8c47e0ae..5d000d818d0 100644
--- a/java-compat/test/src/main/java/test/Ice/udp/AllTests.java
+++ b/java-compat/test/src/main/java/test/Ice/udp/AllTests.java
@@ -130,7 +130,7 @@ public class AllTests
{
test(seq.length > 16384);
}
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
communicator.getProperties().setProperty("Ice.UDP.SndSize", "64000");
seq = new byte[50000];
try
diff --git a/java-compat/test/src/main/java/test/IceSSL/configuration/AllTests.java b/java-compat/test/src/main/java/test/IceSSL/configuration/AllTests.java
index 6e836a3f832..a13868fbeb8 100644
--- a/java-compat/test/src/main/java/test/IceSSL/configuration/AllTests.java
+++ b/java-compat/test/src/main/java/test/IceSSL/configuration/AllTests.java
@@ -891,7 +891,7 @@ public class AllTests
//
verifier.reset();
verifier.returnValue(false);
- server.ice_getConnection().close(false);
+ server.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
server.ice_ping();
diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java b/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java
index ef086dbf88a..13b2d7a1dcc 100644
--- a/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java
+++ b/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java
@@ -165,25 +165,27 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
@Override
- synchronized public void close(boolean force)
+ synchronized public void close(ConnectionClose mode)
{
if(Thread.interrupted())
{
throw new OperationInterruptedException();
}
- if(force)
+ if(mode == ConnectionClose.CloseForcefully)
{
- setState(StateClosed, new ForcedCloseConnectionException());
+ setState(StateClosed, new ConnectionManuallyClosedException(false));
+ }
+ else if(mode == ConnectionClose.CloseGracefully)
+ {
+ setState(StateClosing, new ConnectionManuallyClosedException(true));
}
else
{
+ assert(mode == ConnectionClose.CloseGracefullyAndWait);
+
//
- // If we do a graceful shutdown, then we wait until all
- // outstanding requests have been completed. Otherwise,
- // the CloseConnectionException will cause all outstanding
- // requests to be retried, regardless of whether the
- // server has processed them or not.
+ // Wait until all outstanding requests have been completed.
//
while(!_asyncRequests.isEmpty())
{
@@ -197,7 +199,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
}
- setState(StateClosing, new CloseConnectionException());
+ setState(StateClosing, new ConnectionManuallyClosedException(true));
}
}
@@ -289,14 +291,14 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
// We send a heartbeat if there was no activity in the last
// (timeout / 4) period. Sending a heartbeat sooner than
// really needed is safer to ensure that the receiver will
- // receive in time the heartbeat. Sending the heartbeat if
+ // receive the heartbeat in time. Sending the heartbeat if
// there was no activity in the last (timeout / 2) period
// isn't enough since monitor() is called only every (timeout
// / 2) period.
//
// Note that this doesn't imply that we are sending 4
// heartbeats per timeout period because the monitor() method
- // is sill only called every (timeout / 2) period.
+ // is still only called every (timeout / 2) period.
//
if(acm.heartbeat == ACMHeartbeat.HeartbeatAlways ||
(acm.heartbeat != ACMHeartbeat.HeartbeatOff && _writeStream.isEmpty() &&
@@ -304,7 +306,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
{
if(acm.heartbeat != ACMHeartbeat.HeartbeatOnInvocation || _dispatchCount > 0)
{
- heartbeat();
+ sendHeartbeatNow();
}
}
@@ -480,6 +482,107 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
@Override
+ public void heartbeat()
+ {
+ ObjectPrx.waitForResponseForCompletion(heartbeatAsync());
+ }
+
+ private class HeartbeatAsync extends com.zeroc.IceInternal.OutgoingAsyncBaseI<Void>
+ {
+ public HeartbeatAsync(Communicator communicator, com.zeroc.IceInternal.Instance instance)
+ {
+ super(communicator, instance, "heartbeat");
+ }
+
+ @Override
+ public Connection getConnection()
+ {
+ return ConnectionI.this;
+ }
+
+ @Override
+ protected void markSent()
+ {
+ super.markSent();
+
+ assert((_state & StateOK) != 0);
+ complete(null);
+ }
+
+ @Override
+ protected void markCompleted()
+ {
+ if(_exception != null)
+ {
+ completeExceptionally(_exception);
+ }
+ super.markCompleted();
+ }
+
+ public void invoke()
+ {
+ try
+ {
+ _os.writeBlob(Protocol.magic);
+ ProtocolVersion.ice_write(_os, Protocol.currentProtocol);
+ EncodingVersion.ice_write(_os, Protocol.currentProtocolEncoding);
+ _os.writeByte(Protocol.validateConnectionMsg);
+ _os.writeByte((byte) 0);
+ _os.writeInt(Protocol.headerSize); // Message size.
+
+ int status;
+ if(_instance.queueRequests())
+ {
+ status = _instance.getQueueExecutor().execute(new Callable<Integer>()
+ {
+ @Override
+ public Integer call()
+ throws com.zeroc.IceInternal.RetryException
+ {
+ return ConnectionI.this.sendAsyncRequest(HeartbeatAsync.this, false, false, 0);
+ }
+ });
+ }
+ else
+ {
+ status = ConnectionI.this.sendAsyncRequest(this, false, false, 0);
+ }
+
+ if((status & AsyncStatus.Sent) > 0)
+ {
+ _sentSynchronously = true;
+ if((status & AsyncStatus.InvokeSentCallback) > 0)
+ {
+ invokeSent();
+ }
+ }
+ }
+ catch(com.zeroc.IceInternal.RetryException ex)
+ {
+ if(completed(ex.get()))
+ {
+ invokeCompletedAsync();
+ }
+ }
+ catch(com.zeroc.Ice.Exception ex)
+ {
+ if(completed(ex))
+ {
+ invokeCompletedAsync();
+ }
+ }
+ }
+ }
+
+ @Override
+ public java.util.concurrent.CompletableFuture<Void> heartbeatAsync()
+ {
+ HeartbeatAsync __f = new HeartbeatAsync(_communicator, _instance);
+ __f.invoke();
+ return __f;
+ }
+
+ @Override
synchronized public void setACM(java.util.OptionalInt timeout, java.util.Optional<ACMClose> close,
java.util.Optional<ACMHeartbeat> heartbeat)
{
@@ -664,8 +767,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
public synchronized void invokeException(int requestId, LocalException ex, int invokeNum, boolean amd)
{
//
- // Fatal exception while invoking a request. Since
- // sendResponse/sendNoResponse isn't
+ // Fatal exception while invoking a request. Since sendResponse/sendNoResponse isn't
// called in case of a fatal exception we decrement _dispatchCount here.
//
@@ -931,7 +1033,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
else
{
- assert (_state <= StateClosingPending);
+ assert(_state <= StateClosingPending);
//
// We parse messages first, if we receive a close
@@ -1107,7 +1209,8 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
//
if(info.invokeNum > 0)
{
- invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager, info.adapter);
+ invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager,
+ info.adapter);
//
// Don't increase dispatchedCount, the dispatch count is
@@ -1264,7 +1367,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
// Trace the cause of unexpected connection closures
//
if(!(_exception instanceof CloseConnectionException ||
- _exception instanceof ForcedCloseConnectionException ||
+ _exception instanceof ConnectionManuallyClosedException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException))
@@ -1614,7 +1717,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
// Don't warn about certain expected exceptions.
//
if(!(_exception instanceof CloseConnectionException ||
- _exception instanceof ForcedCloseConnectionException ||
+ _exception instanceof ConnectionManuallyClosedException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException ||
@@ -1804,7 +1907,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
if(_observer != null && state == StateClosed && _exception != null)
{
if(!(_exception instanceof CloseConnectionException ||
- _exception instanceof ForcedCloseConnectionException ||
+ _exception instanceof ConnectionManuallyClosedException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException ||
@@ -1833,8 +1936,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
private void initiateShutdown()
{
- assert (_state == StateClosing);
- assert (_dispatchCount == 0);
+ assert(_state == StateClosing && _dispatchCount == 0);
if(_shutdownInitiated)
{
@@ -1861,8 +1963,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
setState(StateClosingPending);
//
- // Notify the the transceiver of the graceful connection
- // closure.
+ // Notify the transceiver of the graceful connection closure.
//
int op = _transceiver.closing(true, _exception);
if(op != 0)
@@ -1874,7 +1975,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
}
- private void heartbeat()
+ private void sendHeartbeatNow()
{
assert (_state == StateActive);
@@ -2071,8 +2172,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
else if(_state == StateClosingPending && _writeStream.pos() == 0)
{
- // Message wasn't sent, empty the _writeStream, we're not going to
- // send more data.
+ // Message wasn't sent, empty the _writeStream, we're not going to send more data.
OutgoingMessage message = _sendStreams.getFirst();
_writeStream.swap(message.stream);
return SocketOperation.None;
@@ -2149,9 +2249,8 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
}
//
- // 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 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 && _shutdownInitiated)
{
@@ -2376,8 +2475,7 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
setState(StateClosingPending, new CloseConnectionException());
//
- // Notify the the transceiver of the graceful connection
- // closure.
+ // Notify the transceiver of the graceful connection closure.
//
int op = _transceiver.closing(false, _exception);
if(op != 0)
@@ -2393,9 +2491,8 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
{
if(_state >= StateClosing)
{
- TraceUtil.trace("received request during closing\n"
- + "(ignored by server, client will retry)", info.stream, _logger,
- _traceLevels);
+ TraceUtil.trace("received request during closing\n(ignored by server, client will retry)",
+ info.stream, _logger, _traceLevels);
}
else
{
@@ -2413,9 +2510,8 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler
{
if(_state >= StateClosing)
{
- TraceUtil.trace("received batch request during closing\n"
- + "(ignored by server, client will retry)", info.stream, _logger,
- _traceLevels);
+ TraceUtil.trace("received batch request during closing\n(ignored by server, client will retry)",
+ info.stream, _logger, _traceLevels);
}
else
{
diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/IncomingConnectionFactory.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/IncomingConnectionFactory.java
index 337e56f05f7..98dd813fb66 100644
--- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/IncomingConnectionFactory.java
+++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/IncomingConnectionFactory.java
@@ -137,7 +137,7 @@ public final class IncomingConnectionFactory extends EventHandler implements Con
//
for(ConnectionI c : connections)
{
- c.close(true);
+ c.close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
}
throw e;
}
diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/OutgoingConnectionFactory.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/OutgoingConnectionFactory.java
index 3e62623a17f..9bd778ecfb4 100644
--- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/OutgoingConnectionFactory.java
+++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/OutgoingConnectionFactory.java
@@ -138,7 +138,7 @@ public final class OutgoingConnectionFactory
{
for(ConnectionI c : l)
{
- c.close(true);
+ c.close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
}
}
throw new com.zeroc.Ice.OperationInterruptedException();
diff --git a/java/test/src/main/java/test/Ice/acm/AllTests.java b/java/test/src/main/java/test/Ice/acm/AllTests.java
index 8208748c069..97820ba81e6 100644
--- a/java/test/src/main/java/test/Ice/acm/AllTests.java
+++ b/java/test/src/main/java/test/Ice/acm/AllTests.java
@@ -568,6 +568,31 @@ public class AllTests
}
}
+ static class HeartbeatManualTest extends TestCase
+ {
+ public HeartbeatManualTest(Application app, RemoteCommunicatorPrx com, java.io.PrintWriter out)
+ {
+ super(app, "manual heartbeats", com, out);
+ //
+ // Disable heartbeats.
+ //
+ setClientACM(10, -1, 0);
+ setServerACM(10, -1, 0);
+ }
+
+ public void runTestCase(RemoteObjectAdapterPrx adapter, TestIntfPrx proxy)
+ {
+ proxy.startHeartbeatCount();
+ com.zeroc.Ice.Connection con = proxy.ice_getConnection();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ con.heartbeat();
+ proxy.waitForHeartbeatCount(5);
+ }
+ }
+
static class SetACMTest extends TestCase
{
public SetACMTest(Application app, RemoteCommunicatorPrx com, java.io.PrintWriter out)
@@ -600,7 +625,8 @@ public class AllTests
test(acm.heartbeat == ACMHeartbeat.HeartbeatAlways);
// Make sure the client sends few heartbeats to the server
- proxy.waitForHeartbeat(2);
+ proxy.startHeartbeatCount();
+ proxy.waitForHeartbeatCount(2);
}
}
@@ -627,6 +653,7 @@ public class AllTests
tests.add(new HeartbeatOnIdleTest(app, com, out));
tests.add(new HeartbeatAlwaysTest(app, com, out));
+ tests.add(new HeartbeatManualTest(app, com, out));
tests.add(new SetACMTest(app, com, out));
for(TestCase test : tests)
diff --git a/java/test/src/main/java/test/Ice/acm/Test.ice b/java/test/src/main/java/test/Ice/acm/Test.ice
index 117192a2df8..7f71427c741 100644
--- a/java/test/src/main/java/test/Ice/acm/Test.ice
+++ b/java/test/src/main/java/test/Ice/acm/Test.ice
@@ -18,7 +18,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/java/test/src/main/java/test/Ice/acm/TestI.java b/java/test/src/main/java/test/Ice/acm/TestI.java
index 7b9c369e4f3..43e6fb38d0d 100644
--- a/java/test/src/main/java/test/Ice/acm/TestI.java
+++ b/java/test/src/main/java/test/Ice/acm/TestI.java
@@ -50,35 +50,29 @@ public class TestI implements TestIntf
}
}
- static class Counter
- {
- Counter(int v)
- {
- value = v;
- }
-
- int value;
- }
-
- public void waitForHeartbeat(int count, com.zeroc.Ice.Current current)
+ public void startHeartbeatCount(com.zeroc.Ice.Current current)
{
- final Counter c = new Counter(count);
+ _counter = new Counter();
current.con.setHeartbeatCallback(con ->
{
- synchronized(c)
+ synchronized(_counter)
{
- --c.value;
- c.notifyAll();
+ ++_counter.value;
+ _counter.notifyAll();
}
});
+ }
- synchronized(c)
+ public void waitForHeartbeatCount(int count, com.zeroc.Ice.Current current)
+ {
+ assert(_counter != null);
+ synchronized(_counter)
{
- while(c.value > 0)
+ while(_counter.value < count)
{
try
{
- c.wait();
+ _counter.wait();
}
catch(InterruptedException ex)
{
@@ -86,4 +80,11 @@ public class TestI implements TestIntf
}
}
}
+
+ static class Counter
+ {
+ int value;
+ }
+
+ private Counter _counter;
}
diff --git a/java/test/src/main/java/test/Ice/ami/AMI.java b/java/test/src/main/java/test/Ice/ami/AMI.java
index 85a543317a4..0c6b125897a 100644
--- a/java/test/src/main/java/test/Ice/ami/AMI.java
+++ b/java/test/src/main/java/test/Ice/ami/AMI.java
@@ -17,6 +17,7 @@ import java.util.concurrent.CompletionException;
import com.zeroc.Ice.InvocationFuture;
import com.zeroc.Ice.Util;
+import test.Ice.ami.Test.CloseMode;
import test.Ice.ami.Test.TestIntfPrx;
import test.Ice.ami.Test.TestIntfControllerPrx;
import test.Ice.ami.Test.TestIntfException;
@@ -347,7 +348,7 @@ public class AMI
test(p.opBatchCount() == 0);
TestIntfPrx b1 = p.ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
CompletableFuture<Void> r = b1.ice_flushBatchRequestsAsync();
Util.getInvocationFuture(r).whenSent((sentSynchronously, ex) ->
{
@@ -395,7 +396,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity())).
ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
CompletableFuture<Void> r = b1.ice_getConnection().flushBatchRequestsAsync();
Util.getInvocationFuture(r).whenSent((sentSynchronously, ex) ->
{
@@ -444,7 +445,7 @@ public class AMI
TestIntfPrx b1 = TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity())).
ice_batchOneway();
b1.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
CompletableFuture<Void> r = communicator.flushBatchRequestsAsync();
Util.getInvocationFuture(r).whenSent((sentSynchronously, ex) ->
{
@@ -500,7 +501,7 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
+ b1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
CompletableFuture<Void> r = communicator.flushBatchRequestsAsync();
Util.getInvocationFuture(r).whenSent((sentSynchronously, ex) ->
{
@@ -528,8 +529,8 @@ public class AMI
b2.ice_getConnection(); // Ensure connection is established.
b1.opBatch();
b2.opBatch();
- b1.ice_getConnection().close(false);
- b2.ice_getConnection().close(false);
+ b1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
CompletableFuture<Void> r = communicator.flushBatchRequestsAsync();
Util.getInvocationFuture(r).whenSent((sentSynchronously, ex) ->
{
@@ -756,9 +757,35 @@ public class AMI
if(p.ice_getConnection() != null)
{
- out.print("testing close connection with sending queue... ");
+ out.print("testing graceful close connection with wait... ");
out.flush();
{
+ //
+ // Local case: begin several requests, close the connection gracefully, and make sure it waits
+ // for the requests to complete.
+ //
+ java.util.List<CompletableFuture<Void>> results = new java.util.ArrayList<>();
+ for(int i = 0; i < 3; ++i)
+ {
+ results.add(p.sleepAsync(50));
+ }
+ p.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
+ for(CompletableFuture<Void> f : results)
+ {
+ try
+ {
+ f.join();
+ }
+ catch(Throwable ex)
+ {
+ test(false);
+ }
+ }
+ }
+ {
+ //
+ // Remote case.
+ //
byte[] seq = new byte[1024 * 10];
//
@@ -777,7 +804,7 @@ public class AMI
{
results.add(Util.getInvocationFuture(p.opWithPayloadAsync(seq)));
}
- if(!Util.getInvocationFuture(p.closeAsync(false)).isSent())
+ if(!Util.getInvocationFuture(p.closeAsync(CloseMode.CloseGracefullyAndWait)).isSent())
{
for(int i = 0; i < maxQueue; i++)
{
@@ -803,6 +830,98 @@ public class AMI
}
}
out.println("ok");
+
+ out.print("testing graceful close connection without wait... ");
+ out.flush();
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection gracefully on the client side
+ // without waiting for the pending invocation to complete. There will be no retry and we expect the
+ // invocation to fail with ConnectionManuallyClosedException.
+ //
+ // This test requires two threads in the server's thread pool: one will block in sleep() and the other
+ // will process the CloseConnection message.
+ //
+ p.ice_ping();
+ com.zeroc.Ice.Connection con = p.ice_getConnection();
+ CompletableFuture<Void> f = p.sleepAsync(100);
+ con.close(com.zeroc.Ice.ConnectionClose.CloseGracefully);
+ try
+ {
+ f.join();
+ test(false);
+ }
+ catch(CompletionException ex)
+ {
+ test(ex.getCause() instanceof com.zeroc.Ice.ConnectionManuallyClosedException);
+ test(((com.zeroc.Ice.ConnectionManuallyClosedException)ex.getCause()).graceful);
+ }
+ catch(Throwable ex)
+ {
+ test(false);
+ }
+
+ //
+ // Remote case: the server closes the connection gracefully. Our call to TestIntf::close()
+ // completes successfully and then the connection should be closed immediately afterward,
+ // despite the fact that there's a pending call to sleep(). The call to sleep() should be
+ // automatically retried and complete successfully.
+ //
+ p.ice_ping();
+ con = p.ice_getConnection();
+ Callback cb = new Callback();
+ con.setCloseCallback(c -> cb.called());
+ f = p.sleepAsync(100);
+ p.close(CloseMode.CloseGracefully);
+ cb.check();
+ f.join();
+ p.ice_ping();
+ test(p.ice_getConnection() != con);
+ }
+ out.println("ok");
+
+ out.print("testing forceful close connection... ");
+ out.flush();
+ {
+ //
+ // Local case: start a lengthy operation and then close the connection forcefully on the client side.
+ // There will be no retry and we expect the invocation to fail with ConnectionManuallyClosedException.
+ //
+ p.ice_ping();
+ com.zeroc.Ice.Connection con = p.ice_getConnection();
+ CompletableFuture<Void> f = p.sleepAsync(100);
+ con.close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
+ try
+ {
+ f.join();
+ test(false);
+ }
+ catch(CompletionException ex)
+ {
+ test(ex.getCause() instanceof com.zeroc.Ice.ConnectionManuallyClosedException);
+ test(!((com.zeroc.Ice.ConnectionManuallyClosedException)ex.getCause()).graceful);
+ }
+ catch(Throwable ex)
+ {
+ test(false);
+ }
+
+ //
+ // Remote case: the server closes the connection forcefully. This causes the request to fail
+ // with a ConnectionLostException. Since the close() operation is not idempotent, the client
+ // will not retry.
+ //
+ try
+ {
+ p.close(CloseMode.CloseForcefully);
+ test(false);
+ }
+ catch(com.zeroc.Ice.ConnectionLostException ex)
+ {
+ // Expected.
+ }
+ }
+ out.println("ok");
}
}
}
diff --git a/java/test/src/main/java/test/Ice/ami/Client.java b/java/test/src/main/java/test/Ice/ami/Client.java
index f0992f5bece..50fb9fdddee 100644
--- a/java/test/src/main/java/test/Ice/ami/Client.java
+++ b/java/test/src/main/java/test/Ice/ami/Client.java
@@ -24,6 +24,7 @@ public class Client extends test.Util.Application
GetInitDataResult r = super.getInitData(args);
r.initData.properties.setProperty("Ice.Package.Test", "test.Ice.ami");
r.initData.properties.setProperty("Ice.Warn.AMICallback", "0");
+ r.initData.properties.setProperty("Ice.Warn.Connections", "0");
//
// Limit the send buffer size, this test relies on the socket
diff --git a/java/test/src/main/java/test/Ice/ami/Server.java b/java/test/src/main/java/test/Ice/ami/Server.java
index 90a41a5eaf5..c244441f2e5 100644
--- a/java/test/src/main/java/test/Ice/ami/Server.java
+++ b/java/test/src/main/java/test/Ice/ami/Server.java
@@ -33,6 +33,12 @@ public class Server extends test.Util.Application
r.initData.properties.setProperty("TestAdapter.Endpoints", getTestEndpoint(r.initData.properties, 0));
r.initData.properties.setProperty("ControllerAdapter.Endpoints", getTestEndpoint(r.initData.properties, 1));
r.initData.properties.setProperty("ControllerAdapter.ThreadPool.Size", "1");
+
+ //
+ // This test kills connections, so we don't want warnings.
+ //
+ r.initData.properties.setProperty("Ice.Warn.Connections", "0");
+
//
// Limit the recv buffer size, this test relies on the socket
// send() blocking after sending a given amount of data.
diff --git a/java/test/src/main/java/test/Ice/ami/Test.ice b/java/test/src/main/java/test/Ice/ami/Test.ice
index 82b3fe6d383..bbc4d908d65 100644
--- a/java/test/src/main/java/test/Ice/ami/Test.ice
+++ b/java/test/src/main/java/test/Ice/ami/Test.ice
@@ -20,6 +20,13 @@ exception TestIntfException
{
};
+enum CloseMode
+{
+ CloseForcefully,
+ CloseGracefully,
+ CloseGracefullyAndWait
+};
+
interface TestIntf
{
void op();
@@ -30,7 +37,8 @@ interface TestIntf
void opBatch();
int opBatchCount();
bool waitForBatch(int count);
- void close(bool force);
+ void close(CloseMode mode);
+ void sleep(int ms);
void shutdown();
bool supportsFunctionalTests();
diff --git a/java/test/src/main/java/test/Ice/ami/TestI.java b/java/test/src/main/java/test/Ice/ami/TestI.java
index 0153f138dd0..ee7f4eef6f9 100644
--- a/java/test/src/main/java/test/Ice/ami/TestI.java
+++ b/java/test/src/main/java/test/Ice/ami/TestI.java
@@ -9,6 +9,7 @@
package test.Ice.ami;
+import test.Ice.ami.Test.CloseMode;
import test.Ice.ami.Test.TestIntf;
import test.Ice.ami.Test.TestIntfException;
@@ -123,9 +124,22 @@ public class TestI implements TestIntf
@Override
public void
- close(boolean force, com.zeroc.Ice.Current current)
+ close(CloseMode mode, com.zeroc.Ice.Current current)
{
- current.con.close(force);
+ current.con.close(com.zeroc.Ice.ConnectionClose.valueOf(mode.value()));
+ }
+
+ @Override
+ public void
+ sleep(int ms, com.zeroc.Ice.Current current)
+ {
+ try
+ {
+ Thread.sleep(ms);
+ }
+ catch(InterruptedException ex)
+ {
+ }
}
@Override
diff --git a/java/test/src/main/java/test/Ice/background/AllTests.java b/java/test/src/main/java/test/Ice/background/AllTests.java
index ca465338b01..b174df088ed 100644
--- a/java/test/src/main/java/test/Ice/background/AllTests.java
+++ b/java/test/src/main/java/test/Ice/background/AllTests.java
@@ -295,7 +295,7 @@ public class AllTests
configuration.buffered(true);
backgroundController.buffered(true);
background.opAsync();
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
background.opAsync();
java.util.List<CompletableFuture<Void>> results = new java.util.ArrayList<>();
@@ -334,7 +334,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
for(int i = 0; i < 4; ++i)
{
@@ -396,7 +396,7 @@ public class AllTests
}
configuration.connectException(new com.zeroc.Ice.SocketException());
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -439,7 +439,7 @@ public class AllTests
ex.printStackTrace();
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
for(int i = 0; i < 4; i++)
{
@@ -498,7 +498,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -510,7 +510,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -554,7 +554,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -589,7 +589,7 @@ public class AllTests
}
configuration.initializeException(new com.zeroc.Ice.SocketException());
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -615,7 +615,7 @@ public class AllTests
}
configuration.initializeSocketStatus(com.zeroc.IceInternal.SocketOperation.Write);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
try
{
@@ -630,7 +630,7 @@ public class AllTests
configuration.initializeSocketStatus(com.zeroc.IceInternal.SocketOperation.None);
ctl.initializeException(true);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -658,7 +658,7 @@ public class AllTests
try
{
ctl.initializeSocketStatus(com.zeroc.IceInternal.SocketOperation.Write);
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
background.op();
ctl.initializeSocketStatus(com.zeroc.IceInternal.SocketOperation.None);
}
@@ -693,7 +693,7 @@ public class AllTests
{
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -741,7 +741,7 @@ public class AllTests
ex.printStackTrace();
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -815,7 +815,7 @@ public class AllTests
ex.printStackTrace();
test(false);
}
- background.ice_getConnection().close(false);
+ background.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
@@ -845,7 +845,7 @@ public class AllTests
backgroundBatchOneway.op();
ctl.resumeAdapter();
backgroundBatchOneway.ice_flushBatchRequests();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
//
// Send bigger requests to test with auto-flushing.
@@ -857,7 +857,7 @@ public class AllTests
backgroundBatchOneway.opWithPayload(seq);
ctl.resumeAdapter();
backgroundBatchOneway.ice_flushBatchRequests();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
//
// Then try the same thing with async flush.
@@ -869,7 +869,7 @@ public class AllTests
backgroundBatchOneway.op();
ctl.resumeAdapter();
backgroundBatchOneway.ice_flushBatchRequestsAsync();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
ctl.holdAdapter();
backgroundBatchOneway.opWithPayload(seq);
@@ -879,7 +879,7 @@ public class AllTests
ctl.resumeAdapter();
r = backgroundBatchOneway.ice_flushBatchRequestsAsync();
r.join();
- backgroundBatchOneway.ice_getConnection().close(false);
+ backgroundBatchOneway.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
private static void readWriteTests(Configuration configuration, BackgroundPrx background,
@@ -1274,7 +1274,7 @@ public class AllTests
}
background.ice_ping();
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
try
{
Thread.sleep(10);
@@ -1283,7 +1283,7 @@ public class AllTests
{
}
- background.ice_getCachedConnection().close(true);
+ background.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
}
thread1._destroy();
diff --git a/java/test/src/main/java/test/Ice/binding/AllTests.java b/java/test/src/main/java/test/Ice/binding/AllTests.java
index e464b71d8af..068307d7c96 100644
--- a/java/test/src/main/java/test/Ice/binding/AllTests.java
+++ b/java/test/src/main/java/test/Ice/binding/AllTests.java
@@ -16,6 +16,7 @@ import test.Ice.binding.Test.RemoteObjectAdapterPrx;
import test.Ice.binding.Test.TestIntfPrx;
import test.Util.Application;
+import com.zeroc.Ice.ConnectionClose;
import com.zeroc.Ice.Endpoint;
import com.zeroc.Ice.EndpointSelectionType;
@@ -132,7 +133,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(test1.getAdapterName());
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -154,7 +155,7 @@ public class AllTests
for(RemoteObjectAdapterPrx p : adapters)
{
- p.getTestIntf().ice_getConnection().close(false);
+ p.getTestIntf().ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -179,7 +180,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(test1.getAdapterName());
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -287,7 +288,7 @@ public class AllTests
{
try
{
- a.getTestIntf().ice_getConnection().close(false);
+ a.getTestIntf().ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
catch(com.zeroc.Ice.LocalException ex)
{
@@ -328,7 +329,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(getAdapterNameWithAMI(test1));
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -350,7 +351,7 @@ public class AllTests
for(RemoteObjectAdapterPrx p : adapters)
{
- p.getTestIntf().ice_getConnection().close(false);
+ p.getTestIntf().ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -375,7 +376,7 @@ public class AllTests
test(test2.ice_getConnection() == test3.ice_getConnection());
names.remove(getAdapterNameWithAMI(test1));
- test1.ice_getConnection().close(false);
+ test1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
//
@@ -408,7 +409,7 @@ public class AllTests
while(!names.isEmpty())
{
names.remove(test.getAdapterName());
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
test = test.ice_endpointSelection(EndpointSelectionType.Random);
@@ -420,7 +421,7 @@ public class AllTests
while(!names.isEmpty())
{
names.remove(test.getAdapterName());
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
deactivate(rcom, adapters);
@@ -484,11 +485,11 @@ public class AllTests
adapters.add(rcom.createObjectAdapter("Adapter36", endpoints[2].toString()));
for(i = 0; i < nRetry && test.getAdapterName().equals("Adapter36"); i++);
test(i == nRetry);
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
adapters.add(rcom.createObjectAdapter("Adapter35", endpoints[1].toString()));
for(i = 0; i < nRetry && test.getAdapterName().equals("Adapter35"); i++);
test(i == nRetry);
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
adapters.add(rcom.createObjectAdapter("Adapter34", endpoints[0].toString()));
for(i = 0; i < nRetry && test.getAdapterName().equals("Adapter34"); i++);
test(i == nRetry);
@@ -785,7 +786,7 @@ public class AllTests
for(i = 0; i < 5; i++)
{
test(test.getAdapterName().equals("Adapter82"));
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
TestIntfPrx testSecure = test.ice_secure(true);
@@ -801,7 +802,7 @@ public class AllTests
for(i = 0; i < 5; i++)
{
test(test.getAdapterName().equals("Adapter81"));
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
rcom.createObjectAdapter("Adapter83", (test.ice_getEndpoints()[1]).toString()); // Reactive tcp OA.
@@ -809,7 +810,7 @@ public class AllTests
for(i = 0; i < 5; i++)
{
test(test.getAdapterName().equals("Adapter83"));
- test.ice_getConnection().close(false);
+ test.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
rcom.deactivateObjectAdapter(adapters.get(0));
@@ -1004,7 +1005,7 @@ public class AllTests
// Close the connection now to free a FD (it could be done after the sleep but
// there could be race condiutation since the connection might not be closed
// immediately due to threading).
- test.ice_connectionId("0").ice_getConnection().close(false);
+ test.ice_connectionId("0").ice_getConnection().close(ConnectionClose.CloseGracefullyAndWait);
//
// The server closed the acceptor, wait one second and retry after freeing a FD.
diff --git a/java/test/src/main/java/test/Ice/hold/AllTests.java b/java/test/src/main/java/test/Ice/hold/AllTests.java
index 31db0c827da..36974038091 100644
--- a/java/test/src/main/java/test/Ice/hold/AllTests.java
+++ b/java/test/src/main/java/test/Ice/hold/AllTests.java
@@ -205,7 +205,7 @@ public class AllTests
{
f.waitForSent();
holdSerialized.ice_ping(); // Ensure everything's dispatched
- holdSerialized.ice_getConnection().close(false);
+ holdSerialized.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
r.join();
diff --git a/java/test/src/main/java/test/Ice/interrupt/AllTests.java b/java/test/src/main/java/test/Ice/interrupt/AllTests.java
index 233a595197d..62a1d6034e1 100644
--- a/java/test/src/main/java/test/Ice/interrupt/AllTests.java
+++ b/java/test/src/main/java/test/Ice/interrupt/AllTests.java
@@ -336,7 +336,7 @@ public class AllTests
{
final Thread mainThread = Thread.currentThread();
- p.ice_getConnection().close(false);
+ p.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
CompletableFuture<com.zeroc.Ice.Connection> r = p.ice_getConnectionAsync();
mainThread.interrupt();
@@ -358,7 +358,7 @@ public class AllTests
// Expected
}
- p.ice_getConnection().close(false);
+ p.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
final Callback cb = new Callback();
mainThread.interrupt();
diff --git a/java/test/src/main/java/test/Ice/location/AllTests.java b/java/test/src/main/java/test/Ice/location/AllTests.java
index 60bcd506d8f..2b6fb9aa789 100644
--- a/java/test/src/main/java/test/Ice/location/AllTests.java
+++ b/java/test/src/main/java/test/Ice/location/AllTests.java
@@ -592,7 +592,7 @@ public class AllTests
out.flush();
hello = HelloPrx.checkedCast(communicator.stringToProxy("hello"));
obj.migrateHello();
- hello.ice_getConnection().close(false);
+ hello.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
hello.sayHello();
obj.migrateHello();
hello.sayHello();
diff --git a/java/test/src/main/java/test/Ice/metrics/AMDMetricsI.java b/java/test/src/main/java/test/Ice/metrics/AMDMetricsI.java
index 916af54b6ae..c329b58a85b 100644
--- a/java/test/src/main/java/test/Ice/metrics/AMDMetricsI.java
+++ b/java/test/src/main/java/test/Ice/metrics/AMDMetricsI.java
@@ -29,7 +29,7 @@ public final class AMDMetricsI implements Metrics
@Override
public CompletionStage<Void> failAsync(com.zeroc.Ice.Current current)
{
- current.con.close(true);
+ current.con.close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
return CompletableFuture.completedFuture((Void)null);
}
diff --git a/java/test/src/main/java/test/Ice/metrics/AllTests.java b/java/test/src/main/java/test/Ice/metrics/AllTests.java
index 051af2be8a2..5f7ada1e51f 100644
--- a/java/test/src/main/java/test/Ice/metrics/AllTests.java
+++ b/java/test/src/main/java/test/Ice/metrics/AllTests.java
@@ -260,7 +260,7 @@ public class AllTests
{
if(proxy.ice_getCachedConnection() != null)
{
- proxy.ice_getCachedConnection().close(false);
+ proxy.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
try
@@ -273,7 +273,7 @@ public class AllTests
if(proxy.ice_getCachedConnection() != null)
{
- proxy.ice_getCachedConnection().close(false);
+ proxy.ice_getCachedConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
}
@@ -478,8 +478,9 @@ public class AllTests
if(!collocated)
{
- metrics.ice_getConnection().close(false);
- metrics.ice_connectionId("Con1").ice_getConnection().close(false);
+ metrics.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
+ metrics.ice_connectionId("Con1").ice_getConnection().close(
+ com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -582,7 +583,7 @@ public class AllTests
map = toMap(serverMetrics.getMetricsView("View").returnValue.get("Connection"));
test(map.get("holding").current == 1);
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
map = toMap(clientMetrics.getMetricsView("View").returnValue.get("Connection"));
test(map.get("closing").current == 1);
@@ -597,7 +598,7 @@ public class AllTests
props.put("IceMX.Metrics.View.Map.Connection.GroupBy", "none");
updateProps(clientProps, serverProps, props, "Connection");
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
metrics.ice_timeout(500).ice_ping();
controller.hold();
@@ -659,7 +660,7 @@ public class AllTests
testAttribute(clientMetrics, clientProps, "Connection", "mcastHost", "", out);
testAttribute(clientMetrics, clientProps, "Connection", "mcastPort", "", out);
- m.ice_getConnection().close(false);
+ m.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
waitForCurrent(clientMetrics, "View", "Connection", 0);
waitForCurrent(serverMetrics, "View", "Connection", 0);
@@ -680,7 +681,7 @@ public class AllTests
clientMetrics.getMetricsView("View").returnValue.get("ConnectionEstablishment")[0];
test(m1.current == 0 && m1.total == 1 && m1.id.equals(hostAndPort));
- metrics.ice_getConnection().close(false);
+ metrics.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
controller.hold();
try
{
@@ -737,7 +738,7 @@ public class AllTests
try
{
prx.ice_ping();
- prx.ice_getConnection().close(false);
+ prx.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
}
catch(com.zeroc.Ice.LocalException ex)
{
diff --git a/java/test/src/main/java/test/Ice/metrics/MetricsI.java b/java/test/src/main/java/test/Ice/metrics/MetricsI.java
index 8a8342431b1..7c9e1a527e5 100644
--- a/java/test/src/main/java/test/Ice/metrics/MetricsI.java
+++ b/java/test/src/main/java/test/Ice/metrics/MetricsI.java
@@ -25,7 +25,7 @@ public final class MetricsI implements Metrics
@Override
public void fail(com.zeroc.Ice.Current current)
{
- current.con.close(true);
+ current.con.close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
}
@Override
diff --git a/java/test/src/main/java/test/Ice/operations/BatchOneways.java b/java/test/src/main/java/test/Ice/operations/BatchOneways.java
index d47af8c6bc2..30a5672e80d 100644
--- a/java/test/src/main/java/test/Ice/operations/BatchOneways.java
+++ b/java/test/src/main/java/test/Ice/operations/BatchOneways.java
@@ -109,7 +109,7 @@ class BatchOneways
batch1.ice_ping();
batch2.ice_ping();
batch1.ice_flushBatchRequests();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.ice_ping();
batch2.ice_ping();
@@ -117,7 +117,7 @@ class BatchOneways
batch2.ice_getConnection();
batch1.ice_ping();
- batch1.ice_getConnection().close(false);
+ batch1.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
batch1.ice_ping();
batch2.ice_ping();
}
diff --git a/java/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java b/java/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java
index c759e3dc6e9..1093418d3b1 100644
--- a/java/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java
+++ b/java/test/src/main/java/test/Ice/operations/BatchOnewaysAMI.java
@@ -100,7 +100,7 @@ class BatchOnewaysAMI
batch.ice_pingAsync();
batch2.ice_pingAsync();
batch.ice_flushBatchRequestsAsync().join();
- batch.ice_getConnection().close(false);
+ batch.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
batch.ice_pingAsync();
batch2.ice_pingAsync();
@@ -108,7 +108,7 @@ class BatchOnewaysAMI
batch2.ice_getConnection();
batch.ice_pingAsync();
- batch.ice_getConnection().close(false);
+ batch.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
test(!batch.ice_pingAsync().isCompletedExceptionally());
test(!batch2.ice_pingAsync().isCompletedExceptionally());
}
diff --git a/java/test/src/main/java/test/Ice/retry/RetryI.java b/java/test/src/main/java/test/Ice/retry/RetryI.java
index 827365878ee..23d09ead06e 100644
--- a/java/test/src/main/java/test/Ice/retry/RetryI.java
+++ b/java/test/src/main/java/test/Ice/retry/RetryI.java
@@ -24,7 +24,7 @@ public final class RetryI implements Retry
{
if(current.con != null)
{
- current.con.close(true);
+ current.con.close(com.zeroc.Ice.ConnectionClose.CloseForcefully);
}
else
{
diff --git a/java/test/src/main/java/test/Ice/timeout/AllTests.java b/java/test/src/main/java/test/Ice/timeout/AllTests.java
index 0ba6091a244..1b8172762f9 100644
--- a/java/test/src/main/java/test/Ice/timeout/AllTests.java
+++ b/java/test/src/main/java/test/Ice/timeout/AllTests.java
@@ -262,7 +262,7 @@ public class AllTests
TimeoutPrx to = TimeoutPrx.checkedCast(obj.ice_timeout(100 * mult));
com.zeroc.Ice.Connection connection = to.ice_getConnection();
timeout.holdAdapter(500);
- connection.close(false);
+ connection.close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
connection.getInfo(); // getInfo() doesn't throw in the closing state.
@@ -283,9 +283,10 @@ public class AllTests
connection.getInfo();
test(false);
}
- catch(com.zeroc.Ice.CloseConnectionException ex)
+ catch(com.zeroc.Ice.ConnectionManuallyClosedException ex)
{
// Expected.
+ test(ex.graceful);
}
timeout.op(); // Ensure adapter is active.
}
diff --git a/java/test/src/main/java/test/Ice/udp/AllTests.java b/java/test/src/main/java/test/Ice/udp/AllTests.java
index 302f9849122..8fddc3c1388 100644
--- a/java/test/src/main/java/test/Ice/udp/AllTests.java
+++ b/java/test/src/main/java/test/Ice/udp/AllTests.java
@@ -124,7 +124,7 @@ public class AllTests
{
test(seq.length > 16384);
}
- obj.ice_getConnection().close(false);
+ obj.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
communicator.getProperties().setProperty("Ice.UDP.SndSize", "64000");
seq = new byte[50000];
try
diff --git a/java/test/src/main/java/test/IceSSL/configuration/AllTests.java b/java/test/src/main/java/test/IceSSL/configuration/AllTests.java
index 6c21b6c5e08..1ece2537cac 100644
--- a/java/test/src/main/java/test/IceSSL/configuration/AllTests.java
+++ b/java/test/src/main/java/test/IceSSL/configuration/AllTests.java
@@ -889,7 +889,7 @@ public class AllTests
//
verifier.reset();
verifier.returnValue(false);
- server.ice_getConnection().close(false);
+ server.ice_getConnection().close(com.zeroc.Ice.ConnectionClose.CloseGracefullyAndWait);
try
{
server.ice_ping();
diff --git a/js/src/Ice/ConnectionI.js b/js/src/Ice/ConnectionI.js
index c56e764a01e..4541098ae78 100644
--- a/js/src/Ice/ConnectionI.js
+++ b/js/src/Ice/ConnectionI.js
@@ -35,6 +35,7 @@ const InputStream = Ice.InputStream;
const OutputStream = Ice.OutputStream;
const BatchRequestQueue = Ice.BatchRequestQueue;
const ConnectionFlushBatch = Ice.ConnectionFlushBatch;
+const HeartbeatAsync = Ice.HeartbeatAsync;
const Debug = Ice.Debug;
const ExUtil = Ice.ExUtil;
const HashMap = Ice.HashMap;
@@ -49,6 +50,7 @@ const EncodingVersion = Ice.EncodingVersion;
const ACM = Ice.ACM;
const ACMClose = Ice.ACMClose;
const ACMHeartbeat = Ice.ACMHeartbeat;
+const ConnectionClose = Ice.ConnectionClose;
const StateNotInitialized = 0;
const StateNotValidated = 1;
@@ -218,23 +220,26 @@ class ConnectionI
}
}
- close(force)
+ close(mode)
{
const r = new AsyncResultBase(this._communicator, "close", this, null, null);
- if(force)
+ if(mode == ConnectionClose.CloseForcefully)
{
- this.setState(StateClosed, new Ice.ForcedCloseConnectionException());
+ this.setState(StateClosed, new Ice.ConnectionManuallyClosedException(false));
+ r.resolve();
+ }
+ else if(mode == ConnectionClose.CloseGracefully)
+ {
+ this.setState(StateClosing, new Ice.ConnectionManuallyClosedException(true));
r.resolve();
}
else
{
+ Debug.assert(mode == ConnectionClose.CloseGracefullyAndWait);
+
//
- // If we do a graceful shutdown, then we wait until all
- // outstanding requests have been completed. Otherwise,
- // the CloseConnectionException will cause all outstanding
- // requests to be retried, regardless of whether the
- // server has processed them or not.
+ // Wait until all outstanding requests have been completed.
//
this._closePromises.push(r);
this.checkClose();
@@ -246,13 +251,13 @@ class ConnectionI
checkClose()
{
//
- // If close(false) has been called, then we need to check if all
+ // If close(CloseGracefullyAndWait) has been called, then we need to check if all
// requests have completed and we can transition to StateClosing.
// We also complete outstanding promises.
//
if(this._asyncRequests.size === 0 && this._closePromises.length > 0)
{
- this.setState(StateClosing, new Ice.CloseConnectionException());
+ this.setState(StateClosing, new Ice.ConnectionManuallyClosedException(true));
this._closePromises.forEach(p => p.resolve());
this._closePromises = [];
}
@@ -310,13 +315,13 @@ class ConnectionI
// We send a heartbeat if there was no activity in the last
// (timeout / 4) period. Sending a heartbeat sooner than
// really needed is safer to ensure that the receiver will
- // receive in time the heartbeat. Sending the heartbeat if
+ // receive the heartbeat in time. Sending the heartbeat if
// there was no activity in the last (timeout / 2) period
// isn't enough since monitor() is called only every (timeout
// / 2) period.
//
// Note that this doesn't imply that we are sending 4 heartbeats
- // per timeout period because the monitor() method is sill only
+ // per timeout period because the monitor() method is still only
// called every (timeout / 2) period.
//
if(acm.heartbeat == Ice.ACMHeartbeat.HeartbeatAlways ||
@@ -325,7 +330,7 @@ class ConnectionI
{
if(acm.heartbeat != Ice.ACMHeartbeat.HeartbeatOnInvocation || this._dispatchCount > 0)
{
- this.heartbeat(); // Send heartbeat if idle in the last timeout / 2 period.
+ this.sendHeartbeatNow(); // Send heartbeat if idle in the last timeout / 2 period.
}
}
@@ -488,6 +493,13 @@ class ConnectionI
this._heartbeatCallback = callback;
}
+ heartbeat()
+ {
+ const result = new HeartbeatAsync(this, this._communicator);
+ result.invoke();
+ return result;
+ }
+
setACM(timeout, close, heartbeat)
{
if(this._monitor === null || this._state >= StateClosed)
@@ -1008,7 +1020,7 @@ class ConnectionI
// Trace the cause of unexpected connection closures
//
if(!(this._exception instanceof Ice.CloseConnectionException ||
- this._exception instanceof Ice.ForcedCloseConnectionException ||
+ this._exception instanceof Ice.ConnectionManuallyClosedException ||
this._exception instanceof Ice.ConnectionTimeoutException ||
this._exception instanceof Ice.CommunicatorDestroyedException ||
this._exception instanceof Ice.ObjectAdapterDeactivatedException))
@@ -1211,7 +1223,7 @@ class ConnectionI
// Don't warn about certain expected exceptions.
//
if(!(this._exception instanceof Ice.CloseConnectionException ||
- this._exception instanceof Ice.ForcedCloseConnectionException ||
+ this._exception instanceof Ice.ConnectionManuallyClosedException ||
this._exception instanceof Ice.ConnectionTimeoutException ||
this._exception instanceof Ice.CommunicatorDestroyedException ||
this._exception instanceof Ice.ObjectAdapterDeactivatedException ||
@@ -1416,15 +1428,13 @@ class ConnectionI
initiateShutdown()
{
- Debug.assert(this._state === StateClosing);
- Debug.assert(this._dispatchCount === 0);
+ Debug.assert(this._state === StateClosing && this._dispatchCount === 0);
Debug.assert(!this._shutdownInitiated);
if(!this._endpoint.datagram())
{
//
- // Before we shut down, we send a close connection
- // message.
+ // Before we shut down, we send a close connection message.
//
const os = new OutputStream(this._instance, Protocol.currentProtocolEncoding);
os.writeBlob(Protocol.magic);
@@ -1454,7 +1464,7 @@ class ConnectionI
}
}
- heartbeat()
+ sendHeartbeatNow()
{
Debug.assert(this._state === StateActive);
diff --git a/js/src/Ice/OutgoingAsync.js b/js/src/Ice/OutgoingAsync.js
index 62f14f0f64a..bce53bc29a9 100644
--- a/js/src/Ice/OutgoingAsync.js
+++ b/js/src/Ice/OutgoingAsync.js
@@ -578,9 +578,42 @@ class ConnectionFlushBatch extends OutgoingAsyncBase
}
}
+class HeartbeatAsync extends OutgoingAsyncBase
+{
+ constructor(con, communicator)
+ {
+ super(communicator, "heartbeat", con, null, null);
+ }
+
+ invoke()
+ {
+ try
+ {
+ this._os.writeBlob(Protocol.magic);
+ Protocol.currentProtocol._write(this._os);
+ Protocol.currentProtocolEncoding._write(this._os);
+ this._os.writeByte(Protocol.validateConnectionMsg);
+ this._os.writeByte(0);
+ this._os.writeInt(Protocol.headerSize); // Message size.
+
+ let status = this._connection.sendAsyncRequest(this, false, false, 0);
+
+ if((status & AsyncStatus.Sent) > 0)
+ {
+ this._sentSynchronously = true;
+ }
+ }
+ catch(ex)
+ {
+ this.completedEx(ex);
+ }
+ }
+}
+
Ice.OutgoingAsync = OutgoingAsync;
Ice.ProxyFlushBatch = ProxyFlushBatch;
Ice.ProxyGetConnection = ProxyGetConnection;
Ice.ConnectionFlushBatch = ConnectionFlushBatch;
+Ice.HeartbeatAsync = HeartbeatAsync;
module.exports.Ice = Ice;
diff --git a/js/test/Ice/acm/Client.js b/js/test/Ice/acm/Client.js
index e18f45ec0ac..58f8efdf313 100644
--- a/js/test/Ice/acm/Client.js
+++ b/js/test/Ice/acm/Client.js
@@ -391,6 +391,37 @@
}
}
+ class HeartbeatManualTest extends TestCase
+ {
+ constructor(com, out)
+ {
+ super("manual heartbeats", com, out);
+ //
+ // Disable heartbeats.
+ //
+ this.setClientACM(10, -1, 0);
+ this.setServerACM(10, -1, 0);
+ }
+
+ runTestCase(adapter, proxy)
+ {
+ function sendHeartbeats(con)
+ {
+ var p = Promise.resolve();
+ for(var i = 0; i < 5; ++i)
+ {
+ p = p.then(con.heartbeat());
+ }
+ return p;
+ }
+
+ return proxy.startHeartbeatCount().then(
+ () => proxy.ice_getConnection()).then(
+ con => sendHeartbeats(con)).then(
+ () => proxy.waitForHeartbeatCount(5));
+ }
+ }
+
class SetACMTest extends TestCase
{
constructor(com, out)
@@ -421,7 +452,7 @@
test(acm.close === Ice.ACMClose.CloseOnInvocationAndIdle);
test(acm.heartbeat === Ice.ACMHeartbeat.HeartbeatAlways);
- return proxy.waitForHeartbeat(2);
+ return proxy.startHeartbeatCount().then(() => proxy.waitForHeartbeatCount(2));
}
}
@@ -459,6 +490,7 @@
tests.push(new HeartbeatOnIdleTest(com, out));
tests.push(new HeartbeatAlwaysTest(com, out));
+ tests.push(new HeartbeatManualTest(com, out));
tests.push(new SetACMTest(com, out));
}
diff --git a/js/test/Ice/acm/Test.ice b/js/test/Ice/acm/Test.ice
index 117192a2df8..7f71427c741 100644
--- a/js/test/Ice/acm/Test.ice
+++ b/js/test/Ice/acm/Test.ice
@@ -18,7 +18,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/js/test/Ice/ami/Client.js b/js/test/Ice/ami/Client.js
index 07b9ae03db4..39b5aeae704 100644
--- a/js/test/Ice/ami/Client.js
+++ b/js/test/Ice/ami/Client.js
@@ -111,7 +111,7 @@
//
test(batchCount === 0);
b1.opBatch();
- b1.ice_getCachedConnection().close(false);
+ b1.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
return communicator.flushBatchRequests().then(() => p.opBatchCount());
}
).then(batchCount =>
@@ -156,7 +156,7 @@
b2 = prx;
b1.opBatch();
b2.opBatch();
- b1.ice_getCachedConnection().close(false);
+ b1.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
return communicator.flushBatchRequests();
}
).then(() => p.waitForBatch(1)
@@ -181,8 +181,8 @@
b2 = prx;
b1.opBatch();
b2.opBatch();
- b1.ice_getCachedConnection().close(false);
- b2.ice_getCachedConnection().close(false);
+ b1.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
+ b2.ice_getCachedConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait);
return communicator.flushBatchRequests();
}
).then(() => p.opBatchCount());
diff --git a/js/test/Ice/binding/Client.js b/js/test/Ice/binding/Client.js
index ecba375108b..0e59e8256c7 100644
--- a/js/test/Ice/binding/Client.js
+++ b/js/test/Ice/binding/Client.js
@@ -260,7 +260,7 @@
).then(
function(conn)
{
- return conn.close(false);
+ return conn.close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
).then(
function()
@@ -339,7 +339,7 @@
}).then(
function(c)
{
- return c.close(false);
+ return c.close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
);
}));
@@ -422,7 +422,7 @@
).then(
function(conn)
{
- return conn.close(false);
+ return conn.close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
).then(
function()
@@ -585,7 +585,7 @@
}).then(
function(c)
{
- return c.close(false);
+ return c.close(Ice.ConnectionClose.CloseGracefullyAndWait);
},
function(ex)
{
@@ -651,7 +651,7 @@
}
return prx.ice_getConnection();
}
- ).then(conn => conn.close(false)
+ ).then(conn => conn.close(Ice.ConnectionClose.CloseGracefullyAndWait)
).then(() => names.length > 0 ? f1() : prx);
};
@@ -678,7 +678,7 @@
).then(
function(conn)
{
- return conn.close(false);
+ return conn.close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
).then(
function()
diff --git a/js/test/Ice/hold/Client.js b/js/test/Ice/hold/Client.js
index 51e3bf70c12..03f31d4c353 100644
--- a/js/test/Ice/hold/Client.js
+++ b/js/test/Ice/hold/Client.js
@@ -230,7 +230,7 @@
).then(
function(con)
{
- return con.close(false);
+ return con.close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
);
}
diff --git a/js/test/Ice/location/Client.js b/js/test/Ice/location/Client.js
index 5890344ed19..62168831822 100644
--- a/js/test/Ice/location/Client.js
+++ b/js/test/Ice/location/Client.js
@@ -1110,7 +1110,7 @@
).then(
function(con)
{
- return con.close(false);
+ return con.close(Ice.ConnectionClose.CloseGracefullyAndWait);
}
).then(
function()
diff --git a/js/test/Ice/operations/BatchOneways.js b/js/test/Ice/operations/BatchOneways.js
index d3a66fa51c1..b6660b97781 100644
--- a/js/test/Ice/operations/BatchOneways.js
+++ b/js/test/Ice/operations/BatchOneways.js
@@ -82,7 +82,7 @@
).then(count => batch.ice_flushBatchRequests()
).then(() => prx.opByteSOnewayCallCount()
).then(() => batch.ice_getConnection()
- ).then(con => bidir ? undefined : con.close(false)
+ ).then(con => bidir ? undefined : con.close(Ice.ConnectionClose.CloseGracefullyAndWait)
).then(() => Promise.all([batch.ice_ping(), batch2.ice_ping()])
).then(() =>
{
diff --git a/js/test/Ice/timeout/Client.js b/js/test/Ice/timeout/Client.js
index 62790d63f54..9f2872dfecb 100644
--- a/js/test/Ice/timeout/Client.js
+++ b/js/test/Ice/timeout/Client.js
@@ -142,7 +142,7 @@
connection = con;
return timeout.holdAdapter(1500);
}
- ).then(() => connection.close(false)
+ ).then(() => connection.close(Ice.ConnectionClose.CloseGracefullyAndWait)
).then(() =>
{
try
@@ -163,7 +163,7 @@
}
catch(ex)
{
- test(ex instanceof Ice.CloseConnectionException); // Expected
+ test(ex instanceof Ice.ConnectionManuallyClosedException); // Expected
}
return timeout.op();
}
diff --git a/objective-c/src/Ice/ConnectionI.mm b/objective-c/src/Ice/ConnectionI.mm
index 3b0d642b934..6de819d2433 100644
--- a/objective-c/src/Ice/ConnectionI.mm
+++ b/objective-c/src/Ice/ConnectionI.mm
@@ -266,12 +266,12 @@ private:
}
@implementation ICEConnection
--(void) close:(BOOL)force
+-(void) close:(ICEConnectionClose)mode
{
NSException* nsex = nil;
try
{
- CONNECTION->close(force);
+ CONNECTION->close((Ice::ConnectionClose)mode);
}
catch(const std::exception& ex)
{
@@ -379,6 +379,52 @@ private:
{
CONNECTION->setHeartbeatCallback(new HeartbeatCallbackI(self, callback));
}
+-(void) heartbeat
+{
+ NSException* nsex = nil;
+ try
+ {
+ CONNECTION->heartbeat();
+ }
+ catch(const std::exception& ex)
+ {
+ nsex = toObjCException(ex);
+ }
+ if(nsex != nil)
+ {
+ @throw nsex;
+ }
+}
+-(id<ICEAsyncResult>) begin_heartbeat
+{
+ return beginCppCall(^(Ice::AsyncResultPtr& result)
+ {
+ result = CONNECTION->begin_heartbeat();
+ });
+}
+-(id<ICEAsyncResult>) begin_heartbeat:(void(^)(ICEException*))exception
+{
+ return [self begin_heartbeat:exception sent:nil];
+}
+-(id<ICEAsyncResult>) begin_heartbeat:(void(^)(ICEException*))exception sent:(void(^)(BOOL))sent
+{
+ return beginCppCall(^(Ice::AsyncResultPtr& result, const Ice::CallbackPtr& cb)
+ {
+ result = CONNECTION->begin_heartbeat(cb);
+ },
+ ^(const Ice::AsyncResultPtr& result)
+ {
+ CONNECTION->end_heartbeat(result);
+ },
+ exception, sent);
+}
+-(void) end_heartbeat:(id<ICEAsyncResult>)result
+{
+ endCppCall(^(const Ice::AsyncResultPtr& r)
+ {
+ CONNECTION->end_heartbeat(r);
+ }, result);
+}
-(void) setACM:(id)timeout close:(id)close heartbeat:(id)heartbeat
{
IceUtil::Optional<int> to;
diff --git a/objective-c/test/Ice/acm/ACMTest.ice b/objective-c/test/Ice/acm/ACMTest.ice
index d723f023cf1..a8f40466fc5 100644
--- a/objective-c/test/Ice/acm/ACMTest.ice
+++ b/objective-c/test/Ice/acm/ACMTest.ice
@@ -18,7 +18,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/objective-c/test/Ice/acm/AllTests.m b/objective-c/test/Ice/acm/AllTests.m
index 09a49e3788a..8d53772a1ed 100644
--- a/objective-c/test/Ice/acm/AllTests.m
+++ b/objective-c/test/Ice/acm/AllTests.m
@@ -749,6 +749,40 @@
}
@end
+@interface HeartbeatManualTest : TestCase
++(id) testCase:(id<TestACMRemoteCommunicatorPrx>)com;
++(NSString*) getName;
+-(void) runTestCase:(id<TestACMRemoteObjectAdapterPrx>)adapter proxy:(id<TestACMTestIntfPrx>)proxy;
+@end
+
+@implementation HeartbeatManualTest
++(id) testCase:(id<TestACMRemoteCommunicatorPrx>)com
+{
+ id tc = [super testCase:com];
+ //
+ // Disable heartbeats.
+ //
+ [tc setClientACM:10 close:-1 heartbeat:0];
+ [tc setServerACM:10 close:-1 heartbeat:0];
+ return tc;
+}
++(NSString*) getName
+{
+ return @"manual heartbeats";
+}
+-(void) runTestCase:(id<TestACMRemoteObjectAdapterPrx>)adapter proxy:(id<TestACMTestIntfPrx>)proxy
+{
+ [proxy startHeartbeatCount];
+ id con = [proxy ice_getConnection];
+ [con heartbeat];
+ [con heartbeat];
+ [con heartbeat];
+ [con heartbeat];
+ [con heartbeat];
+ [proxy waitForHeartbeatCount:5];
+}
+@end
+
@interface SetACMTest : TestCase
+(id) testCase:(id<TestACMRemoteCommunicatorPrx>)com;
+(NSString*) getName;
@@ -788,7 +822,8 @@
test(acm.close == ICECloseOnInvocationAndIdle);
test(acm.heartbeat == ICEHeartbeatAlways);
- [proxy waitForHeartbeat:2];
+ [proxy startHeartbeatCount];
+ [proxy waitForHeartbeatCount:2];
}
@end
@@ -812,6 +847,7 @@ acmAllTests(id<ICECommunicator> communicator)
[tests addObject:[HeartbeatOnIdleTest testCase:com]];
[tests addObject:[HeartbeatAlwaysTest testCase:com]];
+ [tests addObject:[HeartbeatManualTest testCase:com]];
[tests addObject:[SetACMTest testCase:com]];
for(int i = 0; i < tests.count; ++i)
diff --git a/objective-c/test/Ice/acm/TestI.h b/objective-c/test/Ice/acm/TestI.h
index a4c24b41898..cacae9ee902 100644
--- a/objective-c/test/Ice/acm/TestI.h
+++ b/objective-c/test/Ice/acm/TestI.h
@@ -23,8 +23,17 @@
-(id) initWithAdapter:(id<ICEObjectAdapter>)adapter;
@end
+@interface ConnectionCallbackI : NSObject
+{
+ NSCondition* _cond;
+ int _count;
+}
+-(void) waitForCount:(int)count;
+@end
+
@interface TestACMTestIntfI : TestACMTestIntf<TestACMTestIntf>
{
NSCondition* _cond;
+ ConnectionCallbackI* _callback;
}
@end
diff --git a/objective-c/test/Ice/acm/TestI.m b/objective-c/test/Ice/acm/TestI.m
index 2e24f62d711..8fe726732f9 100644
--- a/objective-c/test/Ice/acm/TestI.m
+++ b/objective-c/test/Ice/acm/TestI.m
@@ -17,7 +17,6 @@
-(void) waitForCount:(int)count;
@end
-
@implementation ACMConnectionCallbackI
-(id) init
{
@@ -33,17 +32,16 @@
-(void) heartbeat:(id<ICEConnection>)c
{
[_cond lock];
- --_count;
+ ++_count;
[_cond signal];
[_cond unlock];
}
-(void) waitForCount:(int)count
{
[_cond lock];
- _count = count;
@try
{
- while(_count > 0)
+ while(_count < count)
{
[_cond wait];
}
@@ -192,15 +190,18 @@
[_cond signal];
[_cond unlock];
}
--(void) waitForHeartbeat:(int)count current:(ICECurrent*)current
+-(void) startHeartbeatCount:(ICECurrent*)current
{
- ACMConnectionCallbackI* callback = [ACMConnectionCallbackI new];
+ _callback = [ACMConnectionCallbackI new];
[current.con setHeartbeatCallback:^(id<ICEConnection> c)
{
- [callback heartbeat:c];
+ [_callback heartbeat:c];
}];
- [callback waitForCount:count];
- ICE_RELEASE(callback);
+}
+-(void) waitForHeartbeatCount:(int)count current:(ICECurrent*)current
+{
+ [_callback waitForCount:count];
+ ICE_RELEASE(_callback);
}
@end
diff --git a/php/src/php5/Connection.cpp b/php/src/php5/Connection.cpp
index 1d85343ed37..68827e63243 100644
--- a/php/src/php5/Connection.cpp
+++ b/php/src/php5/Connection.cpp
@@ -78,15 +78,22 @@ ZEND_METHOD(Ice_Connection, close)
Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis() TSRMLS_CC);
assert(_this);
- zend_bool b;
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("b"), &b TSRMLS_CC) != SUCCESS)
+ zval* mode;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("z"), &mode TSRMLS_CC) != SUCCESS)
{
RETURN_NULL();
}
+ if(Z_TYPE_P(mode) != IS_LONG)
+ {
+ invalidArgument("value for 'mode' argument must be an enumerator of ConnectionClose" TSRMLS_CC);
+ RETURN_NULL();
+ }
+ Ice::ConnectionClose cc = static_cast<Ice::ConnectionClose>(Z_LVAL_P(mode));
+
try
{
- _this->close(b ? true : false);
+ _this->close(cc);
}
catch(const IceUtil::Exception& ex)
{
@@ -140,6 +147,27 @@ ZEND_METHOD(Ice_Connection, flushBatchRequests)
}
}
+ZEND_METHOD(Ice_Connection, heartbeat)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis() TSRMLS_CC);
+ assert(_this);
+
+ try
+ {
+ _this->heartbeat();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ RETURN_NULL();
+ }
+}
+
ZEND_METHOD(Ice_Connection, setACM)
{
Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis() TSRMLS_CC);
@@ -411,6 +439,7 @@ static zend_function_entry _connectionClassMethods[] =
ZEND_ME(Ice_Connection, close, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, getEndpoint, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, flushBatchRequests, ICE_NULLPTR, ZEND_ACC_PUBLIC)
+ ZEND_ME(Ice_Connection, heartbeat, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, setACM, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, getACM, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, type, ICE_NULLPTR, ZEND_ACC_PUBLIC)
diff --git a/php/src/php5/Util.cpp b/php/src/php5/Util.cpp
index 24374f91049..1f3ea98fb8e 100644
--- a/php/src/php5/Util.cpp
+++ b/php/src/php5/Util.cpp
@@ -618,6 +618,10 @@ convertLocalException(const Ice::LocalException& ex, zval* zex TSRMLS_DC)
{
setStringMember(zex, "reason", e.reason TSRMLS_CC);
}
+ catch(const Ice::ConnectionManuallyClosedException& e)
+ {
+ add_property_bool(zex, "graceful", e.graceful ? 1 : 0);
+ }
catch(const Ice::LocalException&)
{
//
diff --git a/php/src/php7/Connection.cpp b/php/src/php7/Connection.cpp
index 2d598fc7da9..57c0b197767 100644
--- a/php/src/php7/Connection.cpp
+++ b/php/src/php7/Connection.cpp
@@ -78,15 +78,22 @@ ZEND_METHOD(Ice_Connection, close)
Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis());
assert(_this);
- zend_bool b;
- if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("b"), &b) != SUCCESS)
+ zval* mode;
+ if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("z"), &mode) != SUCCESS)
{
RETURN_NULL();
}
+ if(Z_TYPE_P(mode) != IS_LONG)
+ {
+ invalidArgument("value for 'mode' argument must be an enumerator of ConnectionClose");
+ RETURN_NULL();
+ }
+ Ice::ConnectionClose cc = static_cast<Ice::ConnectionClose>(Z_LVAL_P(mode));
+
try
{
- _this->close(b ? true : false);
+ _this->close(cc);
}
catch(const IceUtil::Exception& ex)
{
@@ -140,6 +147,27 @@ ZEND_METHOD(Ice_Connection, flushBatchRequests)
}
}
+ZEND_METHOD(Ice_Connection, heartbeat)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis());
+ assert(_this);
+
+ try
+ {
+ _this->heartbeat();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex);
+ RETURN_NULL();
+ }
+}
+
ZEND_METHOD(Ice_Connection, setACM)
{
Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis());
@@ -331,6 +359,27 @@ ZEND_METHOD(Ice_Connection, setBufferSize)
}
}
+ZEND_METHOD(Ice_Connection, throwException)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ Ice::ConnectionPtr _this = Wrapper<Ice::ConnectionPtr>::value(getThis());
+ assert(_this);
+
+ try
+ {
+ _this->throwException();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex);
+ RETURN_NULL();
+ }
+}
+
#ifdef _WIN32
extern "C"
#endif
@@ -406,6 +455,7 @@ static zend_function_entry _connectionClassMethods[] =
ZEND_ME(Ice_Connection, close, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, getEndpoint, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, flushBatchRequests, ICE_NULLPTR, ZEND_ACC_PUBLIC)
+ ZEND_ME(Ice_Connection, heartbeat, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, setACM, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, getACM, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, type, ICE_NULLPTR, ZEND_ACC_PUBLIC)
@@ -413,6 +463,7 @@ static zend_function_entry _connectionClassMethods[] =
ZEND_ME(Ice_Connection, toString, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, getInfo, ICE_NULLPTR, ZEND_ACC_PUBLIC)
ZEND_ME(Ice_Connection, setBufferSize, ICE_NULLPTR, ZEND_ACC_PUBLIC)
+ ZEND_ME(Ice_Connection, throwException, ICE_NULLPTR, ZEND_ACC_PUBLIC)
{0, 0, 0}
};
diff --git a/php/src/php7/Util.cpp b/php/src/php7/Util.cpp
index 0399c940cb1..bb38b45066a 100644
--- a/php/src/php7/Util.cpp
+++ b/php/src/php7/Util.cpp
@@ -565,6 +565,10 @@ convertLocalException(const Ice::LocalException& ex, zval* zex)
{
setStringMember(zex, "reason", e.reason);
}
+ catch(const Ice::ConnectionManuallyClosedException& e)
+ {
+ add_property_bool(zex, "graceful", e.graceful ? 1 : 0);
+ }
catch(const Ice::LocalException&)
{
//
diff --git a/php/test/Ice/acm/Client.php b/php/test/Ice/acm/Client.php
index 387cf2b1d4e..b1b3a0bbd84 100644
--- a/php/test/Ice/acm/Client.php
+++ b/php/test/Ice/acm/Client.php
@@ -30,16 +30,13 @@ function test($b)
}
}
-function allTests($communicator)
+function testSetACM($communicator, $com)
{
global $NS;
echo "testing setACM/getACM... ";
flush();
- $ref = "communicator:default -p 12010";
- $com = $communicator->stringToProxy($ref)->ice_uncheckedCast("::Test::RemoteCommunicator");
-
$adapter = $com->createObjectAdapter(-1, -1, -1);
$initData = $NS ? eval("return new Ice\\InitializationData;") : new Ice_InitializationData;
@@ -83,21 +80,60 @@ function allTests($communicator)
test($acm->close == $CloseOnInvocationAndIdle);
test($acm->heartbeat == $HeartbeatAlways);
- $proxy->waitForHeartbeat(2);
+ $proxy->startHeartbeatCount();
+ $proxy->waitForHeartbeatCount(2);
$adapter->deactivate();
$testCommunicator->destroy();
echo "ok\n";
+}
+
+function testHeartbeatManual($communicator, $com)
+{
+ global $NS;
- echo "shutting down... ";
+ echo "testing manual heartbeats... ";
flush();
- $com->shutdown();
+
+ $adapter = $com->createObjectAdapter(10, -1, 0);
+
+ $initData = $NS ? eval("return new Ice\\InitializationData;") : new Ice_InitializationData;
+ $initData->properties = $communicator->getProperties()->clone();
+ $initData->properties->setProperty("Ice.ACM.Timeout", "10");
+ $initData->properties->setProperty("Ice.ACM.Client.Timeout", "10");
+ $initData->properties->setProperty("Ice.ACM.Client.Close", "0");
+ $initData->properties->setProperty("Ice.ACM.Client.Heartbeat", "0");
+ $testCommunicator = $NS ? eval("return Ice\\initialize(\$initData);") : Ice_initialize($initData);
+ $proxy = $testCommunicator->stringToProxy($adapter->getTestIntf()->ice_toString())->ice_uncheckedCast(
+ "::Test::TestIntf");
+ $con = $proxy->ice_getConnection();
+
+ $proxy->startHeartbeatCount();
+ $con->heartbeat();
+ $con->heartbeat();
+ $con->heartbeat();
+ $con->heartbeat();
+ $con->heartbeat();
+ $proxy->waitForHeartbeatCount(5);
+
+ $adapter->deactivate();
+ $testCommunicator->destroy();
echo "ok\n";
}
+function allTests($communicator)
+{
+ $ref = "communicator:default -p 12010";
+ $com = $communicator->stringToProxy($ref)->ice_uncheckedCast("::Test::RemoteCommunicator");
+
+ testSetACM($communicator, $com);
+ testHeartbeatManual($communicator, $com);
+
+ $com->shutdown();
+}
+
$communicator = $NS ? eval("return Ice\\initialize(\$argv);") :
eval("return Ice_initialize(\$argv);");
-
allTests($communicator);
$communicator->destroy();
diff --git a/php/test/Ice/acm/Test.ice b/php/test/Ice/acm/Test.ice
index 5ab98180dd3..d78abd6eb0f 100644
--- a/php/test/Ice/acm/Test.ice
+++ b/php/test/Ice/acm/Test.ice
@@ -17,7 +17,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/php/test/Ice/binding/Client.php b/php/test/Ice/binding/Client.php
index 378981ce357..291188e5e2c 100644
--- a/php/test/Ice/binding/Client.php
+++ b/php/test/Ice/binding/Client.php
@@ -61,6 +61,9 @@ function allTests($communicator)
$random = $NS ? constant("Ice\\EndpointSelectionType::Random") : constant("Ice_EndpointSelectionType::Random");
$ordered = $NS ? constant("Ice\\EndpointSelectionType::Ordered") : constant("Ice_EndpointSelectionType::Ordered");
+ $closeGracefullyAndWait =
+ $NS ? constant("Ice\\ConnectionClose::CloseGracefullyAndWait") :
+ constant("Ice_ConnectionClose::CloseGracefullyAndWait");
$ref = "communicator:default -p 12010";
$com = $communicator->stringToProxy($ref)->ice_uncheckedCast("::Test::RemoteCommunicator");
@@ -130,7 +133,7 @@ function allTests($communicator)
{
unset($names[$key]);
}
- $test1->ice_getConnection()->close(false);
+ $test1->ice_getConnection()->close($closeGracefullyAndWait);
}
//
@@ -151,7 +154,7 @@ function allTests($communicator)
foreach($adapters as $p)
{
- $p->getTestIntf()->ice_getConnection()->close(false);
+ $p->getTestIntf()->ice_getConnection()->close($closeGracefullyAndWait);
}
}
@@ -179,7 +182,7 @@ function allTests($communicator)
{
unset($names[$key]);
}
- $test1->ice_getConnection()->close(false);
+ $test1->ice_getConnection()->close($closeGracefullyAndWait);
}
//
@@ -213,7 +216,7 @@ function allTests($communicator)
{
unset($names[$key]);
}
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
}
$test = $test->ice_endpointSelection($random)->ice_uncheckedCast("::Test::TestIntf");
@@ -227,7 +230,7 @@ function allTests($communicator)
{
unset($names[$key]);
}
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
}
deactivate($com, $adapters);
@@ -285,11 +288,11 @@ function allTests($communicator)
$adapters[] = $com->createObjectAdapter("Adapter36", $endpoints[2]->toString());
for($i = 0; $i < $nRetry && $test->getAdapterName() == "Adapter36"; $i++);
test($i == $nRetry);
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
$adapters[] = $com->createObjectAdapter("Adapter35", $endpoints[1]->toString());
for($i = 0; $i < $nRetry && $test->getAdapterName() == "Adapter35"; $i++);
test($i == $nRetry);
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
$adapters[] = $com->createObjectAdapter("Adapter34", $endpoints[0]->toString());
for($i = 0; $i < $nRetry && $test->getAdapterName() == "Adapter34"; $i++);
test($i == $nRetry);
@@ -475,7 +478,7 @@ function allTests($communicator)
for($i = 0; $i < 5; $i++)
{
test($test->getAdapterName() == "Adapter82");
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
}
$testSecure = $test->ice_secure(true)->ice_uncheckedCast("::Test::TestIntf");
@@ -491,7 +494,7 @@ function allTests($communicator)
for($i = 0; $i < 5; $i++)
{
test($test->getAdapterName() == "Adapter81");
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
}
$endpts = $test->ice_getEndpoints();
@@ -500,7 +503,7 @@ function allTests($communicator)
for($i = 0; $i < 5; $i++)
{
test($test->getAdapterName() == "Adapter83");
- $test->ice_getConnection()->close(false);
+ $test->ice_getConnection()->close($closeGracefullyAndWait);
}
$com->deactivateObjectAdapter($adapters[0]);
diff --git a/python/modules/IcePy/Connection.cpp b/python/modules/IcePy/Connection.cpp
index ec1e4f8db68..8e9e9286d02 100644
--- a/python/modules/IcePy/Connection.cpp
+++ b/python/modules/IcePy/Connection.cpp
@@ -37,18 +37,18 @@ struct ConnectionObject
Ice::CommunicatorPtr* communicator;
};
-class CloseCallbackI : public Ice::CloseCallback
+class CloseCallbackWrapper : public Ice::CloseCallback
{
public:
- CloseCallbackI(PyObject* cb, PyObject* con) :
+ CloseCallbackWrapper(PyObject* cb, PyObject* con) :
_cb(cb), _con(con)
{
Py_INCREF(cb);
Py_INCREF(con);
}
- virtual ~CloseCallbackI()
+ virtual ~CloseCallbackWrapper()
{
AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
@@ -94,18 +94,18 @@ private:
PyObject* _con;
};
-class HeartbeatCallbackI : public Ice::HeartbeatCallback
+class HeartbeatCallbackWrapper : public Ice::HeartbeatCallback
{
public:
- HeartbeatCallbackI(PyObject* cb, PyObject* con) :
+ HeartbeatCallbackWrapper(PyObject* cb, PyObject* con) :
_cb(cb), _con(con)
{
Py_INCREF(cb);
Py_INCREF(con);
}
- virtual ~HeartbeatCallbackI()
+ virtual ~HeartbeatCallbackWrapper()
{
AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
@@ -151,6 +151,62 @@ private:
PyObject* _con;
};
+class HeartbeatAsyncCallback : public IceUtil::Shared
+{
+public:
+
+ HeartbeatAsyncCallback(PyObject* ex, PyObject* sent, const string& op) :
+ _ex(ex), _sent(sent), _op(op)
+ {
+ assert(_ex);
+ Py_INCREF(_ex);
+ Py_XINCREF(_sent);
+ }
+
+ ~HeartbeatAsyncCallback()
+ {
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+
+ Py_DECREF(_ex);
+ Py_XDECREF(_sent);
+ }
+
+ void exception(const Ice::Exception& ex)
+ {
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+
+ PyObjectHandle exh = convertException(ex);
+ assert(exh.get());
+ PyObjectHandle args = Py_BuildValue(STRCAST("(O)"), exh.get());
+ PyObjectHandle tmp = PyObject_Call(_ex, args.get(), 0);
+ if(PyErr_Occurred())
+ {
+ throwPythonException(); // Callback raised an exception.
+ }
+ }
+
+ void sent(bool sentSynchronously)
+ {
+ if(_sent)
+ {
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+ PyObjectHandle args = Py_BuildValue(STRCAST("(O)"), sentSynchronously ? getTrue() : getFalse());
+ PyObjectHandle tmp = PyObject_Call(_sent, args.get(), 0);
+ if(PyErr_Occurred())
+ {
+ throwPythonException(); // Callback raised an exception.
+ }
+ }
+ }
+
+protected:
+
+ PyObject* _ex;
+ PyObject* _sent;
+ std::string _op;
+};
+typedef IceUtil::Handle<HeartbeatAsyncCallback> HeartbeatAsyncCallbackPtr;
+
}
#ifdef WIN32
@@ -241,17 +297,22 @@ extern "C"
static PyObject*
connectionClose(ConnectionObject* self, PyObject* args)
{
- int force;
- if(!PyArg_ParseTuple(args, STRCAST("i"), &force))
+ PyObject* closeType = lookupType("Ice.ConnectionClose");
+ PyObject* mode;
+ if(!PyArg_ParseTuple(args, STRCAST("O!"), closeType, &mode))
{
return 0;
}
+ PyObjectHandle v = PyObject_GetAttrString(mode, STRCAST("_value"));
+ assert(v.get());
+ Ice::ConnectionClose cc = static_cast<Ice::ConnectionClose>(PyLong_AsLong(v.get()));
+
assert(self->connection);
try
{
AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations.
- (*self->connection)->close(force > 0);
+ (*self->connection)->close(cc);
}
catch(const Ice::Exception& ex)
{
@@ -532,7 +593,7 @@ connectionSetCloseCallback(ConnectionObject* self, PyObject* args)
return 0;
}
- Ice::CloseCallbackPtr wrapper = new CloseCallbackI(cb, reinterpret_cast<PyObject*>(self));
+ Ice::CloseCallbackPtr wrapper = new CloseCallbackWrapper(cb, reinterpret_cast<PyObject*>(self));
try
{
AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations.
@@ -563,7 +624,7 @@ connectionSetHeartbeatCallback(ConnectionObject* self, PyObject* args)
return 0;
}
- Ice::HeartbeatCallbackPtr wrapper = new HeartbeatCallbackI(cb, reinterpret_cast<PyObject*>(self));
+ Ice::HeartbeatCallbackPtr wrapper = new HeartbeatCallbackWrapper(cb, reinterpret_cast<PyObject*>(self));
try
{
AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations.
@@ -583,6 +644,127 @@ connectionSetHeartbeatCallback(ConnectionObject* self, PyObject* args)
extern "C"
#endif
static PyObject*
+connectionHeartbeat(ConnectionObject* self)
+{
+ assert(self->connection);
+ try
+ {
+ AllowThreads allowThreads; // Release Python's global interpreter lock during remote invocations.
+ (*self->connection)->heartbeat();
+ }
+ catch(const Ice::Exception& ex)
+ {
+ setPythonException(ex);
+ return 0;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static PyObject*
+connectionBeginHeartbeat(ConnectionObject* self, PyObject* args, PyObject* kwds)
+{
+ assert(self->connection);
+
+ static char* argNames[] =
+ {
+ const_cast<char*>("_ex"),
+ const_cast<char*>("_sent"),
+ 0
+ };
+ PyObject* ex = Py_None;
+ PyObject* sent = Py_None;
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, STRCAST("|OO"), argNames, &ex, &sent))
+ {
+ return 0;
+ }
+
+ if(ex == Py_None)
+ {
+ ex = 0;
+ }
+ if(sent == Py_None)
+ {
+ sent = 0;
+ }
+
+ if(!ex && sent)
+ {
+ PyErr_Format(PyExc_RuntimeError,
+ STRCAST("exception callback must also be provided when sent callback is used"));
+ return 0;
+ }
+
+ Ice::Callback_Connection_heartbeatPtr cb;
+ if(ex || sent)
+ {
+ HeartbeatAsyncCallbackPtr d = new HeartbeatAsyncCallback(ex, sent, "heartbeat");
+ cb = Ice::newCallback_Connection_heartbeat(d, &HeartbeatAsyncCallback::exception,
+ &HeartbeatAsyncCallback::sent);
+ }
+
+ Ice::AsyncResultPtr result;
+ try
+ {
+ AllowThreads allowThreads; // Release Python's global interpreter lock during remote invocations.
+
+ if(cb)
+ {
+ result = (*self->connection)->begin_heartbeat(cb);
+ }
+ else
+ {
+ result = (*self->connection)->begin_heartbeat();
+ }
+ }
+ catch(const Ice::Exception& ex)
+ {
+ setPythonException(ex);
+ return 0;
+ }
+
+ PyObjectHandle communicator = getCommunicatorWrapper(*self->communicator);
+ return createAsyncResult(result, 0, reinterpret_cast<PyObject*>(self), communicator.get());
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static PyObject*
+connectionEndHeartbeat(ConnectionObject* self, PyObject* args)
+{
+ assert(self->connection);
+
+ PyObject* result;
+ if(!PyArg_ParseTuple(args, STRCAST("O!"), &AsyncResultType, &result))
+ {
+ return 0;
+ }
+
+ Ice::AsyncResultPtr r = getAsyncResult(result);
+ try
+ {
+ AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations.
+ (*self->connection)->end_flushBatchRequests(r);
+ }
+ catch(const Ice::Exception& ex)
+ {
+ setPythonException(ex);
+ return 0;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static PyObject*
connectionSetACM(ConnectionObject* self, PyObject* args)
{
assert(self->connection);
@@ -853,6 +1035,27 @@ connectionSetBufferSize(ConnectionObject* self, PyObject* args)
return Py_None;
}
+#ifdef WIN32
+extern "C"
+#endif
+static PyObject*
+connectionThrowException(ConnectionObject* self)
+{
+ assert(self->connection);
+ try
+ {
+ (*self->connection)->throwException();
+ }
+ catch(const Ice::Exception& ex)
+ {
+ setPythonException(ex);
+ return 0;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
static PyMethodDef ConnectionMethods[] =
{
{ STRCAST("close"), reinterpret_cast<PyCFunction>(connectionClose), METH_VARARGS,
@@ -875,6 +1078,12 @@ static PyMethodDef ConnectionMethods[] =
PyDoc_STR(STRCAST("setCloseCallback(Ice.CloseCallback) -> None")) },
{ STRCAST("setHeartbeatCallback"), reinterpret_cast<PyCFunction>(connectionSetHeartbeatCallback), METH_VARARGS,
PyDoc_STR(STRCAST("setHeartbeatCallback(Ice.HeartbeatCallback) -> None")) },
+ { STRCAST("heartbeat"), reinterpret_cast<PyCFunction>(connectionHeartbeat), METH_NOARGS,
+ PyDoc_STR(STRCAST("heartbeat() -> None")) },
+ { STRCAST("begin_heartbeat"), reinterpret_cast<PyCFunction>(connectionBeginHeartbeat),
+ METH_VARARGS | METH_KEYWORDS, PyDoc_STR(STRCAST("begin_heartbeat([_ex][, _sent]) -> Ice.AsyncResult")) },
+ { STRCAST("end_heartbeat"), reinterpret_cast<PyCFunction>(connectionEndHeartbeat), METH_VARARGS,
+ PyDoc_STR(STRCAST("end_heartbeat(Ice.AsyncResult) -> None")) },
{ STRCAST("setACM"), reinterpret_cast<PyCFunction>(connectionSetACM), METH_VARARGS,
PyDoc_STR(STRCAST("setACM(int, Ice.ACMClose, Ice.ACMHeartbeat) -> None")) },
{ STRCAST("getACM"), reinterpret_cast<PyCFunction>(connectionGetACM), METH_NOARGS,
@@ -891,6 +1100,8 @@ static PyMethodDef ConnectionMethods[] =
PyDoc_STR(STRCAST("getEndpoint() -> Ice.Endpoint")) },
{ STRCAST("setBufferSize"), reinterpret_cast<PyCFunction>(connectionSetBufferSize), METH_VARARGS,
PyDoc_STR(STRCAST("setBufferSize(int, int) -> None")) },
+ { STRCAST("throwException"), reinterpret_cast<PyCFunction>(connectionThrowException), METH_NOARGS,
+ PyDoc_STR(STRCAST("throwException() -> None")) },
{ 0, 0 } /* sentinel */
};
diff --git a/python/modules/IcePy/Util.cpp b/python/modules/IcePy/Util.cpp
index 953bbee84a0..c3b8f18462c 100644
--- a/python/modules/IcePy/Util.cpp
+++ b/python/modules/IcePy/Util.cpp
@@ -857,6 +857,10 @@ convertLocalException(const Ice::LocalException& ex, PyObject* p)
IcePy::PyObjectHandle m = IcePy::createString(e.reason);
PyObject_SetAttrString(p, STRCAST("reason"), m.get());
}
+ catch(const Ice::ConnectionManuallyClosedException& e)
+ {
+ PyObject_SetAttrString(p, STRCAST("graceful"), e.graceful ? IcePy::getTrue() : IcePy::getFalse());
+ }
catch(const Ice::LocalException&)
{
//
diff --git a/python/test/Ice/acm/AllTests.py b/python/test/Ice/acm/AllTests.py
index c10edd1de77..1c7bb57709b 100644
--- a/python/test/Ice/acm/AllTests.py
+++ b/python/test/Ice/acm/AllTests.py
@@ -294,6 +294,25 @@ def allTests(communicator):
with self.m:
test(self._heartbeat >= 3)
+ class HeartbeatManualTest(TestCase):
+ def __init__(self, com):
+ TestCase.__init__(self, "manual heartbeats", com)
+ #
+ # Disable heartbeats.
+ #
+ self.setClientACM(10, -1, 0)
+ self.setServerACM(10, -1, 0)
+
+ def runTestCase(self, adapter, proxy):
+ proxy.startHeartbeatCount()
+ con = proxy.ice_getConnection()
+ con.heartbeat()
+ con.heartbeat()
+ con.heartbeat()
+ con.heartbeat()
+ con.heartbeat()
+ proxy.waitForHeartbeatCount(5)
+
class SetACMTest(TestCase):
def __init__(self, com):
TestCase.__init__(self, "setACM/getACM", com)
@@ -318,7 +337,8 @@ def allTests(communicator):
test(acm.close == Ice.ACMClose.CloseOnInvocationAndIdle)
test(acm.heartbeat == Ice.ACMHeartbeat.HeartbeatAlways)
- proxy.waitForHeartbeat(2)
+ proxy.startHeartbeatCount()
+ proxy.waitForHeartbeatCount(2)
tests.append(InvocationHeartbeatTest(com))
tests.append(InvocationHeartbeatOnHoldTest(com))
@@ -332,6 +352,7 @@ def allTests(communicator):
tests.append(HeartbeatOnIdleTest(com))
tests.append(HeartbeatAlwaysTest(com))
+ tests.append(HeartbeatManualTest(com))
tests.append(SetACMTest(com))
for p in tests:
diff --git a/python/test/Ice/acm/Test.ice b/python/test/Ice/acm/Test.ice
index 5ab98180dd3..d78abd6eb0f 100644
--- a/python/test/Ice/acm/Test.ice
+++ b/python/test/Ice/acm/Test.ice
@@ -17,7 +17,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/python/test/Ice/acm/TestI.py b/python/test/Ice/acm/TestI.py
index 10565ca9540..41f5afe93eb 100644
--- a/python/test/Ice/acm/TestI.py
+++ b/python/test/Ice/acm/TestI.py
@@ -9,6 +9,21 @@
import Ice, Test, threading
+class ConnectionCallbackI():
+ def __init__(self):
+ self.m = threading.Condition()
+ self.count = 0
+
+ def heartbeat(self, con):
+ with self.m:
+ self.count += 1
+ self.m.notifyAll()
+
+ def waitForCount(self, count):
+ with self.m:
+ while self.count < count:
+ self.m.wait()
+
class RemoteCommunicatorI(Test._RemoteCommunicatorDisp):
def createObjectAdapter(self, timeout, close, heartbeat, current=None):
com = current.adapter.getCommunicator()
@@ -68,26 +83,9 @@ class TestIntfI(Test._TestIntfDisp):
with self.m:
self.m.notifyAll()
- def waitForHeartbeat(self, count, current=None):
-
- class ConnectionCallbackI():
-
- def __init__(self):
- self.m = threading.Condition()
- self.count = 0
-
- def heartbeat(self, con):
- with self.m:
- self.count -= 1
- self.m.notifyAll()
-
- def waitForCount(self, count):
- with self.m:
- self.count = count
- while self.count > 0:
- self.m.wait()
-
- callback = ConnectionCallbackI()
- current.con.setHeartbeatCallback(lambda con: callback.heartbeat(con))
- callback.waitForCount(2)
+ def startHeartbeatCount(self, current=None):
+ self.callback = ConnectionCallbackI()
+ current.con.setHeartbeatCallback(lambda con: self.callback.heartbeat(con))
+ def waitForHeartbeatCount(self, count, current=None):
+ self.callback.waitForCount(2)
diff --git a/python/test/Ice/ami/AllTests.py b/python/test/Ice/ami/AllTests.py
index 549915ee12e..71d6237b61a 100644
--- a/python/test/Ice/ami/AllTests.py
+++ b/python/test/Ice/ami/AllTests.py
@@ -769,7 +769,7 @@ def allTests(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = p.ice_batchOneway()
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushCallback()
r = b1.begin_ice_flushBatchRequests(cb.exception, cb.sent)
cb.check()
@@ -783,7 +783,7 @@ def allTests(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = p.ice_batchOneway()
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushCallback(cookie)
r = b1.begin_ice_flushBatchRequests(lambda ex: cb.exceptionWC(ex, cookie), lambda ss: cb.sentWC(ss, cookie))
cb.check()
@@ -830,7 +830,7 @@ def allTests(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = Test.TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway())
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushExCallback()
r = b1.ice_getConnection().begin_flushBatchRequests(cb.exception, cb.sent)
cb.check()
@@ -844,7 +844,7 @@ def allTests(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = Test.TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway())
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushExCallback(cookie)
r = b1.ice_getConnection().begin_flushBatchRequests(lambda ex: cb.exceptionWC(ex, cookie),
lambda ss: cb.sentWC(ss, cookie))
@@ -876,7 +876,7 @@ def allTests(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = Test.TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway())
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushCallback()
r = communicator.begin_flushBatchRequests(cb.exception, cb.sent)
cb.check()
@@ -916,7 +916,7 @@ def allTests(communicator, collocated):
b2.ice_getConnection() # Ensure connection is established.
b1.opBatch()
b2.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushCallback()
r = communicator.begin_flushBatchRequests(cb.exception, cb.sent)
cb.check()
@@ -936,8 +936,8 @@ def allTests(communicator, collocated):
b2.ice_getConnection() # Ensure connection is established.
b1.opBatch()
b2.opBatch()
- b1.ice_getConnection().close(False)
- b2.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FlushCallback()
r = communicator.begin_flushBatchRequests(cb.exception, cb.sent)
cb.check()
@@ -1120,9 +1120,27 @@ def allTests(communicator, collocated):
print("ok")
if p.ice_getConnection():
- sys.stdout.write("testing close connection with sending queue... ")
+ sys.stdout.write("testing graceful close connection with wait... ")
sys.stdout.flush()
+ #
+ # Local case: begin several requests, close the connection gracefully, and make sure it waits
+ # for the requests to complete.
+ #
+ results = []
+ for i in range(0, 3):
+ results.append(p.begin_sleep(50))
+ p.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
+ for r in results:
+ r.waitForCompleted()
+ try:
+ r.throwLocalException()
+ except:
+ test(False)
+
+ #
+ # Remote case.
+ #
if sys.version_info[0] == 2:
b = [chr(random.randint(0, 255)) for x in range(0, 10*1024)]
seq = ''.join(b)
@@ -1143,7 +1161,7 @@ def allTests(communicator, collocated):
results = []
for i in range(0, maxQueue):
results.append(p.begin_opWithPayload(seq))
- if not p.begin_close(False).isSent():
+ if not p.begin_close(Test.CloseMode.CloseGracefullyAndWait).isSent():
for i in range(0, maxQueue):
r = p.begin_opWithPayload(seq)
results.append(r)
@@ -1163,6 +1181,83 @@ def allTests(communicator, collocated):
print("ok")
+ sys.stdout.write("testing graceful close connection without wait... ")
+ sys.stdout.flush()
+
+ #
+ # Local case: start a lengthy operation and then close the connection gracefully on the client side
+ # without waiting for the pending invocation to complete. There will be no retry and we expect the
+ # invocation to fail with ConnectionManuallyClosedException.
+ #
+ # This test requires two threads in the server's thread pool: one will block in sleep() and the other
+ # will process the CloseConnection message.
+ #
+ p.ice_ping()
+ con = p.ice_getConnection()
+ r = p.begin_sleep(1000)
+ con.close(Ice.ConnectionClose.CloseGracefully)
+ r.waitForCompleted()
+ try:
+ r.throwLocalException()
+ test(False)
+ except Ice.ConnectionManuallyClosedException, ex:
+ test(ex.graceful)
+
+ #
+ # Remote case: the server closes the connection gracefully. Our call to TestIntf::close()
+ # completes successfully and then the connection should be closed immediately afterward,
+ # despite the fact that there's a pending call to sleep(). The call to sleep() should be
+ # automatically retried and complete successfully.
+ #
+ p.ice_ping()
+ con = p.ice_getConnection()
+ cb = CallbackBase()
+ con.setCloseCallback(lambda c: cb.called())
+ r = p.begin_sleep(250)
+ p.close(Test.CloseMode.CloseGracefully)
+ cb.check()
+ r.waitForCompleted()
+ try:
+ r.throwLocalException()
+ except:
+ test(false)
+ p.ice_ping()
+ test(p.ice_getConnection() != con)
+
+ print("ok")
+
+ sys.stdout.write("testing forceful close connection... ")
+ sys.stdout.flush()
+
+ #
+ # Local case: start a lengthy operation and then close the connection forcefully on the client side.
+ # There will be no retry and we expect the invocation to fail with ConnectionManuallyClosedException.
+ #
+ p.ice_ping()
+ con = p.ice_getConnection()
+ r = p.begin_sleep(100)
+ con.close(Ice.ConnectionClose.CloseForcefully)
+ r.waitForCompleted()
+ try:
+ r.throwLocalException()
+ test(False)
+ except Ice.ConnectionManuallyClosedException, ex:
+ test(not ex.graceful)
+
+ #
+ # Remote case: the server closes the connection forcefully. This causes the request to fail
+ # with a ConnectionLostException. Since the close() operation is not idempotent, the client
+ # will not retry.
+ #
+ try:
+ p.close(Test.CloseMode.CloseForcefully)
+ test(False)
+ except Ice.ConnectionLostException:
+ # Expected.
+ pass
+
+ print("ok")
+
def allTestsFuture(communicator, collocated):
sref = "test:default -p 12010"
obj = communicator.stringToProxy(sref)
@@ -1404,7 +1499,7 @@ def allTestsFuture(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = p.ice_batchOneway()
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FutureFlushCallback()
f = b1.ice_flushBatchRequestsAsync()
f.add_sent_callback(cb.sent)
@@ -1436,7 +1531,7 @@ def allTestsFuture(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = Test.TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway())
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FutureFlushExCallback()
f = b1.ice_getConnection().flushBatchRequestsAsync()
f.add_done_callback(cb.exception)
@@ -1473,7 +1568,7 @@ def allTestsFuture(communicator, collocated):
test(p.opBatchCount() == 0)
b1 = Test.TestIntfPrx.uncheckedCast(p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway())
b1.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FutureFlushCallback()
f = communicator.flushBatchRequestsAsync()
f.add_sent_callback(cb.sent)
@@ -1517,7 +1612,7 @@ def allTestsFuture(communicator, collocated):
b2.ice_getConnection() # Ensure connection is established.
b1.opBatch()
b2.opBatch()
- b1.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FutureFlushCallback()
f = communicator.flushBatchRequestsAsync()
f.add_sent_callback(cb.sent)
@@ -1539,8 +1634,8 @@ def allTestsFuture(communicator, collocated):
b2.ice_getConnection() # Ensure connection is established.
b1.opBatch()
b2.opBatch()
- b1.ice_getConnection().close(False)
- b2.ice_getConnection().close(False)
+ b1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
+ b2.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
cb = FutureFlushCallback()
f = communicator.flushBatchRequestsAsync()
f.add_sent_callback(cb.sent)
@@ -1723,47 +1818,4 @@ def allTestsFuture(communicator, collocated):
print("ok")
- if p.ice_getConnection():
- sys.stdout.write("testing close connection with sending queue... ")
- sys.stdout.flush()
-
- if sys.version_info[0] == 2:
- b = [chr(random.randint(0, 255)) for x in range(0, 10*1024)]
- seq = ''.join(b)
- else:
- b = [random.randint(0, 255) for x in range(0, 10*1024)]
- seq = bytes(b)
-
- #
- # Send multiple opWithPayload, followed by a close and followed by multiple opWithPaylod.
- # The goal is to make sure that none of the opWithPayload fail even if the server closes
- # the connection gracefully in between.
- #
- maxQueue = 2
- done = False
- while not done and maxQueue < 50:
- done = True
- p.ice_ping()
- results = []
- for i in range(0, maxQueue):
- results.append(p.opWithPayloadAsync(seq))
- if not p.closeAsync(False).is_sent():
- for i in range(0, maxQueue):
- f = p.opWithPayloadAsync(seq)
- results.append(f)
- if f.is_sent():
- done = False
- maxQueue = maxQueue * 2
- break
- else:
- maxQueue = maxQueue * 2
- done = False
- for f in results:
- try:
- f.result()
- except Ice.LocalException:
- test(False)
-
- print("ok")
-
p.shutdown()
diff --git a/python/test/Ice/ami/Client.py b/python/test/Ice/ami/Client.py
index 1966ff4bd6d..6fa2db022ca 100755
--- a/python/test/Ice/ami/Client.py
+++ b/python/test/Ice/ami/Client.py
@@ -33,6 +33,7 @@ try:
initData = Ice.InitializationData()
initData.properties = Ice.createProperties(sys.argv)
initData.properties.setProperty('Ice.Warn.AMICallback', '0')
+ initData.properties.setProperty('Ice.Warn.Connections', '0')
#
# Limit the send buffer size, this test relies on the socket
diff --git a/python/test/Ice/ami/Server.py b/python/test/Ice/ami/Server.py
index 1872276ecb0..a042727fc01 100755
--- a/python/test/Ice/ami/Server.py
+++ b/python/test/Ice/ami/Server.py
@@ -44,13 +44,13 @@ try:
#
# This test kills connections, so we don't want warnings.
#
- initData.properties.setProperty("Ice.Warn.Connections", "0");
+ initData.properties.setProperty("Ice.Warn.Connections", "0")
#
# Limit the recv buffer size, this test relies on the socket
# send() blocking after sending a given amount of data.
#
- initData.properties.setProperty("Ice.TCP.RcvSize", "50000");
+ initData.properties.setProperty("Ice.TCP.RcvSize", "50000")
with Ice.initialize(sys.argv, initData) as communicator:
status = run(sys.argv, communicator)
diff --git a/python/test/Ice/ami/Test.ice b/python/test/Ice/ami/Test.ice
index 4bda44b5c41..9787dd9a1fc 100644
--- a/python/test/Ice/ami/Test.ice
+++ b/python/test/Ice/ami/Test.ice
@@ -19,6 +19,13 @@ exception TestIntfException
{
};
+enum CloseMode
+{
+ CloseForcefully,
+ CloseGracefully,
+ CloseGracefullyAndWait
+};
+
interface TestIntf
{
void op();
@@ -29,7 +36,8 @@ interface TestIntf
void opBatch();
int opBatchCount();
bool waitForBatch(int count);
- void close(bool force);
+ void close(CloseMode mode);
+ void sleep(int ms);
void shutdown();
bool supportsFunctionalTests();
diff --git a/python/test/Ice/ami/TestI.py b/python/test/Ice/ami/TestI.py
index 3770a2c6101..53585189f29 100644
--- a/python/test/Ice/ami/TestI.py
+++ b/python/test/Ice/ami/TestI.py
@@ -7,7 +7,7 @@
#
# **********************************************************************
-import Ice, Test, threading
+import Ice, Test, threading, time
class TestIntfI(Test._TestIntfDisp):
def __init__(self):
@@ -43,8 +43,11 @@ class TestIntfI(Test._TestIntfDisp):
self._batchCount = 0
return result
- def close(self, force, current=None):
- current.con.close(force)
+ def close(self, mode, current=None):
+ current.con.close(Ice.ConnectionClose.valueOf(mode.value))
+
+ def sleep(self, ms, current=None):
+ time.sleep(ms / 1000.0)
def shutdown(self, current=None):
current.adapter.getCommunicator().shutdown()
diff --git a/python/test/Ice/binding/AllTests.py b/python/test/Ice/binding/AllTests.py
index b877fc78ac5..5bf5a02a801 100644
--- a/python/test/Ice/binding/AllTests.py
+++ b/python/test/Ice/binding/AllTests.py
@@ -110,7 +110,7 @@ def allTests(communicator):
name = test1.getAdapterName()
if names.count(name) > 0:
names.remove(name)
- test1.ice_getConnection().close(False)
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
#
# Ensure that the proxy correctly caches the connection (we
@@ -128,7 +128,7 @@ def allTests(communicator):
test(i == nRetry)
for a in adapters:
- a.getTestIntf().ice_getConnection().close(False)
+ a.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
#
# Deactivate an adapter and ensure that we can still
@@ -152,7 +152,7 @@ def allTests(communicator):
name = test1.getAdapterName()
if names.count(name) > 0:
names.remove(name)
- test1.ice_getConnection().close(False)
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
#
# Deactivate an adapter and ensure that we can still
@@ -194,7 +194,7 @@ def allTests(communicator):
name = getAdapterNameWithAMI(test1)
if names.count(name) > 0:
names.remove(name)
- test1.ice_getConnection().close(False)
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
#
# Ensure that the proxy correctly caches the connection (we
@@ -212,7 +212,7 @@ def allTests(communicator):
test(i == nRetry)
for a in adapters:
- a.getTestIntf().ice_getConnection().close(False)
+ a.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
#
# Deactivate an adapter and ensure that we can still
@@ -236,7 +236,7 @@ def allTests(communicator):
name = getAdapterNameWithAMI(test1)
if names.count(name) > 0:
names.remove(name)
- test1.ice_getConnection().close(False)
+ test1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
#
# Deactivate an adapter and ensure that we can still
@@ -266,7 +266,7 @@ def allTests(communicator):
name = t.getAdapterName()
if names.count(name) > 0:
names.remove(name)
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
t = Test.TestIntfPrx.uncheckedCast(t.ice_endpointSelection(Ice.EndpointSelectionType.Random))
test(t.ice_getEndpointSelection() == Ice.EndpointSelectionType.Random)
@@ -278,7 +278,7 @@ def allTests(communicator):
name = t.getAdapterName()
if names.count(name) > 0:
names.remove(name)
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
deactivate(com, adapters)
@@ -337,13 +337,13 @@ def allTests(communicator):
while i < nRetry and t.getAdapterName() == "Adapter36":
i = i + 1
test(i == nRetry)
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
adapters.append(com.createObjectAdapter("Adapter35", endpoints[1].toString()))
i = 0
while i < nRetry and t.getAdapterName() == "Adapter35":
i = i + 1
test(i == nRetry)
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
adapters.append(com.createObjectAdapter("Adapter34", endpoints[0].toString()))
i = 0
while i < nRetry and t.getAdapterName() == "Adapter34":
@@ -618,7 +618,7 @@ def allTests(communicator):
t = createTestIntfPrx(adapters)
for i in range(0, 5):
test(t.getAdapterName() == "Adapter82")
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
testSecure = Test.TestIntfPrx.uncheckedCast(t.ice_secure(True))
test(testSecure.ice_isSecure())
@@ -632,13 +632,13 @@ def allTests(communicator):
for i in range(0, 5):
test(t.getAdapterName() == "Adapter81")
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
com.createObjectAdapter("Adapter83", (t.ice_getEndpoints()[1]).toString()) # Reactive tcp OA.
for i in range(0, 5):
test(t.getAdapterName() == "Adapter83")
- t.ice_getConnection().close(False)
+ t.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
com.deactivateObjectAdapter(adapters[0])
try:
diff --git a/python/test/Ice/location/AllTests.py b/python/test/Ice/location/AllTests.py
index dc0fb5afe5d..205ae91329d 100644
--- a/python/test/Ice/location/AllTests.py
+++ b/python/test/Ice/location/AllTests.py
@@ -22,8 +22,8 @@ def allTests(communicator, ref):
locator = communicator.getDefaultLocator()
test(manager)
- registry = Test.TestLocatorRegistryPrx.checkedCast(locator.getRegistry());
- test(registry);
+ registry = Test.TestLocatorRegistryPrx.checkedCast(locator.getRegistry())
+ test(registry)
sys.stdout.write("testing stringToProxy... ")
sys.stdout.flush()
@@ -36,34 +36,34 @@ def allTests(communicator, ref):
sys.stdout.write("testing ice_locator and ice_getLocator... ")
sys.stdout.flush()
- test(Ice.proxyIdentityEqual(base.ice_getLocator(), communicator.getDefaultLocator()));
- anotherLocator = Ice.LocatorPrx.uncheckedCast(communicator.stringToProxy("anotherLocator"));
- base = base.ice_locator(anotherLocator);
- test(Ice.proxyIdentityEqual(base.ice_getLocator(), anotherLocator));
- communicator.setDefaultLocator(None);
- base = communicator.stringToProxy("test @ TestAdapter");
- test(not base.ice_getLocator());
- base = base.ice_locator(anotherLocator);
- test(Ice.proxyIdentityEqual(base.ice_getLocator(), anotherLocator));
- communicator.setDefaultLocator(locator);
- base = communicator.stringToProxy("test @ TestAdapter");
- test(Ice.proxyIdentityEqual(base.ice_getLocator(), communicator.getDefaultLocator()));
+ test(Ice.proxyIdentityEqual(base.ice_getLocator(), communicator.getDefaultLocator()))
+ anotherLocator = Ice.LocatorPrx.uncheckedCast(communicator.stringToProxy("anotherLocator"))
+ base = base.ice_locator(anotherLocator)
+ test(Ice.proxyIdentityEqual(base.ice_getLocator(), anotherLocator))
+ communicator.setDefaultLocator(None)
+ base = communicator.stringToProxy("test @ TestAdapter")
+ test(not base.ice_getLocator())
+ base = base.ice_locator(anotherLocator)
+ test(Ice.proxyIdentityEqual(base.ice_getLocator(), anotherLocator))
+ communicator.setDefaultLocator(locator)
+ base = communicator.stringToProxy("test @ TestAdapter")
+ test(Ice.proxyIdentityEqual(base.ice_getLocator(), communicator.getDefaultLocator()))
#
# We also test ice_router/ice_getRouter (perhaps we should add a
# test/Ice/router test?)
#
- test(not base.ice_getRouter());
- anotherRouter = Ice.RouterPrx.uncheckedCast(communicator.stringToProxy("anotherRouter"));
- base = base.ice_router(anotherRouter);
- test(Ice.proxyIdentityEqual(base.ice_getRouter(), anotherRouter));
- router = Ice.RouterPrx.uncheckedCast(communicator.stringToProxy("dummyrouter"));
- communicator.setDefaultRouter(router);
- base = communicator.stringToProxy("test @ TestAdapter");
- test(Ice.proxyIdentityEqual(base.ice_getRouter(), communicator.getDefaultRouter()));
- communicator.setDefaultRouter(None);
- base = communicator.stringToProxy("test @ TestAdapter");
- test(not base.ice_getRouter());
+ test(not base.ice_getRouter())
+ anotherRouter = Ice.RouterPrx.uncheckedCast(communicator.stringToProxy("anotherRouter"))
+ base = base.ice_router(anotherRouter)
+ test(Ice.proxyIdentityEqual(base.ice_getRouter(), anotherRouter))
+ router = Ice.RouterPrx.uncheckedCast(communicator.stringToProxy("dummyrouter"))
+ communicator.setDefaultRouter(router)
+ base = communicator.stringToProxy("test @ TestAdapter")
+ test(Ice.proxyIdentityEqual(base.ice_getRouter(), communicator.getDefaultRouter()))
+ communicator.setDefaultRouter(None)
+ base = communicator.stringToProxy("test @ TestAdapter")
+ test(not base.ice_getRouter())
print("ok")
sys.stdout.write("starting server... ")
@@ -200,7 +200,7 @@ def allTests(communicator, ref):
sys.stdout.flush()
hello = Test.HelloPrx.checkedCast(communicator.stringToProxy("hello"))
obj.migrateHello()
- hello.ice_getConnection().close(False);
+ hello.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
hello.sayHello()
obj.migrateHello()
hello.sayHello()
@@ -237,21 +237,21 @@ def allTests(communicator, ref):
#
sys.stdout.write("testing indirect references to collocated objects... ")
sys.stdout.flush()
- properties = communicator.getProperties();
- properties.setProperty("Ice.PrintAdapterReady", "0");
- adapter = communicator.createObjectAdapterWithEndpoints("Hello", "default");
- adapter.setLocator(locator);
+ properties = communicator.getProperties()
+ properties.setProperty("Ice.PrintAdapterReady", "0")
+ adapter = communicator.createObjectAdapterWithEndpoints("Hello", "default")
+ adapter.setLocator(locator)
assert(adapter.getLocator() == locator)
- id = Ice.Identity();
- id.name = Ice.generateUUID();
- registry.addObject(adapter.add(HelloI(), id));
- adapter.activate();
+ id = Ice.Identity()
+ id.name = Ice.generateUUID()
+ registry.addObject(adapter.add(HelloI(), id))
+ adapter.activate()
- helloPrx = Test.HelloPrx.checkedCast(communicator.stringToProxy(communicator.identityToString(id)));
- test(not helloPrx.ice_getConnection());
+ helloPrx = Test.HelloPrx.checkedCast(communicator.stringToProxy(Ice.identityToString(id)))
+ test(not helloPrx.ice_getConnection())
- adapter.deactivate();
+ adapter.deactivate()
print("ok")
sys.stdout.write("shutdown server manager... ")
diff --git a/python/test/Ice/operations/BatchOneways.py b/python/test/Ice/operations/BatchOneways.py
index 5878ff7f7af..ea0fc26c29c 100644
--- a/python/test/Ice/operations/BatchOneways.py
+++ b/python/test/Ice/operations/BatchOneways.py
@@ -82,7 +82,7 @@ def batchOneways(p):
batch1.ice_ping()
batch2.ice_ping()
batch1.ice_flushBatchRequests()
- batch1.ice_getConnection().close(False)
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
batch1.ice_ping()
batch2.ice_ping()
@@ -90,7 +90,7 @@ def batchOneways(p):
batch2.ice_getConnection()
batch1.ice_ping()
- batch1.ice_getConnection().close(False)
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
batch1.ice_ping()
batch2.ice_ping()
diff --git a/python/test/Ice/operations/BatchOnewaysAMI.py b/python/test/Ice/operations/BatchOnewaysAMI.py
index cd53ee94470..f750b3eb02d 100644
--- a/python/test/Ice/operations/BatchOnewaysAMI.py
+++ b/python/test/Ice/operations/BatchOnewaysAMI.py
@@ -61,14 +61,14 @@ def batchOneways(p):
batch1.end_ice_ping(batch1.begin_ice_ping())
batch2.end_ice_ping(batch2.begin_ice_ping())
batch1.end_ice_flushBatchRequests(batch1.begin_ice_flushBatchRequests())
- batch1.ice_getConnection().close(False)
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
batch1.end_ice_ping(batch1.begin_ice_ping())
batch2.end_ice_ping(batch2.begin_ice_ping())
batch1.ice_getConnection()
batch2.ice_getConnection()
- batch1.ice_getConnection().close(False)
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
batch1.end_ice_ping(batch1.begin_ice_ping())
batch2.end_ice_ping(batch2.begin_ice_ping())
diff --git a/python/test/Ice/operations/BatchOnewaysFuture.py b/python/test/Ice/operations/BatchOnewaysFuture.py
index ccf84220aa1..ea1c70bcf94 100644
--- a/python/test/Ice/operations/BatchOnewaysFuture.py
+++ b/python/test/Ice/operations/BatchOnewaysFuture.py
@@ -63,14 +63,14 @@ def batchOneways(p):
batch1.ice_pingAsync()
batch2.ice_pingAsync()
batch1.ice_flushBatchRequestsAsync().result()
- batch1.ice_getConnection().close(False)
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
batch1.ice_pingAsync()
batch2.ice_pingAsync()
batch1.ice_getConnection()
batch2.ice_getConnection()
- batch1.ice_getConnection().close(False)
+ batch1.ice_getConnection().close(Ice.ConnectionClose.CloseGracefullyAndWait)
test(not batch1.ice_pingAsync().done())
test(not batch2.ice_pingAsync().done())
diff --git a/python/test/Ice/timeout/AllTests.py b/python/test/Ice/timeout/AllTests.py
index 16d3d0484f8..391c6b23ca5 100644
--- a/python/test/Ice/timeout/AllTests.py
+++ b/python/test/Ice/timeout/AllTests.py
@@ -116,58 +116,58 @@ def allTests(communicator):
sys.stdout.write("testing invocation timeout... ")
sys.stdout.flush()
- connection = obj.ice_getConnection();
- to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(100));
- test(connection == to.ice_getConnection());
+ connection = obj.ice_getConnection()
+ to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(100))
+ test(connection == to.ice_getConnection())
try:
- to.sleep(750);
- test(False);
+ to.sleep(750)
+ test(False)
except Ice.InvocationTimeoutException:
pass
- obj.ice_ping();
- to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(500));
- test(connection == to.ice_getConnection());
+ obj.ice_ping()
+ to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(500))
+ test(connection == to.ice_getConnection())
try:
- to.sleep(250);
+ to.sleep(250)
except Ice.InvocationTimeoutException:
- test(False);
- test(connection == to.ice_getConnection());
+ test(False)
+ test(connection == to.ice_getConnection())
# #
# # Expect InvocationTimeoutException.
# #
- # to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(250));
- # cb = new Callback();
- # to.begin_sleep(750, newCallback_Timeout_sleep(cb, &Callback.responseEx, &Callback.exceptionEx));
- # cb.check();
+ # to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(250))
+ # cb = new Callback()
+ # to.begin_sleep(750, newCallback_Timeout_sleep(cb, &Callback.responseEx, &Callback.exceptionEx))
+ # cb.check()
# #
# # Expect success.
# #
- # to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(500));
- # cb = new Callback();
- # to.begin_sleep(250, newCallback_Timeout_sleep(cb, &Callback.response, &Callback.exception));
- # cb.check();
+ # to = Test.TimeoutPrx.uncheckedCast(obj.ice_invocationTimeout(500))
+ # cb = new Callback()
+ # to.begin_sleep(250, newCallback_Timeout_sleep(cb, &Callback.response, &Callback.exception))
+ # cb.check()
print("ok")
sys.stdout.write("testing close timeout... ")
sys.stdout.flush()
- to = Test.TimeoutPrx.checkedCast(obj.ice_timeout(100));
- connection = to.ice_getConnection();
- timeout.holdAdapter(500);
- connection.close(False);
+ to = Test.TimeoutPrx.checkedCast(obj.ice_timeout(100))
+ connection = to.ice_getConnection()
+ timeout.holdAdapter(500)
+ connection.close(Ice.ConnectionClose.CloseGracefullyAndWait)
try:
connection.getInfo(); # getInfo() doesn't throw in the closing state.
except Ice.LocalException:
- test(False);
- time.sleep(0.5);
+ test(False)
+ time.sleep(0.5)
try:
- connection.getInfo();
- test(False);
- except Ice.CloseConnectionException:
+ connection.getInfo()
+ test(False)
+ except Ice.ConnectionManuallyClosedException, ex:
# Expected.
- pass
- timeout.op(); # Ensure adapter is active.
+ test(ex.graceful)
+ timeout.op() # Ensure adapter is active.
print("ok")
sys.stdout.write("testing timeout overrides... ")
@@ -193,7 +193,7 @@ def allTests(communicator):
#
timeout.op() # Ensure adapter is active.
to = Test.TimeoutPrx.checkedCast(to.ice_timeout(1000))
- timeout.holdAdapter(500);
+ timeout.holdAdapter(500)
try:
to.sendData(seq)
test(False)
@@ -229,9 +229,9 @@ def allTests(communicator):
# Verify that timeout set via ice_timeout() is still used for requests.
#
timeout.op() # Ensure adapter is active.
- to = Test.TimeoutPrx.uncheckedCast(to.ice_timeout(250));
+ to = Test.TimeoutPrx.uncheckedCast(to.ice_timeout(250))
to.ice_getConnection(); # Establish connection
- timeout.holdAdapter(750);
+ timeout.holdAdapter(750)
try:
to.sendData(seq)
test(False)
@@ -246,11 +246,11 @@ def allTests(communicator):
initData.properties = communicator.getProperties().clone()
initData.properties.setProperty("Ice.Override.CloseTimeout", "100")
comm = Ice.initialize(initData)
- connection = comm.stringToProxy(sref).ice_getConnection();
- timeout.holdAdapter(800);
- now = time.clock();
- comm.destroy();
- test((time.clock() - now) < 0.7);
+ connection = comm.stringToProxy(sref).ice_getConnection()
+ timeout.holdAdapter(800)
+ now = time.clock()
+ comm.destroy()
+ test((time.clock() - now) < 0.7)
print("ok")
diff --git a/ruby/src/IceRuby/Connection.cpp b/ruby/src/IceRuby/Connection.cpp
index 6b4b57efdc7..2c5f65a8434 100644
--- a/ruby/src/IceRuby/Connection.cpp
+++ b/ruby/src/IceRuby/Connection.cpp
@@ -46,14 +46,23 @@ IceRuby::createConnection(const Ice::ConnectionPtr& p)
extern "C"
VALUE
-IceRuby_Connection_close(VALUE self, VALUE b)
+IceRuby_Connection_close(VALUE self, VALUE mode)
{
ICE_RUBY_TRY
{
Ice::ConnectionPtr* p = reinterpret_cast<Ice::ConnectionPtr*>(DATA_PTR(self));
assert(p);
- (*p)->close(RTEST(b));
+ volatile VALUE type = callRuby(rb_path2class, "Ice::ConnectionClose");
+ if(callRuby(rb_obj_is_instance_of, mode, type) != Qtrue)
+ {
+ throw RubyException(rb_eTypeError,
+ "value for 'mode' argument must be an enumerator of Ice.ConnectionClose");
+ }
+ volatile VALUE modeValue = callRuby(rb_funcall, mode, rb_intern("to_i"), 0);
+ assert(TYPE(modeValue) == T_FIXNUM);
+ Ice::ConnectionClose cc = static_cast<Ice::ConnectionClose>(FIX2LONG(modeValue));
+ (*p)->close(cc);
}
ICE_RUBY_CATCH
return Qnil;
@@ -76,6 +85,21 @@ IceRuby_Connection_flushBatchRequests(VALUE self)
extern "C"
VALUE
+IceRuby_Connection_heartbeat(VALUE self)
+{
+ ICE_RUBY_TRY
+ {
+ Ice::ConnectionPtr* p = reinterpret_cast<Ice::ConnectionPtr*>(DATA_PTR(self));
+ assert(p);
+
+ (*p)->heartbeat();
+ }
+ ICE_RUBY_CATCH
+ return Qnil;
+}
+
+extern "C"
+VALUE
IceRuby_Connection_setACM(VALUE self, VALUE t, VALUE c, VALUE h)
{
ICE_RUBY_TRY
@@ -221,6 +245,7 @@ IceRuby_Connection_getEndpoint(VALUE self)
ICE_RUBY_CATCH
return Qnil;
}
+
extern "C"
VALUE
IceRuby_Connection_setBufferSize(VALUE self, VALUE r, VALUE s)
@@ -241,6 +266,21 @@ IceRuby_Connection_setBufferSize(VALUE self, VALUE r, VALUE s)
extern "C"
VALUE
+IceRuby_Connection_throwException(VALUE self)
+{
+ ICE_RUBY_TRY
+ {
+ Ice::ConnectionPtr* p = reinterpret_cast<Ice::ConnectionPtr*>(DATA_PTR(self));
+ assert(p);
+
+ (*p)->throwException();
+ }
+ ICE_RUBY_CATCH
+ return Qnil;
+}
+
+extern "C"
+VALUE
IceRuby_Connection_toString(VALUE self)
{
ICE_RUBY_TRY
@@ -377,6 +417,7 @@ IceRuby::initConnection(VALUE iceModule)
//
rb_define_method(_connectionClass, "close", CAST_METHOD(IceRuby_Connection_close), 1);
rb_define_method(_connectionClass, "flushBatchRequests", CAST_METHOD(IceRuby_Connection_flushBatchRequests), 0);
+ rb_define_method(_connectionClass, "heartbeat", CAST_METHOD(IceRuby_Connection_heartbeat), 0);
rb_define_method(_connectionClass, "setACM", CAST_METHOD(IceRuby_Connection_setACM), 3);
rb_define_method(_connectionClass, "getACM", CAST_METHOD(IceRuby_Connection_getACM), 0);
rb_define_method(_connectionClass, "type", CAST_METHOD(IceRuby_Connection_type), 0);
@@ -384,6 +425,7 @@ IceRuby::initConnection(VALUE iceModule)
rb_define_method(_connectionClass, "getInfo", CAST_METHOD(IceRuby_Connection_getInfo), 0);
rb_define_method(_connectionClass, "getEndpoint", CAST_METHOD(IceRuby_Connection_getEndpoint), 0);
rb_define_method(_connectionClass, "setBufferSize", CAST_METHOD(IceRuby_Connection_setBufferSize), 2);
+ rb_define_method(_connectionClass, "throwException", CAST_METHOD(IceRuby_Connection_throwException), 0);
rb_define_method(_connectionClass, "toString", CAST_METHOD(IceRuby_Connection_toString), 0);
rb_define_method(_connectionClass, "to_s", CAST_METHOD(IceRuby_Connection_toString), 0);
rb_define_method(_connectionClass, "inspect", CAST_METHOD(IceRuby_Connection_toString), 0);
diff --git a/ruby/src/IceRuby/Util.cpp b/ruby/src/IceRuby/Util.cpp
index 7fa1222fb06..84708f2dfb8 100644
--- a/ruby/src/IceRuby/Util.cpp
+++ b/ruby/src/IceRuby/Util.cpp
@@ -732,6 +732,10 @@ setExceptionMembers(const Ice::LocalException& ex, VALUE p)
volatile VALUE v = createString(e.reason);
callRuby(rb_iv_set, p, "@reason", v);
}
+ catch(const Ice::ConnectionManuallyClosedException& e)
+ {
+ callRuby(rb_iv_set, p, "@graceful", e.graceful ? Qtrue : Qfalse);
+ }
catch(const Ice::LocalException&)
{
//
diff --git a/ruby/test/Ice/acm/AllTests.rb b/ruby/test/Ice/acm/AllTests.rb
index 5c6b5e64f66..a147c616693 100644
--- a/ruby/test/Ice/acm/AllTests.rb
+++ b/ruby/test/Ice/acm/AllTests.rb
@@ -7,13 +7,10 @@
#
# **********************************************************************
-def allTests(communicator)
+def testSetACM(communicator, com)
print "testing setACM/getACM... "
STDOUT.flush
- ref = "communicator:default -p 12010"
- com = Test::RemoteCommunicatorPrx::uncheckedCast(communicator.stringToProxy(ref))
-
adapter = com.createObjectAdapter(-1, -1, -1)
initData = Ice::InitializationData.new
@@ -44,14 +41,49 @@ def allTests(communicator)
test(acm.close == Ice::ACMClose::CloseOnInvocationAndIdle)
test(acm.heartbeat == Ice::ACMHeartbeat::HeartbeatAlways)
- proxy.waitForHeartbeat(2)
+ proxy.startHeartbeatCount()
+ proxy.waitForHeartbeatCount(2)
adapter.deactivate()
testCommunicator.destroy()
puts "ok"
+end
- print "shutting down... "
+def testHeartbeatManual(communicator, com)
+ print "testing manual heartbeats... "
STDOUT.flush
- com.shutdown()
+
+ adapter = com.createObjectAdapter(10, -1, 0)
+
+ initData = Ice::InitializationData.new
+ initData.properties = communicator.getProperties().clone()
+ initData.properties.setProperty("Ice.ACM.Timeout", "10")
+ initData.properties.setProperty("Ice.ACM.Client.Timeout", "10")
+ initData.properties.setProperty("Ice.ACM.Client.Close", "0")
+ initData.properties.setProperty("Ice.ACM.Client.Heartbeat", "0")
+ testCommunicator = Ice::initialize(initData)
+ proxy = Test::TestIntfPrx::uncheckedCast(testCommunicator.stringToProxy(adapter.getTestIntf().ice_toString()))
+ con = proxy.ice_getConnection()
+
+ proxy.startHeartbeatCount()
+ con.heartbeat()
+ con.heartbeat()
+ con.heartbeat()
+ con.heartbeat()
+ con.heartbeat()
+ proxy.waitForHeartbeatCount(5)
+
+ adapter.deactivate()
+ testCommunicator.destroy()
puts "ok"
end
+
+def allTests(communicator)
+ ref = "communicator:default -p 12010"
+ com = Test::RemoteCommunicatorPrx::uncheckedCast(communicator.stringToProxy(ref))
+
+ testSetACM(communicator, com)
+ testHeartbeatManual(communicator, com)
+
+ com.shutdown()
+end
diff --git a/ruby/test/Ice/acm/Test.ice b/ruby/test/Ice/acm/Test.ice
index 5ab98180dd3..d78abd6eb0f 100644
--- a/ruby/test/Ice/acm/Test.ice
+++ b/ruby/test/Ice/acm/Test.ice
@@ -17,7 +17,8 @@ interface TestIntf
void sleep(int seconds);
void sleepAndHold(int seconds);
void interruptSleep();
- void waitForHeartbeat(int count);
+ void startHeartbeatCount();
+ void waitForHeartbeatCount(int count);
};
interface RemoteObjectAdapter
diff --git a/ruby/test/Ice/binding/AllTests.rb b/ruby/test/Ice/binding/AllTests.rb
index f4c32a3a999..605063c96e4 100644
--- a/ruby/test/Ice/binding/AllTests.rb
+++ b/ruby/test/Ice/binding/AllTests.rb
@@ -92,7 +92,7 @@ def allTests(communicator)
if names.include?(name)
names.delete(name)
end
- test1.ice_getConnection().close(false)
+ test1.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
#
@@ -113,7 +113,7 @@ def allTests(communicator)
test(i == nRetry)
for a in adapters
- a.getTestIntf().ice_getConnection().close(false)
+ a.getTestIntf().ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
#
@@ -139,7 +139,7 @@ def allTests(communicator)
if names.include?(name)
names.delete(name)
end
- test1.ice_getConnection().close(false)
+ test1.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
#
@@ -171,7 +171,7 @@ def allTests(communicator)
if names.include?(name)
names.delete(name)
end
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
t = Test::TestIntfPrx::uncheckedCast(t.ice_endpointSelection(Ice::EndpointSelectionType::Random))
@@ -185,7 +185,7 @@ def allTests(communicator)
if names.include?(name)
names.delete(name)
end
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
deactivate(com, adapters)
@@ -250,14 +250,14 @@ def allTests(communicator)
i = i + 1
end
test(i == nRetry)
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
adapters.push(com.createObjectAdapter("Adapter35", endpoints[1].toString()))
i = 0
while i < nRetry and t.getAdapterName() == "Adapter35"
i = i + 1
end
test(i == nRetry)
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
adapters.push(com.createObjectAdapter("Adapter34", endpoints[0].toString()))
i = 0
while i < nRetry and t.getAdapterName() == "Adapter34"
@@ -442,7 +442,7 @@ def allTests(communicator)
t = createTestIntfPrx(adapters)
for i in 0...5
test(t.getAdapterName() == "Adapter82")
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
testSecure = Test::TestIntfPrx::uncheckedCast(t.ice_secure(true))
@@ -457,14 +457,14 @@ def allTests(communicator)
for i in 0...5
test(t.getAdapterName() == "Adapter81")
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
com.createObjectAdapter("Adapter83", (t.ice_getEndpoints()[1]).toString()) # Reactive tcp OA.
for i in 0...5
test(t.getAdapterName() == "Adapter83")
- t.ice_getConnection().close(false)
+ t.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
end
com.deactivateObjectAdapter(adapters[0])
diff --git a/ruby/test/Ice/operations/BatchOneways.rb b/ruby/test/Ice/operations/BatchOneways.rb
index 042899d3d6b..99b2225f61b 100644
--- a/ruby/test/Ice/operations/BatchOneways.rb
+++ b/ruby/test/Ice/operations/BatchOneways.rb
@@ -33,7 +33,7 @@ def batchOneways(p)
batch.ice_ping()
batch2.ice_ping()
batch.ice_flushBatchRequests()
- batch.ice_getConnection().close(false)
+ batch.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
batch.ice_ping()
batch2.ice_ping()
@@ -41,7 +41,7 @@ def batchOneways(p)
batch2.ice_getConnection()
batch.ice_ping()
- batch.ice_getConnection().close(false)
+ batch.ice_getConnection().close(Ice::ConnectionClose::CloseGracefullyAndWait)
batch.ice_ping()
batch2.ice_ping()
diff --git a/ruby/test/Ice/timeout/AllTests.rb b/ruby/test/Ice/timeout/AllTests.rb
index 05746528fc6..6c9ccc7ea55 100644
--- a/ruby/test/Ice/timeout/AllTests.rb
+++ b/ruby/test/Ice/timeout/AllTests.rb
@@ -98,7 +98,7 @@ def allTests(communicator)
to = Test::TimeoutPrx.checkedCast(obj.ice_timeout(100))
connection = to.ice_getConnection()
timeout.holdAdapter(500)
- connection.close(false)
+ connection.close(Ice::ConnectionClose::CloseGracefullyAndWait)
begin
connection.getInfo() # getInfo() doesn't throw in the closing state.
rescue Ice::LocalException
@@ -108,8 +108,9 @@ def allTests(communicator)
begin
connection.getInfo()
test(false)
- rescue Ice::CloseConnectionException
+ rescue Ice::ConnectionManuallyClosedException => ex
# Expected.
+ test(ex.graceful)
end
timeout.op() # Ensure adapter is active.
puts "ok"
diff --git a/scripts/tests/Ice/ami.py b/scripts/tests/Ice/ami.py
index 6e5abe02f7f..7ecc8fd7c5f 100644
--- a/scripts/tests/Ice/ami.py
+++ b/scripts/tests/Ice/ami.py
@@ -8,4 +8,4 @@
#
# **********************************************************************
-TestSuite(__name__, options = { "compress" : [False] }) \ No newline at end of file
+TestSuite(__name__, options = { "compress" : [False], "serialize" : [False] })
diff --git a/slice/Ice/Connection.ice b/slice/Ice/Connection.ice
index e87f8527958..af7b03a5a38 100644
--- a/slice/Ice/Connection.ice
+++ b/slice/Ice/Connection.ice
@@ -77,7 +77,8 @@ local interface CloseCallback
/**
*
* This method is called by the the connection when the connection
- * is closed.
+ * is closed. If the callback needs more information about the closure,
+ * it can call {@link Connection#throwException}.
*
* @param con The connection that closed.
**/
@@ -132,6 +133,27 @@ local struct ACM
};
/**
+ * Determines the behavior when manually closing a connection.
+ **/
+["cpp:unscoped"]
+local enum ConnectionClose
+{
+ /**
+ * Close the connection immediately without sending a close connection protocol message to the peer
+ * and waiting for the peer to acknowledge it.
+ **/
+ CloseForcefully,
+ /**
+ * Close the connection by notifying the peer but do not wait for pending invocations to complete.
+ **/
+ CloseGracefully,
+ /**
+ * Wait for all pending invocations to complete before closing the connection.
+ **/
+ CloseGracefullyAndWait
+};
+
+/**
*
* The user-level interface to a connection.
*
@@ -141,17 +163,13 @@ local interface Connection
{
/**
*
- * Close a connection, either gracefully or forcefully. If a
- * connection is closed forcefully, it closes immediately, without
- * sending the relevant close connection protocol messages to the
- * peer and waiting for the peer to acknowledge these protocol
- * messages.
+ * Manually close the connection using the specified closure mode.
*
- * @param force If true, close forcefully. Otherwise the
- * connection is closed gracefully.
+ * @param mode Determines how the connection will be closed.
*
+ * @see ConnectionClose
**/
- void close(bool force);
+ void close(ConnectionClose mode);
/**
*
@@ -225,18 +243,19 @@ local interface Connection
/**
*
- * Set callback on the connection. The callback is called by the
+ * Set a close callback on the connection. The callback is called by the
* connection when it's closed. The callback is called from the
- * Ice thread pool associated with the connection.
+ * Ice thread pool associated with the connection. If the callback needs
+ * more information about the closure, it can call {@link Connection#throwException}.
*
- * @param callback The closed callback object.
+ * @param callback The close callback object.
*
**/
void setCloseCallback(CloseCallback callback);
/**
*
- * Set callback on the connection. The callback is called by the
+ * Set a heartbeat callback on the connection. The callback is called by the
* connection when a heartbeat is received. The callback is called
* from the Ice thread pool associated with the connection.
*
@@ -247,6 +266,13 @@ local interface Connection
/**
*
+ * Send a heartbeat message.
+ *
+ **/
+ ["async-oneway"] void heartbeat();
+
+ /**
+ *
* Set the active connection management parameters.
*
* @param timeout The timeout value in milliseconds.
@@ -307,7 +333,6 @@ local interface Connection
**/
["cpp:const"] ConnectionInfo getInfo();
-
/**
*
* Set the connection buffer receive/send size.
@@ -317,6 +342,17 @@ local interface Connection
*
**/
void setBufferSize(int rcvSize, int sndSize);
+
+ /**
+ *
+ * Throw an exception indicating the reason for connection closure. For example,
+ * {@link CloseConnectionException} is raised if the connection was closed gracefully,
+ * whereas {@link ConnectionManuallyClosedException} is raised if the connection was
+ * manually closed by the application. This operation does nothing if the connection is
+ * not yet closed.
+ *
+ **/
+ ["cpp:const"] void throwException();
};
/**
diff --git a/slice/Ice/LocalException.ice b/slice/Ice/LocalException.ice
index 374a84d9e4c..e0a77945bf5 100644
--- a/slice/Ice/LocalException.ice
+++ b/slice/Ice/LocalException.ice
@@ -814,14 +814,16 @@ local exception CloseConnectionException extends ProtocolException
/**
*
* This exception is raised by an operation call if the application
- * forcefully closes the connection {@link Connection#close}.
+ * closes the connection locally using {@link Connection#close}.
*
* @see Connection#close
*
**/
["cpp:ice_print"]
-local exception ForcedCloseConnectionException extends ProtocolException
+local exception ConnectionManuallyClosedException
{
+ /** True if the connection was closed gracefully, false otherwise. **/
+ bool graceful;
};
/**
@@ -1032,5 +1034,4 @@ local exception ResponseSentException
{
};
-
};