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>'].