fails-components / webtransport

Http/3 webtransport support for node
Other
128 stars 19 forks source link

0-rtt support #213

Open ktprime opened 8 months ago

ktprime commented 8 months ago

can server/client save the cfg/session file to use 0-rtt ?

martenrichter commented 8 months ago

Can you give some additional information? May be a pointer to the spec....

ktprime commented 8 months ago

I know how to set/reuse 0-rtt session only google-quic version(Q043-Q050), but I have no any ideal to ietf quic version.

void QuicSessionEntry::OnCryptoHandshakeComplete()
{
    if (conn_state_ == QuicSessionState::QuicSessionState_Connected)
        return;

    //TODO:if tls serssion.
    if (statics_.use_text >= 0 || config_.quic_version > quic::QUIC_VERSION_50)
    {
        const auto head_protect = config_.quic_version >= quic::QUIC_VERSION_50 ? 12 : 0;
        auto level = ENCRYPTION_FORWARD_SECURE;
        auto* qconnection = qsession_->connection();
        //DebugPrint(dbg_event, " ====== set text %d ===== ", statics_.use_text);

        qconnection->SetEncrypter(level,
                std::make_unique<quic_sdk::TextEncrypter>(qconnection->perspective(), true, head_protect));
        qconnection->SetAlternativeDecrypter(level,
                std::make_unique<quic_sdk::TextDecrypter>(qconnection->perspective(), true, head_protect), false);
    }

    conn_state_ = QuicSessionState::QuicSessionState_Connected;
    has_connected_ = true;

    statics_.hands_time = int(CLOCK_NOWCMS - last_contime_);
    auto num_sent_client_hellos = statics_.hands_rtts;
    auto* ep = packet_transport_->GetPoller();

    if (IsServer()) {
#if HYB_QUIC_SERVER
#ifndef DELAY_NOTIFY_SERVERCON
        ep->NotifyListeren(Fd(), udp_socket_);
#endif
        if (config_.use_0rtt && gserver_cfg_.empty()) {
            gserver_cfg_ = session_factory_->getCryptoServerConfig()->serialized_crypto_config;
            if (QuicHasOption(cfg_file_session_key) == 0)
               WriteString2File("server_config.cfg", gserver_cfg_); //save server 0-rtt session
        }
#endif
    } else {
        ConnectionManager().UpdateTimeOut(Fd(), connection_id());
        if (num_sent_client_hellos > 1 && config_.use_0rtt) {
           ((quic::QuartcClientSession*)qsession_)->get_server_config(server_cfg_);
            WriteString2File("client_config.cfg", server_cfg_); // //save client 0-rtt session
        }
        ep->AddPollEvent(QPOLLOUT, this);
        early_data_.clear();
    }

    server_cfg_.clear(); //never used again.
    LogPrint("%d-RTT hands_time:%d ms, text = %d", num_sent_client_hellos, statics_.hands_time, statics_.use_text);
}
martenrichter commented 8 months ago

Ok, what is the use case for Webtransport. Probably mainly for the server, if it is for the client, where is it in the spec for the WebTransport web javascript interface.

Is it just to save the crypto config of the server or client for later? I currently have no clue about the use case and what change of interface would be needed.

ktprime commented 8 months ago

the crypto config can also be saved in memory for web server/client? it's seem the Http3SessionCache need to be inited by 0-rtt use (from memory crypto cache or file ?)

  void Insert(const QuicServerId& server_id,
              bssl::UniquePtr<SSL_SESSION> session,
              const TransportParameters& params,
              const ApplicationState* application_state) override;
martenrichter commented 8 months ago

Yes, but what will be the use case? That I need to understand how to draft an API for this feature (and also for deciding, if I want to support it).

achingbrain commented 2 months ago

I've just come across this problem as well.

I'm trying to accept connections from webtransport-go clients that use quic-go's EarlyConnection feature, eg:

https://github.com/libp2p/go-libp2p/blob/0385ec924bad172f74a74db09939e97c079b1420/p2p/transport/webtransport/transport.go#L205-L219

I'm trying to create a simple reproduction, it's something like:

package main

import (
    "context"
    "crypto/tls"
    _ "embed"
    "fmt"
    "log"

    "github.com/quic-go/quic-go"
    "github.com/quic-go/webtransport-go"
)

func main() {
    addr := "127.0.0.1:35909"
    url := "https://127.0.0.1:35909"
    ctx := context.Background()

    // n.b. need to load the server cert here if it's self-signed
    tlsConf := &tls.Config{}
    quicConf := &quic.Config{}

    earlyConn, err := quic.DialAddrEarly(ctx, addr, tlsConf, quicConf)
    if err != nil {
        log.Fatal(err)
    }

    dialer := webtransport.Dialer{
        DialAddr: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
            return earlyConn.(quic.EarlyConnection), nil
        },
        QUICConfig: quicConf.Clone(),
    }
    rsp, sess, err := dialer.Dial(ctx, url, nil)
    if err != nil {
        log.Fatal(err)
    }
    if rsp.StatusCode < 200 || rsp.StatusCode > 299 {
        err := fmt.Errorf("invalid response status code from %s : %d", url, rsp.StatusCode)
        log.Fatal(err)
    }

    //...do something with sess
}

The client always gets a 404 from a @fails-components/webtransport-transport-http3-quiche server.

From what I can see the request gets to this line but there's no WebTransport session yet so it continues to this line and a 404 is returned.

achingbrain commented 2 months ago

The use case is transferring small amounts of data - connection establishment ends up adding significant overhead when the expected data payload is small so 0-RTT makes this much more viable.

martenrichter commented 2 months ago

I am not sure if it is the same thing. The issue was regarding reusing the stored data for 0-rtt between different server starts. You seem to want to reuse a WebTransport session from a previous connection. Can you point me to the part of the WebTransport protocol spec where it says this should be possible? I would think that a new WebTransport Session stream has to be established in the 0-rtt case, or should old streams be reused? Currently, I have no idea, how I should it implement it, following the spec.

martenrichter commented 2 months ago

I have read a little more in the specs you find in [https://datatracker.ietf.org/doc/html/[draft-ietf-webtrans-http3-07](https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3-07):

Clients cannot initiate WebTransport in 0-RTT packets, as the CONNECT method is not considered safe; see Section 10.9 of [HTTP3]. However, WebTransport-related SETTINGS parameters may be retained from the previous session as described in Section 7.2.4.2 of [HTTP3]. If the server accepts 0-RTT, the server MUST NOT reduce the limit of maximum open WebTransport sessions from the one negotiated during the previous session; such change would be deemed incompatible, and MUST result in a H3_SETTINGS_ERROR connection error.

Older revisions state that it is impossible to use 0-rtt at all. It still sounds like WebTransport may not be possible or is limited in 0-rtt connections. Anyway, I still have no clue how to act in this case, as the specification does not spell out this case. The second thing is that I rely on the support of this feature in the underlying libquiche, and I also have no clue if it supports this case. So without more information, I can not do anything, and it might not be inside the spec or unsafe.

martenrichter commented 2 months ago

You can look at: https://github.com/google/quiche/blob/065baa708f81459a4c86712945df629edd056ab6/quiche/quic/core/http/quic_spdy_stream.cc#L1342 This is the code, that determines, if it is a web_transport() is set. So basically, if you get a 404, it means, that you do not fulfill the requirements in this piece of code or that it is not executed. (It basically checks the headers of the connect message, if it has protocol and method set right). Furthermore this call https://github.com/google/quiche/blob/065baa708f81459a4c86712945df629edd056ab6/quiche/quic/core/http/quic_spdy_stream.cc#L1343 checks, the conditions here: https://github.com/google/quiche/blob/065baa708f81459a4c86712945df629edd056ab6/quiche/quic/core/http/quic_spdy_session.cc#L1774