major update
This commit is contained in:
parent
e33d213789
commit
cecc1ea127
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,8 @@
|
||||
bin/
|
||||
go.sum
|
||||
.vscode/
|
||||
test/
|
||||
test-bak/
|
||||
rebuild-test.sh
|
||||
test-res/
|
||||
test-res-bak/
|
||||
rebuild-test.sh
|
||||
*_test.go
|
||||
test/
|
||||
36
conn.go
36
conn.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"minimcd/protocol"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
@ -31,14 +32,43 @@ func bridge() {
|
||||
for {
|
||||
msg, _ := <-ConnSignalChan
|
||||
clientSignalChan.TX <- msg
|
||||
clientSignalChan = NewDynamicMultiChan[MCState](false, 2)
|
||||
}
|
||||
}
|
||||
|
||||
const ENABLE_LOGIN_FILTER = true
|
||||
|
||||
func handleConn(clientOriginal net.Conn) {
|
||||
client := timeoutConn{clientOriginal}
|
||||
defer clientOriginal.Close()
|
||||
const DENIED_FMT_STR = "%s refused, it's not login connection"
|
||||
check := func() protocol.Packet {
|
||||
l := protocol.StreamedFromVarNoException[int](clientOriginal)
|
||||
if l == 0 {
|
||||
return nil
|
||||
}
|
||||
pid := protocol.StreamedFromVarNoException[int](clientOriginal)
|
||||
if pid != 0x0 {
|
||||
return nil
|
||||
}
|
||||
ver, addr, port, nxtst := protocol.StreamedFromHandshakePacketDataNoException(clientOriginal)
|
||||
if nxtst != 2 {
|
||||
return nil
|
||||
}
|
||||
return protocol.ToHandshakePacket(ver, addr, port, nxtst)
|
||||
}
|
||||
var firstPacket protocol.Packet
|
||||
if ENABLE_LOGIN_FILTER {
|
||||
if firstPacket = check(); firstPacket == nil {
|
||||
GetLogger().Infof(DENIED_FMT_STR, clientOriginal.RemoteAddr())
|
||||
return
|
||||
}
|
||||
}
|
||||
queryChan := make(QueryChan)
|
||||
defer close(queryChan)
|
||||
QueryChanChan <- queryChan
|
||||
queryChan <- STOPPED
|
||||
st, _ := <-queryChan
|
||||
proceed := func() {
|
||||
server, err := net.Dial("tcp", "127.0.0.1:"+config.MCPort)
|
||||
if err != nil {
|
||||
@ -46,6 +76,9 @@ func handleConn(clientOriginal net.Conn) {
|
||||
return
|
||||
}
|
||||
defer server.Close()
|
||||
if ENABLE_LOGIN_FILTER {
|
||||
server.Write(firstPacket)
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
@ -66,8 +99,6 @@ func handleConn(clientOriginal net.Conn) {
|
||||
wg.Wait()
|
||||
GetLogger().Infof("Connection from %s closed", clientOriginal.RemoteAddr())
|
||||
}
|
||||
queryChan <- STOPPED
|
||||
st, _ := <-queryChan
|
||||
switch st {
|
||||
case RUNNING:
|
||||
CntChan <- INCREASE
|
||||
@ -106,6 +137,7 @@ func Listen() {
|
||||
}
|
||||
//conn.SetReadDeadline(time.Now().Add(time.Duration(config.ConnectTimeout) * time.Second))
|
||||
GetLogger().Infof("New connection from %s", conn.RemoteAddr())
|
||||
conn.SetDeadline(time.Now().Add(time.Duration(config.ConnectTimeout) * time.Second))
|
||||
go handleConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ func Booting() {
|
||||
DaemonChanRX <- struct{}{}
|
||||
GetLogger().Info("enter RUNNING state")
|
||||
go Running()
|
||||
|
||||
}
|
||||
func Running() {
|
||||
<-DaemonChanTX
|
||||
|
||||
22
ds.go
22
ds.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
inf "github.com/Code-Hex/go-infinity-channel"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
@ -103,7 +104,7 @@ type DynamicMultiChan[T constraints.Ordered] struct {
|
||||
TX chan T
|
||||
RX chan T
|
||||
reply bool
|
||||
modify chan modify_t[T]
|
||||
modify *inf.Channel[modify_t[T]]
|
||||
}
|
||||
|
||||
func NewDynamicMultiChan[T constraints.Ordered](reply bool, m int) *DynamicMultiChan[T] {
|
||||
@ -112,7 +113,7 @@ func NewDynamicMultiChan[T constraints.Ordered](reply bool, m int) *DynamicMulti
|
||||
RX: make(chan T),
|
||||
|
||||
reply: reply,
|
||||
modify: make(chan modify_t[T]),
|
||||
modify: inf.NewChannel[modify_t[T]](),
|
||||
}
|
||||
mode := m
|
||||
reload := make([]chan struct{}, 0)
|
||||
@ -123,9 +124,11 @@ func NewDynamicMultiChan[T constraints.Ordered](reply bool, m int) *DynamicMulti
|
||||
selectCases := make([]reflect.SelectCase, 1)
|
||||
viewCnt := 0
|
||||
addQue := NewQueue[int]()
|
||||
|
||||
del := make(map[int]bool)
|
||||
go func() {
|
||||
for {
|
||||
modification, _ := <-ret.modify
|
||||
modification, _ := <-ret.modify.Out()
|
||||
op := modification.op
|
||||
id := modification.id
|
||||
ch := modification.ch
|
||||
@ -158,6 +161,7 @@ func NewDynamicMultiChan[T constraints.Ordered](reply bool, m int) *DynamicMulti
|
||||
}
|
||||
case DELETE:
|
||||
delete(used, id)
|
||||
delete(del, id+1)
|
||||
unused[id] = true
|
||||
list[id] = nil
|
||||
selectCases[id+1] = reflect.SelectCase{
|
||||
@ -194,10 +198,14 @@ func NewDynamicMultiChan[T constraints.Ordered](reply bool, m int) *DynamicMulti
|
||||
// ret.used.Push(id)
|
||||
//
|
||||
// delete(used, id)
|
||||
ret.modify <- modify_t[T]{DELETE, id - 1, nil}
|
||||
<-reload[chanId]
|
||||
if _, Ok := del[id]; !Ok {
|
||||
del[id] = true
|
||||
ret.modify.In() <- modify_t[T]{DELETE, id - 1, nil}
|
||||
<-reload[chanId]
|
||||
<-reload[chanId]
|
||||
}
|
||||
// reloadRX <- struct{}{} //I'm currently not dealing with other chan
|
||||
<-reload[chanId] //waiting for you finished
|
||||
//waiting for you finished
|
||||
// reloadRX <- struct{}{} //I've read all deltas, you can release them
|
||||
continue
|
||||
}
|
||||
@ -252,7 +260,7 @@ func (self DynamicMultiChan[T]) IsReply() bool {
|
||||
return self.reply
|
||||
}
|
||||
func (self *DynamicMultiChan[T]) Add(ch chan T) {
|
||||
self.modify <- modify_t[T]{ADD, -1, ch}
|
||||
self.modify.In() <- modify_t[T]{ADD, -1, ch}
|
||||
}
|
||||
|
||||
// TODO: we need to wait for 2 msg and send 4 msg in chan
|
||||
|
||||
1
fsm.go
1
fsm.go
@ -60,6 +60,7 @@ func handleWaitingToRunning() {
|
||||
_, ok := <-waitChan
|
||||
if ok {
|
||||
state = RUNNING //happens immediately
|
||||
ConnSignalChan <- RUNNING
|
||||
} //else it's too late
|
||||
}
|
||||
func handleRunningToWaiting() {
|
||||
|
||||
1
go.mod
1
go.mod
@ -9,6 +9,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Code-Hex/go-infinity-channel v1.0.0
|
||||
github.com/alecthomas/repr v0.4.0 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
|
||||
|
||||
@ -10,8 +10,14 @@ var logger *logrus.Logger
|
||||
|
||||
func InitLogger() {
|
||||
logger = logrus.New()
|
||||
disableLogColor := os.Getenv("DISABLE_LOG_COLOR")
|
||||
logColor := true
|
||||
if disableLogColor == "true" {
|
||||
logColor = false
|
||||
}
|
||||
logger.SetFormatter(&logrus.TextFormatter{
|
||||
FullTimestamp: true,
|
||||
ForceColors: logColor,
|
||||
})
|
||||
logLevel := os.Getenv("LOG_LEVEL")
|
||||
switch logLevel {
|
||||
|
||||
250
protocol/protocol.go
Normal file
250
protocol/protocol.go
Normal file
@ -0,0 +1,250 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
type intType interface {
|
||||
int | int32 | int64
|
||||
}
|
||||
type Var[T intType] []byte
|
||||
type String []byte
|
||||
|
||||
const SEGMENT_BITS = 0x7F
|
||||
const CONTINUE_BIT = 0x80
|
||||
|
||||
func ToVar[T intType](value T) Var[T] {
|
||||
ret := make(Var[T], 0)
|
||||
for {
|
||||
if (value & ^SEGMENT_BITS) == 0 {
|
||||
ret = append(ret, byte(value))
|
||||
return ret
|
||||
}
|
||||
ret = append(ret, byte((value&SEGMENT_BITS)|CONTINUE_BIT))
|
||||
value = T(uint(value) >> 7)
|
||||
}
|
||||
}
|
||||
func FromVar[T intType](x Var[T]) T {
|
||||
value, position := T(0), 0
|
||||
for i := 0; ; i++ {
|
||||
cur := x[i]
|
||||
value |= T((cur & SEGMENT_BITS) << byte(position))
|
||||
if (cur & CONTINUE_BIT) == 0 {
|
||||
break
|
||||
}
|
||||
position += 7
|
||||
}
|
||||
return value
|
||||
}
|
||||
func StreamedFromVarNoException[T intType](reader io.Reader) T {
|
||||
value, position := T(0), 0
|
||||
buf := make(Var[T], 1)
|
||||
for i := 0; ; i++ {
|
||||
reader.Read(buf)
|
||||
cur := buf[0]
|
||||
value |= (T(cur) & SEGMENT_BITS) << position
|
||||
if (cur & CONTINUE_BIT) == 0 {
|
||||
break
|
||||
}
|
||||
position += 7
|
||||
}
|
||||
return value
|
||||
}
|
||||
func ToString(str string) String {
|
||||
ret := make(String, 0)
|
||||
ret = append(ret, ToVar[int](len(str))...)
|
||||
ret = append(ret, []byte(str)...)
|
||||
return ret
|
||||
}
|
||||
|
||||
func FromString(x String) string {
|
||||
l := FromVar(Var[int](x))
|
||||
ll := Length(Var[int](x))
|
||||
return string(x[ll : ll+l])
|
||||
}
|
||||
func StreamedFromStringNoException(reader io.Reader) string {
|
||||
l := StreamedFromVarNoException[int](reader)
|
||||
buf := make([]byte, l)
|
||||
reader.Read(buf)
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
type PrefixedArray[T intType | byte] []byte
|
||||
|
||||
func ToPrefixedArray[T intType | byte](arr []T) PrefixedArray[T] {
|
||||
ret := make(PrefixedArray[T], 0)
|
||||
ret = append(ret, ToVar[int](len(arr))...)
|
||||
switch any(*new(T)).(type) {
|
||||
case byte:
|
||||
for _, v := range arr {
|
||||
ret = append(ret, byte(v))
|
||||
}
|
||||
default:
|
||||
panic("unimplemented!")
|
||||
}
|
||||
return ret
|
||||
}
|
||||
func StreamedFromPrefixedArrayNoException(reader io.Reader) []byte { //I don't know how to write parser for other types, left for further change
|
||||
l := StreamedFromVarNoException[int](reader)
|
||||
ret := make([]byte, l)
|
||||
reader.Read(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
type VarLengthTypes interface {
|
||||
Var[int] | Var[int32] | Var[int64] | String
|
||||
}
|
||||
|
||||
// TODO: rewrite as method
|
||||
func Length[T VarLengthTypes](x T) int {
|
||||
switch any(x).(type) {
|
||||
case Var[int], Var[int32], Var[int64]:
|
||||
i := 0
|
||||
for ; ; i++ {
|
||||
cur := x[i]
|
||||
if (cur & CONTINUE_BIT) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i + 1
|
||||
case String:
|
||||
return Length[Var[int]](Var[int](x)) + len(FromString(String(x)))
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
type Boolean [4]byte
|
||||
|
||||
func ToBoolean(x bool) (ret Boolean) {
|
||||
if x {
|
||||
ret[3] = 1
|
||||
} else {
|
||||
ret[3] = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
func StreamedFromBooleanNoException(reader io.Reader) bool {
|
||||
buf := Boolean{}
|
||||
reader.Read(buf[:])
|
||||
if buf[3] == 1 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type BigEndian[T constraints.Integer] []byte
|
||||
|
||||
func ToBigEndian[T constraints.Integer](x T) BigEndian[T] {
|
||||
buf := new(bytes.Buffer)
|
||||
binary.Write(buf, binary.BigEndian, x)
|
||||
return buf.Bytes()
|
||||
}
|
||||
func FromBigEndian[T constraints.Integer](x BigEndian[T]) (ret T) {
|
||||
binary.Read(bytes.NewReader(x), binary.BigEndian, &ret)
|
||||
return
|
||||
}
|
||||
func StreamedFromBigEndianNoException[T constraints.Integer](reader io.Reader) (ret T) {
|
||||
buf := make(BigEndian[T], binary.Size(ret))
|
||||
reader.Read(buf)
|
||||
binary.Read(bytes.NewReader(buf), binary.BigEndian, &ret)
|
||||
return
|
||||
}
|
||||
|
||||
type UUID [16]byte // I don't think that I should parse the UUID sent from server, which means the endianess will be kept the same
|
||||
|
||||
type Data []byte
|
||||
|
||||
func ToHandshakePacketData(ver int, addr string, port uint16, nxtst int) Data {
|
||||
ret := make(Data, 0)
|
||||
ret = append(ret, ToVar(ver)...)
|
||||
ret = append(ret, ToString(addr)...)
|
||||
ret = append(ret, ToBigEndian(port)...)
|
||||
ret = append(ret, ToVar(nxtst)...)
|
||||
return ret
|
||||
}
|
||||
func FromHandshakePacketData(x Data) (ver int, addr string, port uint16, nxtst int) {
|
||||
ver = FromVar(Var[int](x))
|
||||
x = x[Length(Var[int](x)):]
|
||||
addr = FromString(String(x))
|
||||
x = x[Length(String(x)):]
|
||||
port = FromBigEndian(BigEndian[uint16](x[:2]))
|
||||
x = x[2:]
|
||||
nxtst = FromVar(Var[int](x))
|
||||
return ver, addr, port, nxtst
|
||||
}
|
||||
func StreamedFromHandshakePacketDataNoException(reader io.Reader) (ver int, addr string, port uint16, nxtst int) {
|
||||
ver = StreamedFromVarNoException[int](reader)
|
||||
//x = x[Length(Var[int](x)):]
|
||||
addr = StreamedFromStringNoException(reader)
|
||||
// x = x[Length(String(x)):]
|
||||
port = StreamedFromBigEndianNoException[uint16](reader)
|
||||
// x = x[2:]
|
||||
nxtst = StreamedFromVarNoException[int](reader)
|
||||
return ver, addr, port, nxtst
|
||||
}
|
||||
func ToLoginStartPacketData(name string, uuid UUID) Data {
|
||||
ret := Data(ToString(name))
|
||||
ret = append(ret, uuid[:]...)
|
||||
return ret
|
||||
}
|
||||
func StreamedFromLoginStartPacketDataNoException(reader io.Reader) (name string, uuid UUID) {
|
||||
name = StreamedFromStringNoException(reader)
|
||||
reader.Read(uuid[:])
|
||||
return
|
||||
}
|
||||
func ToEncryptionRequestPacketData(sid string, pubkey []byte, token []byte, auth bool) Data {
|
||||
ret := make(Data, 0)
|
||||
ret = append(ret, ToString(sid)...)
|
||||
ret = append(ret, ToPrefixedArray(pubkey)...)
|
||||
ret = append(ret, ToPrefixedArray(token)...)
|
||||
authByte := ToBoolean(auth)
|
||||
ret = append(ret, authByte[:]...)
|
||||
return ret
|
||||
}
|
||||
func StreamedFromEncryptionRequestPacketData(reader io.Reader) (sid string, pubkey []byte, token []byte, auth bool) {
|
||||
sid = StreamedFromStringNoException(reader)
|
||||
pubkey = StreamedFromPrefixedArrayNoException(reader)
|
||||
token = StreamedFromPrefixedArrayNoException(reader)
|
||||
auth = StreamedFromBooleanNoException(reader)
|
||||
return
|
||||
}
|
||||
|
||||
type disconnectJsonFields struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func ToDisconnectPacketData(text string) Data {
|
||||
ret, _ := json.Marshal(disconnectJsonFields{"text", text})
|
||||
return ret
|
||||
}
|
||||
|
||||
type Packet []byte
|
||||
|
||||
func ToPacket(p int, data Data) Packet {
|
||||
ret := make(Packet, 0)
|
||||
pid := ToVar[int](p)
|
||||
ret = append(ret, ToVar[int](Length(pid)+len(data))...)
|
||||
ret = append(ret, pid...)
|
||||
ret = append(ret, data...)
|
||||
return ret
|
||||
}
|
||||
func StreamedFromPacketNoException(reader io.Reader) (int, Data) {
|
||||
l := StreamedFromVarNoException[int](reader)
|
||||
// ll := Length(Var[int](x))
|
||||
//pid := FromVar(Var[int](x[ll:]))
|
||||
pid := StreamedFromVarNoException[int](reader)
|
||||
ret := make(Data, l-Length(ToVar(pid)))
|
||||
reader.Read(ret)
|
||||
return pid, ret
|
||||
}
|
||||
func ToHandshakePacket(ver int, addr string, port uint16, nxtst int) Packet {
|
||||
return ToPacket(0x00, ToHandshakePacketData(ver, addr, port, nxtst))
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user