Skip to content

quic: extract transport logic from Application to Session#64127

Open
pimterry wants to merge 1 commit into
nodejs:mainfrom
pimterry:extract-h3-refactor
Open

quic: extract transport logic from Application to Session#64127
pimterry wants to merge 1 commit into
nodejs:mainfrom
pimterry:extract-h3-refactor

Conversation

@pimterry

Copy link
Copy Markdown
Member

Extracting out some standalone refactoring from #63995 for easier review while we keep debating the API. I think this is a helpful refactoring generally, but especially in a world where we're restructuring Application.

This shrinks the application layer by moving generic QUIC logic that will be used by all implementations into the Session itself, and makes the Session act as a clean interface over ngtcp2 - so that the Application exclusively uses Session methods for all connection manipulation, instead of managing ngtcp2 directly. This gives a cleaner split between the low-level QUIC behaviour and the per-application-protocol layer.

There's two small fixes notably included in the migration, contained within the moved code:

  • This fixes a SendPendingData bug where datagrams would stall and never send on an idle connection, in the nwrite == 0 branch.
  • We now check is_destroyed() after StreamCommit, since it calls JS callbacks which could destroy the session.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/quic

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Jun 25, 2026
Two small fixes notably included:

- Fixed a SendPendingData but where datagrams would stall on an idle
  connection in the nwrite == 0 branch.
- Check is_destroyed() after StreamCommit, since it calls JS callbacks
  which could destroy the session.

Signed-off-by: Tim Perry <pimterry@gmail.com>
Comment thread src/quic/session.h
// A block of pending outbound stream data, passed between the application
// layer (which fills it via GetStreamData) and the send pump (which hands
// it to ngtcp2_conn_writev_stream and commits the accepted length).
struct StreamData final {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If at all possible, I think this should likely be moved into class Session (e.g. Session::StreamData). It makes more sense as a child class than it's own top-level.

Comment thread src/quic/session.h
// The stream identifier. If this is a negative value then no stream is
// identified.
stream_id id = -1;
int fin = 0;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're changing things anyway, making this a bool would probably make sense.

Comment thread src/quic/session.h
stream_id id = -1;
int fin = 0;
ngtcp2_vec data[kMaxVectorCount]{};
BaseObjectPtr<Stream> stream;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can drop id and just rely on stream.

Comment thread src/quic/session.h
Comment on lines +449 to +450
// If < 0 is returned, either NGTCP2_ERR_WRITE_MORE or a fatal error is
// returned; the caller must check. If > 0 is returned, the packet is done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// If < 0 is returned, either NGTCP2_ERR_WRITE_MORE or a fatal error is
// returned; the caller must check. If > 0 is returned, the packet is done
// If a negative value is returned, it is either NGTCP2_ERR_WRITE_MORE or
// fatal error; the caller must check. If > 0 is returned, the packet is done

Comment thread src/quic/session.h
// the session, encapsulating ngtcp2 transport details here.

// Open a unidirectional stream, setting *id on success, or returning false
bool OpenUni(stream_id* id);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer to avoid abbreviating. s/OpenUni/OpenUnidirectionalStream

Comment thread src/quic/session.h

void ExtendMaxStreams(Direction direction, uint64_t max);

// Signal that we've consumed $len bytes on stream $id to update flow control

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Signal that we've consumed $len bytes on stream $id to update flow control
// Signal that we've consumed `len` bytes on stream $id to update flow control

Comment thread src/quic/session.cc
PopPendingDatagram();
} else {
Debug(this, "Datagram %" PRIu64 " not accepted into packet", dg.id);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I think this has a bug. If dg_nwrite is positive, it appears to fall-through to the default: case below?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(To be fair, I don't think it's a new bug ;-) ...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants