mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-15 08:25:09 +01:00
Channel server refactoring
This commit is contained in:
84
channelserver/channel_server.go
Normal file
84
channelserver/channel_server.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package channelserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config struct allows configuring the server.
|
||||||
|
type Config struct {
|
||||||
|
DB *sql.DB
|
||||||
|
ListenAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server is a MHF channel server.
|
||||||
|
type Server struct {
|
||||||
|
sync.Mutex
|
||||||
|
acceptConns chan net.Conn
|
||||||
|
deleteConns chan net.Conn
|
||||||
|
sessions map[net.Conn]*Session
|
||||||
|
db *sql.DB
|
||||||
|
listenAddr string
|
||||||
|
listener net.Listener // Listener that is created when Server.Start is called.
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServer creates a new Server type.
|
||||||
|
func NewServer(config *Config) *Server {
|
||||||
|
s := &Server{
|
||||||
|
acceptConns: make(chan net.Conn),
|
||||||
|
deleteConns: make(chan net.Conn),
|
||||||
|
sessions: make(map[net.Conn]*Session),
|
||||||
|
db: config.DB,
|
||||||
|
listenAddr: config.ListenAddr,
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts the server in a new goroutine.
|
||||||
|
func (s *Server) Start() error {
|
||||||
|
l, err := net.Listen("tcp", s.listenAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.listener = l
|
||||||
|
//defer l.Close()
|
||||||
|
|
||||||
|
go s.acceptClients()
|
||||||
|
go s.manageSessions()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) acceptClients() {
|
||||||
|
for {
|
||||||
|
conn, err := s.listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
// TODO(Andoryuuta): Implement shutdown logic to end this goroutine cleanly here.
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.acceptConns <- conn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) manageSessions() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case newConn := <-s.acceptConns:
|
||||||
|
session := NewSession(s, newConn)
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
s.sessions[newConn] = session
|
||||||
|
s.Unlock()
|
||||||
|
|
||||||
|
session.Start()
|
||||||
|
|
||||||
|
case delConn := <-s.deleteConns:
|
||||||
|
s.Lock()
|
||||||
|
delete(s.sessions, delConn)
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
261
channelserver/session.go
Normal file
261
channelserver/session.go
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
package channelserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Andoryuuta/Erupe/network"
|
||||||
|
"github.com/Andoryuuta/byteframe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Session holds state for the channel server connection.
|
||||||
|
type Session struct {
|
||||||
|
sync.Mutex
|
||||||
|
server *Server
|
||||||
|
rawConn net.Conn
|
||||||
|
cryptConn *network.CryptConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSession creates a new Session type.
|
||||||
|
func NewSession(server *Server, conn net.Conn) *Session {
|
||||||
|
s := &Session{
|
||||||
|
server: server,
|
||||||
|
rawConn: conn,
|
||||||
|
cryptConn: network.NewCryptConn(conn),
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts the session packet read&handle loop.
|
||||||
|
func (s *Session) Start() {
|
||||||
|
go func() {
|
||||||
|
fmt.Println("Channel server got connection!")
|
||||||
|
// Unlike the sign and entrance server,
|
||||||
|
// the client DOES NOT initalize the channel connection with 8 NULL bytes.
|
||||||
|
|
||||||
|
for {
|
||||||
|
pkt, err := s.cryptConn.ReadPacket()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
fmt.Println("Error on channel server readpacket")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePacket(s.cryptConn, pkt)
|
||||||
|
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadDataCount int
|
||||||
|
var getPaperDataCount int
|
||||||
|
|
||||||
|
func handlePacket(cc *network.CryptConn, pkt []byte) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("Recovered from panic.")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
bf := byteframe.NewByteFrameFromBytes(pkt)
|
||||||
|
opcode := network.PacketID(bf.ReadUint16())
|
||||||
|
|
||||||
|
if opcode == network.MSG_SYS_EXTEND_THRESHOLD {
|
||||||
|
opcode = network.PacketID(bf.ReadUint16())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Opcode: %s\n", opcode)
|
||||||
|
switch opcode {
|
||||||
|
case network.MSG_SYS_PING:
|
||||||
|
ackHandle := bf.ReadUint32()
|
||||||
|
_ = bf.ReadUint16()
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
|
||||||
|
bfw.WriteUint32(ackHandle)
|
||||||
|
bfw.WriteUint32(0)
|
||||||
|
bfw.WriteUint32(0)
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
case network.MSG_SYS_TIME:
|
||||||
|
_ = bf.ReadUint8()
|
||||||
|
timestamp := bf.ReadUint32() // unix timestamp, e.g. 1577105879
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_TIME))
|
||||||
|
bfw.WriteUint8(0)
|
||||||
|
bfw.WriteUint32(timestamp)
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
case network.MSG_SYS_LOGIN:
|
||||||
|
ackHandle := bf.ReadUint32()
|
||||||
|
charID0 := bf.ReadUint32()
|
||||||
|
loginTokenNumber := bf.ReadUint32()
|
||||||
|
hardcodedZero0 := bf.ReadUint16()
|
||||||
|
requestVersion := bf.ReadUint16()
|
||||||
|
charID1 := bf.ReadUint32()
|
||||||
|
hardcodedZero1 := bf.ReadUint16()
|
||||||
|
loginTokenLength := bf.ReadUint16() // hardcoded to 0x11
|
||||||
|
loginTokenString := bf.ReadBytes(17)
|
||||||
|
|
||||||
|
_ = ackHandle
|
||||||
|
_ = charID0
|
||||||
|
_ = loginTokenNumber
|
||||||
|
_ = hardcodedZero0
|
||||||
|
_ = requestVersion
|
||||||
|
_ = charID1
|
||||||
|
_ = hardcodedZero1
|
||||||
|
_ = loginTokenLength
|
||||||
|
_ = loginTokenString
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
|
||||||
|
bfw.WriteUint32(ackHandle)
|
||||||
|
bfw.WriteUint64(0x000000005E00B9C2) // Timestamp?
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
|
||||||
|
case network.MSG_MHF_ENUMERATE_EVENT:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_ENUMERATE_QUEST:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_ENUMERATE_RANKING:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_READ_MERCENARY_W:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_ETC_POINTS:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_READ_GUILDCARD:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_READ_BEAT_LEVEL:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_EARTH_STATUS:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_EARTH_VALUE:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_WEEKLY_SCHEDULE:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LIST_MEMBER:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_PLATE_DATA:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_PLATE_BOX:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_FAVORITE_QUEST:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_PARTNER:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_TOWER_INFO:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_OTOMO_AIROU:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_DECO_MYSET:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_HUNTER_NAVI:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_UD_SCHEDULE:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_UD_INFO:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_UD_MONSTER_POINT:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_RAND_FROM_TABLE:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_ACQUIRE_MONTHLY_REWARD:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_RENGOKU_RANKING_RANK:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_PLATE_MYSET:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_RENGOKU_DATA:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_ENUMERATE_SHOP:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_LOAD_SCENARIO_DATA:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_BOOST_TIME_LIMIT:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_BOOST_RIGHT:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_REWARD_SONG:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_GACHA_POINT:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_KOURYOU_POINT:
|
||||||
|
fallthrough
|
||||||
|
case network.MSG_MHF_GET_ENHANCED_MINIDATA:
|
||||||
|
|
||||||
|
ackHandle := bf.ReadUint32()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String()))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
|
||||||
|
bfw.WriteUint32(ackHandle)
|
||||||
|
bfw.WriteBytes(data)
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
|
||||||
|
case network.MSG_MHF_INFO_FESTA:
|
||||||
|
ackHandle := bf.ReadUint32()
|
||||||
|
_ = bf.ReadUint32()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String()))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
|
||||||
|
bfw.WriteUint32(ackHandle)
|
||||||
|
bfw.WriteBytes(data)
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
|
||||||
|
case network.MSG_MHF_LOADDATA:
|
||||||
|
ackHandle := bf.ReadUint32()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), loadDataCount))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
|
||||||
|
bfw.WriteUint32(ackHandle)
|
||||||
|
bfw.WriteBytes(data)
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
|
||||||
|
loadDataCount++
|
||||||
|
if loadDataCount > 1 {
|
||||||
|
loadDataCount = 0
|
||||||
|
}
|
||||||
|
case network.MSG_MHF_GET_PAPER_DATA:
|
||||||
|
ackHandle := bf.ReadUint32()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), getPaperDataCount))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bfw := byteframe.NewByteFrame()
|
||||||
|
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
|
||||||
|
bfw.WriteUint32(ackHandle)
|
||||||
|
bfw.WriteBytes(data)
|
||||||
|
cc.SendPacket(bfw.Data())
|
||||||
|
|
||||||
|
getPaperDataCount++
|
||||||
|
if getPaperDataCount > 7 {
|
||||||
|
getPaperDataCount = 0
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Printf("Data:\n%s\n", hex.Dump(pkt))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingData := bf.DataFromCurrent()
|
||||||
|
if len(remainingData) >= 2 && (opcode == network.MSG_SYS_TIME || opcode == network.MSG_MHF_INFO_FESTA) {
|
||||||
|
handlePacket(cc, remainingData)
|
||||||
|
}
|
||||||
|
}
|
||||||
13
main.go
13
main.go
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Andoryuuta/Erupe/channelserver"
|
||||||
"github.com/Andoryuuta/Erupe/signserver"
|
"github.com/Andoryuuta/Erupe/signserver"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
@@ -38,7 +39,17 @@ func main() {
|
|||||||
})
|
})
|
||||||
go signServer.Listen()
|
go signServer.Listen()
|
||||||
|
|
||||||
go doChannelServer(":54001")
|
//go doChannelServer(":54001")
|
||||||
|
channelServer := channelserver.NewServer(
|
||||||
|
&channelserver.Config{
|
||||||
|
DB: db,
|
||||||
|
ListenAddr: ":54001",
|
||||||
|
})
|
||||||
|
|
||||||
|
err = channelServer.Start()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|||||||
Reference in New Issue
Block a user