func CreateLinkGroupsFromRoom(roomID string, maxLinkMembers int) ([][]*user.User, [][]string)
CreateLinkGroupsFromRoom creates an array of link list of users to be used for P2P Links message relay
The users will be sorted by their server-to-client latency and will be grouped accordingly
func CreateP2PSyncBytes(roomID string, users []*user.User) ([]byte, error)
CreateP2PSyncBytes creates a byte array with encryption keys and a list of user client IDs and addresses.
* * === Encryption Key Part === * +----------------+---------------+--------------------+ * | Encryption Key | Encryption IV | Encryption Mac Key | * +----------------+---------------+--------------------+ * | 16 bytes | 16 bytes | 16 bytes | * +----------------+---------------+--------------------+ * * === User client ID and address Part === * User ID and User client address may be repeated as a set. * Big Endian * +--------------+---------+---------------------------+-----------------------+ * | User ID Size | User ID | Base64 Encode String Size | Base64 Encoded String | * +--------------+---------+---------------------------+-----------------------+ * | 4 bytes | | 4 bytes | | * +--------------+---------+---------------------------+-----------------------+ * * === Base64 Encoded String === * address list as a set. * The first address is always the client public address and the rest is local address. * Big Endian * +--------------+---------+ * | Address Size | Address | * +--------------+---------+ * | 4 bytes | | * +--------------+---------+ * * === Outcome byte array === * Currently used * +---------------------+---------------------------------+ * | Encryption Key Part | User client ID and address Part | * +---------------------+---------------------------------+ * | 48 bytes | Variable byte size | * +---------------------+---------------------------------+ * * Currently NOT used * +--------------------------------------+---------------------------------+---------------------+ * | User client ID and address Part size | User client ID and address Part | Encryption Key Part | * +--------------------------------------+---------------------------------+---------------------+ * | 2 bytes big endian | Variable byte size | 48 bytes | * +--------------------------------------+---------------------------------+---------------------+
func ExposeCommands()
ExposeCommands exposes commands to use P2P Links.
func MarkPingTryAsDone(userData *user.User)
MarkPingTryAsDone marks the hole-punching as done
func ParseP2PSyncBytes(payload []byte) (*CryptoData, []*SyncList, error)
ParseP2PSyncBytes returns key, iv, mkey, syncLists, error
func RelayLinkMessage(roomID string, ver uint8, cmd uint16, message []byte, userData *user.User, reliable bool) bool
RelayLinkMessage sends a message via room to selected users to relay among their link groups
func StartP2PFromRoom(ver uint8, cmd uint16, payload []byte, userData *user.User) ([]byte, error)
StartP2PFromRoom starts P2P connections using Room. Returns an error and error bytes if unsuccessful.
CryptoData is a struct that contains encryption keys
type CryptoData struct { Key []byte IV []byte MacKey []byte }
NatType represents the type of NAT
type NatType uint8
NAT types
const ( OpenNAT NatType = 1 AddressRestricted NatType = 2 PortRestricted NatType = 3 SymmetricNAT NatType = 4 )
func CheckNATType(userData *user.User) (NatType, error)
CheckNATType checks the NAT type of connected client
# Sequence Diagram Overview: Detailed depiction of network message flow involving a client, a NAT, and UDP servers, illustrating connectivity
Precondition: - The server should have enableP2P set to true - There should be at least one other server with a different public address
1. Server1 (which is connected to the client) asks Server2 to send a Ping Try packet to the client 2. Server2 sends a packet to the client 3. If Server2 receives a reply from the client, the NAT type is OpenNAT 4. If not, Server1 asks the client to send a packet to the same IP address but a different port. (To create a NAT table entry) 5. Client notifies Server1 that it has sent a packet to Server2 6. Server1 asks Server2 to send a Ping Try packet to the client again 7. If Server2 receives a reply from the client, the NAT type is AddressRestricted 8. If not, Server1 asks the client to send a packet to Server2. (The packet should be 100% reachable.) 9. Server1 asks Server2 to respond with the client's address and port by SID 10. If the address and port are the same as the client's address, the NAT type is PortRestricted 11. If not, the NAT type is Symmetric
╭────────────────────╮ ──────────────── ┌────────────────┐ ┌────────────────┐ │ Client │ NAT │ UDP 1 │ │ UDP 2 │ │ (192.168.0.1:50000)│ (5.5.5.5:60000) │ (1.1.1.1:7100) │ │(2.2.2.2:7100) │ ╰────────────────────╯ ──────────────── └────────────────┘ └────────────────┘ | | | | | | [ Find UDP on the other node ] | | | | | | | ┝━━━━━━━━━━━━━━━━━▶︎ request sending packet to 5.5.5.5:60000 | | | | | ┌----------- Case.1: Open NAT -----------------------------------┐| | | | | |<━━━ Ping Try ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━| | | | | |━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Ping Reply ━▶︎| | | | | | | |<━ reply received━| | | | | | | | = [ NAT Type: Open ] | | | | | └----------------------------------------------------------------┘| | | | | | x<━━━ Ping Try ━━━━━━━━━━━━━━━━━━━━━━━━━━━| | | | | | | |<━━━ no reply ━━━━| | | | | |<━━━━━━━━━━━━━━━━━ send packet to 2.2.2.2:6999 ━| | * 6999 is a random port | | | | |━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━▶︎ Ping Try 2.2.2.2:6999 | | | | |━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ packet sent ━━━━▶︎| | | | | | | | |━━━━━━━━━━▶︎ send packet to 5.5.5.5:60000 again | | | | | ┌----------- Case.2: Address restricted -------------------------┐| | | | | |<━━━ Ping Try ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━| | | | | |━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Ping Reply ━▶︎| | | | | | | |<━ reply received━| | | | | | | | = [ NAT Type: Address restricted ] | | | | | └----------------------------------------------------------------┘| | | | | | x<━━━ Ping Try ━━━━━━━━━━━━━━━━━━━━━━━━━━━| | | | | | | |<━━━ no reply ━━━━| | | | | |<━━━━━━━━━━━━━━━━ send packet to 2.2.2.2:7100━━━| | | | | | |━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ hello (should be 100% reachable)━━━▶︎| | | | | |━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ packet sent ━━━━▶︎| | | | | | | | ┝━━━━━━━━━━▶︎ give me addr and port by SID | | | | | | |<━━━━━━━━━━━━━━━━ here you go | | | | | ┌----------- Case.3: Port restricted ----------------------------┐| | | | Address: 192.168.0.1 | | | Port: 50000 | | | | | | | | = [ NAT Type: Port restricted ] | └----------------------------------------------------------------┘| | ┌----------- Case.4: Symmetric ----------------------------------┐| | | | Address: 192.168.0.1 | | | Port: 50001 (different from 50000) | | | | | | | = [ NAT Type: Symmetric ] | └----------------------------------------------------------------┘| | | | |
[IMPORTANT] Strongly recommended to call it in goroutine as this function has sequential calls to the client and the server.
func GetNATType(userData *user.User) (NatType, error)
GetNATType gets the NAT type of the connected client
func UpdateNATType(userData *user.User) (NatType, error)
UpdateNATType updates the NAT type of the connected client
func (nt NatType) String() string
SyncList is a struct that contains a user ID and their address list The address list contains the client public address and the rest are local addresses
type SyncList struct { UserID string AddressList []string }
func (s *SyncList) String() string