From a6d47929b23352b4c1cfff4947f1f3653c437882 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Wed, 21 Aug 2024 11:06:41 -0400 Subject: [PATCH] Rework manual Connection close in C++ (#2652) --- cpp/include/Ice/Connection.h | 47 +++-- cpp/src/Glacier2/RoutingTable.cpp | 2 +- cpp/src/Glacier2/SessionRouterI.cpp | 4 +- cpp/src/Ice/Connection.cpp | 11 ++ cpp/src/Ice/ConnectionI.cpp | 184 ++++++++++++++---- cpp/src/Ice/ConnectionI.h | 13 +- cpp/src/IceBridge/IceBridge.cpp | 8 +- cpp/src/IceGrid/SessionManager.cpp | 8 +- cpp/test/Ice/ami/AllTests.cpp | 71 +------ cpp/test/Ice/ami/TestI.cpp | 10 +- cpp/test/Ice/background/AllTests.cpp | 38 ++-- cpp/test/Ice/binding/AllTests.cpp | 40 ++-- cpp/test/Ice/hold/AllTests.cpp | 2 +- cpp/test/Ice/location/AllTests.cpp | 2 +- cpp/test/Ice/metrics/AllTests.cpp | 18 +- cpp/test/Ice/metrics/TestAMDI.cpp | 2 +- cpp/test/Ice/metrics/TestI.cpp | 2 +- cpp/test/Ice/operations/BatchOneways.cpp | 4 +- cpp/test/Ice/operations/BatchOnewaysAMI.cpp | 4 +- cpp/test/Ice/retry/TestI.cpp | 2 +- cpp/test/Ice/timeout/AllTests.cpp | 2 +- cpp/test/Ice/udp/AllTests.cpp | 2 +- cpp/test/IceBridge/simple/AllTests.cpp | 2 +- cpp/test/IceBridge/simple/TestI.cpp | 4 +- cpp/test/IceSSL/configuration/AllTests.cpp | 2 +- cpp/test/IceStorm/stress/Subscriber.cpp | 2 +- matlab/lib/+Ice/Connection.m | 24 +-- matlab/lib/+Ice/ConnectionClose.m | 23 --- matlab/src/Connection.cpp | 44 ++--- matlab/src/ice.h | 4 +- matlab/test/Ice/ami/AllTests.m | 42 +--- matlab/test/Ice/binding/AllTests.m | 28 +-- matlab/test/Ice/operations/BatchOneways.m | 4 +- matlab/test/Ice/operations/BatchOnewaysAMI.m | 4 +- php/lib/Ice.php | 1 - php/lib/Ice/ConnectionClose.php | 15 -- php/src/Connection.cpp | 36 ++-- php/test/Ice/binding/Client.php | 20 +- python/modules/IcePy/Connection.cpp | 47 +++-- python/python/Ice/ConnectionClose.py | 52 ----- python/python/Ice/__init__.py | 1 - python/test/Ice/ami/AllTests.py | 38 ++-- python/test/Ice/ami/TestI.py | 5 +- python/test/Ice/binding/AllTests.py | 30 ++- python/test/Ice/current/AllTests.py | 2 +- python/test/Ice/location/AllTests.py | 2 +- python/test/Ice/operations/BatchOneways.py | 4 +- .../test/Ice/operations/BatchOnewaysFuture.py | 4 +- ruby/ruby/Ice.rb | 1 - ruby/ruby/Ice/ConnectionClose.rb | 50 ----- ruby/src/IceRuby/Connection.cpp | 27 ++- ruby/test/Ice/binding/AllTests.rb | 20 +- ruby/test/Ice/operations/BatchOneways.rb | 4 +- swift/src/Ice/Connection.swift | 75 +------ swift/src/Ice/ConnectionI.swift | 9 +- swift/src/IceImpl/Connection.mm | 18 +- swift/src/IceImpl/include/Connection.h | 3 +- swift/test/Ice/ami/AllTests.swift | 71 ++----- swift/test/Ice/ami/TestI.swift | 10 +- swift/test/Ice/binding/AllTests.swift | 28 +-- swift/test/Ice/hold/AllTests.swift | 2 +- swift/test/Ice/location/AllTests.swift | 2 +- swift/test/Ice/operations/BatchOneways.swift | 4 +- swift/test/Ice/retry/TestI.swift | 2 +- swift/test/Ice/timeout/AllTests.swift | 2 +- swift/test/Ice/udp/AllTests.swift | 2 +- 66 files changed, 525 insertions(+), 721 deletions(-) delete mode 100644 matlab/lib/+Ice/ConnectionClose.m delete mode 100644 php/lib/Ice/ConnectionClose.php delete mode 100644 python/python/Ice/ConnectionClose.py delete mode 100644 ruby/ruby/Ice/ConnectionClose.rb diff --git a/cpp/include/Ice/Connection.h b/cpp/include/Ice/Connection.h index d77fcfa3354..ed3f27dc602 100644 --- a/cpp/include/Ice/Connection.h +++ b/cpp/include/Ice/Connection.h @@ -46,27 +46,6 @@ namespace Ice BasedOnProxy }; - /** - * Determines the behavior when manually closing a connection. - */ - enum class ConnectionClose : std::uint8_t - { - /** - * Close the connection immediately without sending a close connection protocol message to the peer and waiting - * for the peer to acknowledge it. - */ - Forcefully, - /** - * Close the connection by notifying the peer but do not wait for pending outgoing invocations to complete. On - * the server side, the connection will not be closed until all incoming invocations have completed. - */ - Gracefully, - /** - * Wait for all pending invocations to complete before closing the connection. - */ - GracefullyWithWait - }; - /** * A collection of HTTP headers. */ @@ -144,11 +123,29 @@ namespace Ice virtual ~Connection() = 0; /** - * Manually close the connection using the specified closure mode. - * @param mode Determines how the connection will be closed. - * @see ConnectionClose + * Aborts this connection. + */ + virtual void abort() noexcept = 0; + + /** + * Starts a graceful closure of this connection once all outstanding invocations have completed. + * @param response A callback that the implementation calls when the connection is closed gracefully. + * @param exception A callback that the implementation calls when the connection closure failed. Its + * exception_ptr parameter is always non-null and describes the reason for the closure. + * @remarks The response and exception callbacks may be called synchronously (from the calling thread); in + * particular, this occurs when you call close on a connection that is already closed. The implementation always + * calls one of the two callbacks once; it never calls both. + * If closing the connection takes longer than the configured close timeout, the connection is aborted with a + * CloseTimeoutException. + */ + virtual void + close(std::function response, std::function exception) noexcept = 0; + + /** + * Starts a graceful closure of this connection once all outstanding invocations have completed. + * @return A future that completes then the connection is closed. */ - virtual void close(ConnectionClose mode) noexcept = 0; + std::future close(); /** * Create a special proxy that always uses this connection. This can be used for callbacks from a server to a diff --git a/cpp/src/Glacier2/RoutingTable.cpp b/cpp/src/Glacier2/RoutingTable.cpp index 806b60cd91d..5876044f27b 100644 --- a/cpp/src/Glacier2/RoutingTable.cpp +++ b/cpp/src/Glacier2/RoutingTable.cpp @@ -61,7 +61,7 @@ Glacier2::RoutingTable::add(const ObjectProxySeq& unfiltered, const Current& cur if (!_verifier->verify(*prx)) { - current.con->close(ConnectionClose::Forcefully); + current.con->abort(); throw ObjectNotExistException(__FILE__, __LINE__); } diff --git a/cpp/src/Glacier2/SessionRouterI.cpp b/cpp/src/Glacier2/SessionRouterI.cpp index e0ec9c96321..59b0b7b3489 100644 --- a/cpp/src/Glacier2/SessionRouterI.cpp +++ b/cpp/src/Glacier2/SessionRouterI.cpp @@ -64,7 +64,7 @@ namespace Glacier2 // Initiate a graceful closure of the connection. Only initiate and graceful because the ultimate caller // can be the Glacier2 client calling us over _connection. - _connection->close(ConnectionClose::Gracefully); + _connection->close(nullptr, nullptr); } private: @@ -842,7 +842,7 @@ SessionRouterI::getRouterImpl(const ConnectionPtr& connection, const Ice::Identi out << "rejecting request, no session is associated with the connection.\n"; out << "identity: " << identityToString(id); } - connection->close(ConnectionClose::Forcefully); + connection->abort(); throw ObjectNotExistException(__FILE__, __LINE__); } return nullptr; diff --git a/cpp/src/Ice/Connection.cpp b/cpp/src/Ice/Connection.cpp index 999bf5aa3e5..10a5f0bbe59 100644 --- a/cpp/src/Ice/Connection.cpp +++ b/cpp/src/Ice/Connection.cpp @@ -32,3 +32,14 @@ Ice::Connection::flushBatchRequestsAsync(CompressBatch compress) [promise](bool) { promise->set_value(); }); return promise->get_future(); } + +future +Ice::Connection::close() +{ + auto sharedPromise = make_shared>(); + close( + [sharedPromise]() { sharedPromise->set_value(); }, + [sharedPromise](exception_ptr closeException) { sharedPromise->set_exception(closeException); }); + + return sharedPromise->get_future(); +} diff --git a/cpp/src/Ice/ConnectionI.cpp b/cpp/src/Ice/ConnectionI.cpp index b01f9e378ec..1f1c6e62f08 100644 --- a/cpp/src/Ice/ConnectionI.cpp +++ b/cpp/src/Ice/ConnectionI.cpp @@ -468,43 +468,76 @@ Ice::ConnectionI::destroy(DestructionReason reason) } void -Ice::ConnectionI::close(ConnectionClose mode) noexcept +Ice::ConnectionI::abort() noexcept { - std::unique_lock lock(_mutex); + std::lock_guard lock(_mutex); + setState( + StateClosed, + make_exception_ptr( + ConnectionAbortedException{__FILE__, __LINE__, "connection aborted by the application", true})); +} - if (mode == ConnectionClose::Forcefully) - { - setState( - StateClosed, - make_exception_ptr( - ConnectionAbortedException{__FILE__, __LINE__, "connection aborted by the application", true})); - } - else if (mode == ConnectionClose::Gracefully) - { - setState( - StateClosing, - make_exception_ptr(ConnectionClosedException{ - __FILE__, - __LINE__, - "connection closed gracefully by the application", - true})); - } - else +void +Ice::ConnectionI::close(function response, function exception) noexcept +{ + std::exception_ptr closeException = nullptr; { - assert(mode == ConnectionClose::GracefullyWithWait); + std::lock_guard lock(_mutex); + if (_state >= StateClosed) + { + closeException = _exception; + assert(closeException); + } + else + { + if (response || exception) + { + _onClosedList.push_back(make_pair(std::move(response), std::move(exception))); + } - // - // Wait until all outstanding requests have been completed. - // - _conditionVariable.wait(lock, [this] { return _asyncRequests.empty(); }); + if (_state < StateClosing) + { + if (_asyncRequests.empty()) + { + doApplicationClose(); + } + else + { + // We'll close the connection when we get the last reply message. + _closeRequested = true; + scheduleCloseTimerTask(); // we don't want to wait forever + } + } + // else nothing to do + } + } - setState( - StateClosing, - make_exception_ptr(ConnectionClosedException{ - __FILE__, - __LINE__, - "connection closed gracefully by the application", - true})); + if (closeException) // already closed + { + try + { + rethrow_exception(closeException); + } + catch (const ConnectionClosedException&) + { + response(); + } + catch (const CloseConnectionException&) + { + response(); + } + catch (const CommunicatorDestroyedException&) + { + response(); + } + catch (const ObjectAdapterDeactivatedException&) + { + response(); + } + catch (...) + { + exception(closeException); + } } } @@ -1688,6 +1721,54 @@ Ice::ConnectionI::finish(bool close) _readStream.clear(); _readStream.b.clear(); + if (!_onClosedList.empty()) + { + bool success; + try + { + rethrow_exception(_exception); + } + catch (const ConnectionClosedException&) + { + success = true; + } + catch (const CloseConnectionException&) + { + success = true; + } + catch (const CommunicatorDestroyedException&) + { + success = true; + } + catch (const ObjectAdapterDeactivatedException&) + { + success = true; + } + catch (...) + { + success = false; + } + + for (auto& pair : _onClosedList) + { + if (success) + { + if (pair.first) + { + pair.first(); + } + } + else + { + if (pair.second) + { + pair.second(_exception); + } + } + } + _onClosedList.clear(); // break potential cycles + } + if (_closeCallback) { closeCallback(_closeCallback); @@ -2177,10 +2258,7 @@ Ice::ConnectionI::initiateShutdown() os.write(static_cast(1)); // compression status: compression supported but not used. os.write(headerSize); // Message size. - if (_closeTimeout > chrono::seconds::zero()) - { - _timer->schedule(make_shared(shared_from_this()), _closeTimeout); - } + scheduleCloseTimerTask(); OutgoingMessage message(&os, false); if (sendMessage(message) & AsyncStatusSent) @@ -3098,10 +3176,7 @@ Ice::ConnectionI::parseMessage(int32_t& upcallCount, functionclosing(false, _exception); if (op) { - if (_closeTimeout > chrono::seconds::zero()) - { - _timer->schedule(make_shared(shared_from_this()), _closeTimeout); - } + scheduleCloseTimerTask(); return op; } setState(StateClosed); @@ -3245,7 +3320,10 @@ Ice::ConnectionI::parseMessage(int32_t& upcallCount, functioncancel(_inactivityTimerTask); } } + +void +ConnectionI::scheduleCloseTimerTask() +{ + // Called with the ConnectionI mutex locked. + + if (_closeTimeout > chrono::seconds::zero()) + { + // We schedule a new task every time this function is called. + _timer->schedule(make_shared(shared_from_this()), _closeTimeout); + } +} + +void +ConnectionI::doApplicationClose() noexcept +{ + // Called with the ConnectionI mutex locked. + assert(_state < StateClosing); + + setState( + StateClosing, + make_exception_ptr( + ConnectionClosedException{__FILE__, __LINE__, "connection closed gracefully by the application", true})); +} diff --git a/cpp/src/Ice/ConnectionI.h b/cpp/src/Ice/ConnectionI.h index 871a1d7ea85..56ecd29f4f4 100644 --- a/cpp/src/Ice/ConnectionI.h +++ b/cpp/src/Ice/ConnectionI.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #ifndef ICE_HAS_BZIP2 @@ -140,7 +141,9 @@ namespace Ice void activate(); void hold(); void destroy(DestructionReason); - void close(ConnectionClose) noexcept final; // From Connection. + + void abort() noexcept final; + void close(std::function response, std::function exception) noexcept final; bool isActiveOrHolding() const; bool isFinished() const; @@ -322,6 +325,9 @@ namespace Ice void scheduleInactivityTimerTask(); void cancelInactivityTimerTask(); + void scheduleCloseTimerTask(); + void doApplicationClose() noexcept; + Ice::CommunicatorPtr _communicator; const IceInternal::InstancePtr _instance; const IceInternal::TransceiverPtr _transceiver; @@ -397,7 +403,12 @@ namespace Ice bool _initialized; bool _validated; + // When true, the application called close and Connection must close the connection when it receives the reply + // for the last outstanding invocation. + bool _closeRequested = false; + CloseCallback _closeCallback; + std::list, std::function>> _onClosedList; mutable std::mutex _mutex; mutable std::condition_variable _conditionVariable; diff --git a/cpp/src/IceBridge/IceBridge.cpp b/cpp/src/IceBridge/IceBridge.cpp index 4cd46b0aa80..514a41cca35 100644 --- a/cpp/src/IceBridge/IceBridge.cpp +++ b/cpp/src/IceBridge/IceBridge.cpp @@ -183,7 +183,7 @@ BridgeConnection::outgoingSuccess(ConnectionPtr outgoing) // The incoming connection is already closed. There's no point in leaving the outgoing // connection open. // - outgoing->close(ConnectionClose::Gracefully); + outgoing->close(nullptr, nullptr); return; } @@ -219,7 +219,7 @@ BridgeConnection::outgoingException(exception_ptr ex) // The outgoing connection failed so we close the incoming connection. closed() will eventually // be called for it when the connection's dispatch count reaches zero. // - _incoming->close(ConnectionClose::Gracefully); + _incoming->close(nullptr, nullptr); // // Complete the queued incoming dispatch, otherwise the incoming connection will never @@ -254,7 +254,7 @@ BridgeConnection::closed(const ConnectionPtr& con) _exception = current_exception(); if (toBeClosed) { - toBeClosed->close(ConnectionClose::Gracefully); + toBeClosed->close(nullptr, nullptr); } } catch (const std::exception&) @@ -262,7 +262,7 @@ BridgeConnection::closed(const ConnectionPtr& con) _exception = current_exception(); if (toBeClosed) { - toBeClosed->close(ConnectionClose::Forcefully); + toBeClosed->abort(); } } diff --git a/cpp/src/IceGrid/SessionManager.cpp b/cpp/src/IceGrid/SessionManager.cpp index 664a27d692d..7488660338a 100644 --- a/cpp/src/IceGrid/SessionManager.cpp +++ b/cpp/src/IceGrid/SessionManager.cpp @@ -49,13 +49,7 @@ SessionManager::findAllQueryObjects(bool cached) auto connection = queryObject->ice_getCachedConnection(); if (connection) { - try - { - connection->close(Ice::ConnectionClose::GracefullyWithWait); - } - catch (const Ice::LocalException&) - { - } + connection->close(); } } queryObjects.clear(); diff --git a/cpp/test/Ice/ami/AllTests.cpp b/cpp/test/Ice/ami/AllTests.cpp index ba743821f6d..837773c8761 100644 --- a/cpp/test/Ice/ami/AllTests.cpp +++ b/cpp/test/Ice/ami/AllTests.cpp @@ -802,7 +802,7 @@ allTests(TestHelper* helper, bool collocated) test(p->opBatchCount() == 0); auto b1 = p->ice_batchOneway(); b1->opBatch(); - b1->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + b1->ice_getConnection()->close().get(); auto id = this_thread::get_id(); promise promise; @@ -870,7 +870,7 @@ allTests(TestHelper* helper, bool collocated) test(p->opBatchCount() == 0); auto b1 = p->ice_fixed(p->ice_getConnection())->ice_batchOneway(); b1->opBatch(); - b1->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + b1->ice_getConnection()->close().get(); promise promise; b1->ice_getConnection()->flushBatchRequestsAsync( @@ -939,7 +939,7 @@ allTests(TestHelper* helper, bool collocated) test(p->opBatchCount() == 0); auto b1 = p->ice_fixed(p->ice_getConnection())->ice_batchOneway(); b1->opBatch(); - b1->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + b1->ice_getConnection()->close().get(); promise promise; auto id = this_thread::get_id(); @@ -1001,8 +1001,8 @@ allTests(TestHelper* helper, bool collocated) b2->ice_getConnection(); // Ensure connection is established. b1->opBatch(); b2->opBatch(); - b1->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); - b2->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + b1->ice_getConnection()->close().get(); + b2->ice_getConnection()->close().get(); promise promise; auto id = this_thread::get_id(); @@ -1077,7 +1077,7 @@ allTests(TestHelper* helper, bool collocated) if (p->ice_getConnection() && protocol != "bt" && p->supportsAMD()) { - cout << "testing graceful close connection with wait... " << flush; + cout << "testing connection close... " << flush; { // // Local case: begin a request, close the connection gracefully, and make sure it waits @@ -1091,7 +1091,7 @@ allTests(TestHelper* helper, bool collocated) p->sleepAsync(100, [s]() { s->set_value(); }, [s](exception_ptr ex) { s->set_exception(ex); }); auto f = s->get_future(); // Blocks until the request completes. - con->close(ConnectionClose::GracefullyWithWait); + con->close().get(); f.get(); // Should complete successfully. fc.get(); } @@ -1176,60 +1176,7 @@ allTests(TestHelper* helper, bool collocated) } cout << "ok" << endl; - cout << "testing graceful close connection without wait... " << flush; - { - // - // Local case: start an 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 ConnectionClosedException. - // - p = p->ice_connectionId("CloseGracefully"); // Start with a new connection. - auto con = p->ice_getConnection(); - auto s = make_shared>(); - auto sent = make_shared>(); - p->startDispatchAsync( - [s]() { s->set_value(); }, - [s](exception_ptr ex) { s->set_exception(ex); }, - [sent](bool) { sent->set_value(); }); - auto f = s->get_future(); - sent->get_future().get(); // Ensure the request was sent before we close the connection. - con->close(ConnectionClose::Gracefully); - try - { - f.get(); - test(false); - } - catch (const ConnectionClosedException& ex) - { - test(ex.closedByApplication()); - } - p->finishDispatch(); - - // - // Remote case: the server closes the connection gracefully, which means the connection - // will not be closed until all pending dispatched requests have completed. - // - con = p->ice_getConnection(); - auto sc = make_shared>(); - con->setCloseCallback([sc](ConnectionPtr) { sc->set_value(); }); - auto fc = sc->get_future(); - s = make_shared>(); - p->sleepAsync(100, [s]() { s->set_value(); }, [s](exception_ptr ex) { s->set_exception(ex); }); - f = s->get_future(); - p->close(CloseMode::Gracefully); // Close is delayed until sleep completes. - fc.get(); // Ensure connection was closed. - try - { - f.get(); - } - catch (const Ice::LocalException&) - { - test(false); - } - } - cout << "ok" << endl; - - cout << "testing forceful close connection... " << flush; + cout << "testing connection abort... " << flush; { // // Local case: start a lengthy operation and then close the connection forcefully on the client side. @@ -1245,7 +1192,7 @@ allTests(TestHelper* helper, bool collocated) [sent](bool) { sent->set_value(); }); auto f = s->get_future(); sent->get_future().get(); // Ensure the request was sent before we close the connection. - con->close(ConnectionClose::Forcefully); + con->abort(); try { f.get(); diff --git a/cpp/test/Ice/ami/TestI.cpp b/cpp/test/Ice/ami/TestI.cpp index a7029e1e33e..e5566366d80 100644 --- a/cpp/test/Ice/ami/TestI.cpp +++ b/cpp/test/Ice/ami/TestI.cpp @@ -97,7 +97,15 @@ TestIntfI::waitForBatch(int32_t count, const Ice::Current&) void TestIntfI::close(Test::CloseMode mode, const Ice::Current& current) { - current.con->close(static_cast(mode)); + switch (mode) + { + case Test::CloseMode::Forcefully: + current.con->abort(); + break; + default: + current.con->close(nullptr, nullptr); + break; + } } void diff --git a/cpp/test/Ice/background/AllTests.cpp b/cpp/test/Ice/background/AllTests.cpp index 5a024c26537..1b7ee97554d 100644 --- a/cpp/test/Ice/background/AllTests.cpp +++ b/cpp/test/Ice/background/AllTests.cpp @@ -204,7 +204,7 @@ allTests(TestHelper* helper) configuration->buffered(true); backgroundController->buffered(true); background->opAsync(); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); background->opAsync(); vector> results; @@ -247,7 +247,7 @@ connectTests(const ConfigurationPtr& configuration, const BackgroundPrx& backgro { test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); for (int i = 0; i < 4; ++i) { @@ -324,7 +324,7 @@ connectTests(const ConfigurationPtr& configuration, const BackgroundPrx& backgro configuration->connectException( make_exception_ptr(Ice::SocketException{__FILE__, __LINE__, socketErrorMessage})); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); this_thread::sleep_for(chrono::milliseconds(10)); configuration->connectException(0); try @@ -358,7 +358,7 @@ initializeTests( cerr << ex << endl; test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); for (int i = 0; i < 4; i++) { @@ -421,7 +421,7 @@ initializeTests( cerr << ex << endl; test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); try { @@ -434,7 +434,7 @@ initializeTests( cerr << ex << endl; test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); #endif // @@ -468,7 +468,7 @@ initializeTests( cerr << ex << endl; test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); try { @@ -509,7 +509,7 @@ initializeTests( configuration->initializeException( make_exception_ptr(Ice::SocketException{__FILE__, __LINE__, socketErrorMessage})); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); this_thread::sleep_for(chrono::milliseconds(10)); configuration->initializeException(0); try @@ -530,12 +530,12 @@ initializeTests( } configuration->initializeSocketOperation(IceInternal::SocketOperationWrite); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); background->ice_ping(); configuration->initializeSocketOperation(IceInternal::SocketOperationNone); ctl->initializeException(true); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); this_thread::sleep_for(chrono::milliseconds(10)); ctl->initializeException(false); try @@ -559,11 +559,11 @@ initializeTests( { #if !defined(ICE_USE_IOCP) && !defined(ICE_USE_CFSTREAM) ctl->initializeSocketOperation(IceInternal::SocketOperationWrite); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); background->op(); ctl->initializeSocketOperation(IceInternal::SocketOperationNone); #else - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); background->op(); #endif } @@ -595,7 +595,7 @@ validationTests( { test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); try { @@ -645,7 +645,7 @@ validationTests( cerr << ex << endl; test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); try { @@ -761,7 +761,7 @@ validationTests( cerr << ex << endl; test(false); } - background->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + background->ice_getConnection()->close().get(); try { @@ -839,7 +839,7 @@ validationTests( backgroundBatchOneway->op(); ctl->resumeAdapter(); backgroundBatchOneway->ice_flushBatchRequestsAsync(); - backgroundBatchOneway->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + backgroundBatchOneway->ice_getConnection()->close().get(); ctl->holdAdapter(); backgroundBatchOneway->opWithPayload(seq); @@ -848,7 +848,7 @@ validationTests( backgroundBatchOneway->opWithPayload(seq); ctl->resumeAdapter(); backgroundBatchOneway->ice_flushBatchRequestsAsync().get(); - backgroundBatchOneway->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + backgroundBatchOneway->ice_getConnection()->close().get(); } void @@ -1289,10 +1289,10 @@ readWriteTests( this_thread::sleep_for(chrono::milliseconds(10)); background->ice_ping(); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); this_thread::sleep_for(chrono::milliseconds(10)); - background->ice_getCachedConnection()->close(Ice::ConnectionClose::Forcefully); + background->ice_getCachedConnection()->abort(); } opThread1->destroy(); diff --git a/cpp/test/Ice/binding/AllTests.cpp b/cpp/test/Ice/binding/AllTests.cpp index a120438b3a4..94d88687a5a 100644 --- a/cpp/test/Ice/binding/AllTests.cpp +++ b/cpp/test/Ice/binding/AllTests.cpp @@ -108,7 +108,7 @@ allTests(Test::TestHelper* helper) test(test2->ice_getConnection() == test3->ice_getConnection()); names.erase(test1->getAdapterName()); - test1->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test1->ice_getConnection()->close().get(); } // @@ -131,7 +131,7 @@ allTests(Test::TestHelper* helper) for (const auto& adapter : adapters) { - adapter->getTestIntf()->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + adapter->getTestIntf()->ice_getConnection()->close().get(); } } @@ -156,7 +156,7 @@ allTests(Test::TestHelper* helper) test(test2->ice_getConnection() == test3->ice_getConnection()); names.erase(test1->getAdapterName()); - test1->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test1->ice_getConnection()->close().get(); } // @@ -243,7 +243,7 @@ allTests(Test::TestHelper* helper) { try { - adapter->getTestIntf()->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + adapter->getTestIntf()->ice_getConnection()->close().get(); } catch (const Ice::LocalException&) { @@ -283,7 +283,7 @@ allTests(Test::TestHelper* helper) test(test2->ice_getConnection() == test3->ice_getConnection()); names.erase(getAdapterNameWithAMI(test1)); - test1->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test1->ice_getConnection()->close().get(); } // @@ -307,7 +307,7 @@ allTests(Test::TestHelper* helper) for (const auto& adapter : adapters) { - adapter->getTestIntf()->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + adapter->getTestIntf()->ice_getConnection()->close().get(); } } @@ -332,7 +332,7 @@ allTests(Test::TestHelper* helper) test(test2->ice_getConnection() == test3->ice_getConnection()); names.erase(test1->getAdapterName()); - test1->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test1->ice_getConnection()->close().get(); } // @@ -364,7 +364,7 @@ allTests(Test::TestHelper* helper) while (!names.empty()) { names.erase(test->getAdapterName()); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); } test = test->ice_endpointSelection(Ice::EndpointSelectionType::Random); @@ -376,7 +376,7 @@ allTests(Test::TestHelper* helper) while (!names.empty()) { names.erase(test->getAdapterName()); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); } deactivate(com, adapters); @@ -405,7 +405,7 @@ allTests(Test::TestHelper* helper) #if TARGET_OS_IPHONE > 0 if (i != nRetry) { - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); for (i = 0; i < nRetry && test->getAdapterName() == "Adapter31"; i++) ; } @@ -417,7 +417,7 @@ allTests(Test::TestHelper* helper) #if TARGET_OS_IPHONE > 0 if (i != nRetry) { - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); for (i = 0; i < nRetry && test->getAdapterName() == "Adapter32"; i++) ; } @@ -429,7 +429,7 @@ allTests(Test::TestHelper* helper) #if TARGET_OS_IPHONE > 0 if (i != nRetry) { - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); for (i = 0; i < nRetry && test->getAdapterName() == "Adapter33"; i++) ; } @@ -461,33 +461,33 @@ allTests(Test::TestHelper* helper) #if TARGET_OS_IPHONE > 0 if (i != nRetry) { - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); for (i = 0; i < nRetry && test->getAdapterName() == "Adapter36"; i++) ; } #endif test(i == nRetry); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); 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(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); for (i = 0; i < nRetry && test->getAdapterName() == "Adapter35"; i++) ; } #endif test(i == nRetry); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); 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(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); for (i = 0; i < nRetry && test->getAdapterName() == "Adapter34"; i++) ; } @@ -809,7 +809,7 @@ allTests(Test::TestHelper* helper) for (i = 0; i < 5; i++) { test(test->getAdapterName() == "Adapter82"); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); } TestIntfPrx testSecure = test->ice_secure(true); @@ -825,7 +825,7 @@ allTests(Test::TestHelper* helper) for (i = 0; i < 5; i++) { test(test->getAdapterName() == "Adapter81"); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); } com->createObjectAdapter("Adapter83", (test->ice_getEndpoints()[1])->toString()); // Reactive tcp OA. @@ -833,7 +833,7 @@ allTests(Test::TestHelper* helper) for (i = 0; i < 5; i++) { test(test->getAdapterName() == "Adapter83"); - test->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + test->ice_getConnection()->close().get(); } com->deactivateObjectAdapter(adapters[0]); diff --git a/cpp/test/Ice/hold/AllTests.cpp b/cpp/test/Ice/hold/AllTests.cpp index fa594d04dbf..7051098260b 100644 --- a/cpp/test/Ice/hold/AllTests.cpp +++ b/cpp/test/Ice/hold/AllTests.cpp @@ -170,7 +170,7 @@ allTests(Test::TestHelper* helper) { completed->get_future().get(); holdSerialized->ice_ping(); // Ensure everything's dispatched - holdSerialized->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + holdSerialized->ice_getConnection()->close().get(); } } completed->get_future().get(); diff --git a/cpp/test/Ice/location/AllTests.cpp b/cpp/test/Ice/location/AllTests.cpp index 5772d7950fa..4160f2d1fc7 100644 --- a/cpp/test/Ice/location/AllTests.cpp +++ b/cpp/test/Ice/location/AllTests.cpp @@ -550,7 +550,7 @@ allTests(Test::TestHelper* helper, const string& ref) cout << "testing object migration... " << flush; hello = HelloPrx(communicator, "hello"); obj->migrateHello(); - hello->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + hello->ice_getConnection()->close().get(); hello->sayHello(); obj->migrateHello(); hello->sayHello(); diff --git a/cpp/test/Ice/metrics/AllTests.cpp b/cpp/test/Ice/metrics/AllTests.cpp index 308628aa872..df9c86face6 100644 --- a/cpp/test/Ice/metrics/AllTests.cpp +++ b/cpp/test/Ice/metrics/AllTests.cpp @@ -233,7 +233,7 @@ namespace { if (proxy->ice_getCachedConnection()) { - proxy->ice_getCachedConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + proxy->ice_getCachedConnection()->close().get(); } try { @@ -244,7 +244,7 @@ namespace } if (proxy->ice_getCachedConnection()) { - proxy->ice_getCachedConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + proxy->ice_getCachedConnection()->close().get(); } } @@ -478,8 +478,8 @@ allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv) if (!collocated) { - metrics->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); - metrics->ice_connectionId("Con1")->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + metrics->ice_getConnection()->close().get(); + metrics->ice_connectionId("Con1")->ice_getConnection()->close().get(); waitForCurrent(clientMetrics, "View", "Connection", 0); waitForCurrent(serverMetrics, "View", "Connection", 0); @@ -594,7 +594,7 @@ allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv) map = toMap(serverMetrics->getMetricsView("View", timestamp)["Connection"]); test(map["holding"]->current == 1); - metrics->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + metrics->ice_getConnection()->close(nullptr, nullptr); map = toMap(clientMetrics->getMetricsView("View", timestamp)["Connection"]); test(map["closing"]->current == 1); @@ -609,7 +609,7 @@ allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv) props["IceMX.Metrics.View.Map.Connection.GroupBy"] = "none"; updateProps(clientProps, serverProps, update.get(), props, "Connection"); - metrics->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + metrics->ice_getConnection()->close().get(); // TODO: this appears necessary on slow macos VMs to give time to the server to clean-up the connection. this_thread::sleep_for(chrono::milliseconds(100)); @@ -638,7 +638,7 @@ allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv) testAttribute(clientMetrics, clientProps, update.get(), "Connection", "mcastHost", ""); testAttribute(clientMetrics, clientProps, update.get(), "Connection", "mcastPort", ""); - m->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + m->ice_getConnection()->close().get(); waitForCurrent(clientMetrics, "View", "Connection", 0); waitForCurrent(serverMetrics, "View", "Connection", 0); @@ -657,7 +657,7 @@ allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv) IceMX::MetricsPtr m1 = clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"][0]; test(m1->current == 0 && m1->total == 1 && m1->id == hostAndPort); - metrics->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + metrics->ice_getConnection()->close().get(); controller->hold(); try { @@ -742,7 +742,7 @@ allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv) try { prx->ice_ping(); - prx->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + prx->ice_getConnection()->close().get(); } catch (const Ice::LocalException&) { diff --git a/cpp/test/Ice/metrics/TestAMDI.cpp b/cpp/test/Ice/metrics/TestAMDI.cpp index a46f78aa10a..760e14128ec 100644 --- a/cpp/test/Ice/metrics/TestAMDI.cpp +++ b/cpp/test/Ice/metrics/TestAMDI.cpp @@ -16,7 +16,7 @@ MetricsI::opAsync(function response, function, cons void MetricsI::failAsync(function response, function, const Ice::Current& current) { - current.con->close(Ice::ConnectionClose::Forcefully); + current.con->abort(); response(); } diff --git a/cpp/test/Ice/metrics/TestI.cpp b/cpp/test/Ice/metrics/TestI.cpp index e410f10a8b6..934dbf1cc1b 100644 --- a/cpp/test/Ice/metrics/TestI.cpp +++ b/cpp/test/Ice/metrics/TestI.cpp @@ -17,7 +17,7 @@ MetricsI::op(const Current&) void MetricsI::fail(const Current& current) { - current.con->close(ConnectionClose::Forcefully); + current.con->abort(); } void diff --git a/cpp/test/Ice/operations/BatchOneways.cpp b/cpp/test/Ice/operations/BatchOneways.cpp index 101a13b1d66..a6dc8f8f8e8 100644 --- a/cpp/test/Ice/operations/BatchOneways.cpp +++ b/cpp/test/Ice/operations/BatchOneways.cpp @@ -104,7 +104,7 @@ batchOneways(const MyClassPrx& p) batch1->ice_ping(); batch2->ice_ping(); batch1->ice_flushBatchRequests(); - batch1->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + batch1->ice_getConnection()->close().get(); batch1->ice_ping(); batch2->ice_ping(); @@ -112,7 +112,7 @@ batchOneways(const MyClassPrx& p) batch2->ice_getConnection(); batch1->ice_ping(); - batch1->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + batch1->ice_getConnection()->close().get(); batch1->ice_ping(); batch2->ice_ping(); } diff --git a/cpp/test/Ice/operations/BatchOnewaysAMI.cpp b/cpp/test/Ice/operations/BatchOnewaysAMI.cpp index 90ee3cdd2a5..b0bd5a9929d 100644 --- a/cpp/test/Ice/operations/BatchOnewaysAMI.cpp +++ b/cpp/test/Ice/operations/BatchOnewaysAMI.cpp @@ -47,7 +47,7 @@ batchOnewaysAMI(const Test::MyClassPrx& p) batch1->ice_pingAsync().get(); batch2->ice_pingAsync().get(); batch1->ice_flushBatchRequestsAsync().get(); - batch1->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + batch1->ice_getConnection()->close().get(); batch1->ice_pingAsync().get(); batch2->ice_pingAsync().get(); @@ -55,7 +55,7 @@ batchOnewaysAMI(const Test::MyClassPrx& p) batch2->ice_getConnection(); batch1->ice_pingAsync().get(); - batch1->ice_getConnection()->close(Ice::ConnectionClose::GracefullyWithWait); + batch1->ice_getConnection()->close().get(); batch1->ice_pingAsync().get(); batch2->ice_pingAsync().get(); diff --git a/cpp/test/Ice/retry/TestI.cpp b/cpp/test/Ice/retry/TestI.cpp index 6dfe6b9a4b4..be3524b4618 100644 --- a/cpp/test/Ice/retry/TestI.cpp +++ b/cpp/test/Ice/retry/TestI.cpp @@ -18,7 +18,7 @@ RetryI::op(bool kill, const Ice::Current& current) { if (current.con) { - current.con->close(Ice::ConnectionClose::Forcefully); + current.con->abort(); } else { diff --git a/cpp/test/Ice/timeout/AllTests.cpp b/cpp/test/Ice/timeout/AllTests.cpp index d433e6382b2..50283bdc9c8 100644 --- a/cpp/test/Ice/timeout/AllTests.cpp +++ b/cpp/test/Ice/timeout/AllTests.cpp @@ -156,7 +156,7 @@ allTestsWithController(Test::TestHelper* helper, const ControllerPrx& controller { Ice::ConnectionPtr connection = connect(timeout); controller->holdAdapter(-1); - connection->close(Ice::ConnectionClose::GracefullyWithWait); + connection->close(nullptr, nullptr); try { connection->getInfo(); // getInfo() doesn't throw in the closing state. diff --git a/cpp/test/Ice/udp/AllTests.cpp b/cpp/test/Ice/udp/AllTests.cpp index c5fdb3a8e41..ef8c205c744 100644 --- a/cpp/test/Ice/udp/AllTests.cpp +++ b/cpp/test/Ice/udp/AllTests.cpp @@ -96,7 +96,7 @@ allTests(Test::TestHelper* helper) { test(seq.size() > 16384); } - obj->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + obj->ice_getConnection()->close().get(); communicator->getProperties()->setProperty("Ice.UDP.SndSize", "64000"); seq.resize(50000); try diff --git a/cpp/test/IceBridge/simple/AllTests.cpp b/cpp/test/IceBridge/simple/AllTests.cpp index 62aef2c90cf..c0cb6d226a1 100644 --- a/cpp/test/IceBridge/simple/AllTests.cpp +++ b/cpp/test/IceBridge/simple/AllTests.cpp @@ -111,7 +111,7 @@ allTests(Test::TestHelper* helper) test(cl->getConnectionCount() == 2); test(cl->ice_connectionId("other")->getConnectionInfo() != cl->getConnectionInfo()); test(cl->getConnectionCount() == 3); - cl->ice_connectionId("other")->ice_getConnection()->close(Ice::ConnectionClose::Gracefully); + cl->ice_connectionId("other")->ice_getConnection()->close(nullptr, nullptr); nRetry = 20; while (cl->getConnectionCount() != 2 && --nRetry > 0) { diff --git a/cpp/test/IceBridge/simple/TestI.cpp b/cpp/test/IceBridge/simple/TestI.cpp index f50cb3b7de4..8dd11109185 100644 --- a/cpp/test/IceBridge/simple/TestI.cpp +++ b/cpp/test/IceBridge/simple/TestI.cpp @@ -85,11 +85,11 @@ MyClassI::closeConnection(bool forceful, const Ice::Current& current) checkConnection(current.con); if (forceful) { - current.con->close(Ice::ConnectionClose::Forcefully); + current.con->abort(); } else { - current.con->close(Ice::ConnectionClose::Gracefully); + current.con->close(nullptr, nullptr); } } diff --git a/cpp/test/IceSSL/configuration/AllTests.cpp b/cpp/test/IceSSL/configuration/AllTests.cpp index 9ba5c44ba13..a46a9f0bb3b 100644 --- a/cpp/test/IceSSL/configuration/AllTests.cpp +++ b/cpp/test/IceSSL/configuration/AllTests.cpp @@ -431,7 +431,7 @@ allTests(Test::TestHelper* helper, const string& /*testDir*/, bool p12) try { server->noCert(); - server->ice_getConnection()->close(ConnectionClose::GracefullyWithWait); + server->ice_getConnection()->close().get(); server->noCert(); } catch (const LocalException& ex) diff --git a/cpp/test/IceStorm/stress/Subscriber.cpp b/cpp/test/IceStorm/stress/Subscriber.cpp index bd4adbc7e4c..c9a4990a342 100644 --- a/cpp/test/IceStorm/stress/Subscriber.cpp +++ b/cpp/test/IceStorm/stress/Subscriber.cpp @@ -121,7 +121,7 @@ class ErraticEventI final : public EventI if (!_done && (_rd() % 10 == 1 || ++_count == _total)) { _done = true; - current.con->close(ConnectionClose::Forcefully); + current.con->abort(); // Deactivate the OA. This ensures that the subscribers // that have subscribed with oneway QoS will be booted. current.adapter->deactivate(); diff --git a/matlab/lib/+Ice/Connection.m b/matlab/lib/+Ice/Connection.m index a7fd7a2d9f3..1078be0d6b2 100644 --- a/matlab/lib/+Ice/Connection.m +++ b/matlab/lib/+Ice/Connection.m @@ -44,29 +44,19 @@ r = obj.iceCallWithResult('equals', other.impl_); end end - function close(obj, mode) - % close Manually close the connection using the specified - % closure mode. + function abort(obj) + % abort Aborts this connection. % - % Parameters: - % mode (Ice.ConnectionClose) - Determines how the connection - % will be closed. - obj.iceCall('close', mode); + obj.iceCall('abort'); end - function f = closeAsync(obj) - % closeAsync Manually close the connection using the specified - % closure mode. - % - % Parameters: - % mode (Ice.ConnectionClose) - Determines how the connection - % will be closed. + function f = close(obj) + % close Closes the connection gracefully after waiting for all outstanding invocations to complete. % - % Returns (Ice.Future) - A future that will be completed when the - % invocation completes. + % Returns (Ice.Future) - A future that completes when the connnection is closed. future = libpointer('voidPtr'); - obj.iceCall('closeAsync', future); + obj.iceCall('close', future); assert(~isNull(future)); f = Ice.Future(future, 'close', 0, 'Ice_SimpleFuture', @(fut) fut.iceCall('check')); end diff --git a/matlab/lib/+Ice/ConnectionClose.m b/matlab/lib/+Ice/ConnectionClose.m deleted file mode 100644 index f1f3fd83bf7..00000000000 --- a/matlab/lib/+Ice/ConnectionClose.m +++ /dev/null @@ -1,23 +0,0 @@ -% ConnectionClose Summary of ConnectionClose -% -% Determines the behavior when manually closing a connection. -% -% ConnectionClose Properties: -% Forcefully - Close the connection immediately without sending a close connection protocol message to the peer and waiting for the peer to acknowledge it. -% Gracefully - Close the connection by notifying the peer but do not wait for pending outgoing invocations to complete. -% GracefullyWithWait - Wait for all pending invocations to complete before closing the connection. - -% Copyright (c) ZeroC, Inc. All rights reserved. - -classdef ConnectionClose < uint8 - enumeration - % Close the connection immediately without sending a close connection protocol message to the peer and waiting - % for the peer to acknowledge it. - Forcefully (0) - % Close the connection by notifying the peer but do not wait for pending outgoing invocations to complete. On the - % server side, the connection will not be closed until all incoming invocations have completed. - Gracefully (1) - % Wait for all pending invocations to complete before closing the connection. - GracefullyWithWait (2) - end -end diff --git a/matlab/src/Connection.cpp b/matlab/src/Connection.cpp index 0e5720f1978..7c4b334dc86 100644 --- a/matlab/src/Connection.cpp +++ b/matlab/src/Connection.cpp @@ -145,43 +145,23 @@ extern "C" } } - mxArray* Ice_Connection_close(void* self, mxArray* m) + mxArray* Ice_Connection_abort(void* self) { - try - { - auto mode = static_cast(getEnumerator(m, "Ice.ConnectionClose")); - deref(self)->close(mode); - } - catch (...) - { - return convertException(std::current_exception()); - } - return 0; + deref(self)->abort(); + return nullptr; } - mxArray* Ice_Connection_closeAsync(void* self, mxArray* m, void** future) + mxArray* Ice_Connection_close(void* self, void** future) { - *future = 0; - auto c = deref(self); - auto f = make_shared(); + auto connection = deref(self); - thread t( - [m, c, f] - { - try - { - auto mode = static_cast(getEnumerator(m, "Ice.ConnectionClose")); - c->close(mode); - f->done(); - } - catch (const std::exception&) - { - f->exception(current_exception()); - } - }); - t.detach(); - *future = new shared_ptr(move(f)); - return 0; + auto futurePtr = make_shared(); + connection->close( + [futurePtr]() { futurePtr->done(); }, + [futurePtr](exception_ptr closeException) { futurePtr->exception(closeException); }); + + *future = new shared_ptr(move(futurePtr)); + return nullptr; } mxArray* Ice_Connection_createProxy(void* self, mxArray* id, void** r) diff --git a/matlab/src/ice.h b/matlab/src/ice.h index 728a8bd0df2..bf25823e8af 100644 --- a/matlab/src/ice.h +++ b/matlab/src/ice.h @@ -160,8 +160,8 @@ extern "C" ICE_MATLAB_API mxArray* Ice_Connection_unref(void*); ICE_MATLAB_API mxArray* Ice_Connection_equals(void*, void*); - ICE_MATLAB_API mxArray* Ice_Connection_close(void*, mxArray*); - ICE_MATLAB_API mxArray* Ice_Connection_closeAsync(void*, mxArray*, void**); + ICE_MATLAB_API mxArray* Ice_Connection_abort(void*); + ICE_MATLAB_API mxArray* Ice_Connection_close(void*, void**); ICE_MATLAB_API mxArray* Ice_Connection_createProxy(void*, mxArray*, void**); ICE_MATLAB_API mxArray* Ice_Connection_flushBatchRequests(void*, mxArray*); ICE_MATLAB_API mxArray* Ice_Connection_flushBatchRequestsAsync(void*, mxArray*, void**); diff --git a/matlab/test/Ice/ami/AllTests.m b/matlab/test/Ice/ami/AllTests.m index e0caae4dfb2..dc78df4006f 100644 --- a/matlab/test/Ice/ami/AllTests.m +++ b/matlab/test/Ice/ami/AllTests.m @@ -156,7 +156,7 @@ function allTests(helper) fprintf('ok\n'); if ~isempty(p.ice_getConnection()) && p.supportsAMD() - fprintf('testing graceful close connection with wait... '); + fprintf('testing connection close... '); % % Local case: begin a request, close the connection gracefully, and make sure it waits @@ -164,7 +164,7 @@ function allTests(helper) % con = p.ice_getConnection(); f = p.sleepAsync(100); - con.close(Ice.ConnectionClose.GracefullyWithWait); % Blocks until the request completes. + con.close().fetchOutputs(); try f.fetchOutputs(); % Should complete successfully catch ex @@ -173,41 +173,7 @@ function allTests(helper) fprintf('ok\n'); - fprintf('testing graceful close connection without wait... '); - - % - % Local case: start an 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 ConnectionClosedException. - % - p = p.ice_connectionId('CloseGracefully'); % Start with a new connection. - con = p.ice_getConnection(); - f = p.startDispatchAsync(); - while ~strcmp(f.State, 'sent') % Ensure the request was sent before we close the connection - pause(0.1); - end - con.close(Ice.ConnectionClose.Gracefully); - try - f.fetchOutputs(); - assert(false); - catch ex - assert(isa(ex, 'Ice.ConnectionClosedException')); - assert(ex.closedByApplication); - end - p.finishDispatch(); - - % - % Remote case: the server closes the connection gracefully, which means the connection - % will not be closed until all pending dispatched requests have completed. - % - con = p.ice_getConnection(); - f = p.sleepAsync(100); - p.close(CloseMode.Gracefully); % Close is delayed until sleep completes. - f.fetchOutputs(); - - fprintf('ok\n'); - - fprintf('testing forceful close connection... '); + fprintf('testing connection abort... '); % % Local case: start an operation and then close the connection forcefully on the client side. @@ -219,7 +185,7 @@ function allTests(helper) while ~strcmp(f.State, 'sent') % Ensure the request was sent before we close the connection pause(0.1); end - con.close(Ice.ConnectionClose.Forcefully); + con.abort(); try f.fetchOutputs(); assert(false); diff --git a/matlab/test/Ice/binding/AllTests.m b/matlab/test/Ice/binding/AllTests.m index a991d308c71..4f2fd284bc9 100644 --- a/matlab/test/Ice/binding/AllTests.m +++ b/matlab/test/Ice/binding/AllTests.m @@ -98,7 +98,7 @@ function allTests(helper) if ~isempty(pos) names(pos) = []; % Using the () syntax removes the element from the cell array. end - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test1.ice_getConnection().close().fetchOutputs(); end % @@ -119,7 +119,7 @@ function allTests(helper) assert(i == nRetry); for i = 1:length(adapters) - adapters{i}.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + adapters{i}.getTestIntf().ice_getConnection().close().fetchOutputs(); end % @@ -145,7 +145,7 @@ function allTests(helper) if ~isempty(pos) names(pos) = []; % Using the () syntax removes the element from the cell array. end - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test1.ice_getConnection().close().fetchOutputs(); end % @@ -232,7 +232,7 @@ function allTests(helper) for i = 1:length(adapters) try - adapters{i}.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + adapters{i}.getTestIntf().ice_getConnection().close().fetchOutputs(); catch ex if isa(ex, 'Ice.LocalException') % Expected if adapter is down. @@ -273,7 +273,7 @@ function allTests(helper) if ~isempty(pos) names(pos) = []; % Using the () syntax removes the element from the cell array. end - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test1.ice_getConnection().close().fetchOutputs(); end % @@ -294,7 +294,7 @@ function allTests(helper) assert(i == nRetry); for i = 1:length(adapters) - adapters{i}.getTestIntf().ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + adapters{i}.getTestIntf().ice_getConnection().close().fetchOutputs(); end % @@ -320,7 +320,7 @@ function allTests(helper) if ~isempty(pos) names(pos) = []; % Using the () syntax removes the element from the cell array. end - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test1.ice_getConnection().close().fetchOutputs(); end % @@ -351,7 +351,7 @@ function allTests(helper) if ~isempty(pos) names(pos) = []; % Using the () syntax removes the element from the cell array. end - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); end test = test.ice_endpointSelection(Ice.EndpointSelectionType.Random); @@ -363,7 +363,7 @@ function allTests(helper) if ~isempty(pos) names(pos) = []; % Using the () syntax removes the element from the cell array. end - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); end AllTests.deactivate(rcom, adapters); @@ -436,14 +436,14 @@ function allTests(helper) i = i + 1; end assert(i == nRetry); - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); adapters{end + 1} = rcom.createObjectAdapter('Adapter35', endpoints{2}.toString()); i = 0; while i < nRetry && strcmp(test.getAdapterName(), 'Adapter35') i = i + 1; end assert(i == nRetry); - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); adapters{end + 1} = rcom.createObjectAdapter('Adapter34', endpoints{1}.toString()); i = 0; while i < nRetry && strcmp(test.getAdapterName(), 'Adapter34') @@ -764,7 +764,7 @@ function allTests(helper) test = AllTests.createTestIntfPrx(adapters); for i = 1:5 assert(strcmp(test.getAdapterName(), 'Adapter82')); - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); end testSecure = test.ice_secure(true); @@ -779,7 +779,7 @@ function allTests(helper) for i = 1:5 assert(strcmp(test.getAdapterName(), 'Adapter81')); - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); end endpts = test.ice_getEndpoints(); @@ -787,7 +787,7 @@ function allTests(helper) for i = 1:5 assert(strcmp(test.getAdapterName(), 'Adapter83')); - test.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + test.ice_getConnection().close().fetchOutputs(); end rcom.deactivateObjectAdapter(adapters{1}); diff --git a/matlab/test/Ice/operations/BatchOneways.m b/matlab/test/Ice/operations/BatchOneways.m index df6acafa2b2..167f3bea40f 100644 --- a/matlab/test/Ice/operations/BatchOneways.m +++ b/matlab/test/Ice/operations/BatchOneways.m @@ -46,7 +46,7 @@ function batchOneways(helper, p) batch1.ice_ping(); batch2.ice_ping(); batch1.ice_flushBatchRequests(); - batch1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + batch1.ice_getConnection().close().fetchOutputs(); batch1.ice_ping(); batch2.ice_ping(); @@ -54,7 +54,7 @@ function batchOneways(helper, p) batch2.ice_getConnection(); batch1.ice_ping(); - batch1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + batch1.ice_getConnection().close().fetchOutputs(); batch1.ice_ping(); batch2.ice_ping(); end diff --git a/matlab/test/Ice/operations/BatchOnewaysAMI.m b/matlab/test/Ice/operations/BatchOnewaysAMI.m index b12e31a9f0f..d0851c4311a 100644 --- a/matlab/test/Ice/operations/BatchOnewaysAMI.m +++ b/matlab/test/Ice/operations/BatchOnewaysAMI.m @@ -32,7 +32,7 @@ function batchOneways(p) batch.ice_pingAsync(); batch2.ice_pingAsync(); assert(batch.ice_flushBatchRequestsAsync().wait()); - batch.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + batch.ice_getConnection().close().fetchOutputs(); batch.ice_pingAsync(); batch2.ice_pingAsync(); @@ -40,7 +40,7 @@ function batchOneways(p) batch2.ice_getConnection(); batch.ice_pingAsync(); - batch.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait); + batch.ice_getConnection().close().fetchOutputs(); assert(batch.ice_pingAsync().wait()); assert(batch2.ice_pingAsync().wait()); end diff --git a/php/lib/Ice.php b/php/lib/Ice.php index 07d4bce6163..6efc71485b1 100644 --- a/php/lib/Ice.php +++ b/php/lib/Ice.php @@ -24,7 +24,6 @@ require_once 'Ice/BuiltinSequences.php'; require_once 'Ice/CompressBatch.php'; -require_once 'Ice/ConnectionClose.php'; require_once 'Ice/EndpointSelectionType.php'; require_once 'Ice/EndpointTypes.php'; require_once 'Ice/Identity.php'; diff --git a/php/lib/Ice/ConnectionClose.php b/php/lib/Ice/ConnectionClose.php deleted file mode 100644 index e75ac624629..00000000000 --- a/php/lib/Ice/ConnectionClose.php +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/php/src/Connection.cpp b/php/src/Connection.cpp index fd3de817af4..04da2ed66fc 100644 --- a/php/src/Connection.cpp +++ b/php/src/Connection.cpp @@ -65,31 +65,32 @@ ZEND_METHOD(Ice_Connection, __toString) } } -ZEND_BEGIN_ARG_INFO_EX(Ice_Connection_close_arginfo, 1, ZEND_RETURN_VALUE, static_cast(1)) -ZEND_ARG_INFO(0, mode) -ZEND_END_ARG_INFO() - -ZEND_METHOD(Ice_Connection, close) +ZEND_METHOD(Ice_Connection, abort) { + if (ZEND_NUM_ARGS() > 0) + { + WRONG_PARAM_COUNT; + } + Ice::ConnectionPtr _this = Wrapper::value(getThis()); assert(_this); - zval* mode; - if (zend_parse_parameters(ZEND_NUM_ARGS(), const_cast("z"), &mode) != SUCCESS) - { - RETURN_NULL(); - } + _this->abort(); +} - if (Z_TYPE_P(mode) != IS_LONG) +ZEND_METHOD(Ice_Connection, close) +{ + if (ZEND_NUM_ARGS() > 0) { - invalidArgument("value for 'mode' argument must be an enumerator of ConnectionClose"); - RETURN_NULL(); + WRONG_PARAM_COUNT; } - Ice::ConnectionClose cc = static_cast(Z_LVAL_P(mode)); + Ice::ConnectionPtr _this = Wrapper::value(getThis()); + assert(_this); + try { - _this->close(cc); + _this->close().get(); } catch (...) { @@ -301,14 +302,17 @@ static zend_function_entry _connectionClassMethods[] = { ZEND_ME(Ice_Connection, __construct, ice_void_arginfo, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR) // __toString ZEND_ME(Ice_Connection, __toString, ice_to_string_arginfo, ZEND_ACC_PUBLIC) + // abort + ZEND_ME(Ice_Connection, abort, ice_void_arginfo, ZEND_ACC_PUBLIC) // close - ZEND_ME(Ice_Connection, close, Ice_Connection_close_arginfo, ZEND_ACC_PUBLIC) + ZEND_ME(Ice_Connection, close, ice_void_arginfo, ZEND_ACC_PUBLIC) // getEndpoint ZEND_ME(Ice_Connection, getEndpoint, ice_void_arginfo, ZEND_ACC_PUBLIC) // flushBatchRequests ZEND_ME(Ice_Connection, flushBatchRequests, Ice_Connection_flushBatchRequests_arginfo, ZEND_ACC_PUBLIC) // type ZEND_ME(Ice_Connection, type, ice_void_arginfo, ZEND_ACC_PUBLIC) + // toString ZEND_ME(Ice_Connection, toString, ice_void_arginfo, ZEND_ACC_PUBLIC) // getInfo diff --git a/php/test/Ice/binding/Client.php b/php/test/Ice/binding/Client.php index 1c75b8936f0..c7420b8ab70 100644 --- a/php/test/Ice/binding/Client.php +++ b/php/test/Ice/binding/Client.php @@ -100,7 +100,7 @@ function allTests($helper) { unset($names[$key]); } - $test1->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test1->ice_getConnection()->close(); } // @@ -121,7 +121,7 @@ function allTests($helper) foreach($adapters as $p) { - $p->getTestIntf()->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $p->getTestIntf()->ice_getConnection()->close(); } } @@ -149,7 +149,7 @@ function allTests($helper) { unset($names[$key]); } - $test1->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test1->ice_getConnection()->close(); } // @@ -183,7 +183,7 @@ function allTests($helper) { unset($names[$key]); } - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); } $test = $test->ice_endpointSelection(Ice\EndpointSelectionType::Random); @@ -197,7 +197,7 @@ function allTests($helper) { unset($names[$key]); } - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); } deactivate($com, $adapters); @@ -254,11 +254,11 @@ function allTests($helper) $adapters[] = $com->createObjectAdapter("Adapter36", $endpoints[2]->toString()); for($i = 0; $i < $nRetry && $test->getAdapterName() == "Adapter36"; $i++); test($i == $nRetry); - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); $adapters[] = $com->createObjectAdapter("Adapter35", $endpoints[1]->toString()); for($i = 0; $i < $nRetry && $test->getAdapterName() == "Adapter35"; $i++); test($i == $nRetry); - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); $adapters[] = $com->createObjectAdapter("Adapter34", $endpoints[0]->toString()); for($i = 0; $i < $nRetry && $test->getAdapterName() == "Adapter34"; $i++); test($i == $nRetry); @@ -440,7 +440,7 @@ function allTests($helper) for($i = 0; $i < 5; $i++) { test($test->getAdapterName() == "Adapter82"); - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); } $testSecure = $test->ice_secure(true); @@ -456,7 +456,7 @@ function allTests($helper) for($i = 0; $i < 5; $i++) { test($test->getAdapterName() == "Adapter81"); - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); } $endpts = $test->ice_getEndpoints(); @@ -465,7 +465,7 @@ function allTests($helper) for($i = 0; $i < 5; $i++) { test($test->getAdapterName() == "Adapter83"); - $test->ice_getConnection()->close(Ice\ConnectionClose::GracefullyWithWait); + $test->ice_getConnection()->close(); } $com->deactivateObjectAdapter($adapters[0]); diff --git a/python/modules/IcePy/Connection.cpp b/python/modules/IcePy/Connection.cpp index a0801b9f5eb..d05d2fc4033 100644 --- a/python/modules/IcePy/Connection.cpp +++ b/python/modules/IcePy/Connection.cpp @@ -193,24 +193,49 @@ connectionHash(ConnectionObject* self) } extern "C" PyObject* -connectionClose(ConnectionObject* self, PyObject* args) +connectionAbort(ConnectionObject* self, PyObject* /* args */) { - PyObject* closeType = lookupType("Ice.ConnectionClose"); - PyObject* mode; - if (!PyArg_ParseTuple(args, "O!", closeType, &mode)) + assert(self->connection); + try + { + AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations. + (*self->connection)->abort(); + } + catch (...) { + setPythonException(current_exception()); return nullptr; } - PyObjectHandle v{getAttr(mode, "_value", true)}; - assert(v.get()); - Ice::ConnectionClose cc = static_cast(PyLong_AsLong(v.get())); + return Py_None; +} + +extern "C" PyObject* +connectionClose(ConnectionObject* self, PyObject* args) +{ + // TODO: temporary. For now True = wait (default) and False = don't wait. + + bool waitForClose = true; + + PyObject* flag = nullptr; + if (!PyArg_ParseTuple(args, "|O", &flag)) + { + return nullptr; + } + if (flag) + { + waitForClose = PyObject_IsTrue(flag) == 1; + } assert(self->connection); try { AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations. - (*self->connection)->close(cc); + auto future = (*self->connection)->close(); + if (waitForClose) + { + future.get(); + } } catch (...) { @@ -545,10 +570,8 @@ connectionThrowException(ConnectionObject* self, PyObject* /*args*/) } static PyMethodDef ConnectionMethods[] = { - {"close", - reinterpret_cast(connectionClose), - METH_VARARGS, - PyDoc_STR("close(Ice.ConnectionClose) -> None")}, + {"abort", reinterpret_cast(connectionAbort), METH_NOARGS, PyDoc_STR("abort() -> None")}, + {"close", reinterpret_cast(connectionClose), METH_VARARGS, PyDoc_STR("close(bool) -> None")}, {"createProxy", reinterpret_cast(connectionCreateProxy), METH_VARARGS, diff --git a/python/python/Ice/ConnectionClose.py b/python/python/Ice/ConnectionClose.py deleted file mode 100644 index fc69436cb6e..00000000000 --- a/python/python/Ice/ConnectionClose.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) ZeroC, Inc. All rights reserved. - -from .EnumBase import EnumBase - -__name__ = "Ice" - -class ConnectionClose(EnumBase): - """ - Determines the behavior when manually closing a connection. - - Enumerators - ----------- - Forcefully : ConnectionClose - Close the connection immediately without sending a close connection protocol message to the peer and - waiting for the peer to acknowledge it. - Gracefully : ConnectionClose - Close the connection by notifying the peer but do not wait for pending outgoing invocations to complete. - On the server side, the connection will not be closed until all incoming invocations have completed. - GracefullyWithWait : ConnectionClose - Wait for all pending invocations to complete before closing the connection. - """ - - def __init__(self, _n, _v): - super().__init__(_n, _v) - - def valueOf(self, value): - """ - Get the enumerator corresponding to the given value. - - Parameters - ---------- - value : int - The enumerator's value. - - Returns - ------- - ConnectionClose or None - The enumerator corresponding to the given value, or None if no such enumerator exists. - """ - return self._enumerators[value] if value in self._enumerators else None - - valueOf = classmethod(valueOf) - - -ConnectionClose.Forcefully = ConnectionClose("Forcefully", 0) -ConnectionClose.Gracefully = ConnectionClose("Gracefully", 1) -ConnectionClose.GracefullyWithWait = ConnectionClose("GracefullyWithWait", 2) -ConnectionClose._enumerators = { - 0: ConnectionClose.Forcefully, - 1: ConnectionClose.Gracefully, - 2: ConnectionClose.GracefullyWithWait, -} diff --git a/python/python/Ice/__init__.py b/python/python/Ice/__init__.py index 9912497093f..227338ef0a7 100644 --- a/python/python/Ice/__init__.py +++ b/python/python/Ice/__init__.py @@ -56,7 +56,6 @@ from .EndpointSelectionType import * from .ObjectAdapter import * from .ValueFactory import * -from .ConnectionClose import * from .CompressBatch import CompressBatch from .ServantLocator import * from .InitializationData import * diff --git a/python/test/Ice/ami/AllTests.py b/python/test/Ice/ami/AllTests.py index d7680af23d1..ca664f5c191 100644 --- a/python/test/Ice/ami/AllTests.py +++ b/python/test/Ice/ami/AllTests.py @@ -6,6 +6,7 @@ import IcePy import Test import sys +import time import threading import random @@ -419,25 +420,26 @@ def allTests(helper, communicator, collocated): p = Test.TestIntfPrx(communicator, f"test:{helper.getTestEndpoint(num=0)}") if p.ice_getConnection() and p.supportsAMD(): - sys.stdout.write("testing graceful close connection without wait... ") + sys.stdout.write("testing close connection... ") sys.stdout.flush() # - # Local case: start an 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 ConnectionClosedException. + # Local case: begin a request, close the connection gracefully, and make sure it waits + # for the request to complete. # p = p.ice_connectionId("CloseGracefully") # Start with a new connection. con = p.ice_getConnection() + cb = CallbackBase() + con.setCloseCallback(lambda c: cb.called()) f = p.startDispatchAsync() f.sent() # Ensure the request was sent before we close the connection. - con.close(Ice.ConnectionClose.Gracefully) - try: - f.result() - test(False) - except Ice.ConnectionClosedException as ex: - test(ex.closedByApplication) + con.close(False) + + # give time for startDispatch to start in the server before we call finishDispatch + time.sleep(0.1) # 100ms p.finishDispatch() + f.result() + cb.check() # # Remote case: the server closes the connection gracefully, which means the connection @@ -456,7 +458,7 @@ def allTests(helper, communicator, collocated): print("ok") - sys.stdout.write("testing forceful close connection... ") + sys.stdout.write("testing abort connection... ") sys.stdout.flush() # @@ -467,7 +469,7 @@ def allTests(helper, communicator, collocated): con = p.ice_getConnection() f = p.startDispatchAsync() f.sent() # Ensure the request was sent before we close the connection. - con.close(Ice.ConnectionClose.Forcefully) + con.abort() try: f.result() test(False) @@ -800,7 +802,7 @@ def allTestsFuture(helper, communicator, collocated): test(p.opBatchCount() == 0) b1 = p.ice_batchOneway() b1.opBatch() - b1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + b1.ice_getConnection().close() cb = FutureFlushCallback() f = b1.ice_flushBatchRequestsAsync() f.add_sent_callback(cb.sent) @@ -838,7 +840,7 @@ def allTestsFuture(helper, communicator, collocated): p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway() ) b1.opBatch() - b1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + b1.ice_getConnection().close() cb = FutureFlushExCallback() f = b1.ice_getConnection().flushBatchRequestsAsync( Ice.CompressBatch.BasedOnProxy @@ -881,7 +883,7 @@ def allTestsFuture(helper, communicator, collocated): p.ice_getConnection().createProxy(p.ice_getIdentity()).ice_batchOneway() ) b1.opBatch() - b1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + b1.ice_getConnection().close() cb = FutureFlushCallback() f = communicator.flushBatchRequestsAsync(Ice.CompressBatch.BasedOnProxy) f.add_sent_callback(cb.sent) @@ -937,7 +939,7 @@ def allTestsFuture(helper, communicator, collocated): b2.ice_getConnection() # Ensure connection is established. b1.opBatch() b2.opBatch() - b1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + b1.ice_getConnection().close() cb = FutureFlushCallback() f = communicator.flushBatchRequestsAsync(Ice.CompressBatch.BasedOnProxy) f.add_sent_callback(cb.sent) @@ -965,8 +967,8 @@ def allTestsFuture(helper, communicator, collocated): b2.ice_getConnection() # Ensure connection is established. b1.opBatch() b2.opBatch() - b1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) - b2.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + b1.ice_getConnection().close() + b2.ice_getConnection().close() cb = FutureFlushCallback() f = communicator.flushBatchRequestsAsync(Ice.CompressBatch.BasedOnProxy) f.add_sent_callback(cb.sent) diff --git a/python/test/Ice/ami/TestI.py b/python/test/Ice/ami/TestI.py index c943171446b..8da06eb18ce 100644 --- a/python/test/Ice/ami/TestI.py +++ b/python/test/Ice/ami/TestI.py @@ -45,7 +45,10 @@ def waitForBatch(self, count, current): return result def close(self, mode, current): - current.con.close(Ice.ConnectionClose.valueOf(mode.value)) + if mode == Test.CloseMode.Forcefully: + current.con.abort() + else: + current.con.close(False) def sleep(self, ms, current): time.sleep(ms / 1000.0) diff --git a/python/test/Ice/binding/AllTests.py b/python/test/Ice/binding/AllTests.py index 84238275fdf..dbe806c9829 100644 --- a/python/test/Ice/binding/AllTests.py +++ b/python/test/Ice/binding/AllTests.py @@ -110,7 +110,7 @@ def allTests(helper, communicator): name = test1.getAdapterName() if names.count(name) > 0: names.remove(name) - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + test1.ice_getConnection().close() # # Ensure that the proxy correctly caches the connection (we @@ -128,9 +128,7 @@ def allTests(helper, communicator): test(i == nRetry) for a in adapters: - a.getTestIntf().ice_getConnection().close( - Ice.ConnectionClose.GracefullyWithWait - ) + a.getTestIntf().ice_getConnection().close() # # Deactivate an adapter and ensure that we can still @@ -154,7 +152,7 @@ def allTests(helper, communicator): name = test1.getAdapterName() if names.count(name) > 0: names.remove(name) - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + test1.ice_getConnection().close() # # Deactivate an adapter and ensure that we can still @@ -196,7 +194,7 @@ def allTests(helper, communicator): name = getAdapterNameWithAMI(test1) if names.count(name) > 0: names.remove(name) - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + test1.ice_getConnection().close() # # Ensure that the proxy correctly caches the connection (we @@ -214,9 +212,7 @@ def allTests(helper, communicator): test(i == nRetry) for a in adapters: - a.getTestIntf().ice_getConnection().close( - Ice.ConnectionClose.GracefullyWithWait - ) + a.getTestIntf().ice_getConnection().close() # # Deactivate an adapter and ensure that we can still @@ -240,7 +236,7 @@ def allTests(helper, communicator): name = getAdapterNameWithAMI(test1) if names.count(name) > 0: names.remove(name) - test1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + test1.ice_getConnection().close() # # Deactivate an adapter and ensure that we can still @@ -270,7 +266,7 @@ def allTests(helper, communicator): name = t.getAdapterName() if names.count(name) > 0: names.remove(name) - t.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() t = t.ice_endpointSelection(Ice.EndpointSelectionType.Random) test(t.ice_getEndpointSelection() == Ice.EndpointSelectionType.Random) @@ -282,7 +278,7 @@ def allTests(helper, communicator): name = t.getAdapterName() if names.count(name) > 0: names.remove(name) - t.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() deactivate(com, adapters) @@ -341,13 +337,13 @@ def allTests(helper, communicator): while i < nRetry and t.getAdapterName() == "Adapter36": i = i + 1 test(i == nRetry) - t.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() 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(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() adapters.append(com.createObjectAdapter("Adapter34", endpoints[0].toString())) i = 0 while i < nRetry and t.getAdapterName() == "Adapter34": @@ -624,7 +620,7 @@ def allTests(helper, communicator): t = createTestIntfPrx(adapters) for i in range(0, 5): test(t.getAdapterName() == "Adapter82") - t.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() testSecure = t.ice_secure(True) test(testSecure.ice_isSecure()) @@ -638,7 +634,7 @@ def allTests(helper, communicator): for i in range(0, 5): test(t.getAdapterName() == "Adapter81") - t.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() com.createObjectAdapter( "Adapter83", (t.ice_getEndpoints()[1]).toString() @@ -646,7 +642,7 @@ def allTests(helper, communicator): for i in range(0, 5): test(t.getAdapterName() == "Adapter83") - t.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + t.ice_getConnection().close() com.deactivateObjectAdapter(adapters[0]) try: diff --git a/python/test/Ice/current/AllTests.py b/python/test/Ice/current/AllTests.py index 5d3dea8033c..5de699b8db7 100644 --- a/python/test/Ice/current/AllTests.py +++ b/python/test/Ice/current/AllTests.py @@ -60,7 +60,7 @@ def allTests(helper, communicator, collocated): if collocated: test(7 == proxy.getRequestId()) else: - proxy.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + proxy.ice_getConnection().close() test(1 == proxy.getRequestId()) print("ok") diff --git a/python/test/Ice/location/AllTests.py b/python/test/Ice/location/AllTests.py index f7b925149b3..dc816c41ba7 100644 --- a/python/test/Ice/location/AllTests.py +++ b/python/test/Ice/location/AllTests.py @@ -205,7 +205,7 @@ def allTests(helper, communicator): sys.stdout.flush() hello = Test.HelloPrx(communicator, "hello") obj.migrateHello() - hello.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + hello.ice_getConnection().close() hello.sayHello() obj.migrateHello() hello.sayHello() diff --git a/python/test/Ice/operations/BatchOneways.py b/python/test/Ice/operations/BatchOneways.py index f06dffa415a..9eeedac04a1 100644 --- a/python/test/Ice/operations/BatchOneways.py +++ b/python/test/Ice/operations/BatchOneways.py @@ -77,7 +77,7 @@ def batchOneways(p): batch1.ice_ping() batch2.ice_ping() batch1.ice_flushBatchRequests() - batch1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + batch1.ice_getConnection().close() batch1.ice_ping() batch2.ice_ping() @@ -85,7 +85,7 @@ def batchOneways(p): batch2.ice_getConnection() batch1.ice_ping() - batch1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + batch1.ice_getConnection().close() batch1.ice_ping() batch2.ice_ping() diff --git a/python/test/Ice/operations/BatchOnewaysFuture.py b/python/test/Ice/operations/BatchOnewaysFuture.py index b558c596694..51a02265b38 100644 --- a/python/test/Ice/operations/BatchOnewaysFuture.py +++ b/python/test/Ice/operations/BatchOnewaysFuture.py @@ -56,7 +56,7 @@ def batchOneways(p): batch1.ice_pingAsync() batch2.ice_pingAsync() batch1.ice_flushBatchRequestsAsync().result() - batch1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + batch1.ice_getConnection().close() batch1.ice_pingAsync() batch2.ice_pingAsync() @@ -64,7 +64,7 @@ def batchOneways(p): batch2.ice_getConnection() batch1.ice_pingAsync() - batch1.ice_getConnection().close(Ice.ConnectionClose.GracefullyWithWait) + batch1.ice_getConnection().close() test(batch1.ice_pingAsync().done() and not batch1.ice_pingAsync().exception()) test(batch2.ice_pingAsync().done() and not batch1.ice_pingAsync().exception()) diff --git a/ruby/ruby/Ice.rb b/ruby/ruby/Ice.rb index 574ad81ba98..a81ea96dff9 100644 --- a/ruby/ruby/Ice.rb +++ b/ruby/ruby/Ice.rb @@ -12,7 +12,6 @@ require_relative 'Ice/BuiltinSequences.rb' require_relative 'Ice/CompressBatch.rb' -require_relative 'Ice/ConnectionClose.rb' require_relative 'Ice/Context.rb' require_relative 'Ice/EndpointSelectionType.rb' require_relative 'Ice/EndpointTypes.rb' diff --git a/ruby/ruby/Ice/ConnectionClose.rb b/ruby/ruby/Ice/ConnectionClose.rb deleted file mode 100644 index 5e9c09e11c0..00000000000 --- a/ruby/ruby/Ice/ConnectionClose.rb +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) ZeroC, Inc. - -module Ice - - class ConnectionClose - include Comparable - - def initialize(name, value) - @name = name - @value = value - end - - def ConnectionClose.from_int(val) - @@_enumerators[val] - end - - def to_s - @name - end - - def to_i - @value - end - - def <=>(other) - other.is_a?(ConnectionClose) or raise ArgumentError, "value must be a ConnectionClose" - @value <=> other.to_i - end - - def hash - @value.hash - end - - def ConnectionClose.each(&block) - @@_enumerators.each_value(&block) - end - - Forcefully = ConnectionClose.new("Forcefully", 0) - Gracefully = ConnectionClose.new("Gracefully", 1) - GracefullyWithWait = ConnectionClose.new("GracefullyWithWait", 2) - - @@_enumerators = {0=>Forcefully, 1=>Gracefully, 2=>GracefullyWithWait} - - def ConnectionClose._enumerators - @@_enumerators - end - - private_class_method :new - end -end diff --git a/ruby/src/IceRuby/Connection.cpp b/ruby/src/IceRuby/Connection.cpp index 769a9503883..251827f67fe 100644 --- a/ruby/src/IceRuby/Connection.cpp +++ b/ruby/src/IceRuby/Connection.cpp @@ -37,24 +37,22 @@ IceRuby::createConnection(const Ice::ConnectionPtr& p) } extern "C" VALUE -IceRuby_Connection_close(VALUE self, VALUE mode) +IceRuby_Connection_abort(VALUE self) +{ + Ice::ConnectionPtr* p = reinterpret_cast(DATA_PTR(self)); + assert(p); + (*p)->abort(); + return Qnil; +} + +extern "C" VALUE +IceRuby_Connection_close(VALUE self) { ICE_RUBY_TRY { Ice::ConnectionPtr* p = reinterpret_cast(DATA_PTR(self)); assert(p); - - 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(FIX2LONG(modeValue)); - (*p)->close(cc); + (*p)->close().get(); } ICE_RUBY_CATCH return Qnil; @@ -294,7 +292,8 @@ IceRuby::initConnection(VALUE iceModule) // // Instance methods. // - rb_define_method(_connectionClass, "close", CAST_METHOD(IceRuby_Connection_close), 1); + rb_define_method(_connectionClass, "abort", CAST_METHOD(IceRuby_Connection_abort), 0); + rb_define_method(_connectionClass, "close", CAST_METHOD(IceRuby_Connection_close), 0); rb_define_method(_connectionClass, "flushBatchRequests", CAST_METHOD(IceRuby_Connection_flushBatchRequests), 1); rb_define_method(_connectionClass, "type", CAST_METHOD(IceRuby_Connection_type), 0); rb_define_method(_connectionClass, "getInfo", CAST_METHOD(IceRuby_Connection_getInfo), 0); diff --git a/ruby/test/Ice/binding/AllTests.rb b/ruby/test/Ice/binding/AllTests.rb index 277f53b76d4..e8e3d93bca6 100644 --- a/ruby/test/Ice/binding/AllTests.rb +++ b/ruby/test/Ice/binding/AllTests.rb @@ -85,7 +85,7 @@ def allTests(helper, communicator) if names.include?(name) names.delete(name) end - test1.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + test1.ice_getConnection().close() end # @@ -106,7 +106,7 @@ def allTests(helper, communicator) test(i == nRetry) for a in adapters - a.getTestIntf().ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + a.getTestIntf().ice_getConnection().close() end # @@ -132,7 +132,7 @@ def allTests(helper, communicator) if names.include?(name) names.delete(name) end - test1.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + test1.ice_getConnection().close() end # @@ -164,7 +164,7 @@ def allTests(helper, communicator) if names.include?(name) names.delete(name) end - t.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() end t = t.ice_endpointSelection(Ice::EndpointSelectionType::Random) @@ -178,7 +178,7 @@ def allTests(helper, communicator) if names.include?(name) names.delete(name) end - t.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() end deactivate(com, adapters) @@ -243,14 +243,14 @@ def allTests(helper, communicator) i = i + 1 end test(i == nRetry) - t.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() 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(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() adapters.push(com.createObjectAdapter("Adapter34", endpoints[0].toString())) i = 0 while i < nRetry and t.getAdapterName() == "Adapter34" @@ -431,7 +431,7 @@ def allTests(helper, communicator) t = createTestIntfPrx(adapters) for i in 0...5 test(t.getAdapterName() == "Adapter82") - t.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() end testSecure = t.ice_secure(true) @@ -446,14 +446,14 @@ def allTests(helper, communicator) for i in 0...5 test(t.getAdapterName() == "Adapter81") - t.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() 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(Ice::ConnectionClose::GracefullyWithWait) + t.ice_getConnection().close() end com.deactivateObjectAdapter(adapters[0]) diff --git a/ruby/test/Ice/operations/BatchOneways.rb b/ruby/test/Ice/operations/BatchOneways.rb index de313acf1d1..e5726f38220 100644 --- a/ruby/test/Ice/operations/BatchOneways.rb +++ b/ruby/test/Ice/operations/BatchOneways.rb @@ -30,7 +30,7 @@ def batchOneways(p) batch.ice_ping() batch2.ice_ping() batch.ice_flushBatchRequests() - batch.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + batch.ice_getConnection().close() batch.ice_ping() batch2.ice_ping() @@ -38,7 +38,7 @@ def batchOneways(p) batch2.ice_getConnection() batch.ice_ping() - batch.ice_getConnection().close(Ice::ConnectionClose::GracefullyWithWait) + batch.ice_getConnection().close() batch.ice_ping() batch2.ice_ping() diff --git a/swift/src/Ice/Connection.swift b/swift/src/Ice/Connection.swift index 89b12f0f2b3..92bcb004c82 100644 --- a/swift/src/Ice/Connection.swift +++ b/swift/src/Ice/Connection.swift @@ -63,69 +63,6 @@ extension OutputStream { } } -/// Determines the behavior when manually closing a connection. -public enum ConnectionClose: UInt8 { - /// Forcefully Close the connection immediately without sending a close connection protocol message to the peer - /// and waiting for the peer to acknowledge it. - case Forcefully = 0 - /// Gracefully Close the connection by notifying the peer but do not wait for pending outgoing invocations to - /// complete. On the server side, the connection will not be closed until all incoming invocations have completed. - case Gracefully = 1 - /// GracefullyWithWait Wait for all pending invocations to complete before closing the connection. - case GracefullyWithWait = 2 - public init() { - self = .Forcefully - } -} - -/// An `Ice.InputStream` extension to read `ConnectionClose` enumerated values from the stream. -extension InputStream { - /// Read an enumerated value. - /// - /// - returns: `ConnectionClose` - The enumerated value. - public func read() throws -> ConnectionClose { - let rawValue: UInt8 = try read(enumMaxValue: 2) - guard let val = ConnectionClose(rawValue: rawValue) else { - throw MarshalException("invalid enum value") - } - return val - } - - /// Read an optional enumerated value from the stream. - /// - /// - parameter tag: `Int32` - The numeric tag associated with the value. - /// - /// - returns: `ConnectionClose` - The enumerated value. - public func read(tag: Int32) throws -> ConnectionClose? { - guard try readOptional(tag: tag, expectedFormat: .Size) else { - return nil - } - return try read() as ConnectionClose - } -} - -/// An `Ice.OutputStream` extension to write `ConnectionClose` enumerated values to the stream. -extension OutputStream { - /// Writes an enumerated value to the stream. - /// - /// parameter _: `ConnectionClose` - The enumerator to write. - public func write(_ v: ConnectionClose) { - write(enum: v.rawValue, maxValue: 2) - } - - /// Writes an optional enumerated value to the stream. - /// - /// parameter tag: `Int32` - The numeric tag associated with the value. - /// - /// parameter _: `ConnectionClose` - The enumerator to write. - public func write(tag: Int32, value: ConnectionClose?) { - guard let v = value else { - return - } - write(tag: tag, val: v.rawValue, maxValue: 2) - } -} - /// A collection of HTTP headers. public typealias HeaderDict = [String: String] @@ -151,10 +88,14 @@ public typealias CloseCallback = (Connection?) -> Void /// The user-level interface to a connection. public protocol Connection: AnyObject, CustomStringConvertible { - /// Manually close the connection using the specified closure mode. - /// - /// - parameter _: `ConnectionClose` Determines how the connection will be closed. - func close(_ mode: ConnectionClose) throws + + /// Aborts this connection. + func abort() + + /// Closes this connection gracefully after all outstanding invocations have completed. + /// If this operation takes longer than the configured close timeout, the connection is aborted with a + /// `CloseTimeoutException`. + func close() async throws /// Create a special proxy that always uses this connection. This can be used for callbacks from a server to a /// client if the server cannot directly establish a connection to the client, for example because of firewalls. In diff --git a/swift/src/Ice/ConnectionI.swift b/swift/src/Ice/ConnectionI.swift index 413c683b42f..b16bff7302a 100644 --- a/swift/src/Ice/ConnectionI.swift +++ b/swift/src/Ice/ConnectionI.swift @@ -10,8 +10,13 @@ extension Connection { } class ConnectionI: LocalObject, Connection { - func close(_ mode: ConnectionClose) { - handle.close(mode.rawValue) + + func abort() { + handle.abort() + } + + func close() async throws { + try await handle.close() } func createProxy(_ id: Identity) throws -> ObjectPrx { diff --git a/swift/src/IceImpl/Connection.mm b/swift/src/IceImpl/Connection.mm index 1652ac38175..c4247546cb5 100644 --- a/swift/src/IceImpl/Connection.mm +++ b/swift/src/IceImpl/Connection.mm @@ -16,9 +16,23 @@ @implementation ICEConnection return std::static_pointer_cast(self.cppObject); } -- (void)close:(std::uint8_t)mode +- (void)abort { - self.connection->close(Ice::ConnectionClose(mode)); + self.connection->abort(); +} + +- (void)close:(void (^)(NSError* _Nullable error))completionHandler +{ + self.connection->close( + [completionHandler]() { completionHandler(nil); }, + [completionHandler](std::exception_ptr closeException) + { + // TODO: explain why we need an autoreleasepool here. + @autoreleasepool + { + completionHandler(convertException(closeException)); + } + }); } - (nullable ICEObjectPrx*)createProxy:(NSString*)name category:(NSString*)category error:(NSError**)error diff --git a/swift/src/IceImpl/include/Connection.h b/swift/src/IceImpl/include/Connection.h index b4fd583292c..11ada38e9d2 100644 --- a/swift/src/IceImpl/include/Connection.h +++ b/swift/src/IceImpl/include/Connection.h @@ -8,7 +8,8 @@ NS_ASSUME_NONNULL_BEGIN ICEIMPL_API @interface ICEConnection : ICELocalObject -- (void)close:(uint8_t)mode; +- (void)abort; +- (void)close:(void (^)(NSError* _Nullable error))completionHandler; // auto-mapped to Swift 'func close() async throws' - (nullable ICEObjectPrx*)createProxy:(NSString*)name category:(NSString*)category error:(NSError* _Nullable* _Nullable)error; diff --git a/swift/test/Ice/ami/AllTests.swift b/swift/test/Ice/ami/AllTests.swift index 45b0114189c..fd1b83e1b7d 100644 --- a/swift/test/Ice/ami/AllTests.swift +++ b/swift/test/Ice/ami/AllTests.swift @@ -134,7 +134,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { try await test(p.opBatchCount() == 0) let b1 = p.ice_batchOneway() try await b1.opBatch() - try await b1.ice_getConnection()!.close(.GracefullyWithWait) + try await b1.ice_getConnection()!.close() try await b1.ice_flushBatchRequests() try await test(p.waitForBatch(1)) @@ -158,7 +158,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { try await test(p.opBatchCount() == 0) let b1 = try await p.ice_fixed(p.ice_getConnection()!).ice_batchOneway() try await b1.opBatch() - try await b1.ice_getConnection()!.close(.GracefullyWithWait) + try await b1.ice_getConnection()!.close() do { try await b1.ice_getConnection()!.flushBatchRequests(.BasedOnProxy) @@ -189,7 +189,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { try await test(p.opBatchCount() == 0) let b1 = try await p.ice_fixed(p.ice_getConnection()!).ice_batchOneway() try await b1.opBatch() - try await b1.ice_getConnection()!.close(.GracefullyWithWait) + try await b1.ice_getConnection()!.close() try await communicator.flushBatchRequests(.BasedOnProxy) try await test(p.opBatchCount() == 0) } @@ -224,7 +224,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { let b2 = p.ice_fixed(con).ice_batchOneway() try await b1.opBatch() try await b2.opBatch() - try await b1.ice_getConnection()!.close(.GracefullyWithWait) + try await b1.ice_getConnection()!.close() try await communicator.flushBatchRequests(.BasedOnProxy) try await test(p.waitForBatch(1)) } @@ -242,8 +242,8 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { let b2 = p.ice_fixed(con).ice_batchOneway() try await b1.opBatch() try await b2.opBatch() - try await b1.ice_getConnection()!.close(.GracefullyWithWait) - try await b2.ice_getConnection()!.close(.GracefullyWithWait) + try await b1.ice_getConnection()!.close() + try await b2.ice_getConnection()!.close() try await communicator.flushBatchRequests(.BasedOnProxy) try await test(p.opBatchCount() == 0) } @@ -251,7 +251,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { } if try await p.ice_getConnection() != nil, try await p.supportsAMD() { - output.write("testing graceful close connection with wait... ") + output.write("testing connection close... ") do { // // Local case: begin a request, close the connection gracefully, and make sure it waits @@ -271,7 +271,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { let p1 = p async let r = Task { try await p1.sleep(100) } - try con.close(.GracefullyWithWait) + try await con.close() try await r.value // Should complete successfully. await cb.value } @@ -299,7 +299,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { // } // var cb = Promise { seal in - // _ = p.close(.GracefullyWithWait) { + // _ = p.close() { // seal.fulfill($0) // } // } @@ -328,56 +328,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { // } output.writeLine("ok") - output.write("testing graceful close connection without wait... ") - do { - // - // Local case: start an 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 ConnectionClosedException. - // - let p = p.ice_connectionId("CloseGracefully") // Start with a new connection. - let con = try await p.ice_getConnection()! - - do { - // Ensure the request was sent before we close the connection. Oneway invocations are - // completed when the request is sent. - async let startDispatch: Void = p.startDispatch() - try await Task.sleep(for: .milliseconds(100)) // Wait for the request to be sent. - try con.close(.Gracefully) - try await startDispatch - try test(false) - - } catch let ex as Ice.ConnectionClosedException { - try test(ex.closedByApplication) - } - try await p.finishDispatch() - } - - do { - // - // Remote case: the server closes the connection gracefully, which means the connection - // will not be closed until all pending dispatched requests have completed. - // - let con = try await p.ice_getConnection()! - - async let cb = Task { - await withCheckedContinuation { continuation in - do { - try con.setCloseCallback { _ in continuation.resume() } - } catch { - fatalError("unexpected error: \(error)") - } - } - } - - async let t = Task { try await p.sleep(100) } - try await p.close(.Gracefully) // Close is delayed until sleep completes. - await cb.value - try await t.value - } - output.writeLine("ok") - - output.write("testing forceful close connection... ") + output.write("testing connection abort... ") do { // // Local case: start an operation and then close the connection forcefully on the client side. @@ -388,7 +339,7 @@ func allTests(_ helper: TestHelper, collocated: Bool = false) async throws { async let startDispatch: Void = p.startDispatch() try await Task.sleep(for: .milliseconds(100)) // Wait for the request to be sent. - try con.close(.Forcefully) + con.abort() do { try await startDispatch try test(false) diff --git a/swift/test/Ice/ami/TestI.swift b/swift/test/Ice/ami/TestI.swift index 84fcf00e5d5..f4b56437cf1 100644 --- a/swift/test/Ice/ami/TestI.swift +++ b/swift/test/Ice/ami/TestI.swift @@ -137,10 +137,12 @@ class TestI: TestIntf { } func close(mode: CloseMode, current: Current) async throws { - if let con = current.con, - let closeMode = ConnectionClose(rawValue: mode.rawValue) - { - try con.close(closeMode) + if let con = current.con { + if mode == .Forcefully { + con.abort() + } else { + async let _ = con.close() + } } } diff --git a/swift/test/Ice/binding/AllTests.swift b/swift/test/Ice/binding/AllTests.swift index 03be9eafd89..be694e5c5ba 100644 --- a/swift/test/Ice/binding/AllTests.swift +++ b/swift/test/Ice/binding/AllTests.swift @@ -89,7 +89,7 @@ func allTests(_ helper: TestHelper) async throws { let adapterName = try await test1.getAdapterName() names.removeAll(where: { $0 == adapterName }) - try await test1.ice_getConnection()!.close(.GracefullyWithWait) + try await test1.ice_getConnection()!.close() } // @@ -112,7 +112,7 @@ func allTests(_ helper: TestHelper) async throws { try test(i == nRetry) for adpt in adapters { - try await adpt.getTestIntf()!.ice_getConnection()!.close(.GracefullyWithWait) + try await adpt.getTestIntf()!.ice_getConnection()!.close() } } @@ -139,7 +139,7 @@ func allTests(_ helper: TestHelper) async throws { let adapterName = try await test1.getAdapterName() names.removeAll(where: { $0 == adapterName }) - try await test1.ice_getConnection()!.close(.GracefullyWithWait) + try await test1.ice_getConnection()!.close() } // @@ -206,7 +206,7 @@ func allTests(_ helper: TestHelper) async throws { for a in adapters { do { - try await a.getTestIntf()!.ice_getConnection()!.close(.GracefullyWithWait) + try await a.getTestIntf()!.ice_getConnection()!.close() } catch is Ice.LocalException {} // Expected if adapter is down. } } @@ -240,7 +240,7 @@ func allTests(_ helper: TestHelper) async throws { let adapterName = try await test1.getAdapterName() names.removeAll(where: { $0 == adapterName }) - try await test1.ice_getConnection()!.close(.GracefullyWithWait) + try await test1.ice_getConnection()!.close() } // @@ -262,7 +262,7 @@ func allTests(_ helper: TestHelper) async throws { try test(i == nRetry) for adpt in adapters { - try await adpt.getTestIntf()!.ice_getConnection()!.close(.GracefullyWithWait) + try await adpt.getTestIntf()!.ice_getConnection()!.close() } } @@ -286,7 +286,7 @@ func allTests(_ helper: TestHelper) async throws { let adapterName = try await test1.getAdapterName() names.removeAll(where: { $0 == adapterName }) - try await test1.ice_getConnection()!.close(.GracefullyWithWait) + try await test1.ice_getConnection()!.close() } // @@ -316,7 +316,7 @@ func allTests(_ helper: TestHelper) async throws { while names.count > 0 { let adapterName = try await obj.getAdapterName() names.removeAll(where: { $0 == adapterName }) - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() } obj = obj.ice_endpointSelection(.Random) @@ -329,7 +329,7 @@ func allTests(_ helper: TestHelper) async throws { while names.count > 0 { let adapterName = try await obj.getAdapterName() names.removeAll(where: { $0 == adapterName }) - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() } try await deactivate(communicator: com, adapters: adapters) @@ -397,7 +397,7 @@ func allTests(_ helper: TestHelper) async throws { i += 1 } try test(i == nRetry) - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() try await adapters.append( com.createObjectAdapter(name: "Adapter35", endpoints: endpoints[1].toString())!) @@ -406,7 +406,7 @@ func allTests(_ helper: TestHelper) async throws { i += 1 } try test(i == nRetry) - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() try await adapters.append( com.createObjectAdapter(name: "Adapter34", endpoints: endpoints[0].toString())!) @@ -711,7 +711,7 @@ func allTests(_ helper: TestHelper) async throws { let obj = try await createTestIntfPrx(adapters) for _ in 0..<5 { try await test(obj.getAdapterName() == "Adapter82") - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() } var testSecure = obj.ice_secure(true) @@ -726,7 +726,7 @@ func allTests(_ helper: TestHelper) async throws { for _ in 0..<5 { try await test(obj.getAdapterName() == "Adapter81") - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() } // Reactive tcp OA. @@ -735,7 +735,7 @@ func allTests(_ helper: TestHelper) async throws { for _ in 0..<5 { try await test(obj.getAdapterName() == "Adapter83") - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() } try await com.deactivateObjectAdapter(adapters[0]) diff --git a/swift/test/Ice/hold/AllTests.swift b/swift/test/Ice/hold/AllTests.swift index 2bc079e8525..d0fc08eda0d 100644 --- a/swift/test/Ice/hold/AllTests.swift +++ b/swift/test/Ice/hold/AllTests.swift @@ -124,7 +124,7 @@ func allTests(_ helper: TestHelper) async throws { // if (i % 100) == 0 { // try await completed.value // try holdSerialized.ice_ping() // Ensure everything's dispatched. - // try holdSerialized.ice_getConnection()!.close(.GracefullyWithWait) + // try holdSerialized.ice_getConnection()!.close() // } // } // try await completed.value diff --git a/swift/test/Ice/location/AllTests.swift b/swift/test/Ice/location/AllTests.swift index c71fa8ffb44..4cf388cdde2 100644 --- a/swift/test/Ice/location/AllTests.swift +++ b/swift/test/Ice/location/AllTests.swift @@ -461,7 +461,7 @@ func allTests(_ helper: TestHelper) async throws { output.write("testing object migration... ") hello = try makeProxy(communicator: communicator, proxyString: "hello", type: HelloPrx.self) try await obj.migrateHello() - try await hello.ice_getConnection()!.close(.GracefullyWithWait) + try await hello.ice_getConnection()!.close() try await hello.sayHello() try await obj.migrateHello() try await hello.sayHello() diff --git a/swift/test/Ice/operations/BatchOneways.swift b/swift/test/Ice/operations/BatchOneways.swift index e39f09e667e..fef33df0a8a 100644 --- a/swift/test/Ice/operations/BatchOneways.swift +++ b/swift/test/Ice/operations/BatchOneways.swift @@ -37,7 +37,7 @@ func batchOneways(_ helper: TestHelper, _ p: MyClassPrx) async throws { try await batch1.ice_ping() try await batch2.ice_ping() try await batch1.ice_flushBatchRequests() - try await batch1.ice_getConnection()!.close(Ice.ConnectionClose.GracefullyWithWait) + try await batch1.ice_getConnection()!.close() try await batch1.ice_ping() try await batch2.ice_ping() @@ -45,7 +45,7 @@ func batchOneways(_ helper: TestHelper, _ p: MyClassPrx) async throws { _ = try await batch2.ice_getConnection() try await batch1.ice_ping() - try await batch1.ice_getConnection()!.close(Ice.ConnectionClose.GracefullyWithWait) + try await batch1.ice_getConnection()!.close() try await batch1.ice_ping() try await batch2.ice_ping() } diff --git a/swift/test/Ice/retry/TestI.swift b/swift/test/Ice/retry/TestI.swift index 14a0deb3022..e7dd597fc0e 100644 --- a/swift/test/Ice/retry/TestI.swift +++ b/swift/test/Ice/retry/TestI.swift @@ -13,7 +13,7 @@ class RetryI: Retry { func op(kill: Bool, current: Ice.Current) async throws { if kill { if let con = current.con { - try con.close(.Forcefully) + con.abort() } else { throw Ice.ConnectionLostException("op failed") } diff --git a/swift/test/Ice/timeout/AllTests.swift b/swift/test/Ice/timeout/AllTests.swift index 26288e69ba6..a4b4b6dc226 100644 --- a/swift/test/Ice/timeout/AllTests.swift +++ b/swift/test/Ice/timeout/AllTests.swift @@ -124,7 +124,7 @@ public func allTestsWithController(helper: TestHelper, controller: ControllerPrx let to = timeout let connection = try await connect(to) try await controller.holdAdapter(-1) - try connection.close(.GracefullyWithWait) + async let _ = connection.close() do { _ = try connection.getInfo() // getInfo() doesn't throw in the closing state. } catch is Ice.LocalException { diff --git a/swift/test/Ice/udp/AllTests.swift b/swift/test/Ice/udp/AllTests.swift index 7bbfc071d88..6f3c3badd07 100644 --- a/swift/test/Ice/udp/AllTests.swift +++ b/swift/test/Ice/udp/AllTests.swift @@ -104,7 +104,7 @@ public func allTests(_ helper: TestHelper) async throws { // try test(seq.count > 16384) } - try await obj.ice_getConnection()!.close(.GracefullyWithWait) + try await obj.ice_getConnection()!.close() communicator.getProperties().setProperty(key: "Ice.UDP.SndSize", value: "64000") seq = ByteSeq(repeating: 0, count: 50000) do {