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/28 13:17:16 UTC

[trafficserver] branch quic-latest updated (d828038 -> c33d80e)

This is an automated email from the ASF dual-hosted git repository.

masaori pushed a change to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git.


    from d828038  Add QUICHandshake test & refactoring
     new 9ac1e8d  Add initial code of QUIC client
     new c33d80e  Start QUIC handshake from client

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                   |   7 +-
 cmd/Makefile.am                              |   4 +-
 {iocore/aio => cmd/traffic_quic}/Makefile.am |  60 +++--
 cmd/traffic_quic/traffic_quic.cc             | 317 +++++++++++++++++++++++++++
 configure.ac                                 |   1 +
 iocore/net/P_QUICNetProcessor.h              |   3 +
 iocore/net/P_QUICNetVConnection.h            |  17 +-
 iocore/net/QUICNetProcessor.cc               |  53 ++++-
 iocore/net/QUICNetVConnection.cc             |  34 ++-
 iocore/net/UnixUDPNet.cc                     |  12 +-
 iocore/net/quic/QUICCrypto.cc                |  13 +-
 iocore/net/quic/QUICHandshake.cc             |   7 +-
 iocore/net/quic/QUICStreamManager.h          |   2 +
 iocore/net/quic/test/test_QUICHandshake.cc   |   3 +
 14 files changed, 467 insertions(+), 66 deletions(-)
 copy {iocore/aio => cmd/traffic_quic}/Makefile.am (71%)
 create mode 100644 cmd/traffic_quic/traffic_quic.cc

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].

[trafficserver] 01/02: Add initial code of QUIC client

Posted by ma...@apache.org.
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

commit 9ac1e8d777a7bd2ba789c6e67c74d8f81822f3e3
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Tue Dec 26 16:06:36 2017 +0900

    Add initial code of QUIC client
---
 .gitignore                       |   7 +-
 cmd/Makefile.am                  |   4 +-
 cmd/traffic_quic/Makefile.am     |  59 ++++++++
 cmd/traffic_quic/traffic_quic.cc | 313 +++++++++++++++++++++++++++++++++++++++
 configure.ac                     |   1 +
 iocore/net/P_QUICNetProcessor.h  |   3 +
 iocore/net/QUICNetProcessor.cc   |  45 +++++-
 7 files changed, 424 insertions(+), 8 deletions(-)

diff --git a/.gitignore b/.gitignore
index f1a64f5..e056037 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,12 +49,13 @@ MYMETA.*
 pm_to_blib
 
 cmd/traffic_cop/traffic_cop
-cmd/traffic_ctl/traffic_ctl
 cmd/traffic_crashlog/traffic_crashlog
-cmd/traffic_top/traffic_top
+cmd/traffic_ctl/traffic_ctl
+cmd/traffic_layout/traffic_layout
 cmd/traffic_manager/traffic_manager
 cmd/traffic_manager/test_metrics
-cmd/traffic_layout/traffic_layout
+cmd/traffic_quic/traffic_quic
+cmd/traffic_top/traffic_top
 cmd/traffic_via/traffic_via
 cmd/traffic_wccp/traffic_wccp
 
diff --git a/cmd/Makefile.am b/cmd/Makefile.am
index 00a63b4..55bdec8 100644
--- a/cmd/Makefile.am
+++ b/cmd/Makefile.am
@@ -27,7 +27,9 @@ SUBDIRS = \
 TESTS = $(check_PROGRAMS)
 
 if BUILD_WCCP
-
 SUBDIRS += traffic_wccp
+endif
 
+if ENABLE_QUIC
+SUBDIRS += traffic_quic
 endif
diff --git a/cmd/traffic_quic/Makefile.am b/cmd/traffic_quic/Makefile.am
new file mode 100644
index 0000000..a737ade
--- /dev/null
+++ b/cmd/traffic_quic/Makefile.am
@@ -0,0 +1,59 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+bin_PROGRAMS = traffic_quic
+
+AM_CPPFLAGS += \
+  $(iocore_include_dirs) \
+  -I$(abs_top_srcdir)/lib \
+  -I$(abs_top_srcdir)/lib/records \
+  -I$(abs_top_srcdir)/mgmt \
+  -I$(abs_top_srcdir)/mgmt/utils \
+  -I$(abs_top_srcdir)/proxy \
+  -I$(abs_top_srcdir)/proxy/hdrs \
+  -I$(abs_top_srcdir)/proxy/http \
+  -I$(abs_top_srcdir)/proxy/logging \
+  -I$(abs_top_srcdir)/proxy/shared \
+  @OPENSSL_INCLUDES@
+
+traffic_quic_CPPFLAGS = \
+  $(AM_CPPFLAGS)
+
+traffic_quic_LDFLAGS = \
+  @AM_LDFLAGS@
+
+traffic_quic_SOURCES = \
+  traffic_quic.cc
+
+traffic_quic_LDADD = \
+  $(top_builddir)/iocore/net/libinknet.a \
+  $(top_builddir)/iocore/net/quic/libquic.a \
+  $(top_builddir)/iocore/eventsystem/libinkevent.a \
+  $(top_builddir)/mgmt/libmgmt_p.la \
+  $(top_builddir)/lib/records/librecords_p.a \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  $(top_builddir)/proxy/ParentSelectionStrategy.o \
+  $(top_builddir)/lib/tsconfig/libtsconfig.la \
+  $(top_builddir)/lib/luajit/src/libluajit.a \
+  @LIBTCL@ \
+  @HWLOC_LIBS@ \
+  @OPENSSL_LIBS@
+
+include $(top_srcdir)/build/tidy.mk
+
+tidy-local: $(DIST_SOURCES)
+	$(CXX_Clang_Tidy)
diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc
new file mode 100644
index 0000000..a0223fe
--- /dev/null
+++ b/cmd/traffic_quic/traffic_quic.cc
@@ -0,0 +1,313 @@
+/** @file
+ *
+ *  A brief file description
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "I_EventSystem.h"
+#include "I_NetVConnection.h"
+#include "P_QUICNetProcessor.h"
+
+#include "ts/ink_string.h"
+#include "ts/I_Layout.h"
+
+#define THREADS 1
+#define DIAGS_LOG_FILE "diags.log"
+
+constexpr size_t stacksize = 1048576;
+
+static void
+reconfigure_diags()
+{
+  int i;
+  DiagsConfigState c;
+
+  // initial value set to 0 or 1 based on command line tags
+  c.enabled[DiagsTagType_Debug]  = (diags->base_debug_tags != nullptr);
+  c.enabled[DiagsTagType_Action] = (diags->base_action_tags != nullptr);
+
+  c.enabled[DiagsTagType_Debug]  = 1;
+  c.enabled[DiagsTagType_Action] = 1;
+  diags->show_location           = SHOW_LOCATION_ALL;
+
+  // read output routing values
+  for (i = 0; i < DL_Status; i++) {
+    c.outputs[i].to_stdout   = 0;
+    c.outputs[i].to_stderr   = 1;
+    c.outputs[i].to_syslog   = 0;
+    c.outputs[i].to_diagslog = 0;
+  }
+
+  for (i = DL_Status; i < DiagsLevel_Count; i++) {
+    c.outputs[i].to_stdout   = 0;
+    c.outputs[i].to_stderr   = 0;
+    c.outputs[i].to_syslog   = 0;
+    c.outputs[i].to_diagslog = 1;
+  }
+
+  //////////////////////////////
+  // clear out old tag tables //
+  //////////////////////////////
+
+  diags->deactivate_all(DiagsTagType_Debug);
+  diags->deactivate_all(DiagsTagType_Action);
+
+  //////////////////////////////////////////////////////////////////////
+  //                     add new tag tables
+  //////////////////////////////////////////////////////////////////////
+
+  if (diags->base_debug_tags)
+    diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug);
+  if (diags->base_action_tags)
+    diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action);
+
+////////////////////////////////////
+// change the diags config values //
+////////////////////////////////////
+#if !defined(__GNUC__) && !defined(hpux)
+  diags->config = c;
+#else
+  memcpy(((void *)&diags->config), ((void *)&c), sizeof(DiagsConfigState));
+#endif
+}
+
+static void
+init_diags(const char *bdt, const char *bat)
+{
+  char diags_logpath[500];
+  strcpy(diags_logpath, DIAGS_LOG_FILE);
+
+  diags = new Diags("tq", bdt, bat, new BaseLogFile(diags_logpath));
+  Status("opened %s", diags_logpath);
+
+  reconfigure_diags();
+}
+
+class QUICClient : public Continuation
+{
+public:
+  QUICClient() : Continuation(new_ProxyMutex()) { SET_HANDLER(&QUICClient::state_http_server_open); };
+  void start();
+  int state_http_server_open(int event, void *data);
+};
+
+// HttpSM::state_http_server_open(int event, void *data)
+int
+QUICClient::state_http_server_open(int event, void *data)
+{
+  switch (event) {
+  case NET_EVENT_OPEN: {
+    // TODO: create ProxyServerSession / ProxyServerTransaction
+    // TODO: send HTTP/0.9 message
+    Debug("quic_client", "start proxy server ssn/txn");
+    break;
+  }
+  case NET_EVENT_OPEN_FAILED: {
+    ink_assert(false);
+    break;
+  }
+  default:
+    ink_assert(false);
+  }
+
+  return 0;
+}
+
+// TODO: ip:port
+void
+QUICClient::start()
+{
+  sockaddr_in addr;
+  addr.sin_family      = AF_INET;
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr.sin_port        = htons(4433);
+
+  NetVCOptions opt;
+  opt.ip_proto  = NetVCOptions::USE_UDP;
+  opt.ip_family = addr.sin_family;
+
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+
+  quic_NetProcessor.connect_re(this, reinterpret_cast<sockaddr const *>(&addr), &opt);
+}
+
+int
+main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
+{
+  Layout::create();
+  init_diags("udp|quic", nullptr);
+  RecProcessInit(RECM_STAND_ALONE);
+
+  SSLInitializeLibrary();
+  SSLConfig::startup();
+
+  ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION);
+  eventProcessor.start(THREADS);
+  udpNet.start(1, stacksize);
+  quic_NetProcessor.start(-1, stacksize);
+
+  Thread *main_thread = new EThread;
+  main_thread->set_specific();
+
+  QUICClient client;
+  client.start();
+}
+
+//
+// stub
+//
+void
+initialize_thread_for_http_sessions(EThread *, int)
+{
+  ink_assert(false);
+}
+
+#include "P_UnixNet.h"
+#include "P_DNSConnection.h"
+int
+DNSConnection::close()
+{
+  ink_assert(false);
+  return 0;
+}
+
+void
+DNSConnection::trigger()
+{
+  ink_assert(false);
+}
+
+#include "StatPages.h"
+void
+StatPagesManager::register_http(char const *, Action *(*)(Continuation *, HTTPHdr *))
+{
+  ink_assert(false);
+}
+
+#include "ParentSelection.h"
+void
+SocksServerConfig::startup()
+{
+  ink_assert(false);
+}
+
+int SocksServerConfig::m_id = 0;
+
+void
+ParentConfigParams::findParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int)
+{
+  ink_assert(false);
+}
+
+void
+ParentConfigParams::nextParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int)
+{
+  ink_assert(false);
+}
+
+#include "Log.h"
+void
+Log::trace_in(sockaddr const *, unsigned short, char const *, ...)
+{
+  ink_assert(false);
+}
+
+void
+Log::trace_out(sockaddr const *, unsigned short, char const *, ...)
+{
+  ink_assert(false);
+}
+
+#include "InkAPIInternal.h"
+int
+APIHook::invoke(int, void *)
+{
+  ink_assert(false);
+  return 0;
+}
+
+APIHook *
+APIHook::next() const
+{
+  ink_assert(false);
+  return nullptr;
+}
+
+APIHook *
+APIHooks::get() const
+{
+  ink_assert(false);
+  return nullptr;
+}
+
+void
+ConfigUpdateCbTable::invoke(const char * /* name ATS_UNUSED */)
+{
+  ink_release_assert(false);
+}
+
+#include "ControlMatcher.h"
+char *
+HttpRequestData::get_string()
+{
+  ink_assert(false);
+  return nullptr;
+}
+
+const char *
+HttpRequestData::get_host()
+{
+  ink_assert(false);
+  return nullptr;
+}
+
+sockaddr const *
+HttpRequestData::get_ip()
+{
+  ink_assert(false);
+  return nullptr;
+}
+
+sockaddr const *
+HttpRequestData::get_client_ip()
+{
+  ink_assert(false);
+  return nullptr;
+}
+
+SslAPIHooks *ssl_hooks = nullptr;
+StatPagesManager statPagesManager;
+
+#include "ProcessManager.h"
+inkcoreapi ProcessManager *pmgmt = nullptr;
+
+int
+BaseManager::registerMgmtCallback(int, MgmtCallback, void *)
+{
+  ink_assert(false);
+  return 0;
+}
+
+void
+ProcessManager::signalManager(int, char const *, int)
+{
+  ink_assert(false);
+  return;
+}
diff --git a/configure.ac b/configure.ac
index e2ef11a..1bce3c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2015,6 +2015,7 @@ AC_CONFIG_FILES([
   cmd/traffic_ctl/Makefile
   cmd/traffic_layout/Makefile
   cmd/traffic_manager/Makefile
+  cmd/traffic_quic/Makefile
   cmd/traffic_top/Makefile
   cmd/traffic_via/Makefile
   cmd/traffic_wccp/Makefile
diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h
index 9f97454..2972060 100644
--- a/iocore/net/P_QUICNetProcessor.h
+++ b/iocore/net/P_QUICNetProcessor.h
@@ -58,6 +58,9 @@ public:
 
   virtual int start(int, size_t stacksize) override;
   void cleanup();
+  // TODO: refactoring NetProcessor::connect_re and UnixNetProcessor::connect_re_internal
+  // Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opts) override;
+  Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opts);
 
   virtual NetAccept *createNetAccept(const NetProcessor::AcceptOptions &opt) override;
   virtual NetVConnection *allocate_vc(EThread *t) override;
diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc
index 608f3d7..9a782cc 100644
--- a/iocore/net/QUICNetProcessor.cc
+++ b/iocore/net/QUICNetProcessor.cc
@@ -35,9 +35,7 @@
 
 QUICNetProcessor quic_NetProcessor;
 
-QUICNetProcessor::QUICNetProcessor()
-{
-}
+QUICNetProcessor::QUICNetProcessor() {}
 
 QUICNetProcessor::~QUICNetProcessor()
 {
@@ -79,7 +77,7 @@ QUICNetProcessor::start(int, size_t stacksize)
 
   if (SSL_CTX_check_private_key(this->_ssl_ctx) != 1) {
     Error("check private key failed");
-    ink_assert(false);
+    // ink_assert(false);
   }
 
   return 0;
@@ -110,6 +108,45 @@ QUICNetProcessor::allocate_vc(EThread *t)
 }
 
 Action *
+QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opt)
+{
+  Debug("quic_ps", "connect to server");
+
+  EThread *t = cont->mutex->thread_holding;
+  ink_assert(t);
+
+  QUICNetVConnection *vc = static_cast<QUICNetVConnection *>(this->allocate_vc(t));
+
+  // Setup QUICNetVConnection
+  // TODO: randomize
+  QUICConnectionId id = 0x00;
+  UDPConnection *con  = new UnixUDPConnection(NO_FD);
+  AcceptOptions const accept_opt;
+  QUICPacketHandler *ph = new QUICPacketHandler(accept_opt, this->_ssl_ctx);
+
+  vc->init(id, con, ph);
+
+  if (opt) {
+    vc->options = *opt;
+  } else {
+    opt = &vc->options;
+  }
+
+  vc->set_context(NET_VCONNECTION_OUT);
+  vc->con.setRemote(addr);
+  vc->id          = net_next_connection_number();
+  vc->submit_time = Thread::get_hrtime();
+  vc->mutex       = cont->mutex;
+  vc->action_     = cont;
+
+  vc->start(this->_ssl_ctx);
+
+  vc->action_.continuation->handleEvent(NET_EVENT_OPEN, this);
+
+  return ACTION_RESULT_DONE;
+}
+
+Action *
 QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const &opt)
 {
   // UnixNetProcessor *this_unp = static_cast<UnixNetProcessor *>(this);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 02/02: Start QUIC handshake from client

Posted by ma...@apache.org.
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

commit c33d80e362819450c5eeaccd5ab5a26e210ed75d
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Thu Dec 28 22:13:46 2017 +0900

    Start QUIC handshake from client
---
 cmd/traffic_quic/traffic_quic.cc           |  8 +++++--
 iocore/net/P_QUICNetVConnection.h          | 17 ++++++++++-----
 iocore/net/QUICNetProcessor.cc             | 30 ++++++++++++++++----------
 iocore/net/QUICNetVConnection.cc           | 34 ++++++++++++++++++++++++++++--
 iocore/net/UnixUDPNet.cc                   | 12 +++--------
 iocore/net/quic/QUICCrypto.cc              | 13 +++++-------
 iocore/net/quic/QUICHandshake.cc           |  7 +++++-
 iocore/net/quic/QUICStreamManager.h        |  2 ++
 iocore/net/quic/test/test_QUICHandshake.cc |  3 +++
 9 files changed, 88 insertions(+), 38 deletions(-)

diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc
index a0223fe..965f618 100644
--- a/cmd/traffic_quic/traffic_quic.cc
+++ b/cmd/traffic_quic/traffic_quic.cc
@@ -1,3 +1,4 @@
+
 /** @file
  *
  *  A brief file description
@@ -33,6 +34,7 @@
 
 constexpr size_t stacksize = 1048576;
 
+// copy from iocore/utils/diags.i
 static void
 reconfigure_diags()
 {
@@ -94,7 +96,7 @@ init_diags(const char *bdt, const char *bat)
   char diags_logpath[500];
   strcpy(diags_logpath, DIAGS_LOG_FILE);
 
-  diags = new Diags("tq", bdt, bat, new BaseLogFile(diags_logpath));
+  diags = new Diags("Client", bdt, bat, new BaseLogFile(diags_logpath));
   Status("opened %s", diags_logpath);
 
   reconfigure_diags();
@@ -152,7 +154,7 @@ int
 main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
 {
   Layout::create();
-  init_diags("udp|quic", nullptr);
+  init_diags("quic|udp", nullptr);
   RecProcessInit(RECM_STAND_ALONE);
 
   SSLInitializeLibrary();
@@ -168,6 +170,8 @@ main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
 
   QUICClient client;
   client.start();
+
+  main_thread->execute();
 }
 
 //
diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h
index 3f9d1c2..7fdb83d 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -98,14 +98,17 @@ class SSLNextProtocolSet;
  * @detail
  *
  * state_pre_handshake()
- *  |
+ *  | READ:
+ *  |   Do nothing
+ *  | WRITE:
+ *  |   _state_common_send_packet()
  *  v
  * state_handshake()
  *  | READ:
- *  |   _state_handshake_process__packet()
- *  |     _state_handshake_process_initial_client_packet()
- *  |     _state_handshake_process_client_cleartext_packet()
- *  |     _state_handshake_process_zero_rtt_protected_packet()
+ *  |   _state_handshake_process_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()
  *  v
@@ -139,7 +142,9 @@ public:
   void reenable(VIO *vio) override;
   VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
   VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override;
+  int connectUp(EThread *t, int fd) override;
 
+  // QUICNetVConnection
   int startEvent(int event, Event *e);
   int state_pre_handshake(int event, Event *data);
   int state_handshake(int event, Event *data);
@@ -237,6 +242,8 @@ private:
   std::queue<QUICFrameUPtr> _frame_send_queue;
   std::queue<QUICFrameUPtr> _stream_frame_send_queue;
 
+  bool _is_initial = true;
+
   void _schedule_packet_write_ready();
   void _unschedule_packet_write_ready();
   void _close_packet_write_ready(Event *data);
diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc
index 9a782cc..f089bab 100644
--- a/iocore/net/QUICNetProcessor.cc
+++ b/iocore/net/QUICNetProcessor.cc
@@ -115,16 +115,24 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOpti
   EThread *t = cont->mutex->thread_holding;
   ink_assert(t);
 
-  QUICNetVConnection *vc = static_cast<QUICNetVConnection *>(this->allocate_vc(t));
-
-  // Setup QUICNetVConnection
-  // TODO: randomize
-  QUICConnectionId id = 0x00;
-  UDPConnection *con  = new UnixUDPConnection(NO_FD);
+  // Setup UDPConnection
+  // FIXME: use udpNet.CreateUDPSocket
+  int fd                 = socket(AF_INET, SOCK_DGRAM, 0);
+  UnixUDPConnection *con = new UnixUDPConnection(fd);
   AcceptOptions const accept_opt;
-  QUICPacketHandler *ph = new QUICPacketHandler(accept_opt, this->_ssl_ctx);
+  QUICPacketHandler *packet_handler = new QUICPacketHandler(accept_opt, this->_ssl_ctx);
+  con->setBinding(addr);
+  con->bindToThread(packet_handler);
 
-  vc->init(id, con, ph);
+  PollCont *pc       = get_UDPPollCont(con->ethread);
+  PollDescriptor *pd = pc->pollDescriptor;
+  con->ep.start(pd, con, EVENTIO_READ);
+
+  // Setup QUICNetVConnection
+  QUICConnectionId cid;
+  cid.randomize();
+  QUICNetVConnection *vc = static_cast<QUICNetVConnection *>(this->allocate_vc(t));
+  vc->init(cid, con, packet_handler);
 
   if (opt) {
     vc->options = *opt;
@@ -132,16 +140,16 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOpti
     opt = &vc->options;
   }
 
+  // Connection ID will be changed
+  vc->id = net_next_connection_number();
   vc->set_context(NET_VCONNECTION_OUT);
   vc->con.setRemote(addr);
-  vc->id          = net_next_connection_number();
   vc->submit_time = Thread::get_hrtime();
   vc->mutex       = cont->mutex;
   vc->action_     = cont;
 
   vc->start(this->_ssl_ctx);
-
-  vc->action_.continuation->handleEvent(NET_EVENT_OPEN, this);
+  vc->connectUp(t, NO_FD);
 
   return ACTION_RESULT_DONE;
 }
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 124a292..ac9cb6d 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -153,6 +153,24 @@ QUICNetVConnection::reenable(VIO *vio)
   return;
 }
 
+int
+QUICNetVConnection::connectUp(EThread *t, int fd)
+{
+  // create stream 0
+  // FIXME: integration w/ QUICStreamManager
+  QUICStream *stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream();
+  stream->init(this, this->connection_id(), STREAM_ID_FOR_HANDSHAKE);
+  if (!this->_handshake_handler->is_stream_set(stream)) {
+    this->_handshake_handler->set_stream(stream);
+  }
+
+  // start QUIC handshake
+  this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+
+  // action_.continuation->handleEvent(NET_EVENT_OPEN, this);
+  return CONNECT_SUCCESS;
+}
+
 QUICConnectionId
 QUICNetVConnection::original_connection_id()
 {
@@ -853,6 +871,11 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi
   QUICPacketUPtr packet = QUICPacketFactory::create_null_packet();
 
   switch (type) {
+  case QUICPacketType::INITIAL:
+    ink_assert(this->get_context() == NET_VCONNECTION_OUT);
+    packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(),
+                                                         QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len);
+    break;
   case QUICPacketType::HANDSHAKE:
     packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(),
                                                            std::move(buf), len, retransmittable);
@@ -862,8 +885,15 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi
       packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(),
                                                                     std::move(buf), len, retransmittable);
     } else {
-      packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(),
-                                                             std::move(buf), len, retransmittable);
+      // FIXME: remove this flag
+      if (this->get_context() == NET_VCONNECTION_OUT && this->_is_initial) {
+        this->_is_initial = false;
+        packet            = this->_packet_factory.create_initial_packet(
+          this->_original_quic_connection_id, this->largest_acked_packet_number(), QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len);
+      } else {
+        packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(),
+                                                               std::move(buf), len, retransmittable);
+      }
     }
     break;
   }
diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc
index 7c27016..9f5daab 100644
--- a/iocore/net/UnixUDPNet.cc
+++ b/iocore/net/UnixUDPNet.cc
@@ -303,9 +303,7 @@ UDPReadContinuation::UDPReadContinuation(Event *completionToken)
   }
 }
 
-UDPReadContinuation::UDPReadContinuation() : Continuation(nullptr)
-{
-}
+UDPReadContinuation::UDPReadContinuation() : Continuation(nullptr) {}
 
 inline void
 UDPReadContinuation::free()
@@ -710,13 +708,9 @@ Lerror:
 }
 
 // send out all packets that need to be sent out as of time=now
-UDPQueue::UDPQueue()
-{
-}
+UDPQueue::UDPQueue() {}
 
-UDPQueue::~UDPQueue()
-{
-}
+UDPQueue::~UDPQueue() {}
 
 /*
  * Driver function that aggregates packets across cont's and sends them
diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc
index 558e45a..db61dc3 100644
--- a/iocore/net/quic/QUICCrypto.cc
+++ b/iocore/net/quic/QUICCrypto.cc
@@ -38,10 +38,10 @@ static void
 to_hex(uint8_t *out, uint8_t *in, int in_len)
 {
   for (int i = 0; i < in_len; ++i) {
-    int u4 = in[i] / 16;
-    int l4 = in[i] % 16;
-    out [i * 2]     = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10);
-    out [i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10);
+    int u4         = in[i] / 16;
+    int l4         = in[i] % 16;
+    out[i * 2]     = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10);
+    out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10);
   }
   out[in_len * 2] = 0;
 }
@@ -50,9 +50,7 @@ to_hex(uint8_t *out, uint8_t *in, int in_len)
 // QUICPacketProtection
 //
 
-QUICPacketProtection::~QUICPacketProtection()
-{
-}
+QUICPacketProtection::~QUICPacketProtection() {}
 
 void
 QUICPacketProtection::set_key(std::unique_ptr<KeyMaterial> km, QUICKeyPhase phase)
@@ -173,7 +171,6 @@ QUICCryptoTls::is_handshake_finished() const
 int
 QUICCryptoTls::initialize_key_materials(QUICConnectionId cid)
 {
-
   // Generate keys
   uint8_t print_buf[512];
   std::unique_ptr<KeyMaterial> km;
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index c374dd3..1952a73 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -94,6 +94,8 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless
   this->_version_negotiator = new QUICVersionNegotiator();
 
   this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id());
+  // for client initial
+  this->_load_local_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]);
 
   SET_HANDLER(&QUICHandshake::state_initial);
 }
@@ -392,11 +394,14 @@ QUICHandshake::_do_handshake(bool initial)
 QUICErrorUPtr
 QUICHandshake::_process_initial()
 {
-  QUICErrorUPtr error = _do_handshake(true);
+  QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE);
+  QUICErrorUPtr error     = _do_handshake(true);
 
   if (error->cls == QUICErrorClass::NONE) {
     QUICHSDebug("Enter state_key_exchange");
     SET_HANDLER(&QUICHandshake::state_key_exchange);
+
+    stream_io->write_reenable();
   }
 
   return error;
diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h
index 5493e58..05be5c8 100644
--- a/iocore/net/quic/QUICStreamManager.h
+++ b/iocore/net/quic/QUICStreamManager.h
@@ -30,6 +30,8 @@
 #include "QUICFrame.h"
 #include "QUICFrameTransmitter.h"
 
+extern ClassAllocator<QUICStream> quicStreamAllocator;
+
 class QUICTransportParameters;
 
 class QUICStreamManager : public QUICFrameHandler
diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc
index 4263857..71d51af 100644
--- a/iocore/net/quic/test/test_QUICHandshake.cc
+++ b/iocore/net/quic/test/test_QUICHandshake.cc
@@ -25,11 +25,14 @@
 
 #include "Mock.h"
 #include "QUICHandshake.h"
+#include "QUICConfig.h"
 
 #include "./server_cert.h"
 
 TEST_CASE("1-RTT handshake ", "[quic]")
 {
+  QUICConfig::startup();
+
   // setup client
   QUICConnection *client_qc = new MockQUICConnection(NET_VCONNECTION_OUT);
 

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.