This is an automated email from the ASF dual-hosted git repository. masaori pushed a commit to branch quic-latest in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/quic-latest by this push: new 7052a17 Close QUIC Connection by inactivity timeout 7052a17 is described below commit 7052a17f4e884e013d6efc78167375a6e2787093 Author: Masaori Koshiba <masa...@apache.org> AuthorDate: Wed Aug 9 15:20:35 2017 +0900 Close QUIC Connection by inactivity timeout --- iocore/net/P_QUICNetVConnection.h | 30 +++++++++++---- iocore/net/P_UnixNetVConnection.h | 15 ++++---- iocore/net/QUICNetVConnection.cc | 75 ++++++++++++++++++++++++++++++++++--- iocore/net/quic/QUICEvents.h | 1 + iocore/net/quic/QUICLossDetector.cc | 14 ++++++- iocore/net/quic/QUICLossDetector.h | 1 + 6 files changed, 114 insertions(+), 22 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e0bd7cc..09caae2 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -93,6 +93,15 @@ typedef enum { QUIC_HOOK_OP_LAST = QUIC_HOOK_OP_TERMINATE ///< End marker value. } QuicVConnOp; +enum class QUICConnectionState { + Open = 0, + Handshake, + Established, + TimeWait, + Closing, + Closed, +}; + ////////////////////////////////////////////////////////////////// // // class NetVConnection @@ -113,20 +122,23 @@ class QUICLossDetector; * * state_handshake() * | READ: - * | _state_handshake_process_initial_client_packet() - * | _state_handshake_process_client_cleartext_packet() - * | _state_handshake_process_zero_rtt_protected_packet() + * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_client_cleartext_packet() + * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: - * | _state_common_send_packet() + * | _state_common_send_packet() * v * state_connection_established() * | READ: - * | _state_connection_established_process_packet() + * | _state_connection_established_process_packet() * | WRITE: - * | _state_common_send_packet() + * | _state_common_send_packet() * v - * X - * + * state_connection_close() + * READ: + * Do nothing + * WRITE: + * _state_common_send_packet() **/ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitter, public QUICFrameTransmitter { @@ -143,6 +155,7 @@ public: int startEvent(int event, Event *e); int state_handshake(int event, Event *data); int state_connection_established(int event, Event *data); + int state_connection_closed(int event, Event *data); void start(SSL_CTX *); uint32_t maximum_quic_packet_size(); uint32_t minimum_quic_packet_size(); @@ -168,6 +181,7 @@ private: QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; + QUICConnectionState _state = QUICConnectionState::Open; uint32_t _pmtu = 1280; diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h index c86a136..91b8d2c 100644 --- a/iocore/net/P_UnixNetVConnection.h +++ b/iocore/net/P_UnixNetVConnection.h @@ -150,14 +150,14 @@ public: // called when handing an event from this NetVConnection,// // or the NetVConnection creation callback. // //////////////////////////////////////////////////////////// - void set_active_timeout(ink_hrtime timeout_in) override; - void set_inactivity_timeout(ink_hrtime timeout_in) override; - void cancel_active_timeout() override; - void cancel_inactivity_timeout() override; + virtual void set_active_timeout(ink_hrtime timeout_in) override; + virtual void set_inactivity_timeout(ink_hrtime timeout_in) override; + virtual void cancel_active_timeout() override; + virtual void cancel_inactivity_timeout() override; void set_action(Continuation *c) override; - void add_to_keep_alive_queue() override; - void remove_from_keep_alive_queue() override; - bool add_to_active_queue() override; + virtual void add_to_keep_alive_queue() override; + virtual void remove_from_keep_alive_queue() override; + virtual bool add_to_active_queue() override; virtual void remove_from_active_queue(); // The public interface is VIO::reenable() @@ -432,5 +432,6 @@ UnixNetVConnection::set_action(Continuation *c) void close_UnixNetVConnection(UnixNetVConnection *vc, EThread *t); void write_to_net(NetHandler *nh, UnixNetVConnection *vc, EThread *thread); void write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread); +void net_activity(UnixNetVConnection *vc, EThread *thread); #endif diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index afb4226..5eb4130 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -49,6 +49,7 @@ ClassAllocator<QUICNetVConnection> quicNetVCAllocator("quicNetVCAllocator"); QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() { + this->_state = QUICConnectionState::Handshake; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); } @@ -99,16 +100,13 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) std::shared_ptr<QUICCongestionController> congestionController = std::make_shared<QUICCongestionController>(); this->_frame_dispatcher = new QUICFrameDispatcher(connectionManager, this->_stream_manager, flowController, congestionController, this->_loss_detector); - - // TODO set timeout from conf - this->set_active_timeout(0); - this->set_inactivity_timeout(2); } -// TODO: call free when close connection void QUICNetVConnection::free(EThread *t) { + Debug(tag, "Free connection: %p", this); + this->_udp_con = nullptr; this->_packet_handler = nullptr; @@ -215,6 +213,7 @@ QUICNetVConnection::close(QUICError error) this->transmit_frame(QUICFrameFactory::create_connection_close_frame(error.code, 0, "")); } +// TODO: Timeout by active_timeout / inactive_timeout int QUICNetVConnection::state_handshake(int event, Event *data) { @@ -231,6 +230,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { std::unique_ptr<const QUICPacket> p = std::unique_ptr<const QUICPacket>(this->_packet_recv_queue.dequeue()); + net_activity(this, this_ethread()); + switch (p->type()) { case QUICPacketType::CLIENT_INITIAL: error = this->_state_handshake_process_initial_client_packet(std::move(p)); @@ -263,7 +264,14 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (this->_handshake_handler && this->_handshake_handler->is_completed()) { Debug(tag, "Enter state_connection_established"); + this->_state = QUICConnectionState::Established; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + + // TODO: switch waiting for a CONNECTION_CLOSE frame for first implementation + // TODO: read idle_timeout from Transport Prameters + ink_hrtime idle_timeout = HRTIME_SECONDS(3); + this->set_inactivity_timeout(idle_timeout); + this->add_to_active_queue(); } return EVENT_CONT; @@ -276,6 +284,8 @@ QUICNetVConnection::state_connection_established(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { std::unique_ptr<const QUICPacket> p = std::unique_ptr<const QUICPacket>(this->_packet_recv_queue.dequeue()); + net_activity(this, this_ethread()); + switch (p->type()) { case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: @@ -291,6 +301,22 @@ QUICNetVConnection::state_connection_established(int event, Event *data) error = this->_state_common_send_packet(); break; } + + case EVENT_IMMEDIATE: { + // Start Implicit Shutdown. Because no network activity for the duration of the idle timeout. + this->remove_from_active_queue(); + + // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application + Debug(tag, "Enter state_connection_close"); + this->_state = QUICConnectionState::Closing; + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + + this->close({QUICErrorClass::NONE, QUICErrorCode::QUIC_TRANSPORT_ERROR}); + + break; + } + default: + Debug(tag, "Unexpected event: %u", event); } if (error.cls != QUICErrorClass::NONE) { @@ -301,6 +327,43 @@ QUICNetVConnection::state_connection_established(int event, Event *data) return EVENT_CONT; } +int +QUICNetVConnection::state_connection_closed(int event, Event *data) +{ + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: { + // TODO: send GOAWAY frame + break; + } + case QUIC_EVENT_PACKET_WRITE_READY: { + // TODO: Retransmit CONNECTION_CLOSE when Explicit Shutdown (Out of scope from first implementation) + // Inplicit Shutdown + if (this->_state == QUICConnectionState::Closing) { + this->_state_common_send_packet(); + this->_state = QUICConnectionState::Closed; + + this->next_inactivity_timeout_at = 0; + this->next_activity_timeout_at = 0; + + this->inactivity_timeout_in = 0; + this->active_timeout_in = 0; + + // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler + // Shutdown loss detector + this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + + this->free(this_ethread()); + } + + break; + } + default: + Debug(tag, "Unexpected event: %u", event); + } + + return EVENT_DONE; +} + UDPConnection * QUICNetVConnection::get_udp_con() { @@ -437,6 +500,8 @@ QUICNetVConnection::_state_common_send_packet() this->_loss_detector->on_packet_sent(std::unique_ptr<const QUICPacket>(packet)); } + net_activity(this, this_ethread()); + return QUICError(QUICErrorClass::NONE); } diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index 1a8a9b2..de27a78 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -28,4 +28,5 @@ enum { QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, QUIC_EVENT_PACKET_WRITE_READY, + QUIC_EVENT_LD_SHUTDOWN, }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 5ffc58f..4e2cdbf 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -53,9 +53,19 @@ int QUICLossDetector::event_handler(int event, Event *edata) { switch (event) { - case EVENT_INTERVAL: + case EVENT_INTERVAL: { this->_on_loss_detection_alarm(); break; + } + case QUIC_EVENT_LD_SHUTDOWN: { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + Debug("quic_loss_detector", "Shutdown"); + + if (this->_loss_detection_alarm) { + this->_loss_detection_alarm->cancel(); + } + break; + } default: break; } @@ -121,7 +131,7 @@ QUICLossDetector::on_packet_sent(std::unique_ptr<const QUICPacket> packet) { bool is_handshake = false; QUICPacketType type = packet->type(); - if (type != QUICPacketType::ZERO_RTT_PROTECTED || type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 || + if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { is_handshake = true; } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 0a2b71c..7d6f325 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -100,6 +100,7 @@ private: void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); void _on_loss_detection_alarm(); + std::set<QUICPacketNumber> _determine_newly_acked_packets(const QUICAckFrame &ack_frame); void _retransmit_handshake_packets(); -- To stop receiving notification emails like this one, please contact ['"commits@trafficserver.apache.org" <commits@trafficserver.apache.org>'].