Skip to content

Commit

Permalink
internal/message: Be more consistent with original RakNet in field na…
Browse files Browse the repository at this point in the history
…ming.
  • Loading branch information
Sandertv committed May 4, 2024
1 parent 664f9c4 commit 08602c9
Show file tree
Hide file tree
Showing 15 changed files with 111 additions and 102 deletions.
2 changes: 1 addition & 1 deletion conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (conn *Conn) startTicking() {
}
if i%5 == 0 {
// Ping the other end periodically to prevent timeouts.
_ = conn.send(&message.ConnectedPing{ClientTimestamp: timestamp()})
_ = conn.send(&message.ConnectedPing{PingTime: timestamp()})

conn.mu.Lock()
if t.Sub(*conn.lastActivity.Load()) > time.Second*5+conn.retransmission.rtt(t)*2 {
Expand Down
28 changes: 15 additions & 13 deletions dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (dialer Dialer) PingContext(ctx context.Context, address string) (response
}
defer conn.Close()

data, _ := (&message.UnconnectedPing{SendTimestamp: timestamp(), ClientGUID: atomic.AddInt64(&dialerID, 1)}).MarshalBinary()
data, _ := (&message.UnconnectedPing{PingTime: timestamp(), ClientGUID: atomic.AddInt64(&dialerID, 1)}).MarshalBinary()
if _, err := conn.Write(data); err != nil {
return nil, dialer.error("ping", err)
}
Expand Down Expand Up @@ -230,9 +230,11 @@ func (dialer Dialer) DialContext(ctx context.Context, address string) (*Conn, er
return dialer.connect(ctx, cs)
}

// dial finishes the RakNet connection sequence and returns a Conn if
// successful.
func (dialer Dialer) connect(ctx context.Context, state *connState) (*Conn, error) {
conn := newConn(internal.ConnToPacketConn(state.conn), state.raddr, state.mtu, dialerConnectionHandler{})
if err := conn.send((&message.ConnectionRequest{ClientGUID: state.id, RequestTimestamp: timestamp()})); err != nil {
if err := conn.send((&message.ConnectionRequest{ClientGUID: state.id, RequestTime: timestamp()})); err != nil {
return nil, dialer.error("dial", fmt.Errorf("send connection request: %w", err))
}

Expand Down Expand Up @@ -316,16 +318,16 @@ func (state *connState) discoverMTU(ctx context.Context) error {
if err := response.UnmarshalBinary(b[1:n]); err != nil {
return fmt.Errorf("read open connection reply 1: %w", err)
}
state.serverSecurity, state.cookie = response.Secure, response.Cookie
if response.ServerGUID == 0 || response.ServerPreferredMTUSize < 400 || response.ServerPreferredMTUSize > 1500 {
state.serverSecurity, state.cookie = response.ServerHasSecurity, response.Cookie
if response.ServerGUID == 0 || response.MTU < 400 || response.MTU > 1500 {
// This is an awful hack we cooked up to deal with OVH 'DDoS'
// protection. For some reason they send a broken MTU size
// first. Sending a Request2 followed by a Request1 deals with
// this.
state.openConnectionRequest2(response.ServerPreferredMTUSize)
state.openConnectionRequest2(response.MTU)
continue
}
state.mtu = response.ServerPreferredMTUSize
state.mtu = response.MTU
return nil
case message.IDIncompatibleProtocolVersion:
response := &message.IncompatibleProtocolVersion{}
Expand Down Expand Up @@ -378,7 +380,7 @@ func (state *connState) openConnection(ctx context.Context) error {
if err = pk.UnmarshalBinary(b[1:n]); err != nil {
return fmt.Errorf("read open connection reply 2: %v", err)
}
state.mtu = pk.MTUSize
state.mtu = pk.MTU
return nil
}
}
Expand All @@ -400,19 +402,19 @@ func (state *connState) request2(ctx context.Context, mtu uint16) {
// openConnectionRequest1 sends an open connection request 1 packet to the
// server. If not successful, an error is returned.
func (state *connState) openConnectionRequest1(mtu uint16) {
data, _ := (&message.OpenConnectionRequest1{Protocol: protocolVersion, MaximumSizeNotDropped: mtu}).MarshalBinary()
data, _ := (&message.OpenConnectionRequest1{ClientProtocol: protocolVersion, MTU: mtu}).MarshalBinary()
_, _ = state.conn.Write(data)
}

// openConnectionRequest2 sends an open connection request 2 packet to the
// server. If not successful, an error is returned.
func (state *connState) openConnectionRequest2(mtu uint16) {
data, _ := (&message.OpenConnectionRequest2{
ServerAddress: resolve(state.raddr),
ClientPreferredMTUSize: mtu,
ClientGUID: state.id,
ServerHasSecurity: state.serverSecurity,
Cookie: state.cookie,
ServerAddress: resolve(state.raddr),
MTU: mtu,
ClientGUID: state.id,
ServerHasSecurity: state.serverSecurity,
Cookie: state.cookie,
}).MarshalBinary()
_, _ = state.conn.Write(data)
}
Expand Down
26 changes: 13 additions & 13 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (h listenerConnectionHandler) handle(conn *Conn, b []byte) (handled bool, e
return true, nil
case message.IDDetectLostConnections:
// Let the other end know the connection is still alive.
return true, conn.send(&message.ConnectedPing{ClientTimestamp: timestamp()})
return true, conn.send(&message.ConnectedPing{PingTime: timestamp()})
default:
return false, nil
}
Expand All @@ -77,7 +77,7 @@ func (h listenerConnectionHandler) handleUnconnectedPing(b []byte, addr net.Addr
if err := pk.UnmarshalBinary(b); err != nil {
return fmt.Errorf("read UNCONNECTED_PING: %w", err)
}
data, _ := (&message.UnconnectedPong{ServerGUID: h.l.id, SendTimestamp: pk.SendTimestamp, Data: *h.l.pongData.Load()}).MarshalBinary()
data, _ := (&message.UnconnectedPong{ServerGUID: h.l.id, PingTime: pk.PingTime, Data: *h.l.pongData.Load()}).MarshalBinary()
_, err := h.l.conn.WriteTo(data, addr)
return err
}
Expand All @@ -89,15 +89,15 @@ func (h listenerConnectionHandler) handleOpenConnectionRequest1(b []byte, addr n
if err := pk.UnmarshalBinary(b); err != nil {
return fmt.Errorf("read OPEN_CONNECTION_REQUEST_1: %w", err)
}
mtuSize := min(pk.MaximumSizeNotDropped, maxMTUSize)
mtuSize := min(pk.MTU, maxMTUSize)

if pk.Protocol != protocolVersion {
if pk.ClientProtocol != protocolVersion {
data, _ := (&message.IncompatibleProtocolVersion{ServerGUID: h.l.id, ServerProtocol: protocolVersion}).MarshalBinary()
_, _ = h.l.conn.WriteTo(data, addr)
return fmt.Errorf("handle OPEN_CONNECTION_REQUEST_1: incompatible protocol version %v (listener protocol = %v)", pk.Protocol, protocolVersion)
return fmt.Errorf("handle OPEN_CONNECTION_REQUEST_1: incompatible protocol version %v (listener protocol = %v)", pk.ClientProtocol, protocolVersion)
}

data, _ := (&message.OpenConnectionReply1{ServerGUID: h.l.id, Secure: false, ServerPreferredMTUSize: mtuSize}).MarshalBinary()
data, _ := (&message.OpenConnectionReply1{ServerGUID: h.l.id, ServerHasSecurity: false, MTU: mtuSize}).MarshalBinary()
_, err := h.l.conn.WriteTo(data, addr)
return err
}
Expand All @@ -109,9 +109,9 @@ func (h listenerConnectionHandler) handleOpenConnectionRequest2(b []byte, addr n
if err := pk.UnmarshalBinary(b); err != nil {
return fmt.Errorf("read OPEN_CONNECTION_REQUEST_2: %w", err)
}
mtuSize := min(pk.ClientPreferredMTUSize, maxMTUSize)
mtuSize := min(pk.MTU, maxMTUSize)

data, _ := (&message.OpenConnectionReply2{ServerGUID: h.l.id, ClientAddress: resolve(addr), MTUSize: mtuSize}).MarshalBinary()
data, _ := (&message.OpenConnectionReply2{ServerGUID: h.l.id, ClientAddress: resolve(addr), MTU: mtuSize}).MarshalBinary()
if _, err := h.l.conn.WriteTo(data, addr); err != nil {
return fmt.Errorf("send OPEN_CONNECTION_REPLY_2: %w", err)
}
Expand Down Expand Up @@ -146,7 +146,7 @@ func (h listenerConnectionHandler) handleConnectionRequest(conn *Conn, b []byte)
if err := pk.UnmarshalBinary(b); err != nil {
return fmt.Errorf("read CONNECTION_REQUEST: %w", err)
}
return conn.send(&message.ConnectionRequestAccepted{ClientAddress: resolve(conn.raddr), RequestTimestamp: pk.RequestTimestamp, AcceptedTimestamp: timestamp()})
return conn.send(&message.ConnectionRequestAccepted{ClientAddress: resolve(conn.raddr), PingTime: pk.RequestTime, PongTime: timestamp()})
}

// handleNewIncomingConnection handles an incoming connection packet from the
Expand Down Expand Up @@ -194,7 +194,7 @@ func (h dialerConnectionHandler) handle(conn *Conn, b []byte) (handled bool, err
return true, nil
case message.IDDetectLostConnections:
// Let the other end know the connection is still alive.
return true, conn.send(&message.ConnectedPing{ClientTimestamp: timestamp()})
return true, conn.send(&message.ConnectedPing{PingTime: timestamp()})
default:
return false, nil
}
Expand All @@ -212,7 +212,7 @@ func (h dialerConnectionHandler) handleConnectionRequestAccepted(conn *Conn, b [
return errUnexpectedAdditionalCRA
default:
// Make sure to send NewIncomingConnection before closing conn.connected.
err := conn.send(&message.NewIncomingConnection{ServerAddress: resolve(conn.raddr), RequestTimestamp: pk.AcceptedTimestamp, AcceptedTimestamp: timestamp()})
err := conn.send(&message.NewIncomingConnection{ServerAddress: resolve(conn.raddr), PingTime: pk.PongTime, PongTime: timestamp()})
close(conn.connected)
return err
}
Expand All @@ -227,7 +227,7 @@ func handleConnectedPing(conn *Conn, b []byte) error {
}
// Respond with a connected pong that has the ping timestamp found in the
// connected ping, and our own timestamp for the pong timestamp.
return conn.send(&message.ConnectedPong{ClientTimestamp: pk.ClientTimestamp, ServerTimestamp: timestamp()})
return conn.send(&message.ConnectedPong{PingTime: pk.PingTime, PongTime: timestamp()})
}

// handleConnectedPong handles a connected pong packet inside of buffer b. An
Expand All @@ -237,7 +237,7 @@ func handleConnectedPong(b []byte) error {
if err := pk.UnmarshalBinary(b); err != nil {
return fmt.Errorf("read CONNECTED_PONG: %w", err)
}
if pk.ClientTimestamp > timestamp() {
if pk.PingTime > timestamp() {
return fmt.Errorf("handle CONNECTED_PONG: timestamp is in the future")
}
// We don't actually use the ConnectedPong to measure rtt. It is too
Expand Down
6 changes: 3 additions & 3 deletions internal/message/connected_ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import (
)

type ConnectedPing struct {
ClientTimestamp int64
PingTime int64
}

func (pk *ConnectedPing) UnmarshalBinary(data []byte) error {
if len(data) < 8 {
return io.ErrUnexpectedEOF
}
pk.ClientTimestamp = int64(binary.BigEndian.Uint64(data))
pk.PingTime = int64(binary.BigEndian.Uint64(data))
return nil
}

func (pk *ConnectedPing) MarshalBinary() (data []byte, err error) {
b := make([]byte, 9)
b[0] = IDConnectedPing
binary.BigEndian.PutUint64(b[1:], uint64(pk.ClientTimestamp))
binary.BigEndian.PutUint64(b[1:], uint64(pk.PingTime))
return b, nil
}
12 changes: 6 additions & 6 deletions internal/message/connected_pong.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ import (
)

type ConnectedPong struct {
ClientTimestamp int64
ServerTimestamp int64
PingTime int64
PongTime int64
}

func (pk *ConnectedPong) UnmarshalBinary(data []byte) error {
if len(data) < 16 {
return io.ErrUnexpectedEOF
}
pk.ClientTimestamp = int64(binary.BigEndian.Uint64(data))
pk.ServerTimestamp = int64(binary.BigEndian.Uint64(data[8:]))
pk.PingTime = int64(binary.BigEndian.Uint64(data))
pk.PongTime = int64(binary.BigEndian.Uint64(data[8:]))
return nil
}

func (pk *ConnectedPong) MarshalBinary() (data []byte, err error) {
b := make([]byte, 17)
b[0] = IDConnectedPong
binary.BigEndian.PutUint64(b[1:], uint64(pk.ClientTimestamp))
binary.BigEndian.PutUint64(b[9:], uint64(pk.ServerTimestamp))
binary.BigEndian.PutUint64(b[1:], uint64(pk.PingTime))
binary.BigEndian.PutUint64(b[9:], uint64(pk.PongTime))
return b, nil
}
11 changes: 6 additions & 5 deletions internal/message/connection_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import (
)

type ConnectionRequest struct {
ClientGUID int64
RequestTimestamp int64
Secure bool
ClientGUID int64
// RequestTime is a timestamp from the moment the packet is sent.
RequestTime int64
Secure bool
}

func (pk *ConnectionRequest) UnmarshalBinary(data []byte) error {
if len(data) < 17 {
return io.ErrUnexpectedEOF
}
pk.ClientGUID = int64(binary.BigEndian.Uint64(data))
pk.RequestTimestamp = int64(binary.BigEndian.Uint64(data[8:]))
pk.RequestTime = int64(binary.BigEndian.Uint64(data[8:]))
pk.Secure = data[16] != 0
return nil
}
Expand All @@ -25,7 +26,7 @@ func (pk *ConnectionRequest) MarshalBinary() (data []byte, err error) {
b := make([]byte, 18)
b[0] = IDConnectionRequest
binary.BigEndian.PutUint64(b[1:], uint64(pk.ClientGUID))
binary.BigEndian.PutUint64(b[9:], uint64(pk.RequestTimestamp))
binary.BigEndian.PutUint64(b[9:], uint64(pk.RequestTime))
if pk.Secure {
b[17] = 1
}
Expand Down
27 changes: 16 additions & 11 deletions internal/message/connection_request_accepted.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
)

type ConnectionRequestAccepted struct {
ClientAddress netip.AddrPort
SystemAddresses systemAddresses
RequestTimestamp int64
AcceptedTimestamp int64
ClientAddress netip.AddrPort
SystemIndex uint16
SystemAddresses systemAddresses
// PingTime is filled out with ConnectionRequest.RequestTime.
PingTime int64
// PongTime is a timestamp from the moment the packet is sent.
PongTime int64
}

func (pk *ConnectionRequestAccepted) UnmarshalBinary(data []byte) error {
Expand All @@ -19,7 +22,8 @@ func (pk *ConnectionRequestAccepted) UnmarshalBinary(data []byte) error {
}
var offset int
pk.ClientAddress, offset = addr(data)
offset += 2 // Zero int16.
pk.SystemIndex = binary.BigEndian.Uint16(data[offset:])
offset += 2
for i := range 20 {
if len(data) < addrSize(data[offset:]) {
return io.ErrUnexpectedEOF
Expand All @@ -36,20 +40,21 @@ func (pk *ConnectionRequestAccepted) UnmarshalBinary(data []byte) error {
if len(data[offset:]) < 16 {
return io.ErrUnexpectedEOF
}
pk.RequestTimestamp = int64(binary.BigEndian.Uint64(data[offset:]))
pk.AcceptedTimestamp = int64(binary.BigEndian.Uint64(data[offset+8:]))
pk.PingTime = int64(binary.BigEndian.Uint64(data[offset:]))
pk.PongTime = int64(binary.BigEndian.Uint64(data[offset+8:]))
return nil
}

func (pk *ConnectionRequestAccepted) MarshalBinary() (data []byte, err error) {
nAddr, nSys := sizeofAddr(pk.ClientAddress), pk.SystemAddresses.sizeOf()
b := make([]byte, 1+nAddr+2+nSys+16)
b[0] = IDConnectionRequestAccepted
offset := 1 + putAddr(b[1:], pk.ClientAddress) + 2 // Zero int16.
offset := 1 + putAddr(b[1:], pk.ClientAddress)
binary.BigEndian.PutUint16(b[offset:], pk.SystemIndex)
for _, addr := range pk.SystemAddresses {
offset += putAddr(b[offset:], addr)
offset += putAddr(b[offset+2:], addr)
}
binary.BigEndian.PutUint64(b[offset:], uint64(pk.RequestTimestamp))
binary.BigEndian.PutUint64(b[offset+8:], uint64(pk.AcceptedTimestamp))
binary.BigEndian.PutUint64(b[offset+2:], uint64(pk.PingTime))
binary.BigEndian.PutUint64(b[offset+10:], uint64(pk.PongTime))
return b, nil
}
1 change: 0 additions & 1 deletion internal/message/incompatible_protocol_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
)

type IncompatibleProtocolVersion struct {
Magic [16]byte
ServerProtocol byte
ServerGUID int64
}
Expand Down
18 changes: 10 additions & 8 deletions internal/message/new_incoming_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
)

type NewIncomingConnection struct {
ServerAddress netip.AddrPort
SystemAddresses systemAddresses
RequestTimestamp int64
AcceptedTimestamp int64
ServerAddress netip.AddrPort
SystemAddresses systemAddresses
// PingTime is filled out with ConnectionRequestAccepted.PongTime.
PingTime int64
// PongTime is a timestamp from the moment the packet is sent.
PongTime int64
}

func (pk *NewIncomingConnection) UnmarshalBinary(data []byte) error {
Expand All @@ -35,8 +37,8 @@ func (pk *NewIncomingConnection) UnmarshalBinary(data []byte) error {
if len(data[offset:]) < 16 {
return io.ErrUnexpectedEOF
}
pk.RequestTimestamp = int64(binary.BigEndian.Uint64(data[offset:]))
pk.AcceptedTimestamp = int64(binary.BigEndian.Uint64(data[offset+8:]))
pk.PingTime = int64(binary.BigEndian.Uint64(data[offset:]))
pk.PongTime = int64(binary.BigEndian.Uint64(data[offset+8:]))
return nil
}

Expand All @@ -48,7 +50,7 @@ func (pk *NewIncomingConnection) MarshalBinary() (data []byte, err error) {
for _, addr := range pk.SystemAddresses {
offset += putAddr(b[offset:], addr)
}
binary.BigEndian.PutUint64(b[offset:], uint64(pk.RequestTimestamp))
binary.BigEndian.PutUint64(b[offset+8:], uint64(pk.AcceptedTimestamp))
binary.BigEndian.PutUint64(b[offset:], uint64(pk.PingTime))
binary.BigEndian.PutUint64(b[offset+8:], uint64(pk.PongTime))
return b, nil
}
Loading

0 comments on commit 08602c9

Please sign in to comment.