mirror of
https://github.com/PretendoNetwork/nex-go.git
synced 2025-04-02 11:02:14 -04:00
246 lines
7 KiB
Go
246 lines
7 KiB
Go
package nex
|
|
|
|
import (
|
|
"crypto/rc4"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// Client represents a connected or non-connected PRUDP client
|
|
type Client struct {
|
|
address *net.UDPAddr
|
|
server *Server
|
|
cipher *rc4.Cipher
|
|
decipher *rc4.Cipher
|
|
prudpProtocolMinorVersion int
|
|
supportedFunctions int
|
|
signatureKey []byte
|
|
signatureBase int
|
|
serverConnectionSignature []byte
|
|
clientConnectionSignature []byte
|
|
sessionKey []byte
|
|
sequenceIDIn *Counter
|
|
sequenceIDOut *Counter
|
|
pid uint32
|
|
stationURLs []string
|
|
connectionID uint32
|
|
pingCheckTimer *time.Timer
|
|
pingKickTimer *time.Timer
|
|
connected bool
|
|
}
|
|
|
|
// Reset resets the Client to default values
|
|
func (client *Client) Reset() error {
|
|
client.sequenceIDIn = NewCounter(0)
|
|
client.sequenceIDOut = NewCounter(0)
|
|
|
|
client.UpdateAccessKey(client.Server().AccessKey())
|
|
err := client.UpdateRC4Key([]byte("CD&ML"))
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to update client RC4 key. %s", err.Error())
|
|
}
|
|
|
|
if client.Server().PRUDPVersion() == 0 {
|
|
client.SetServerConnectionSignature(make([]byte, 4))
|
|
client.SetClientConnectionSignature(make([]byte, 4))
|
|
} else {
|
|
client.SetServerConnectionSignature([]byte{})
|
|
client.SetClientConnectionSignature([]byte{})
|
|
}
|
|
|
|
client.SetConnected(false)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Address returns the clients UDP address
|
|
func (client *Client) Address() *net.UDPAddr {
|
|
return client.address
|
|
}
|
|
|
|
// Server returns the server the client is currently connected to
|
|
func (client *Client) Server() *Server {
|
|
return client.server
|
|
}
|
|
|
|
// PRUDPProtocolMinorVersion returns the client PRUDP minor version
|
|
func (client *Client) PRUDPProtocolMinorVersion() int {
|
|
return client.prudpProtocolMinorVersion
|
|
}
|
|
|
|
// SetPRUDPProtocolMinorVersion sets the client PRUDP minor
|
|
func (client *Client) SetPRUDPProtocolMinorVersion(prudpProtocolMinorVersion int) {
|
|
client.prudpProtocolMinorVersion = prudpProtocolMinorVersion
|
|
}
|
|
|
|
// SupportedFunctions returns the supported PRUDP functions by the client
|
|
func (client *Client) SupportedFunctions() int {
|
|
return client.supportedFunctions
|
|
}
|
|
|
|
// SetSupportedFunctions sets the supported PRUDP functions by the client
|
|
func (client *Client) SetSupportedFunctions(supportedFunctions int) {
|
|
client.supportedFunctions = supportedFunctions
|
|
}
|
|
|
|
// UpdateRC4Key sets the client RC4 stream key
|
|
func (client *Client) UpdateRC4Key(key []byte) error {
|
|
cipher, err := rc4.NewCipher(key)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to create RC4 cipher. %s", err.Error())
|
|
}
|
|
|
|
client.cipher = cipher
|
|
|
|
decipher, err := rc4.NewCipher(key)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to create RC4 decipher. %s", err.Error())
|
|
}
|
|
|
|
client.decipher = decipher
|
|
|
|
return nil
|
|
}
|
|
|
|
// Cipher returns the RC4 cipher stream for out-bound packets
|
|
func (client *Client) Cipher() *rc4.Cipher {
|
|
return client.cipher
|
|
}
|
|
|
|
// Decipher returns the RC4 cipher stream for in-bound packets
|
|
func (client *Client) Decipher() *rc4.Cipher {
|
|
return client.decipher
|
|
}
|
|
|
|
// UpdateAccessKey sets the client signature base and signature key
|
|
func (client *Client) UpdateAccessKey(accessKey string) {
|
|
client.signatureBase = sum([]byte(accessKey))
|
|
client.signatureKey = MD5Hash([]byte(accessKey))
|
|
}
|
|
|
|
// SignatureBase returns the v0 checksum signature base
|
|
func (client *Client) SignatureBase() int {
|
|
return client.signatureBase
|
|
}
|
|
|
|
// SignatureKey returns signature key
|
|
func (client *Client) SignatureKey() []byte {
|
|
return client.signatureKey
|
|
}
|
|
|
|
// SetServerConnectionSignature sets the clients server-side connection signature
|
|
func (client *Client) SetServerConnectionSignature(serverConnectionSignature []byte) {
|
|
client.serverConnectionSignature = serverConnectionSignature
|
|
}
|
|
|
|
// ServerConnectionSignature returns the clients server-side connection signature
|
|
func (client *Client) ServerConnectionSignature() []byte {
|
|
return client.serverConnectionSignature
|
|
}
|
|
|
|
// SetClientConnectionSignature sets the clients client-side connection signature
|
|
func (client *Client) SetClientConnectionSignature(clientConnectionSignature []byte) {
|
|
client.clientConnectionSignature = clientConnectionSignature
|
|
}
|
|
|
|
// ClientConnectionSignature returns the clients client-side connection signature
|
|
func (client *Client) ClientConnectionSignature() []byte {
|
|
return client.clientConnectionSignature
|
|
}
|
|
|
|
// SequenceIDCounterOut returns the clients packet SequenceID counter for out-going packets
|
|
func (client *Client) SequenceIDCounterOut() *Counter {
|
|
return client.sequenceIDOut
|
|
}
|
|
|
|
// SequenceIDCounterIn returns the clients packet SequenceID counter for incoming packets
|
|
func (client *Client) SequenceIDCounterIn() *Counter {
|
|
return client.sequenceIDIn
|
|
}
|
|
|
|
// SetSessionKey sets the clients session key
|
|
func (client *Client) SetSessionKey(sessionKey []byte) {
|
|
client.sessionKey = sessionKey
|
|
}
|
|
|
|
// SessionKey returns the clients session key
|
|
func (client *Client) SessionKey() []byte {
|
|
return client.sessionKey
|
|
}
|
|
|
|
// SetPID sets the clients NEX PID
|
|
func (client *Client) SetPID(pid uint32) {
|
|
client.pid = pid
|
|
}
|
|
|
|
// PID returns the clients NEX PID
|
|
func (client *Client) PID() uint32 {
|
|
return client.pid
|
|
}
|
|
|
|
// SetStationURLs sets the clients Station URLs
|
|
func (client *Client) SetStationURLs(stationURLs []string) {
|
|
client.stationURLs = stationURLs
|
|
}
|
|
|
|
// StationURLs returns the clients Station URLs
|
|
func (client *Client) StationURLs() []string {
|
|
return client.stationURLs
|
|
}
|
|
|
|
// SetConnectionID sets the clients Connection ID
|
|
func (client *Client) SetConnectionID(connectionID uint32) {
|
|
client.connectionID = connectionID
|
|
}
|
|
|
|
// ConnectionID returns the clients Connection ID
|
|
func (client *Client) ConnectionID() uint32 {
|
|
return client.connectionID
|
|
}
|
|
|
|
// SetConnected sets the clients connection status
|
|
func (client *Client) SetConnected(connected bool) {
|
|
client.connected = connected
|
|
}
|
|
|
|
// IncreasePingTimeoutTime adds a number of seconds to the check timer
|
|
func (client *Client) IncreasePingTimeoutTime(seconds int) {
|
|
//Stop the kick timer if we get something back
|
|
if client.pingKickTimer != nil {
|
|
client.pingKickTimer.Stop()
|
|
}
|
|
//and reset the check timer
|
|
if client.pingCheckTimer != nil {
|
|
client.pingCheckTimer.Reset(time.Second * time.Duration(seconds))
|
|
}
|
|
}
|
|
|
|
// StartTimeoutTimer begins the packet timeout timer
|
|
func (client *Client) StartTimeoutTimer() {
|
|
//if we haven't gotten a ping *from* the client, send them one to check all is well
|
|
client.pingCheckTimer = time.AfterFunc(time.Second*time.Duration(client.server.PingTimeout()), func() {
|
|
client.server.SendPing(client)
|
|
//if we *still* get nothing, they're gone
|
|
client.pingKickTimer = time.AfterFunc(time.Second*time.Duration(client.server.PingTimeout()), func() {
|
|
client.server.TimeoutKick(client)
|
|
})
|
|
})
|
|
}
|
|
|
|
// NewClient returns a new PRUDP client
|
|
func NewClient(address *net.UDPAddr, server *Server) *Client {
|
|
client := &Client{
|
|
address: address,
|
|
server: server,
|
|
}
|
|
|
|
err := client.Reset()
|
|
if err != nil {
|
|
// TODO - Should this return the error too?
|
|
logger.Error(err.Error())
|
|
return nil
|
|
}
|
|
|
|
return client
|
|
}
|