# PacketHandshake

Singleton implementing handshake over UDP.

The point of the handshake itself is to confirm two-way connection between
two parties - i.e. both parties can receive message from the other and 
receive acknowledgement from the other that their messages have arrived.

This is an important step before establishing connection for actual game 
play, as this lets both the client's and server's routers ( if any ) know 
that traffic is expected and should be let through.

## NAT punchthrough

Most players are behind a router. Routers are directly connected to the
internet, and protect machines behind them from unwanted traffic.

When routers receive packets from an unknown source, those packets are rejected
and don't reach the player's device. When data was sent to that address first,
routers see traffic as a reply and allow incoming data.

To take an example, if a random PC starts sending traffic your way, the router
will reject it. If you send data to the host behind godotengine.org, your
router will allow incoming traffic from it. Otherwise, you wouldn't be able to
open the website in your browser, as the incoming HTTP response would be
rejected.

This can be used to our advantage. If both players start sending traffic
towards eachother, eventually the routers will assume it's a response to some
request and allow the traffic.

> This is a very simplified description of how routers work. NAT punchthrough
> does not always work. For further reading, see [Network address translation].

## Handshake process

To confirm two-way connectivity, a string is sent back and forth, encoding the
player's knowledge about the connection:

The *Read flag* is set once we have received data from the other player.

The *Write flag* is set once we send data to the other player. Since data is
always sent, this flag is always set.

The *Duplex flag* is set when we have received data from the other player
knowing that they have also received data from us. This means that data flows
both ways.

The handshake process is successful when both players have the *Duplex flag*
set *and* both players know that the other player has the *Duplex flag* set.

Each flag is encoded as its specific character or a hyphen. The encoded string
is prepended with a dollar sign. For example:

* *$rw-* means that we have sent and received data from the other player
* *$rwx* means that the *read*, *write*, and *duplex* flags are all set

Here's the handshake process illustrated:

```puml
@startuml

actor "Player A" as A
entity "Router A" as RA
boundary Internet as Net
entity "Router B" as RB
actor "Player B" as B

A ->x RB : $-w-
note over RB: Packet denied

B ->x RA : $-w-
note over RA: Packet denied

note over RA, RB: NAT table updated on both routers

A -> B: $-w-
note over RB: Packed allowed

B -> A: $-w-
note over RB: Packed allowed

A -> B: $rwx
B -> A: $rwx

note over Net #lightgreen: Connection established

@enduml
```

## Handshake over PacketPeer

To run the handshake over raw UDP, call `PacketHandshake.over_packet_peer()`. The
specified PacketPeer will be used to send data until two-way connectivity is
confirmed or the timeout is reached. Between every packet sent, it takes a
short pause.

!!!note
    The PacketPeer must already be configured with a target address.

## Handshake over ENet

If the game is already running, the handshake must be done over the already
active connection. For this case, use `PacketHandshake.over_enet_peer()`. If
the [ENetMultiplayerPeer] is not accessible from where you want to do the
handshake, use `PacketHandshake.over_enet()`.

This connection can't be used to receive custom packets, only to send them. So
the target address will be spammed with traffic confirming two-way connectivity
until timeout. Handshake will always be considered successful.

If the connectivity exists, players will simply connect. Otherwise,
connectivity will fail as expected, regardless of the handshake results.

[Network address translation]: https://en.wikipedia.org/wiki/Network_address_translation
[ENetMultiplayerPeer]: https://docs.godotengine.org/en/4.1/classes/class_enetmultiplayerpeer.html
