Skip to content
Please note that GitHub no longer supports Internet Explorer.

We recommend upgrading to the latest Microsoft Edge, Google Chrome, or Firefox.

Learn more
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] quic: initial experimental quic implementation #30943

Open
wants to merge 8 commits into
base: master
from

Conversation

@jasnell
Copy link
Member

jasnell commented Dec 13, 2019

THIS IS A WORK IN PROGRESS THAT WILL BE UPDATED OVER TIME

To follow up the discussion from the Collaborator Summit, I will be hosting (and recording) a call on Friday December 20th at 8am Pacific Time to go through the QUIC PR to help break down how to start reviewing the PR. This will be the first of several calls. I will post the call details here Friday morning.

(Note: I meant to open this as a draft PR but hit the wrong button and can't change it now.... PLEASE DON'T EVEN CONSIDER LANDING THIS YET ;-) ...)

This is the initial QUIC implementation. It is experimental, it is still unfinished, and it's very complicated. I'm opening this draft PR to start the process, but there is still much to do before it can be landed.

Reviewing: I will be scheduling an hour long call in the next couple of weeks to walk people through the implementation, answer questions, and help guide the review process. That will be recorded for those who cannot make it.

To get started with this, use ./configure --experimental-quic or vcbuild experimental-quic to build with the quic support enabled.

EXPECT BUGS!!

This adds two new dependencies: ngtcp2 and nghttp3.

This also patches openssl to add the new boringssl quic apis. This is a floated patch that hopefully we'll be able to drop later.

There will be a significantly more detailed bit of information added to this PR later.

It is semver-major because of the additional top level module and the changes to openssl (there are no functional changes to openssl if quic is not being used)

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
addaleax and others added 7 commits Oct 1, 2019
PR-URL: nodejs/quic#145
Reviewed-By: James M Snell <jasnell@gmail.com>
PR-URL: nodejs/quic#150
Reviewed-By: James M Snell <jasnell@gmail.com>
Allow using the handle more directly for I/O in other parts of
the codebase.

PR-URL: nodejs/quic#165
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
PR-URL: nodejs/quic#138
Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: nodejs/quic#138
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Co-authored-by: Anna Henningsen <anna@addaleax.net>
Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>
Co-authored-by: gengjiawen <technicalcute@gmail.com>
Co-authored-by: James M Snell <jasnell@gmail.com>
Co-authored-by: Lucas Pardue <lucaspardue.24.7@gmail.com>
Co-authored-by: Ouyang Yadong <oyydoibh@gmail.com>
Co-authored-by: Juan Jos<C3><A9> Arboleda <soyjuanarbol@gmail.com>
Co-authored-by: Trivikram Kamat <trivikr.dev@gmail.com>
Co-authored-by: Denys Otrishko <shishugi@gmail.com>
@jasnell

This comment has been minimized.

Copy link
Member Author

jasnell commented Dec 13, 2019

Some initial details to get started...

This PR adds two new additional dependencies: ngtcp2 and nghttp3, and patches openssl for quic support.

  • ngtcp2 implements the core of the QUIC protocol on our behalf. There are extremely complex state management requirements, protocol flow, serialization, etc that this library handles for us.
  • nghttp3 implements the http3 specific bits for us. It is similar to nghttp2, and there are some areas of overlap, but it is designed specifically to work with ngtcp2. Where there is overall, we have implemented some utility wrappers that can be used to abstract away the differences.

For OpenSSL... QUIC includes built in support for TLS 1.3 but the timing of key generation is different for QUIC than it is for TCP. The BoringSSL project has implemented a new set of QUIC specific APIs that are currently being actively backported to OpenSSL 3.x. The PR, however, has not yet landed in OpenSSL. Since we are running OpenSSL 1.1.1, I further backported the APIs from that open OpenSSL 3 PR to our instance of 1.1.1. Whee! Once we are able to move to OpenSSL 3.x, will be able to avoid floating those patches. When QUIC is not being used, there are no changes to OpenSSL function at runtime. One practical limitation of this is that it means we can only use the bundled version of OpenSSL and cannot use the shared version.

Additional information in a later update.

@@ -1125,6 +1125,56 @@ E('ERR_OUT_OF_RANGE',
msg += ` It must be ${range}. Received ${received}`;
return msg;
}, RangeError);
E('ERR_QUICCLIENTSESSION_FAILED',
'Failed to create a new QuicClientSession: %s', Error);
E('ERR_QUICCLIENTSESSION_FAILED_SETSOCKET',

This comment has been minimized.

Copy link
@gengjiawen

gengjiawen Dec 14, 2019

Member

ERR_QUICCLIENTSESSION_FAILED_SETSOCKET -> ERR_QUIC_CLIENT_SESSION_FAILED_SETSOCKET is easier to read.

doc/api/quic.md Show resolved Hide resolved
doc/api/quic.md Show resolved Hide resolved
doc/api/quic.md Show resolved Hide resolved
doc/api/quic.md Show resolved Hide resolved
doc/api/quic.md Show resolved Hide resolved
@gengjiawen

This comment has been minimized.

Copy link
Member

gengjiawen commented Dec 14, 2019

I am unable build successfully on macOS (works on linux), anyone tried yet ?

OS: macOS 10.15.2
Xcode: 11.3/11C29 - /usr/bin/xcodebuil
In file included from ../../src/env.h:35:
In file included from ../../src/handle_wrap.h:27:
In file included from ../../src/async_wrap.h:27:
../../src/base_object.h:100:23: error: inline function 'node::BaseObject::OnGCCollect' is not defined [-Werror,-Wundefined-inline]
  virtual inline void OnGCCollect();
                      ^
../../src/node_crypto.h:95:3: note: used here
  ~SecureContext() override {
  ^
5 errors generated.
[900/942] CXX obj/src/libnode.node_quic_socket.o
../../src/node_quic_socket.cc:1071:15: warning: unused variable 'socket' [-Wunused-variable]
  QuicSocket* socket =
              ^
1 warning generated.
[901/942] CXX obj/src/libnode.node_quic_session.o
../../src/node_quic_session.cc:2944:8: warning: unused variable 'n' [-Wunused-variable]
  auto n = ngtcp2_conn_get_remote_addr(conn);
       ^
1 warning generated.
[902/942] CXX obj/src/libnode.node_crypto.o
../../src/node_crypto.cc:2597:15: warning: unused variable 'cipher_version' [-Wunused-variable]
  const char* cipher_version = SSL_CIPHER_get_version(c);
              ^
1 warning generated.
ninja: build stopped: subcommand failed.
@addaleax

This comment has been minimized.

Copy link
Member

addaleax commented Dec 14, 2019

@gengjiawen I think @danbev’s nodejs/quic#220 would be addressing this?

@gengjiawen

This comment has been minimized.

Copy link
Member

gengjiawen commented Dec 15, 2019

@gengjiawen I think @danbev’s nodejs/quic#220 would be addressing this?

This PR works :)

@sam-github sam-github mentioned this pull request Dec 17, 2019
2 of 2 tasks complete
@jasnell

This comment has been minimized.

Copy link
Member Author

jasnell commented Dec 20, 2019

~~In a few minutes (8am Pacific time on 12/20), I will be kicking off an hour long call where I will be going through the PR in detail. It will be recorded and will be the first of several calls that I will do to help guide folks through the pull request and current status of QUIC development.

Details for joining the call here: nodejs/quic#229 (comment)~~

Cancelled after no one else showed after 15 minutes... only @addaleax was there. Will schedule another one in early January.


* `code` {number}

Closes the `QuicStream`.

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

What's the difference between QuicStream.close and Duplex.destroy?

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

Seems like a graceful variant of destroy. Is this something we should move one level up into Duplex? Graceful shutdown of Readable is push(null) and for Writable it is end(), but I guess this is for Duplex which should do both.

This comment has been minimized.

Copy link
@jasnell

jasnell Dec 27, 2019

Author Member

We could potentially add a similar concept to Duplex in general. Would have to see what makes sense.

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

What's the purpose of the 'abort' event? Detecting ungraceful shutdown? Isn't that the same as premature close? i.e. do we need this?

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

autoDestroy: true (or at least explicit false)?

This comment has been minimized.

Copy link
@ronag

ronag Jan 3, 2020

Member

@jasnell: FYI, master now sets autoDestroy: true by default (instead of false)... in case that affects anything.

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

Forwarding all options like this is something I would prefer we avoid. Can we just forward potentially relevant options? In this case I believe it's only (readable|writable|)highWaterMark?

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

This is fiddling with stream internals. Maybe a note on why it's required?

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

This is fiddling with stream internals. Maybe a note on why it's required?

@ronag

This comment has been minimized.

Copy link
Member

ronag commented Dec 26, 2019

Pending PR's with potential impact on the streams part of this PR:

#29656
#29179
#30623

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

Shouldn't this happen in _destroy or inside an event listener for finish & end?

e.g.

function onEndFinish () {
  if (this.writableFinished && this.readableEnded) {
    this[kHandle].resetStream(code, family);
  }
}
this.on('end', onEndFinish);
this.on('finish', onEndFinish);

Or something along those lines...

options,
this.#qlogEnabled);
// We no longer need these, unset them so

This comment has been minimized.

Copy link
@ronag

ronag Dec 26, 2019

Member

Why is this read() call required?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.