You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2017/12/12 05:01:06 UTC
[trafficserver] branch quic-latest updated: Send NEW_CONNECTION_ID
frames when connection establish
This is an automated email from the ASF dual-hosted git repository.
maskit 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 9786e2b Send NEW_CONNECTION_ID frames when connection establish
9786e2b is described below
commit 9786e2b8507c0eb76c6f874b5bcf66e4f7012565
Author: Masakazu Kitajo <ma...@apache.org>
AuthorDate: Tue Dec 12 14:00:12 2017 +0900
Send NEW_CONNECTION_ID frames when connection establish
---
iocore/net/P_QUICNetVConnection.h | 14 +++++++
iocore/net/P_QUICPacketHandler.h | 2 +
iocore/net/QUICNetVConnection.cc | 51 +++++++++++++++++++++++++-
iocore/net/QUICPacketHandler.cc | 8 +++-
iocore/net/quic/QUICFrame.cc | 27 ++++++++++++--
iocore/net/quic/QUICFrame.h | 12 +++++-
iocore/net/quic/QUICStreamManager.cc | 5 +--
iocore/net/quic/QUICTypes.h | 47 +++++++++++++-----------
iocore/net/quic/test/test_QUICFrame.cc | 22 ++++++-----
iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +-
10 files changed, 146 insertions(+), 44 deletions(-)
diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h
index d7efa38..6d3a12a 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -189,9 +189,22 @@ public:
QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame> frame) override;
private:
+ class AltConnectionInfo
+ {
+ public:
+ int seq_num;
+ QUICConnectionId id;
+ QUICStatelessResetToken token;
+ };
+
std::random_device _rnd;
+
QUICConnectionId _original_quic_connection_id;
QUICConnectionId _quic_connection_id;
+
+ AltConnectionInfo _alt_quic_connection_ids[3];
+ int8_t _alt_quic_connection_id_seq_num = 0;
+
QUICPacketNumber _largest_received_packet_number = 0;
UDPConnection *_udp_con = nullptr;
QUICPacketHandler *_packet_handler = nullptr;
@@ -264,6 +277,7 @@ private:
void _switch_to_close_state();
void _handle_idle_timeout();
+ void _update_alt_connection_ids(uint8_t chosen);
QUICStatelessResetToken _reset_token;
};
diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h
index e1ea3fb..564dbba 100644
--- a/iocore/net/P_QUICPacketHandler.h
+++ b/iocore/net/P_QUICPacketHandler.h
@@ -43,6 +43,8 @@ public:
void send_packet(const QUICPacket &packet, QUICNetVConnection *vc);
void send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu);
+ void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc);
+
private:
void _recv_packet(int event, UDPPacket *udpPacket);
bool _read_connection_id(QUICConnectionId &cid, IOBufferBlock *block);
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index af0a167..226fcd2 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -93,12 +93,12 @@ QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e)
void
QUICNetVConnection::start(SSL_CTX *ssl_ctx)
{
- // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not
{
QUICConfig::scoped_config params;
- this->_reset_token.generate(_quic_connection_id ^ params->server_id());
+ this->_reset_token.generate(this->_quic_connection_id, params->server_id());
}
+ // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not
this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token);
this->_application_map = new QUICApplicationMap();
this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler);
@@ -667,6 +667,8 @@ QUICNetVConnection::_state_common_receive_packet()
{
QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
QUICPacketCreationResult result;
+
+ // Receive a QUIC packet
QUICPacketUPtr p = this->_dequeue_recv_packet(result);
if (result == QUICPacketCreationResult::FAILED) {
return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
@@ -675,6 +677,25 @@ QUICNetVConnection::_state_common_receive_packet()
}
net_activity(this, this_ethread());
+ // Check connection migration
+ if (p->connection_id() != this->_quic_connection_id) {
+ for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) {
+ AltConnectionInfo &info = this->_alt_quic_connection_ids[i];
+ if (info.id == p->connection_id()) {
+ // Migrate connection
+ // TODO Address Validation
+ // TODO Adjust expected packet number with a gap computed based on info.seq_num
+ // TODO Unregister the old connection id (Should we wait for a while?)
+ this->_quic_connection_id = info.id;
+ this->_reset_token = info.token;
+ this->_update_alt_connection_ids(i);
+ break;
+ }
+ }
+ ink_assert(p->connection_id() == this->_quic_connection_id);
+ }
+
+ // Process the packet
switch (p->type()) {
case QUICPacketType::PROTECTED:
error = this->_state_connection_established_process_packet(std::move(p));
@@ -1012,6 +1033,7 @@ QUICNetVConnection::_switch_to_established_state()
if (this->_complete_handshake_if_possible() == 0) {
QUICConDebug("Enter state_connection_established");
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established);
+ this->_update_alt_connection_ids(countof(this->_alt_quic_connection_ids) - 1);
} else {
// Illegal state change
ink_assert(!"Handshake has to be completed");
@@ -1052,3 +1074,28 @@ QUICNetVConnection::_handle_idle_timeout()
// TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application
}
+
+void
+QUICNetVConnection::_update_alt_connection_ids(uint8_t chosen)
+{
+ QUICConfig::scoped_config params;
+ int n = sizeof(this->_alt_quic_connection_ids);
+ int current = this->_alt_quic_connection_id_seq_num % n;
+ int delta = chosen - current;
+ int count = (n + delta) % n + 1;
+
+ for (int i = 0; i < count; ++i) {
+ int index = (current + i) % n;
+ QUICConnectionId conn_id;
+ QUICStatelessResetToken token;
+
+ conn_id.randomize();
+ token.generate(conn_id, params->server_id());
+ this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token};
+ this->_packet_handler->registerAltConnectionId(conn_id, this);
+ this->transmit_frame(QUICFrameFactory::create_new_connection_id_frame(this->_alt_quic_connection_ids[index].seq_num,
+ this->_alt_quic_connection_ids[index].id,
+ this->_alt_quic_connection_ids[index].token));
+ }
+ this->_alt_quic_connection_id_seq_num += count;
+}
diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc
index fb20376..5c5583f 100644
--- a/iocore/net/QUICPacketHandler.cc
+++ b/iocore/net/QUICPacketHandler.cc
@@ -139,7 +139,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket)
QUICStatelessResetToken token;
{
QUICConfig::scoped_config params;
- token.generate(cid ^ params->server_id());
+ token.generate(cid, params->server_id());
}
auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token);
this->send_packet(*packet, udpPacket->getConnection(), con.addr, 1200);
@@ -208,3 +208,9 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con,
udp_con->send(this, udpPkt);
}
+
+void
+QUICPacketHandler::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc)
+{
+ this->_connections.put(id, vc);
+}
diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 4e61a1c..a91c78f 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -1107,10 +1107,10 @@ QUICStreamIdNeededFrame::store(uint8_t *buf, size_t *len) const
// NEW_CONNECTION_ID frame
//
-QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id)
+QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_i,
+ QUICStatelessResetToken stateless_reset_token)
+ : _sequence(sequence), _connection_id(connection_i), _stateless_reset_token(stateless_reset_token)
{
- this->_sequence = sequence;
- this->_connection_id = connection_id;
}
QUICFrameType
@@ -1136,6 +1136,8 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const
p += n;
QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n);
p += n;
+ memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN);
+ p += QUICStatelessResetToken::LEN;
*len = p - buf;
}
@@ -1160,6 +1162,16 @@ QUICNewConnectionIdFrame::connection_id() const
}
}
+QUICStatelessResetToken
+QUICNewConnectionIdFrame::stateless_reset_token() const
+{
+ if (this->_buf) {
+ return QUICStatelessResetToken(this->_buf + 11);
+ } else {
+ return this->_stateless_reset_token;
+ }
+}
+
//
// STOP_SENDING frame
//
@@ -1471,6 +1483,15 @@ QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppError
return std::unique_ptr<QUICStopSendingFrame, QUICFrameDeleterFunc>(frame, &QUICFrameDeleter::delete_stop_sending_frame);
}
+std::unique_ptr<QUICNewConnectionIdFrame, QUICFrameDeleterFunc>
+QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnectionId connectoin_id,
+ QUICStatelessResetToken stateless_reset_token)
+{
+ QUICNewConnectionIdFrame *frame = quicNewConnectionIdFrameAllocator.alloc();
+ new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token);
+ return std::unique_ptr<QUICNewConnectionIdFrame, QUICFrameDeleterFunc>(frame, &QUICFrameDeleter::delete_new_connection_id_frame);
+}
+
std::unique_ptr<QUICRetransmissionFrame, QUICFrameDeleterFunc>
QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, const QUICPacket &original_packet)
{
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 9f51b3f..59fd66d 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -36,7 +36,7 @@ class QUICFrame
public:
QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){};
virtual QUICFrameType type() const;
- virtual size_t size() const = 0;
+ virtual size_t size() const = 0;
virtual void store(uint8_t *buf, size_t *len) const = 0;
virtual void reset(const uint8_t *buf, size_t len);
static QUICFrameType type(const uint8_t *buf);
@@ -407,16 +407,18 @@ class QUICNewConnectionIdFrame : public QUICFrame
public:
QUICNewConnectionIdFrame() : QUICFrame() {}
QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
- QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id);
+ QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual void store(uint8_t *buf, size_t *len) const override;
uint16_t sequence() const;
QUICConnectionId connection_id() const;
+ QUICStatelessResetToken stateless_reset_token() const;
private:
uint16_t _sequence = 0;
QUICConnectionId _connection_id = 0;
+ QUICStatelessResetToken _stateless_reset_token;
};
//
@@ -678,6 +680,12 @@ public:
QUICAppErrorCode error_code);
/*
+ * Creates a NEW_CONNECTION_ID frame.
+ */
+ static std::unique_ptr<QUICNewConnectionIdFrame, QUICFrameDeleterFunc> create_new_connection_id_frame(
+ uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token);
+
+ /*
* Creates a retransmission frame, which is very special.
* This retransmission frame will be used only for retransmission and it's not a standard frame type.
*/
diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc
index 5223bb4..f3b3d94 100644
--- a/iocore/net/quic/QUICStreamManager.cc
+++ b/iocore/net/quic/QUICStreamManager.cc
@@ -40,10 +40,7 @@ std::vector<QUICFrameType>
QUICStreamManager::interests()
{
return {
- QUICFrameType::STREAM,
- QUICFrameType::RST_STREAM,
- QUICFrameType::MAX_STREAM_DATA,
- QUICFrameType::MAX_STREAM_ID,
+ QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID,
};
}
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index b0a1374..6757d70 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -200,27 +200,6 @@ using QUICErrorUPtr = std::unique_ptr<QUICError>;
using QUICConnectionErrorUPtr = std::unique_ptr<QUICConnectionError>;
using QUICStreamErrorUPtr = std::unique_ptr<QUICStreamError>;
-class QUICStatelessResetToken
-{
-public:
- void
- generate(uint64_t data)
- {
- this->_gen_token(data);
- }
-
- const uint8_t *
- buf() const
- {
- return _token;
- }
-
-private:
- uint8_t _token[16] = {0};
-
- void _gen_token(uint64_t data);
-};
-
class QUICConnectionId
{
public:
@@ -240,6 +219,32 @@ private:
uint64_t _id;
};
+class QUICStatelessResetToken
+{
+public:
+ constexpr static int8_t LEN = 16;
+
+ QUICStatelessResetToken() {}
+ QUICStatelessResetToken(const uint8_t *buf) { memcpy(this->_token, buf, QUICStatelessResetToken::LEN); }
+
+ void
+ generate(QUICConnectionId conn_id, uint32_t server_id)
+ {
+ this->_gen_token(conn_id ^ server_id);
+ }
+
+ const uint8_t *
+ buf() const
+ {
+ return _token;
+ }
+
+private:
+ uint8_t _token[16] = {0};
+
+ void _gen_token(uint64_t data);
+};
+
enum class QUICStreamType { SERVER, CLIENT, HANDSHAKE };
class QUICTypeUtil
diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc
index 84a6fbb..3489746 100644
--- a/iocore/net/quic/test/test_QUICFrame.cc
+++ b/iocore/net/quic/test/test_QUICFrame.cc
@@ -720,9 +720,11 @@ TEST_CASE("Store StreamIdNeeded Frame", "[quic]")
TEST_CASE("Load NewConnectionId Frame", "[quic]")
{
uint8_t buf1[] = {
- 0x0b, // Type
- 0x01, 0x02, // Sequence
- 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Connection ID
+ 0x0b, // Type
+ 0x01, 0x02, // Sequence
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token
+ 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
};
std::shared_ptr<const QUICFrame> frame1 = QUICFrameFactory::create(buf1, sizeof(buf1));
CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID);
@@ -732,6 +734,7 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]")
CHECK(newConnectionIdFrame1 != nullptr);
CHECK(newConnectionIdFrame1->sequence() == 0x0102);
CHECK(newConnectionIdFrame1->connection_id() == 0x1122334455667788ULL);
+ CHECK(memcmp(newConnectionIdFrame1->stateless_reset_token().buf(), buf1 + 11, 16) == 0);
}
TEST_CASE("Store NewConnectionId Frame", "[quic]")
@@ -739,14 +742,13 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]")
uint8_t buf[65535];
size_t len;
- uint8_t expected[] = {
- 0x0b, // Type
- 0x01, 0x02, // Sequence
- 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Connection ID
- };
- QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL);
+ uint8_t expected[] = {0x0b, // Type
+ 0x01, 0x02, // Sequence
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL, {expected + 11});
newConnectionIdFrame.store(buf, &len);
- CHECK(len == 11);
+ CHECK(len == 27);
CHECK(memcmp(buf, expected, len) == 0);
}
diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc
index b6f6dcf..f5fcf15 100644
--- a/iocore/net/quic/test/test_QUICPacketFactory.cc
+++ b/iocore/net/quic/test/test_QUICPacketFactory.cc
@@ -78,7 +78,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]")
MockQUICCrypto crypto;
factory.set_crypto_module(&crypto);
QUICStatelessResetToken token;
- token.generate(12345);
+ token.generate(12345, 67890);
uint8_t expected_output[] = {
0x41, // 0CK0001
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, // Connection ID
--
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].