Commit ef89c4a8 authored by Chunchi Che's avatar Chunchi Che Committed by GitHub

Merge pull request #9 from DarkNeos/dev

Dev
parents 4d91f8af bb7863da
......@@ -10,13 +10,14 @@ import (
"unicode/utf16"
"github.com/sktt1ryze/ygopro-proxy/DarkNeos/ygopropb"
util "github.com/sktt1ryze/ygopro-proxy/util"
"google.golang.org/protobuf/proto"
)
const FILLING_TOKEN uint16 = 0xcccc
const UTF16_BUFFER_MAX_LEN int = 20
const PACKET_MIN_LEN int = 3
const COMPONENT = "[transform]"
const (
ProtobufToRawBuf = 1
RawBufToProtobuf = 2
......@@ -26,8 +27,9 @@ const (
CtosProtoPlayerInfo = 16
CtosProtoJoinGame = 18
StocJoinGame = 18
StocChat = 25
StocJoinGame = 18
StocChat = 25
StocHsPlayerEnter = 32
)
type YgoPacket struct {
......@@ -64,7 +66,7 @@ func packetToBuffer(pkt YgoPacket) []byte {
return buf
}
func bufferToPacket(p []byte) (YgoPacket, error) {
func bufferToPacket(p []byte, ctx *util.Context) (YgoPacket, error) {
if len(p) < PACKET_MIN_LEN {
return YgoPacket{}, errors.New(fmt.Sprintf("Packet len too short, len=%d", len(p)))
}
......@@ -72,6 +74,17 @@ func bufferToPacket(p []byte) (YgoPacket, error) {
// todo: impl Reader/Writer for buffer
packet_len := binary.LittleEndian.Uint16(p)
proto := p[2]
if len(p) < int(packet_len+2) {
log.Printf(COMPONENT+
`Unmatched packet size, proto=%d, buffer_length=%d, packet_len=%d, infa_read_len=%d
Use the buffer length.\n`,
proto, len(p), packet_len, ctx.InfaReadBufferLen,
)
packet_len = uint16(len(p) - 2)
}
exdata := p[3 : packet_len+2]
return YgoPacket{
......@@ -81,7 +94,7 @@ func bufferToPacket(p []byte) (YgoPacket, error) {
}, nil
}
func Transform(src []byte, tranformType int) ([]byte, error) {
func Transform(src []byte, tranformType int, ctx *util.Context) ([]byte, error) {
if tranformType == ProtobufToRawBuf {
message := &ygopropb.YgoCtosMsg{}
err := proto.Unmarshal(src, message)
......@@ -96,13 +109,13 @@ func Transform(src []byte, tranformType int) ([]byte, error) {
case *(ygopropb.YgoCtosMsg_CtosJoinGame):
packet = (*pCtosJoinGame)(message.GetCtosJoinGame()).Pb2Packet()
default:
return nil, errors.New("Unhandled YgoCtosMsg type")
return nil, errors.New(COMPONENT + "Unhandled YgoCtosMsg type")
}
return packetToBuffer(packet), nil
} else if tranformType == RawBufToProtobuf {
packet, err := bufferToPacket(src)
packet, err := bufferToPacket(src, ctx)
if err != nil {
return nil, err
}
......@@ -113,13 +126,15 @@ func Transform(src []byte, tranformType int) ([]byte, error) {
pb = pStocChat{}.Packet2Pb(packet)
case StocJoinGame:
pb = pStocJoinGame{}.Packet2Pb(packet)
case StocHsPlayerEnter:
pb = pStocHsPlayerEnter{}.Packet2Pb(packet)
default:
return nil, errors.New(fmt.Sprintf("Unhandled YgoStocMsg type, proto=%d", packet.Proto))
return nil, errors.New(fmt.Sprintf(COMPONENT+"Unhandled YgoStocMsg type, proto=%d", packet.Proto))
}
return proto.Marshal(&pb)
} else {
return nil, errors.New("Unknown tranformType")
return nil, errors.New(COMPONENT + "Unknown tranformType")
}
}
......@@ -233,6 +248,25 @@ func (_ pStocJoinGame) Packet2Pb(pkt YgoPacket) ygopropb.YgoStocMsg {
}
}
type pStocHsPlayerEnter struct{}
func (_ pStocHsPlayerEnter) Packet2Pb(pkt YgoPacket) ygopropb.YgoStocMsg {
name_max := UTF16_BUFFER_MAX_LEN * 2
name := utf16BufferToStr(pkt.Exdata[:name_max])
pos := pkt.Exdata[name_max]
msg := ygopropb.YgoStocMsg_StocHsPlayerEnter{
StocHsPlayerEnter: &ygopropb.StocHsPlayerEnter{
Name: name,
Pos: int32(pos),
},
}
return ygopropb.YgoStocMsg{
Msg: &msg,
}
}
// +++++ Util Functions +++++
func strToUtf16Buffer(s string) []uint16 {
......
package main
import (
"bufio"
"encoding/binary"
"io"
"log"
"net"
......@@ -10,6 +10,7 @@ import (
"github.com/gorilla/websocket"
darkneos "github.com/sktt1ryze/ygopro-proxy/DarkNeos"
util "github.com/sktt1ryze/ygopro-proxy/util"
)
const TARGET_PORT = ":8000"
......@@ -17,14 +18,19 @@ const PROXY_PORT = ":3344"
const CHANNEL_SIZE = 0x1000
const BUFFER_SIZE = 0x1000
const TIME_OUT = 5
const COMPONENT = "[proxy]"
var upgrader = websocket.Upgrader{
ReadBufferSize: 0x1000,
WriteBufferSize: 0x1000,
}
// todo: create Context
func ygoEndpoint(w http.ResponseWriter, r *http.Request) {
defer log.Println("ygoEndpoint finished")
defer log.Println(COMPONENT + "ygoEndpoint finished")
ctx := util.NewContext()
upgrader.CheckOrigin = wsChecker
......@@ -32,15 +38,17 @@ func ygoEndpoint(w http.ResponseWriter, r *http.Request) {
if err != nil {
log.Fatal(err)
}
ctx.WsConnected = true
log.Println("Connection to ws://localhost" + TARGET_PORT + " [websocket] succeeded!")
log.Println(COMPONENT + "Connection to ws://localhost" + TARGET_PORT + " [websocket] succeeded!")
tcp, err := net.Dial("tcp", "127.0.0.1"+PROXY_PORT)
if err != nil {
log.Fatal(err)
}
ctx.TcpConnected = true
log.Println("Connection to " + "12.0.0.1" + PROXY_PORT + " [tcp] succeeded!")
log.Println(COMPONENT + "Connection to " + "12.0.0.1" + PROXY_PORT + " [tcp] succeeded!")
wsCh := make(chan []byte, CHANNEL_SIZE)
tcpCh := make(chan []byte, CHANNEL_SIZE)
......@@ -55,8 +63,8 @@ func ygoEndpoint(w http.ResponseWriter, r *http.Request) {
close(tcpStopCh)
}()
go wsProxy(ws, wsCh, wsStopCh)
go tcpProxy(tcp, tcpCh, tcpStopCh)
go wsProxy(ws, wsCh, wsStopCh, ctx)
go tcpProxy(tcp, tcpCh, tcpStopCh, ctx)
for {
select {
......@@ -82,15 +90,15 @@ func ygoEndpoint(w http.ResponseWriter, r *http.Request) {
}
}
// todo: generic
func wsProxy(ws *websocket.Conn, Ch chan<- []byte, stopCh <-chan bool) {
// todo: use interface
func wsProxy(ws *websocket.Conn, Ch chan<- []byte, stopCh <-chan bool, ctx util.Context) {
defer ws.Close()
defer close(Ch)
for {
select {
case _, ok := <-stopCh:
log.Println("wsProxy recv stop singal, exit. channel closed: ", ok)
log.Println(COMPONENT+"wsProxy recv stop singal, exit. channel closed: ", ok)
return
default:
// if err := ws.SetReadDeadline(time.Now().Add(time.Second * TIME_OUT)); err != nil {
......@@ -107,13 +115,14 @@ func wsProxy(ws *websocket.Conn, Ch chan<- []byte, stopCh <-chan bool) {
log.Println(err)
return
}
ctx.InfaReadBufferLen = len(buffer)
if messageType == websocket.CloseMessage {
log.Println("Websocket closed")
log.Println(COMPONENT + "Websocket closed")
return
}
buffer, err = darkneos.Transform(buffer, darkneos.ProtobufToRawBuf)
buffer, err = darkneos.Transform(buffer, darkneos.ProtobufToRawBuf, &ctx)
if err != nil {
log.Println(err)
return
......@@ -124,17 +133,15 @@ func wsProxy(ws *websocket.Conn, Ch chan<- []byte, stopCh <-chan bool) {
}
}
func tcpProxy(tcp net.Conn, Ch chan<- []byte, stopCh <-chan bool) {
func tcpProxy(tcp net.Conn, Ch chan<- []byte, stopCh <-chan bool, ctx util.Context) {
const PACKET_LEN_PENDING = 2
defer tcp.Close()
defer close(Ch)
reader := bufio.NewReader(tcp)
buffer := make([]byte, BUFFER_SIZE)
for {
select {
case _, ok := <-stopCh:
log.Println("tcpProxy recv stop singal, exit. channel closed: ", ok)
log.Println(COMPONENT+"tcpProxy recv stop singal, exit. channel closed: ", ok)
return
default:
if err := tcp.SetReadDeadline(time.Now().Add(time.Second * TIME_OUT)); err != nil {
......@@ -142,12 +149,8 @@ func tcpProxy(tcp net.Conn, Ch chan<- []byte, stopCh <-chan bool) {
return
}
_, err := reader.Read(buffer)
if err != nil {
if err == io.EOF {
continue
}
guardBuf := make([]byte, PACKET_LEN_PENDING)
if _, err := tcp.Read(guardBuf); err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
}
......@@ -156,13 +159,29 @@ func tcpProxy(tcp net.Conn, Ch chan<- []byte, stopCh <-chan bool) {
return
}
buffer, err = darkneos.Transform(buffer, darkneos.RawBufToProtobuf)
packet_len := int(binary.LittleEndian.Uint16(guardBuf))
ctx.InfaReadBufferLen = PACKET_LEN_PENDING
buffer := make([]byte, packet_len+PACKET_LEN_PENDING)
copy(buffer, guardBuf)
if packet_len > 0 {
n, err := io.ReadAtLeast(tcp, buffer[PACKET_LEN_PENDING:], packet_len)
if err != nil && err != io.EOF {
log.Println(err)
return
}
ctx.InfaReadBufferLen += n
}
newBuffer, err := darkneos.Transform(buffer, darkneos.RawBufToProtobuf, &ctx)
if err != nil {
log.Println(err)
return
}
Ch <- buffer
Ch <- newBuffer
}
}
}
......@@ -178,5 +197,7 @@ func main() {
setupRoutes()
log.Println(COMPONENT + "start listening on ws://localhost:" + TARGET_PORT)
log.Fatal(http.ListenAndServe(TARGET_PORT, nil))
}
package util
type Context struct {
ContextId int64
WsConnected bool
TcpConnected bool
InfaReadBufferLen int
}
func NewContext() Context {
return Context{
ContextId: 0, // todo
WsConnected: false,
TcpConnected: false,
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment