Skip to content

Commit

Permalink
Merge pull request #38 from PretendoNetwork/nex-go-rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniElectra authored Apr 7, 2024
2 parents c45eff3 + ed01e5c commit a138523
Show file tree
Hide file tree
Showing 911 changed files with 41,883 additions and 36,329 deletions.
48 changes: 28 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,59 @@
# NEX Protocols Go
## NEX servers with protocol support in Go

[![GoDoc](https://godoc.org/github.com/PretendoNetwork/nex-protocols-go?status.svg)](https://godoc.org/github.com/PretendoNetwork/nex-protocols-go)
[![GoDoc](https://godoc.org/github.com/PretendoNetwork/nex-protocols-go/v2?status.svg)](https://godoc.org/github.com/PretendoNetwork/nex-protocols-go/v2)

### Other NEX libraries
[nex-go](https://github.com/PretendoNetwork/nex-go) - Barebones NEX/PRUDP server implementation
[nex-go](https://github.com/PretendoNetwork/nex-go/v2) - Barebones NEX/PRUDP server implementation

[nex-protocols-common-go](https://github.com/PretendoNetwork/nex-protocols-common-go) - NEX protocols used by many games with premade handlers and a high level API

### Install

`go get github.com/PretendoNetwork/nex-protocols-go`
`go get github.com/PretendoNetwork/nex-protocols-go/v2`

### Usage

`nex-protocols-go` provides a higher level API than the [NEX Go module](https://github.com/PretendoNetwork/nex-go) to the underlying PRUDP server by providing a set of NEX protocols. This module only provides access to the lower level raw RMC method calls, however, and all method handlers must be defined in full manually. For a higher level API, see the [common NEX method handlers module](https://github.com/PretendoNetwork/nex-protocols-common-go)
`nex-protocols-go` provides a higher level API than the [NEX Go module](https://github.com/PretendoNetwork/nex-go/v2) to the underlying PRUDP server by providing a set of NEX protocols. This module only provides access to the lower level raw RMC method calls, however, and all method handlers must be defined in full manually. For a higher level API, see the [common NEX method handlers module](https://github.com/PretendoNetwork/nex-protocols-common-go)

### Example, friends (Wii U) authentication server
### For a complete example, see the complete [Friends Authentication Server](https://github.com/PretendoNetwork/friends-authentication), and other game servers
### For a complete example, see the complete [Friends Server](https://github.com/PretendoNetwork/friends), and other game servers

```go
package main

import (
"fmt"

nex "github.com/PretendoNetwork/nex-go"
nexproto "github.com/PretendoNetwork/nex-protocols-go"
nex "github.com/PretendoNetwork/nex-go/v2"
ticket_granting "github.com/PretendoNetwork/nex-protocols-go/v2/ticket-granting"
)

var nexServer *nex.Server
var nexServer *nex.PRUDPServer

func main() {
nexServer = nex.NewServer()
nexServer.SetPrudpVersion(0)
nexServer.SetSignatureVersion(1)
nexServer.SetKerberosKeySize(16)
nexServer.SetAccessKey("ridfebb9")
nexServer := nex.NewPRUDPServer()

endpoint := nex.NewPRUDPEndPoint(1)
endpoint.ServerAccount = nex.NewAccount(types.NewPID(1), "Quazal Authentication", "password"))
endpoint.AccountDetailsByPID = accountDetailsByPID
endpoint.AccountDetailsByUsername = accountDetailsByUsername

authenticationServer := nexproto.NewAuthenticationProtocol(nexServer)
nexServer.BindPRUDPEndPoint(endpoint)
nexServer.SetFragmentSize(962)
nexServer.LibraryVersions.SetDefault(nex.NewLibraryVersion(1, 1, 0))
nexServer.SessionKeyLength = 16
nexServer.AccessKey = "ridfebb9"

ticketGrantingProtocol := ticket_granting.NewProtocol(endpoint)

// Handle Login RMC method
authenticationServer.Login(login)
ticketGrantingProtocol.Login = login

// Handle RequestTicket RMC method
authenticationServer.RequestTicket(requestTicket)
ticketGrantingProtocol.RequestTicket = requestTicket

// Register the protocol on the endpoint
endpoint.RegisterServiceProtocol(ticketGrantingProtocol)

nexServer.Listen(":60000")
nexServer.Listen(60000)
}
```
```
32 changes: 15 additions & 17 deletions aa-user/get_application_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@
package protocol

import (
nex "github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/nex-protocols-go/globals"
nex "github.com/PretendoNetwork/nex-go/v2"
"github.com/PretendoNetwork/nex-protocols-go/v2/globals"
)

// GetApplicationInfo sets the GetApplicationInfo handler function
func (protocol *Protocol) GetApplicationInfo(handler func(err error, packet nex.PacketInterface, callID uint32) uint32) {
protocol.getApplicationInfoHandler = handler
}

func (protocol *Protocol) handleGetApplicationInfo(packet nex.PacketInterface) {
var errorCode uint32
if protocol.GetApplicationInfo == nil {
err := nex.NewError(nex.ResultCodes.Core.NotImplemented, "AAUser::GetApplicationInfo not implemented")

globals.Logger.Warning(err.Message)
globals.RespondError(packet, ProtocolID, err)

if protocol.getApplicationInfoHandler == nil {
globals.Logger.Warning("AAUser::GetApplicationInfo not implemented")
go globals.RespondError(packet, ProtocolID, nex.Errors.Core.NotImplemented)
return
}

request := packet.RMCRequest()
request := packet.RMCMessage()
callID := request.CallID

callID := request.CallID()

errorCode = protocol.getApplicationInfoHandler(nil, packet, callID)
if errorCode != 0 {
globals.RespondError(packet, ProtocolID, errorCode)
rmcMessage, rmcError := protocol.GetApplicationInfo(nil, packet, callID)
if rmcError != nil {
globals.RespondError(packet, ProtocolID, rmcError)
return
}

globals.Respond(packet, rmcMessage)
}
116 changes: 82 additions & 34 deletions aa-user/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package protocol

import (
"fmt"
"slices"

nex "github.com/PretendoNetwork/nex-go"
aauser_types "github.com/PretendoNetwork/nex-protocols-go/aa-user/types"
"github.com/PretendoNetwork/nex-protocols-go/globals"
nex "github.com/PretendoNetwork/nex-go/v2"
"github.com/PretendoNetwork/nex-go/v2/types"
aauser_types "github.com/PretendoNetwork/nex-protocols-go/v2/aa-user/types"
"github.com/PretendoNetwork/nex-protocols-go/v2/globals"
)

const (
Expand All @@ -28,41 +30,87 @@ const (

// Protocol stores all the RMC method handlers for the AAUser protocol and listens for requests
type Protocol struct {
Server *nex.Server
registerApplicationHandler func(err error, packet nex.PacketInterface, callID uint32, titleID uint64) uint32
unregisterApplicationHandler func(err error, packet nex.PacketInterface, callID uint32, titleID uint64) uint32
setApplicationInfoHandler func(err error, packet nex.PacketInterface, callID uint32, applicationInfo []*aauser_types.ApplicationInfo) uint32
getApplicationInfoHandler func(err error, packet nex.PacketInterface, callID uint32) uint32
endpoint nex.EndpointInterface
RegisterApplication func(err error, packet nex.PacketInterface, callID uint32, titleID *types.PrimitiveU64) (*nex.RMCMessage, *nex.Error)
UnregisterApplication func(err error, packet nex.PacketInterface, callID uint32, titleID *types.PrimitiveU64) (*nex.RMCMessage, *nex.Error)
SetApplicationInfo func(err error, packet nex.PacketInterface, callID uint32, applicationInfo *types.List[*aauser_types.ApplicationInfo]) (*nex.RMCMessage, *nex.Error)
GetApplicationInfo func(err error, packet nex.PacketInterface, callID uint32) (*nex.RMCMessage, *nex.Error)
Patches nex.ServiceProtocol
PatchedMethods []uint32
}

// Setup initializes the protocol
func (protocol *Protocol) Setup() {
protocol.Server.On("Data", func(packet nex.PacketInterface) {
request := packet.RMCRequest()

if request.ProtocolID() == ProtocolID {
switch request.MethodID() {
case MethodRegisterApplication:
go protocol.handleRegisterApplication(packet)
case MethodUnregisterApplication:
go protocol.handleUnregisterApplication(packet)
case MethodSetApplicationInfo:
go protocol.handleSetApplicationInfo(packet)
case MethodGetApplicationInfo:
go protocol.handleGetApplicationInfo(packet)
default:
go globals.RespondError(packet, ProtocolID, nex.Errors.Core.NotImplemented)
fmt.Printf("Unsupported AAUser method ID: %#v\n", request.MethodID())
}
}
})
// Interface implements the methods present on the AAUser Protocol struct
type Interface interface {
Endpoint() nex.EndpointInterface
SetEndpoint(endpoint nex.EndpointInterface)
SetHandlerRegisterApplication(handler func(err error, packet nex.PacketInterface, callID uint32, titleID *types.PrimitiveU64) (*nex.RMCMessage, *nex.Error))
SetHandlerUnregisterApplication(handler func(err error, packet nex.PacketInterface, callID uint32, titleID *types.PrimitiveU64) (*nex.RMCMessage, *nex.Error))
SetHandlerSetApplicationInfo(handler func(err error, packet nex.PacketInterface, callID uint32, applicationInfo *types.List[*aauser_types.ApplicationInfo]) (*nex.RMCMessage, *nex.Error))
SetHandlerGetApplicationInfo(handler func(err error, packet nex.PacketInterface, callID uint32) (*nex.RMCMessage, *nex.Error))
}

// NewProtocol returns a new AAUser protocol
func NewProtocol(server *nex.Server) *Protocol {
protocol := &Protocol{Server: server}
// Endpoint returns the endpoint implementing the protocol
func (protocol *Protocol) Endpoint() nex.EndpointInterface {
return protocol.endpoint
}

// SetEndpoint sets the endpoint implementing the protocol
func (protocol *Protocol) SetEndpoint(endpoint nex.EndpointInterface) {
protocol.endpoint = endpoint
}

// SetHandlerRegisterApplication sets the handler for the RegisterApplication method
func (protocol *Protocol) SetHandlerRegisterApplication(handler func(err error, packet nex.PacketInterface, callID uint32, titleID *types.PrimitiveU64) (*nex.RMCMessage, *nex.Error)) {
protocol.RegisterApplication = handler
}

// SetHandlerUnregisterApplication sets the handler for the UnregisterApplication method
func (protocol *Protocol) SetHandlerUnregisterApplication(handler func(err error, packet nex.PacketInterface, callID uint32, titleID *types.PrimitiveU64) (*nex.RMCMessage, *nex.Error)) {
protocol.UnregisterApplication = handler
}

// SetHandlerSetApplicationInfo sets the handler for the SetApplicationInfo method
func (protocol *Protocol) SetHandlerSetApplicationInfo(handler func(err error, packet nex.PacketInterface, callID uint32, applicationInfo *types.List[*aauser_types.ApplicationInfo]) (*nex.RMCMessage, *nex.Error)) {
protocol.SetApplicationInfo = handler
}

// SetHandlerGetApplicationInfo sets the handler for the GetApplicationInfo method
func (protocol *Protocol) SetHandlerGetApplicationInfo(handler func(err error, packet nex.PacketInterface, callID uint32) (*nex.RMCMessage, *nex.Error)) {
protocol.GetApplicationInfo = handler
}

// HandlePacket sends the packet to the correct RMC method handler
func (protocol *Protocol) HandlePacket(packet nex.PacketInterface) {
message := packet.RMCMessage()

if !message.IsRequest || message.ProtocolID != ProtocolID {
return
}

protocol.Setup()
if protocol.Patches != nil && slices.Contains(protocol.PatchedMethods, message.MethodID) {
protocol.Patches.HandlePacket(packet)
return
}

return protocol
switch message.MethodID {
case MethodRegisterApplication:
protocol.handleRegisterApplication(packet)
case MethodUnregisterApplication:
protocol.handleUnregisterApplication(packet)
case MethodSetApplicationInfo:
protocol.handleSetApplicationInfo(packet)
case MethodGetApplicationInfo:
protocol.handleGetApplicationInfo(packet)
default:
errMessage := fmt.Sprintf("Unsupported AAUser method ID: %#v\n", message.MethodID)
err := nex.NewError(nex.ResultCodes.Core.NotImplemented, errMessage)

globals.RespondError(packet, ProtocolID, err)
globals.Logger.Warning(err.Message)
}
}

// NewProtocol returns a new AAUser protocol
func NewProtocol() *Protocol {
return &Protocol{}
}
47 changes: 24 additions & 23 deletions aa-user/register_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,44 @@ package protocol
import (
"fmt"

nex "github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/nex-protocols-go/globals"
nex "github.com/PretendoNetwork/nex-go/v2"
"github.com/PretendoNetwork/nex-go/v2/types"
"github.com/PretendoNetwork/nex-protocols-go/v2/globals"
)

// RegisterApplication sets the RegisterApplication handler function
func (protocol *Protocol) RegisterApplication(handler func(err error, packet nex.PacketInterface, callID uint32, titleID uint64) uint32) {
protocol.registerApplicationHandler = handler
}

func (protocol *Protocol) handleRegisterApplication(packet nex.PacketInterface) {
var errorCode uint32
if protocol.RegisterApplication == nil {
err := nex.NewError(nex.ResultCodes.Core.NotImplemented, "AAUser::RegisterApplication not implemented")

globals.Logger.Warning(err.Message)
globals.RespondError(packet, ProtocolID, err)

if protocol.registerApplicationHandler == nil {
globals.Logger.Warning("AAUser::RegisterApplication not implemented")
go globals.RespondError(packet, ProtocolID, nex.Errors.Core.NotImplemented)
return
}

request := packet.RMCRequest()
request := packet.RMCMessage()
callID := request.CallID
parameters := request.Parameters
endpoint := packet.Sender().Endpoint()
parametersStream := nex.NewByteStreamIn(parameters, endpoint.LibraryVersions(), endpoint.ByteStreamSettings())

callID := request.CallID()
parameters := request.Parameters()
titleID := types.NewPrimitiveU64(0)

parametersStream := nex.NewStreamIn(parameters, protocol.Server)

titleID, err := parametersStream.ReadUInt64LE()
err := titleID.ExtractFrom(parametersStream)
if err != nil {
errorCode = protocol.registerApplicationHandler(fmt.Errorf("Failed to read titleID from parameters. %s", err.Error()), packet, callID, 0)
if errorCode != 0 {
globals.RespondError(packet, ProtocolID, errorCode)
_, rmcError := protocol.RegisterApplication(fmt.Errorf("Failed to read titleID from parameters. %s", err.Error()), packet, callID, nil)
if rmcError != nil {
globals.RespondError(packet, ProtocolID, rmcError)
}

return
}

errorCode = protocol.registerApplicationHandler(nil, packet, callID, titleID)
if errorCode != 0 {
globals.RespondError(packet, ProtocolID, errorCode)
rmcMessage, rmcError := protocol.RegisterApplication(nil, packet, callID, titleID)
if rmcError != nil {
globals.RespondError(packet, ProtocolID, rmcError)
return
}

globals.Respond(packet, rmcMessage)
}
Loading

0 comments on commit a138523

Please sign in to comment.