# How XQUIC Supports QUIC Draft-29: Implementation Details in the Alibaba Library

> Explore how XQUIC implements QUIC draft-29 with dedicated constants, draft-specific TLS salts, ALPN mapping, and configurable engine parameters for clients and servers.

- Repository: [Alibaba/xquic](https://github.com/alibaba/xquic)
- Tags: internals
- Published: 2026-02-24

---

**XQUIC implements IETF QUIC draft-29 through dedicated protocol version constants, draft-specific TLS cryptographic salts, ALPN mapping to `h3-29`, and configurable engine parameters that enable both client and server operations.**

The Alibaba XQUIC library maintains backward compatibility with IETF QUIC draft-29 alongside QUIC v1, allowing interoperability with legacy implementations. This support is embedded at multiple layers of the stack, from wire-format constants to connection-level version negotiation. Understanding these implementation details helps developers configure the library for specific protocol requirements.

## Protocol Version Constants and Enumeration

XQUIC defines draft-29 as a distinct protocol version through the enumeration system in [`include/xquic/xquic.h`](https://github.com/alibaba/xquic/blob/main/include/xquic/xquic.h). The library assigns `XQC_IDRAFT_VER_29` the numeric value `2`, separating it from QUIC v1 and other draft iterations.

The wire-format constants reside in [`src/transport/xqc_defs.h`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_defs.h). Here, XQUIC specifies the 32-bit version number `0xFF00001D` and the 4-byte field `{0xFF,0x00,0x00,0x1D}` used in packet headers. These values match the IETF specification for draft-29 version identification.

## Cryptographic Parameters for Draft-29

Draft-29 requires specific initial salts and retry integrity keys for TLS 1.3 handshake integration. XQUIC stores these parameters in [`src/tls/xqc_tls_common.h`](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_common.h), defining the **initial salt**, **retry key**, and **retry nonce** required for draft-29 operation.

Notably, XQUIC shares these cryptographic constants between draft-29 and drafts 30-32, as these versions used identical TLS parameter sets before the final QUIC v1 specification changed the salt values.

## HTTP/3 ALPN Negotiation

For HTTP/3 support, XQUIC maps draft-29 to the application-layer protocol negotiation (ALPN) string `h3-29` in [`src/http3/xqc_h3_defs.c`](https://github.com/alibaba/xquic/blob/main/src/http3/xqc_h3_defs.c). This mapping ensures that when a connection negotiates draft-29, the corresponding HTTP/3 layer correctly advertises the draft-specific protocol identifier during the TLS handshake.

## Engine Configuration and Version Validation

The transport layer configures draft-29 support through the engine API in [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c). Server configurations populate the `support_version_list` array with `XQC_IDRAFT_VER_29_VALUE`, advertising draft-29 availability during version negotiation.

Version validation occurs through the `xqc_check_proto_version_valid()` macro defined in [`src/transport/xqc_defs.h`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_defs.h). This macro guarantees that only explicitly defined versions—including draft-29—are accepted during connection establishment, preventing negotiation of unsupported protocol variants.

## Connection Handling and Retry Logic

In [`src/transport/xqc_conn.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_conn.c), XQUIC implements draft-specific connection behaviors. When processing retry packets, the library treats draft-29 as "too old" for retry packet logic, matching the IETF specification's guidance that legacy drafts should bypass certain retry mechanisms. This distinction appears in the connection state machine around line 4173.

## Practical Implementation: Client and Server Examples

### Configuring a Draft-29 Client

To force a client connection to use draft-29, set the `proto_version` field in the configuration structure:

```c
#include <xquic/xquic.h>

int main(void) {
    xqc_engine_t *engine = xqc_engine_create(XQC_ENGINE_CLIENT, NULL);
    if (!engine) return -1;

    xqc_config_t cfg = XQC_CLIENT_DEFAULT_CONFIG;
    cfg.proto_version = XQC_IDRAFT_VER_29;  /* Select draft-29 */

    if (xqc_engine_set_config(engine, &cfg) != 0) return -1;

    xqc_connection_t *conn = NULL;
    xqc_engine_connect(engine, &conn, "example.com", 4433,
                       XQC_IDRAFT_VER_29, NULL);
    /* Handle streams and I/O */
    return 0;
}

```

The `cfg.proto_version = XQC_IDRAFT_VER_29` assignment forces the client to use version `0xFF00001D`, automatically selecting the matching TLS initial salt and `h3-29` ALPN.

### Advertising Draft-29 on a Server

Servers can support both v1 and draft-29 by populating the version list:

```c
#include <xquic/xquic.h>

int main(void) {
    xqc_engine_t *engine = xqc_engine_create(XQC_ENGINE_SERVER, NULL);
    if (!engine) return -1;

    xqc_config_t cfg = XQC_SERVER_DEFAULT_CONFIG;
    cfg.support_version_count = 2;
    cfg.support_version_list[0] = XQC_VERSION_V1_VALUE;      /* QUIC v1 */
    cfg.support_version_list[1] = XQC_IDRAFT_VER_29_VALUE;   /* Draft-29 */

    xqc_engine_set_config(engine, &cfg);
    /* Bind to UDP socket and accept connections */
    return 0;
}

```

This configuration announces both versions during the version negotiation phase, allowing the client to select its preferred protocol.

## Summary

- XQUIC defines draft-29 as `XQC_IDRAFT_VER_29` (value `2`) in [`include/xquic/xquic.h`](https://github.com/alibaba/xquic/blob/main/include/xquic/xquic.h) with wire-format constant `0xFF00001D` in [`src/transport/xqc_defs.h`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_defs.h).
- Cryptographic parameters including initial salt and retry keys are shared between draft-29 and drafts 30-32 in [`src/tls/xqc_tls_common.h`](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_common.h).
- The HTTP/3 layer maps draft-29 to ALPN string `h3-29` via [`src/http3/xqc_h3_defs.c`](https://github.com/alibaba/xquic/blob/main/src/http3/xqc_h3_defs.c).
- Clients select draft-29 through `cfg.proto_version`, while servers advertise it via `support_version_list` in the engine configuration.
- Version validation uses the `xqc_check_proto_version_valid()` macro to enforce protocol compliance.

## Frequently Asked Questions

### What is the numeric version identifier for draft-29 in XQUIC?

XQUIC represents draft-29 as the 32-bit hexadecimal value `0xFF00001D` (defined as `XQC_IDRAFT_VER_29_VALUE` in [`src/transport/xqc_defs.h`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_defs.h)) and the enum value `XQC_IDRAFT_VER_29` equal to `2`. These constants appear in packet headers during the wire protocol exchange.

### Does XQUIC share cryptographic parameters between draft-29 and newer versions?

Yes, according to the implementation in [`src/tls/xqc_tls_common.h`](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_common.h), XQUIC uses identical initial salts, retry keys, and retry nonces for draft-29 through draft-32. This cryptographic continuity distinguishes these drafts from QUIC v1, which employs different salt values.

### How do I force a client connection to use draft-29 instead of QUIC v1?

Set `cfg.proto_version = XQC_IDRAFT_VER_29` in the `xqc_config_t` structure before calling `xqc_engine_set_config()`. This overrides the default version selection and forces the connection to use draft-29's version number (`0xFF00001D`) and corresponding `h3-29` ALPN.

### Why does XQUIC treat draft-29 as "too old" for retry packet processing?

As implemented in [`src/transport/xqc_conn.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_conn.c), XQUIC excludes draft-29 from retry packet logic because the IETF specification updated retry integrity tag calculation in later versions. Treating draft-29 as a legacy version ensures compliance with the specific retry packet requirements that existed during that draft era.