# What Is xqc_engine_register_alpn in XQUIC? ALPN Registration Explained

> Learn how xqc_engine_register_alpn in XQUIC registers ALPN identifiers to enable TLS handshake protocol negotiation and route connections efficiently. Understand ALPN registration.

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

---

**`xqc_engine_register_alpn` binds an Application-Layer Protocol Negotiation (ALPN) identifier to an XQUIC engine, enabling the TLS handshake to advertise supported protocols while routing incoming connections to the correct protocol-specific callback handlers.**

After creating an `xqc_engine_t` instance in the alibaba/xquic repository, developers use `xqc_engine_register_alpn` to declare which application protocols the engine supports. This function serves as the bridge between TLS-level ALPN negotiation and XQUIC's modular protocol stack, allowing a single engine to simultaneously handle HTTP/3, HQ, or custom transport protocols without reconstruction.

## How xqc_engine_register_alpn Works

The function performs three coordinated tasks to integrate protocol support into the engine:

1. **TLS Context Registration** – Calls `xqc_tls_ctx_register_alpn` to append raw ALPN bytes to the internal `alpn_list` buffer, ensuring the TLS handshake advertises supported protocols to peers.

2. **Callback Storage** – Saves an `xqc_app_proto_callbacks_t` structure in an `xqc_alpn_registration_t` entry within the engine's `alpn_reg_list`. This table contains functions for connection creation, packet processing, and stream handling specific to the protocol.

3. **Lookup Helper Registration** – Enables subsequent retrieval via `xqc_engine_get_alpn_callbacks` and `xqc_engine_get_alpn_ctx`, allowing the engine to route packets to the correct module after ALPN selection.

This architecture enables **multi-protocol support** and **runtime callback updates** without rebuilding the engine. The internal relationship between components follows this structure:

```

+-------------------+        +------------------------+
| xqc_engine_t      | <----> | xqc_tls_ctx_t          |
|  - alpn_reg_list  |        |  - alpn_list (raw bytes)|
|  - callbacks ... |        +------------------------+
+-------------------+
        |
        |  xqc_engine_register_alpn(...)
        v
+-------------------------------+
| xqc_alpn_registration_t      |
|  - alpn string                |
|  - ap_cbs (protocol callbacks)|
|  - alp_ctx (user data)        |
+-------------------------------+

```

## Implementation in the XQUIC Source

The registration logic resides in [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c), where the public API validates inputs and delegates to internal helpers that synchronize state with the TLS layer.

### Engine Registration Logic

In [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c) (lines 1396–1420), `xqc_engine_register_alpn` validates parameters and delegates to `xqc_engine_add_alpn`:

```c
xqc_int_t
xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len,
    xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx)
{
    /* validation, duplicate check, and delegation */
    return xqc_engine_add_alpn(engine, alpn, alpn_len, ap_cbs, alp_ctx);
}

```

The internal `xqc_engine_add_alpn` function checks for duplicate entries at lines 1007–1015. If the ALPN already exists, it updates the stored callbacks rather than creating a new registration, enabling hot-swapping of protocol handlers.

### TLS Layer Integration

The TLS context receives length-prefixed ALPN bytes through `xqc_tls_ctx_register_alpn` in [`src/tls/xqc_tls_ctx.c`](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_ctx.c) (lines 38–73):

```c
xqc_int_t
xqc_tls_ctx_register_alpn(xqc_tls_ctx_t *ctx, const char *alpn, size_t alpn_len)
{
    /* buffer growth and formatting via snprintf("%c%s", len, alpn) */
    return XQC_OK;
}

```

This appends the ALPN to the `alpn_list` buffer used during ClientHello and ServerHello processing, as documented in the public API at [`docs/API.md`](https://github.com/alibaba/xquic/blob/main/docs/API.md).

## Practical Code Examples

### Registering a Custom Transport Protocol

To add support for a custom protocol like "myproto", define the callbacks and register them after engine creation:

```c
/* Define protocol-specific callbacks */
static xqc_app_proto_callbacks_t my_proto_cbs = {
    .conn_cbs.conn_create_notify = my_conn_create,
    .stream_cbs.stream_open_notify = my_stream_open,
    /* additional handlers... */
};

/* Create engine and register ALPN */
xqc_engine_t *engine = xqc_engine_create(...);

xqc_int_t ret = xqc_engine_register_alpn(engine,
                                         "myproto", 7,
                                         &my_proto_cbs,
                                         NULL);   /* optional user context */
if (ret != XQC_OK) {
    /* handle registration failure */
}

```

*Source:* Reference implementation in [`tests/unittest/xqc_packet_test.c`](https://github.com/alibaba/xquic/blob/main/tests/unittest/xqc_packet_test.c) (lines 69–71) demonstrates this pattern for the "transport" ALPN.

### Updating Callbacks at Runtime

XQUIC supports dynamic callback replacement by re-registering the same ALPN. When duplicate detection triggers at lines 1007–1015 in [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c), the engine replaces the existing callback table:

```c
/* Define updated callback table */
xqc_app_proto_callbacks_t new_cbs = {
    .conn_cbs.conn_create_notify = new_conn_create,
    .stream_cbs.stream_write_notify = new_stream_write,
};

/* Re-register to hot-swap handlers for existing "transport" ALPN */
xqc_engine_register_alpn(engine, "transport", 9, &new_cbs, NULL);

```

### Retrieving User Context

Store and retrieve protocol-specific user data via the registration API:

```c
/* Register with custom context pointer */
void *my_ctx = custom_protocol_state;
xqc_engine_register_alpn(engine, "hq", 2, &hq_cbs, my_ctx);

/* Later retrieval during connection handling */
void *retrieved_ctx = xqc_engine_get_alpn_ctx(engine, "hq", 2);
if (retrieved_ctx) {
    /* access custom protocol state */
}

```

The `xqc_engine_get_alpn_ctx` function is implemented in [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c) (lines 24–38).

## Key Source Files

- **[`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c)** – Core registration logic, duplicate detection (lines 1007–1015), and lookup helpers `xqc_engine_get_alpn_ctx` and `xqc_engine_get_alpn_callbacks`.  
  [View source](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c)

- **[`src/tls/xqc_tls_ctx.c`](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_ctx.c)** – TLS-level ALPN buffer management via `xqc_tls_ctx_register_alpn`.  
  [View source](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_ctx.c)

- **[`include/xquic/xquic.h`](https://github.com/alibaba/xquic/blob/main/include/xquic/xquic.h)** – Public API declarations for `xqc_engine_register_alpn` and the `xqc_app_proto_callbacks_t` structure.  
  [View source](https://github.com/alibaba/xquic/blob/main/include/xquic/xquic.h)

- **[`demo/xqc_hq_ctx.c`](https://github.com/alibaba/xquic/blob/main/demo/xqc_hq_ctx.c)** – Production example registering "hq" and "hq-29" ALPNs with complete callback implementations.  
  [View source](https://github.com/alibaba/xquic/blob/main/demo/xqc_hq_ctx.c)

## Summary

- **`xqc_engine_register_alpn`** is the mandatory API for binding ALPN identifiers to protocol implementations in alibaba/xquic.
- The function registers ALPN strings with the underlying TLS context while storing callback tables in the engine's `alpn_reg_list`.
- It supports **multi-protocol engines** by allowing multiple registrations on a single `xqc_engine_t` instance.
- **Runtime updates** are supported through duplicate detection logic that replaces existing callback tables rather than failing.
- Lookup helpers like `xqc_engine_get_alpn_ctx` enable protocol-specific state retrieval during connection and stream processing.

## Frequently Asked Questions

### What does ALPN negotiation accomplish in XQUIC?

ALPN (Application-Layer Protocol Negotiation) allows the client and server to agree on which application protocol to use—such as HTTP/3 ("h3") or HQ ("hq")—during the TLS handshake. The `xqc_engine_register_alpn` function ensures the engine advertises supported protocols via the TLS layer and routes negotiated connections to the appropriate callback handlers.

### Can a single XQUIC engine support multiple protocols simultaneously?

Yes. By calling `xqc_engine_register_alpn` multiple times with different ALPN strings, a single engine instance can handle multiple protocols concurrently. The engine maintains an `alpn_reg_list` (a linked list of `xqc_alpn_registration_t` entries), with each node containing distinct callback tables for its respective protocol.

### How does xqc_engine_register_alpn handle duplicate ALPN registrations?

When the function detects an existing registration for the same ALPN string (implemented in `xqc_engine_add_alpn` at lines 1007–1015 of [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c)), it updates the stored `xqc_app_proto_callbacks_t` pointer and user context rather than returning an error. This design enables hot-swapping of protocol handlers at runtime without destroying the engine.

### Where is the ALPN data stored after registration?

The ALPN identifier exists in two locations: the raw length-prefixed bytes reside in the TLS context's `alpn_list` buffer (managed in [`src/tls/xqc_tls_ctx.c`](https://github.com/alibaba/xquic/blob/main/src/tls/xqc_tls_ctx.c)), while the structured registration entry containing the callback table and user context resides in the engine's `alpn_reg_list` (managed in [`src/transport/xqc_engine.c`](https://github.com/alibaba/xquic/blob/main/src/transport/xqc_engine.c)). This separation allows the TLS layer to handle handshake advertisement while the transport layer manages protocol-specific behavior.