# Mux.Cool 协议

Mux.Cool 协议是一个多路复用传输协议，用于在一条已建立的数据流中传输多个各自独立的数据流。

## 版本

当前版本是 1 Beta。

## 依赖

### 底层协议

Mux.Cool 必须运行在一个已建立的可靠数据流之上。

## 通讯过程

一个 Mux.Cool 连接中可传输若干个子连接，每个子连接有一个独立的 ID 和状态。传输过程由帧（Frame）组成，每一帧用于传输一个特定的子连接的数据。

### 客户端行为

当有连接需求时并且没有现有可用的连接时，客户端向服务器发起一个新连接，以下称为“主连接”。

1. 一个主连接可用于发送若干个子连接。客户端可自主决定主连接可承载的子连接数量。
1. 对于一个新的子连接，客户端必须发送状态`New`以通知服务器建立子连接，然后使用状态`Keep`来传送数据。
1. 当子连接结束时，客户端发送`End`状态来通知服务器关闭子连接。
1. 客户端可自行决定何时关闭主连接，但必须确定服务器也同时保持连接。
1. 客户端可使用 KeepAlive 状态来避免服务器关闭主连接。

### 服务器端行为

当服务器端接收到新的子连接时，服务器应当按正常的连接来处理。

1. 当收到状态`End`时，服务器端可以关闭对目标地址的上行连接。
1. 在服务器的响应中，必须使用与请求相同的 ID 来传输子连接的数据。
1. 服务器不能使用`New`状态。
1. 服务器可使用 KeepAlive 状态来避免客户端关闭主连接。

## 传输格式

Mux.Cool 使用对称传输格式，即客户端和服务器发送和接收相同格式的数据。

### 帧格式

| 2 字节       | L 字节 | X 字节   |
| ------------ | ------ | -------- |
| 元数据长度 L | 元数据 | 额外数据 |

### 元数据

元数据有若干种类型。所有类型的元数据都包含 ID 和 Opt 两项，其含义为：

- ID: 子连接的唯一标识
  - 对于一般 Mux 子连接，ID 由 1 开始累加
  - 对于 Xray 实现的 [Single XUDP](https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go)，ID 始终为 0
- Opt:
  - D(0x01): 有额外数据

当选项 Opt(D) 开启时，额外数据格式如下：

| 2 字节   | X-2 字节 |
| -------- | -------- |
| 长度 X-2 | 数据     |

### 新建子连接 (New)

| 2 字节 | 1 字节 | 1 字节   | 1 字节     | 2 字节 | 1 字节     | A 字节 | 8 字节           |
| ------ | ------ | -------- | ---------- | ------ | ---------- | ------ | ---------------- |
| ID     | 0x01   | 选项 Opt | 网络类型 N | 端口   | 地址类型 T | 地址 A | Global ID (XUDP) |

其中：

- 网络类型 N：
  - 0x01：TCP，表示当前子连接的流量应当以 TCP 的方式发送至目标。
  - 0x02：UDP，表示当前子连接的流量应当以 UDP 的方式发送至目标。
- 地址类型 T：
  - 0x01：IPv4
  - 0x02：域名
  - 0x03：IPv6
- 地址 A：
  - 当 T = 0x01 时，A 为 4 字节 IPv4 地址；
  - 当 T = 0x02 时，A 为 1 字节长度（L） + L 字节域名；
  - 当 T = 0x03 时，A 为 16 字节 IPv6 地址；
- Global ID (XUDP)：
  - 客户端计算出 UDP 来源二元组的全局独特 ID，服务端用以确保当 XUDP 断线重连时，仍使用同一个端口与目标通信。

在新建子连接时，若 Opt(D) 开启，则这一帧所带的数据需要被发往目标主机。

### 保持子连接 (Keep)

TCP

| 2 字节 | 1 字节 | 1 字节   |
| ------ | ------ | -------- |
| ID     | 0x02   | 选项 Opt |

UDP

| 2 字节 | 1 字节 | 1 字节   | 1 字节     | 2 字节 | 1 字节     | A 字节 |
| ------ | ------ | -------- | ---------- | ------ | ---------- | ------ |
| ID     | 0x02   | 选项 Opt | 网络类型 N | 端口   | 地址类型 T | 地址 A |

在保持子连接时，若 Opt(D) 开启，则这一帧所带的数据需要被发往目标主机。
XUDP 在 Opt(D) 之后加 UDP 地址，格式同新建子连接，但没有 Global ID。

### 关闭子连接 (End)

| 2 字节 | 1 字节 | 1 字节   |
| ------ | ------ | -------- |
| ID     | 0x03   | 选项 Opt |

在保持子连接时，若 Opt(D) 开启，则这一帧所带的数据需要被发往目标主机。

### 保持连接 (KeepAlive)

| 2 字节 | 1 字节 | 1 字节   |
| ------ | ------ | -------- |
| ID     | 0x04   | 选项 Opt |

在保持连接时:

- 若 Opt(D) 开启，则这一帧所带的数据必须被丢弃。
- ID 可为随机值。

## 应用

Mux.Cool 协议与底层协议无关，理论上可以使用任何可靠的流式连接来传输 Mux.Cool 的协议数据。

在目标导向的协议如 Shadowsocks 和 VMess 协议中，连接建立时必须包含一个指定的地址。
为了保持兼容性，Mux.Cool 协议指定地址为“v1.mux.cool”。即当主连接的目标地址与之匹配时，则进行 Mux.Cool 方式的转发，否则按传统方式进行转发。（注：这是一个程序内的标记，VMess 和 VLESS 并不会在数据包中发送“v1.mux.cool”地址）
