add new file

This commit is contained in:
he liu
2022-01-23 17:30:38 +08:00
parent 05b2e55f39
commit c482967f8c
125 changed files with 9688 additions and 0 deletions

34
lib/cert/cert.go Normal file
View File

@@ -0,0 +1,34 @@
package cert
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"github.com/pkg/errors"
)
// GetCertSnFromConfig return SerialNumber by tls.Config
func GetCertSnFromConfig(config *tls.Config) (string, error) {
if len(config.Certificates) == 0 || len(config.Certificates[0].Certificate) == 0 {
return "", errors.New("certificates is empty")
}
return GetCertSnFromBlock(config.Certificates[0].Certificate[0])
}
// GetCertSnFromEncode return SerialNumber by encoded cert
func GetCertSnFromEncode(b []byte) (string, error) {
block, _ := pem.Decode(b)
if block == nil {
return "", errors.New("block is not a cert encoded")
}
return GetCertSnFromBlock(block.Bytes)
}
// GetCertSnFromBlock return SerialNumber by decode block
func GetCertSnFromBlock(block []byte) (string, error) {
cert, err := x509.ParseCertificate(block)
if err != nil {
return "", errors.Wrap(err, "ParseCertificate")
}
return cert.SerialNumber.String(), nil
}

42
lib/cert/cert_test.go Normal file
View File

@@ -0,0 +1,42 @@
package cert
import (
"crypto/tls"
"crypto/x509/pkix"
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"testing"
)
func TestGetCertSerialNumber(t *testing.T) {
g := NewX509Generator(pkix.Name{
Country: []string{"CN"},
Organization: []string{"Ehang.io"},
OrganizationalUnit: []string{"nps"},
Province: []string{"Beijing"},
CommonName: "nps",
Locality: []string{"Beijing"},
})
cert, key, err := g.CreateRootCa()
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(os.TempDir(), "cert.pem"), cert, 0600))
assert.NoError(t, os.WriteFile(filepath.Join(os.TempDir(), "key.pem"), key, 0600))
assert.NoError(t, err)
cliCrt, err := tls.LoadX509KeyPair(filepath.Join(os.TempDir(), "cert.pem"), filepath.Join(os.TempDir(), "key.pem"))
assert.NoError(t, err)
config := &tls.Config{
Certificates: []tls.Certificate{cliCrt},
}
sn1, err := GetCertSnFromConfig(config)
assert.NoError(t, err)
assert.NotEmpty(t, sn1)
sn2, err := GetCertSnFromEncode(cert)
assert.NoError(t, err)
assert.NotEmpty(t, sn2)
assert.Equal(t, sn1, sn2)
}

253
lib/cert/client_hello.go Normal file
View File

@@ -0,0 +1,253 @@
package cert
import (
"strings"
)
type CurveID uint16
type SignatureScheme uint16
const (
statusTypeOCSP uint8 = 1
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
scsvRenegotiation uint16 = 0x00ff
)
type ClientHelloMsg struct {
raw []byte
vers uint16
random []byte
sessionId []byte
cipherSuites []uint16
compressionMethods []uint8
nextProtoNeg bool
serverName string
ocspStapling bool
scts bool
supportedCurves []CurveID
supportedPoints []uint8
ticketSupported bool
sessionTicket []uint8
supportedSignatureAlgorithms []SignatureScheme
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
}
func (m *ClientHelloMsg) GetServerName() string {
return m.serverName
}
func (m *ClientHelloMsg) Unmarshal(data []byte) bool {
if len(data) < 42 {
return false
}
m.raw = data
m.vers = uint16(data[4])<<8 | uint16(data[5])
m.random = data[6:38]
sessionIdLen := int(data[38])
if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
return false
}
m.sessionId = data[39 : 39+sessionIdLen]
data = data[39+sessionIdLen:]
if len(data) < 2 {
return false
}
// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
// they are uint16s, the number must be even.
cipherSuiteLen := int(data[0])<<8 | int(data[1])
if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
return false
}
numCipherSuites := cipherSuiteLen / 2
m.cipherSuites = make([]uint16, numCipherSuites)
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
if m.cipherSuites[i] == scsvRenegotiation {
m.secureRenegotiationSupported = true
}
}
data = data[2+cipherSuiteLen:]
if len(data) < 1 {
return false
}
compressionMethodsLen := int(data[0])
if len(data) < 1+compressionMethodsLen {
return false
}
m.compressionMethods = data[1 : 1+compressionMethodsLen]
data = data[1+compressionMethodsLen:]
m.nextProtoNeg = false
m.serverName = ""
m.ocspStapling = false
m.ticketSupported = false
m.sessionTicket = nil
m.supportedSignatureAlgorithms = nil
m.alpnProtocols = nil
m.scts = false
if len(data) == 0 {
// ClientHello is optionally followed by extension data
return true
}
if len(data) < 2 {
return false
}
extensionsLength := int(data[0])<<8 | int(data[1])
data = data[2:]
if extensionsLength != len(data) {
return false
}
for len(data) != 0 {
if len(data) < 4 {
return false
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return false
}
switch extension {
case extensionServerName:
d := data[:length]
if len(d) < 2 {
return false
}
namesLen := int(d[0])<<8 | int(d[1])
d = d[2:]
if len(d) != namesLen {
return false
}
for len(d) > 0 {
if len(d) < 3 {
return false
}
nameType := d[0]
nameLen := int(d[1])<<8 | int(d[2])
d = d[3:]
if len(d) < nameLen {
return false
}
if nameType == 0 {
m.serverName = string(d[:nameLen])
// An SNI value may not include a
// trailing dot. See
// https://tools.ietf.org/html/rfc6066#section-3.
if strings.HasSuffix(m.serverName, ".") {
return false
}
break
}
d = d[nameLen:]
}
case extensionNextProtoNeg:
if length > 0 {
return false
}
m.nextProtoNeg = true
case extensionStatusRequest:
m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
case extensionSupportedCurves:
// https://tools.ietf.org/html/rfc4492#section-5.5.1
if length < 2 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l%2 == 1 || length != l+2 {
return false
}
numCurves := l / 2
m.supportedCurves = make([]CurveID, numCurves)
d := data[2:]
for i := 0; i < numCurves; i++ {
m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
d = d[2:]
}
case extensionSupportedPoints:
// https://tools.ietf.org/html/rfc4492#section-5.5.2
if length < 1 {
return false
}
l := int(data[0])
if length != l+1 {
return false
}
m.supportedPoints = make([]uint8, l)
copy(m.supportedPoints, data[1:])
case extensionSessionTicket:
// https://tools.ietf.org/html/rfc5077#section-3.2
m.ticketSupported = true
m.sessionTicket = data[:length]
case extensionSignatureAlgorithms:
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
if length < 2 || length&1 != 0 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return false
}
n := l / 2
d := data[2:]
m.supportedSignatureAlgorithms = make([]SignatureScheme, n)
for i := range m.supportedSignatureAlgorithms {
m.supportedSignatureAlgorithms[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1])
d = d[2:]
}
case extensionRenegotiationInfo:
if length == 0 {
return false
}
d := data[:length]
l := int(d[0])
d = d[1:]
if l != len(d) {
return false
}
m.secureRenegotiation = d
m.secureRenegotiationSupported = true
case extensionALPN:
if length < 2 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return false
}
d := data[2:length]
for len(d) != 0 {
stringLen := int(d[0])
d = d[1:]
if stringLen == 0 || stringLen > len(d) {
return false
}
m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
d = d[stringLen:]
}
case extensionSCT:
m.scts = true
if length != 0 {
return false
}
}
data = data[length:]
}
return true
}

108
lib/cert/generate.go Normal file
View File

@@ -0,0 +1,108 @@
package cert
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"math/big"
"time"
)
var _ Generator = (*X509Generator)(nil)
type Generator interface {
CreateRootCa() ([]byte, []byte, error)
CreateCert(dnsName string) ([]byte, []byte, error)
InitRootCa(rootCa []byte, rootKey []byte) error
}
type X509Generator struct {
rootCert *x509.Certificate
rootRsaPrivate *rsa.PrivateKey
subject pkix.Name
}
func NewX509Generator(subject pkix.Name) *X509Generator {
return &X509Generator{
subject: subject,
}
}
func (cg *X509Generator) InitRootCa(rootCa []byte, rootKey []byte) error {
var err error
caBlock, _ := pem.Decode(rootCa)
cg.rootCert, err = x509.ParseCertificate(caBlock.Bytes)
if err != nil {
return err
}
keyBlock, _ := pem.Decode(rootKey)
cg.rootRsaPrivate, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
if err != nil {
return err
}
return nil
}
func (cg *X509Generator) CreateCert(dnsName string) ([]byte, []byte, error) {
return cg.create(false, dnsName)
}
func (cg *X509Generator) CreateRootCa() ([]byte, []byte, error) {
return cg.create(true, "")
}
func (cg *X509Generator) create(isRootCa bool, dnsName string) ([]byte, []byte, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
template := &x509.Certificate{
SerialNumber: serialNumber,
Subject: cg.subject,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(3, 0, 0),
BasicConstraintsValid: true,
IsCA: false,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment,
DNSNames: []string{dnsName},
}
if isRootCa {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
}
priKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
var ca []byte
if !isRootCa {
if cg.rootCert == nil || cg.rootRsaPrivate == nil {
return nil, nil, errors.New("root ca is not exist")
}
ca, err = x509.CreateCertificate(rand.Reader, template, cg.rootCert, &priKey.PublicKey, cg.rootRsaPrivate)
} else {
ca, err = x509.CreateCertificate(rand.Reader, template, template, &priKey.PublicKey, priKey)
}
if err != nil {
return nil, nil, err
}
caPem := &pem.Block{
Type: "CERTIFICATE",
Bytes: ca,
}
ca = pem.EncodeToMemory(caPem)
buf := x509.MarshalPKCS1PrivateKey(priKey)
keyPem := &pem.Block{
Type: "PRIVATE KEY",
Bytes: buf,
}
key := pem.EncodeToMemory(keyPem)
return ca, key, nil
}

62
lib/cert/generate_test.go Normal file
View File

@@ -0,0 +1,62 @@
package cert
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"testing"
)
func TestCreateCert(t *testing.T) {
dnsName := "ehang.io"
g := NewX509Generator(pkix.Name{
Country: []string{"CN"},
Organization: []string{"ehang.io"},
OrganizationalUnit: []string{"nps"},
Province: []string{"Beijing"},
CommonName: "nps",
Locality: []string{"Beijing"},
})
// generate root ca
rootCa, rootKey, err := g.CreateRootCa()
if err != nil {
t.Fatal(err)
}
err = g.InitRootCa(rootCa, rootKey)
if err != nil {
t.Fatal(err)
}
// generate npc cert
clientCa, _, err := g.CreateCert(dnsName)
if err != nil {
t.Fatal(err)
}
// verify npc cert by root cert
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(rootCa)
if !ok {
panic("failed to parse root certificate")
}
block, _ := pem.Decode(clientCa)
if block == nil {
t.Fatal("failed to parse certificate PEM")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatal("failed to parse certificate: " + err.Error())
}
opts := x509.VerifyOptions{
Roots: roots,
DNSName: dnsName,
Intermediates: x509.NewCertPool(),
}
if _, err := cert.Verify(opts); err != nil {
t.Fatal("failed to verify certificate: " + err.Error())
}
}

141
lib/common/addr.go Normal file
View File

@@ -0,0 +1,141 @@
package common
import (
"errors"
"io"
"net"
"strconv"
)
var AddrError = errors.New("addr error")
// SOCKS address types as defined in RFC 1928 section 5.
const (
AtypIPv4 = 1
AtypDomainName = 3
AtypIPv6 = 4
)
// MaxAddrLen is the maximum size of SOCKS address in bytes.
const MaxAddrLen = 1 + 1 + 255 + 2
// Addr represents a SOCKS address as defined in RFC 1928 section 5.
type Addr []byte
// String serializes SOCKS address a to string form.
func (a Addr) String() string {
var host, port string
switch a[0] { // address type
case AtypDomainName:
host = string(a[2 : 2+int(a[1])])
port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1]))
case AtypIPv4:
host = net.IP(a[1 : 1+net.IPv4len]).String()
port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1]))
case AtypIPv6:
host = net.IP(a[1 : 1+net.IPv6len]).String()
port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1]))
}
return net.JoinHostPort(host, port)
}
func readAddr(r io.Reader, b []byte) (Addr, error) {
if len(b) < MaxAddrLen {
return nil, io.ErrShortBuffer
}
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
if err != nil {
return nil, err
}
switch b[0] {
case AtypDomainName:
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
if err != nil {
return nil, err
}
_, err = io.ReadFull(r, b[2:2+int(b[1])+2])
return b[:1+1+int(b[1])+2], err
case AtypIPv4:
_, err = io.ReadFull(r, b[1:1+net.IPv4len+2])
return b[:1+net.IPv4len+2], err
case AtypIPv6:
_, err = io.ReadFull(r, b[1:1+net.IPv6len+2])
return b[:1+net.IPv6len+2], err
}
return nil, errors.New("addr type not supported")
}
// ReadAddr reads just enough bytes from r to get a valid Addr.
func ReadAddr(r io.Reader) (Addr, error) {
return readAddr(r, make([]byte, MaxAddrLen))
}
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
func SplitAddr(b []byte) (Addr, error) {
addrLen := 1
if len(b) < addrLen {
return nil, AddrError
}
switch b[0] {
case AtypDomainName:
if len(b) < 2 {
return nil, AddrError
}
addrLen = 1 + 1 + int(b[1]) + 2
case AtypIPv4:
addrLen = 1 + net.IPv4len + 2
case AtypIPv6:
addrLen = 1 + net.IPv6len + 2
default:
return nil, AddrError
}
if len(b) < addrLen {
return nil, AddrError
}
return b[:addrLen], nil
}
// ParseAddr parses the address in string s. Returns nil if failed.
func ParseAddr(s string) (Addr, error) {
var addr Addr
host, port, err := net.SplitHostPort(s)
if err != nil {
return nil, AddrError
}
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
addr = make([]byte, 1+net.IPv4len+2)
addr[0] = AtypIPv4
copy(addr[1:], ip4)
} else {
addr = make([]byte, 1+net.IPv6len+2)
addr[0] = AtypIPv6
copy(addr[1:], ip)
}
} else {
if len(host) > 255 {
return nil, AddrError
}
addr = make([]byte, 1+1+len(host)+2)
addr[0] = AtypDomainName
addr[1] = byte(len(host))
copy(addr[2:], host)
}
portnum, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return nil, AddrError
}
addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum)
return addr, nil
}

75
lib/common/utils.go Normal file
View File

@@ -0,0 +1,75 @@
package common
import (
"encoding/binary"
"github.com/pkg/errors"
"io"
"strings"
)
// CopyBuffer is an implement of io.Copy with buffer pool
func CopyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw < 0 || nr < nw {
nw = 0
if ew == nil {
ew = errors.New("invalid write result")
}
}
written += int64(nw)
if ew != nil {
err = ew
break
}
if nr != nw {
err = errors.New("short write")
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
}
return written, err
}
// HostContains tests whether the string host contained ruleHost
func HostContains(ruleHost string, host string) bool {
return strings.HasSuffix(host, strings.Replace(ruleHost, "*", "", -1))
}
// WriteLenBytes is used to write length and bytes to writer
func WriteLenBytes(w io.Writer, b []byte) (int, error) {
err := binary.Write(w, binary.LittleEndian, uint32(len(b)))
if err != nil {
return 0, errors.Wrap(err, "write len")
}
n, err := w.Write(b)
if err != nil {
return 0, errors.Wrap(err, "write bytes")
}
return n, nil
}
// ReadLenBytes is used to read bytes from reader
func ReadLenBytes(r io.Reader, b []byte) (int, error) {
var l int32
err := binary.Read(r, binary.LittleEndian, &l)
if err != nil {
return 0, errors.Wrap(err, "read len")
}
if int(l) > len(b) {
return 0, errors.Errorf("data is too long(%d)", l)
}
n, err := io.ReadAtLeast(r, b, int(l))
if err != nil {
return n, errors.Wrap(err, "read data error")
}
return n, nil
}

119
lib/enet/conn.go Normal file
View File

@@ -0,0 +1,119 @@
package enet
import (
"ehang.io/nps/lib/pool"
"errors"
"net"
"sync"
"syscall"
)
type Conn interface {
net.Conn
Reset(int) error
Clear()
Readable() bool
AllBytes() ([]byte, error)
SyscallConn() (syscall.RawConn, error)
}
var _ Conn = (*ReaderConn)(nil)
var bp = pool.NewBufferPool(MaxReadSize)
const MaxReadSize = 32 * 1024
// ReaderConn is an implement of reusable data connection
type ReaderConn struct {
buf []byte
nowIndex int
hasRead int
hasClear bool
net.Conn
sync.RWMutex
}
// NewReaderConn returns a new ReaderConn
func NewReaderConn(conn net.Conn) *ReaderConn {
return &ReaderConn{Conn: conn, buf: bp.Get()}
}
// SyscallConn returns a raw network connection
func (rc *ReaderConn) SyscallConn() (syscall.RawConn, error) {
return rc.Conn.(syscall.Conn).SyscallConn()
}
// Read is an implement of Net.Conn Read function
func (rc *ReaderConn) Read(b []byte) (n int, err error) {
rc.Lock()
defer rc.Unlock()
if rc.hasClear || (rc.nowIndex == rc.hasRead && rc.hasRead == MaxReadSize) {
if !rc.hasClear {
rc.Clear()
}
return rc.Conn.Read(b)
}
if rc.hasRead > rc.nowIndex {
n = copy(b, rc.buf[rc.nowIndex:rc.hasRead])
rc.nowIndex += n
return
}
if rc.hasRead == MaxReadSize {
n = copy(b, rc.buf[rc.nowIndex:rc.hasRead])
rc.nowIndex += n
return
}
err = rc.readOnce()
if err != nil {
return
}
n = copy(b, rc.buf[rc.nowIndex:rc.hasRead])
rc.nowIndex += n
return
}
// readOnce
func (rc *ReaderConn) readOnce() error {
// int(math.Min(float64(MaxReadSize-rc.hasRead), float64(len(b)-(rc.hasRead-rc.nowIndex))))
// read as much as possible to judge whether there is still readable
n, err := rc.Conn.Read(rc.buf[rc.nowIndex : rc.hasRead+MaxReadSize-rc.hasRead])
rc.hasRead += n
return err
}
// Readable return whether there is data in the buffer
func (rc *ReaderConn) Readable() bool {
return (rc.hasRead - rc.nowIndex) > 0
}
// AllBytes return all data in the buffer
func (rc *ReaderConn) AllBytes() ([]byte, error) {
rc.Lock()
defer rc.Unlock()
if rc.hasRead == 0 {
if err := rc.readOnce(); err != nil {
return nil, err
}
}
if !rc.Readable() {
return nil, errors.New("can not read '")
}
b := rc.buf[rc.nowIndex:rc.hasRead]
rc.nowIndex = rc.hasRead
return b, nil
}
// Reset will reset data index
func (rc *ReaderConn) Reset(n int) error {
if !rc.hasClear {
rc.nowIndex = n
return nil
}
return errors.New("the enet can not reset anymore")
}
// Clear will put buf to pool and can not reuse anymore
func (rc *ReaderConn) Clear() {
rc.hasClear = true
bp.Put(rc.buf)
}

81
lib/enet/conn_test.go Normal file
View File

@@ -0,0 +1,81 @@
package enet
import (
"math/rand"
"net"
"testing"
"time"
)
func TestReaderConn_Read(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:61254")
if err != nil {
t.Fatal(err)
}
b := make([]byte, 33*1024)
go func() {
conn, err := net.Dial("tcp", "127.0.0.1:61254")
if err != nil {
t.Fatal(err)
}
rand.Seed(time.Now().UnixNano())
for i := 0; i < 33*1024; i++ {
b[i] = byte(rand.Intn(128))
}
conn.Write(b)
}()
conn, err := ln.Accept()
if err != nil {
t.Fatal(err)
}
rConn := NewReaderConn(conn)
buf := make([]byte, 1024)
nn := 0
times := 0
for {
n, err := rConn.Read(buf)
if err != nil {
t.Fatal(err)
}
for i := 0; i < 1024; i++ {
if b[times*1024+i] != buf[i] {
t.Fatal("data error")
}
}
times++
nn += n
if nn > 30*1024 {
break
}
if times > 100 {
t.Fatal("read error")
}
}
rConn.Reset(0)
nn = 0
times = 0
for {
n, err := rConn.Read(buf)
if err != nil {
t.Fatal(err)
}
for i := 0; i < 1024; i++ {
if b[times*1024+i] != buf[i] {
t.Fatal("data error")
}
}
nn += n
times++
if nn > 32*1024 {
break
}
if times > 100 {
t.Fatal("read error")
}
}
if !rConn.hasClear || rConn.hasRead != rConn.nowIndex || rConn.nowIndex != MaxReadSize {
t.Fatal("read error")
}
}

62
lib/enet/listener.go Normal file
View File

@@ -0,0 +1,62 @@
package enet
import (
"errors"
"net"
"sync/atomic"
)
var _ net.Listener = (*Listener)(nil)
// Listener is an implementation of net.Listener
type Listener struct {
ch chan net.Conn
closeCh chan struct{}
closed int32
nowNum int32
addr net.Addr
}
// NewListener returns an initialized Listener
func NewListener() *Listener {
return &Listener{ch: make(chan net.Conn, 10), closeCh: make(chan struct{})}
}
// SendConn is used to add connection to the listener
func (bl *Listener) SendConn(c net.Conn) error {
if atomic.LoadInt32(&bl.closed) == 1 {
return errors.New("the listener is already closed")
}
atomic.AddInt32(&bl.nowNum, 1)
select {
case bl.ch <- c:
return nil
case <-bl.closeCh:
}
if atomic.AddInt32(&bl.nowNum, -1) == 0 && atomic.LoadInt32(&bl.closed) == 1 {
close(bl.ch)
}
return errors.New("the listener is already closed")
}
// Accept is used to get connection from the listener
func (bl *Listener) Accept() (net.Conn, error) {
c := <-bl.ch
if c == nil {
return nil, errors.New("the listener is already closed")
}
return c, nil
}
// Close is used to close the listener, it will discard all existing connections
func (bl *Listener) Close() error {
if atomic.CompareAndSwapInt32(&bl.closed, 0, 1) {
close(bl.closeCh)
}
return nil
}
// Addr returns the listener's address'
func (bl *Listener) Addr() net.Addr {
return bl.addr
}

161
lib/enet/paket.go Normal file
View File

@@ -0,0 +1,161 @@
package enet
import (
"bytes"
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/pool"
"github.com/pkg/errors"
"net"
"sync/atomic"
"time"
)
var (
_ net.PacketConn = (*TcpPacketConn)(nil)
_ PacketConn = (*ReaderPacketConn)(nil)
)
type PacketConn interface {
net.PacketConn
SendPacket([]byte, net.Addr) error
FirstPacket() ([]byte, net.Addr, error)
}
var udpBp = pool.NewBufferPool(1500)
// TcpPacketConn is an implement of net.PacketConn by net.Conn
type TcpPacketConn struct {
udpBp []byte
net.Conn
}
// NewTcpPacketConn return a *TcpPacketConn
func NewTcpPacketConn(conn net.Conn) *TcpPacketConn {
return &TcpPacketConn{Conn: conn}
}
// ReadFrom is a implement of net.PacketConn ReadFrom
func (tp *TcpPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
b := udpBp.Get()
defer udpBp.Put(b)
n, err = common.ReadLenBytes(tp.Conn, b)
if err != nil {
return
}
rAddr, err := common.ReadAddr(bytes.NewReader(b[:n]))
if err != nil {
return
}
n = copy(p, b[len(rAddr):n])
addr, err = net.ResolveUDPAddr("udp", rAddr.String())
return
}
// WriteTo is a implement of net.PacketConn WriteTo
func (tp *TcpPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
var pAddr common.Addr
pAddr, err = common.ParseAddr(addr.String())
if err != nil {
return
}
return common.WriteLenBytes(tp.Conn, append(pAddr, p...))
}
// ReaderPacketConn is an implementation of net.PacketConn
type ReaderPacketConn struct {
ch chan *packet
closeCh chan struct{}
closed int32
nowNum int32
addr net.Addr
writePacketConn net.PacketConn
readTimer *time.Timer
firstPacket []byte
}
type packet struct {
b []byte
addr net.Addr
}
// NewReaderPacketConn returns an initialized PacketConn
func NewReaderPacketConn(writePacketConn net.PacketConn, firstPacket []byte, addr net.Addr) *ReaderPacketConn {
return &ReaderPacketConn{
ch: make(chan *packet, 10),
closeCh: make(chan struct{}),
addr: addr,
writePacketConn: writePacketConn,
readTimer: time.NewTimer(time.Hour * 24 * 3650),
firstPacket: firstPacket,
}
}
func (pc *ReaderPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
var pt *packet
select {
case pt = <-pc.ch:
case <-pc.readTimer.C:
}
if pt == nil {
return 0, nil, errors.New("the PacketConn is already closed")
}
copy(p, pt.b)
return len(pt.b), pt.addr, nil
}
func (pc *ReaderPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return pc.writePacketConn.WriteTo(p, addr)
}
// LocalAddr returns the listener's address
func (pc *ReaderPacketConn) LocalAddr() net.Addr {
return pc.addr
}
func (pc *ReaderPacketConn) SetDeadline(t time.Time) error {
pc.readTimer.Reset(t.Sub(time.Now()))
return pc.writePacketConn.SetWriteDeadline(t)
}
func (pc *ReaderPacketConn) SetReadDeadline(t time.Time) error {
pc.readTimer.Reset(t.Sub(time.Now()))
return nil
}
func (pc *ReaderPacketConn) SetWriteDeadline(t time.Time) error {
return pc.writePacketConn.SetWriteDeadline(t)
}
func (pc *ReaderPacketConn) FirstPacket() ([]byte, net.Addr, error) {
if pc.firstPacket == nil || pc.addr == nil {
return nil, nil, errors.New("not found first packet")
}
return pc.firstPacket, pc.addr, nil
}
// SendPacket is used to add connection to the listener
func (pc *ReaderPacketConn) SendPacket(b []byte, addr net.Addr) error {
if atomic.LoadInt32(&pc.closed) == 1 {
return errors.New("the listener is already closed")
}
atomic.AddInt32(&pc.nowNum, 1)
select {
case pc.ch <- &packet{b: b, addr: addr}:
return nil
case <-pc.closeCh:
case <-pc.readTimer.C:
_ = pc.Close()
}
if atomic.AddInt32(&pc.nowNum, -1) == 0 && atomic.LoadInt32(&pc.closed) == 1 {
close(pc.ch)
}
return errors.New("the packetConn is already closed")
}
// Close is used to close the listener, it will discard all existing connections
func (pc *ReaderPacketConn) Close() error {
if atomic.CompareAndSwapInt32(&pc.closed, 0, 1) {
close(pc.closeCh)
}
return nil
}

78
lib/enet/paket_test.go Normal file
View File

@@ -0,0 +1,78 @@
package enet
import (
"bytes"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestTcpPacketConn(t *testing.T) {
bs := bytes.Repeat([]byte{1}, 100)
targetAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:53")
assert.NoError(t, err)
finish := make(chan struct{}, 0)
ln, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
conn, err := ln.Accept()
assert.NoError(t, err)
b := make([]byte, 1024)
n, addr, err := NewTcpPacketConn(conn).ReadFrom(b)
assert.NoError(t, err)
assert.Equal(t, targetAddr, addr)
assert.Equal(t, n, 100)
finish <- struct{}{}
}()
conn, err := net.Dial("tcp", ln.Addr().String())
assert.NoError(t, err)
_, err = NewTcpPacketConn(conn).WriteTo(bs, targetAddr)
assert.NoError(t, err)
<-finish
}
func TestPacketConn(t *testing.T) {
finish := make(chan struct{}, 0)
sPacketConn, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
cPacketConn, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
bPacketConn := NewReaderPacketConn(sPacketConn, nil, sPacketConn.LocalAddr())
sendAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:53")
assert.NoError(t, err)
go func() {
b := make([]byte, 1024)
n, addr, err := bPacketConn.ReadFrom(b)
assert.NoError(t, err)
assert.Equal(t, sendAddr, addr)
assert.Equal(t, n, 4)
_, err = bPacketConn.WriteTo(bytes.Repeat(b[:n], 10), cPacketConn.LocalAddr())
assert.NoError(t, err)
finish <- struct{}{}
}()
err = bPacketConn.SendPacket([]byte{0, 0, 0, 0}, sendAddr)
assert.NoError(t, err)
b := make([]byte, 1024)
n, addr, err := cPacketConn.ReadFrom(b)
assert.NoError(t, err)
assert.Equal(t, n, 40)
assert.Equal(t, addr, sPacketConn.LocalAddr())
<-finish
}

55
lib/enet/s5_packet.go Normal file
View File

@@ -0,0 +1,55 @@
package enet
import (
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/pool"
"github.com/pkg/errors"
"net"
)
var packetBp = pool.NewBufferPool(1500)
type S5PacketConn struct {
net.PacketConn
remoteAddr net.Addr
}
func NewS5PacketConn(pc net.PacketConn, remoteAddr net.Addr) *S5PacketConn {
return &S5PacketConn{PacketConn: pc, remoteAddr: remoteAddr}
}
func (s *S5PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
b := packetBp.Get()
defer packetBp.Put(b)
n, addr, err = s.PacketConn.ReadFrom(b)
if err != nil {
return
}
var targetAddr common.Addr
targetAddr, err = common.SplitAddr(b[3:])
if err != nil {
return
}
n = copy(p, b[3+len(targetAddr):n])
addr, err = net.ResolveUDPAddr("udp", targetAddr.String())
return
}
func (s *S5PacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
n = len(p)
b := packetBp.Get()
defer packetBp.Put(b)
var sAddr common.Addr
sAddr, err = common.ParseAddr(addr.String())
if err != nil {
return
}
copy(b[3:], sAddr)
if (3 + len(sAddr) + len(p)) > len(b) {
err = errors.Errorf("data too long(%d)", len(p))
return
}
copy(b[3+len(sAddr):], p)
_, err = s.PacketConn.WriteTo(b[:3+len(sAddr)+len(p)], s.remoteAddr)
return
}

View File

@@ -0,0 +1,50 @@
package enet
import (
"ehang.io/nps/lib/common"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestNewS5PacketConn(t *testing.T) {
serverPc, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
localPc, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
appAddr, err := net.ResolveUDPAddr("udp", "8.8.8.8:53")
assert.NoError(t, err)
data := []byte("test")
go func() {
p := make([]byte, 1500)
n, addr, err := serverPc.ReadFrom(p)
assert.NoError(t, err)
pc := NewReaderPacketConn(serverPc, p[:n], addr)
err = pc.SendPacket(p[:n], addr)
assert.NoError(t, err)
_, addr, err = pc.FirstPacket()
assert.NoError(t, err)
s5Pc := NewS5PacketConn(pc, addr)
n, addr, err = s5Pc.ReadFrom(p)
assert.NoError(t, err)
assert.Equal(t, data, p[:n])
assert.Equal(t, addr.String(), "8.8.8.8:53")
_, err = s5Pc.WriteTo(data, appAddr)
assert.NoError(t, err)
}()
b := []byte{0, 0, 0}
pAddr, err := common.ParseAddr(appAddr.String())
assert.NoError(t, err)
b = append(b, pAddr...)
b = append(b, data...)
_, err = localPc.WriteTo(b, serverPc.LocalAddr())
assert.NoError(t, err)
p := make([]byte, 1500)
n, _, err := localPc.ReadFrom(p)
assert.NoError(t, err)
respAddr, err := common.SplitAddr(p[3:])
assert.NoError(t, err)
assert.Equal(t, respAddr.String(), appAddr.String())
assert.Equal(t, p[3+len(respAddr):n], data)
}

96
lib/lb/algo.go Normal file
View File

@@ -0,0 +1,96 @@
package lb
import (
"errors"
"sync"
)
func GetLbAlgo(algo string) Algo {
// switch
return NewRoundRobin()
}
type Algo interface {
Next() (interface{}, error)
Append(i interface{}) error
Remove(i interface{}) error
Empty() bool
}
// rotation
type roundRobin struct {
head *server
now *server
sync.RWMutex
}
type server struct {
self interface{}
next *server
}
func NewRoundRobin() *roundRobin {
return &roundRobin{}
}
func (r *roundRobin) Append(i interface{}) error {
r.Lock()
defer r.Unlock()
if r.head == nil {
r.head = &server{self: i}
return nil
}
r.now = r.head
for {
if r.now.next == nil {
r.now.next = &server{self: i}
break
}
r.now = r.now.next
}
return nil
}
func (r *roundRobin) Remove(i interface{}) error {
r.Lock()
defer r.Unlock()
o := r.head
var last *server
for {
if o == nil {
return errors.New("not round")
}
if o.self == i {
if last == nil {
r.head = o.next
} else {
last.next = o.next
}
r.now = r.head
return nil
}
last = o
o = o.next
}
}
func (r *roundRobin) Next() (interface{}, error) {
r.Lock()
defer r.Unlock()
if r.head == nil {
return nil, errors.New("not found component")
}
if r.now == nil {
r.now = r.head
}
i := r.now
r.now = r.now.next
return i.self, nil
}
func (r *roundRobin) Empty() bool {
if r.head != nil {
return false
}
return true
}

59
lib/lb/lb.go Normal file
View File

@@ -0,0 +1,59 @@
package lb
import (
"errors"
"sync"
)
func NewLoadBalancer() *LoadBalancer {
return &LoadBalancer{
instances: make(map[string]Algo, 0),
}
}
type LoadBalancer struct {
instances map[string]Algo
Algo string
sync.RWMutex
}
func (lb *LoadBalancer) SetClient(id string, instance interface{}) error {
lb.Lock()
defer lb.Unlock()
var l Algo
var ok bool
if l, ok = lb.instances[id]; !ok {
l = GetLbAlgo(lb.Algo)
lb.instances[id] = l
}
return l.Append(instance)
}
func (lb *LoadBalancer) RemoveClient(id string, instance interface{}) error {
lb.Lock()
defer lb.Unlock()
var l Algo
var ok bool
if l, ok = lb.instances[id]; !ok {
return errors.New("not found Client")
}
err := l.Remove(instance)
if l.Empty() {
delete(lb.instances, id)
}
return err
}
func (lb *LoadBalancer) GetClient(id string) (interface{}, error) {
lb.Lock()
l, ok := lb.instances[id]
lb.Unlock()
if !ok {
return nil, errors.New("client can not found")
}
i, err := l.Next()
if err != nil {
return nil, err
}
return i, nil
}

49
lib/lb/lb_test.go Normal file
View File

@@ -0,0 +1,49 @@
package lb
import (
"github.com/stretchr/testify/assert"
"testing"
)
type test struct {
id int
}
func TestLb(t *testing.T) {
lb := NewLoadBalancer()
for i := 1; i <= 100; i++ {
err := lb.SetClient("test", &test{id: i})
assert.NoError(t, err)
}
m := make(map[int]bool)
for i := 1; i <= 100; i++ {
tt, err := lb.GetClient("test")
assert.NoError(t, err)
if _, ok := m[tt.(*test).id]; ok {
t.Fail()
}
m[tt.(*test).id] = true
}
for i := 1; i <= 50; i++ {
tt, err := lb.GetClient("test")
assert.NoError(t, err)
err = lb.RemoveClient("test", tt)
assert.NoError(t, err)
}
m = make(map[int]bool)
for i := 1; i <= 50; i++ {
tt, err := lb.GetClient("test")
assert.NoError(t, err)
if _, ok := m[tt.(*test).id]; ok {
t.Fail()
}
m[tt.(*test).id] = true
}
}

93
lib/logger/logger.go Normal file
View File

@@ -0,0 +1,93 @@
package logger
import (
"os"
"path/filepath"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
var log *zap.Logger
var atomicLevel zap.AtomicLevel
func Debug(msg string, fields ...zap.Field) {
log.Debug(msg, fields...)
}
func Info(msg string, fields ...zap.Field) {
log.Info(msg, fields...)
}
func Warn(msg string, fields ...zap.Field) {
log.Warn(msg, fields...)
}
func Error(msg string, fields ...zap.Field) {
log.Error(msg, fields...)
}
func DPanic(msg string, fields ...zap.Field) {
log.DPanic(msg, fields...)
}
func Panic(msg string, fields ...zap.Field) {
log.Panic(msg, fields...)
}
func Fatal(msg string, fields ...zap.Field) {
log.Fatal(msg, fields...)
}
func Sync() {
log.Sync()
}
func SetLogLevel(level int) {
atomicLevel.SetLevel(zapcore.Level(level))
}
func init() {
hook := lumberjack.Logger{
Filename: filepath.Join(os.TempDir(), "nps.log"),
MaxSize: 128,
MaxBackups: 30,
MaxAge: 7,
Compress: true,
}
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoderConfig.TimeKey = "log_time"
encoderConfig.LevelKey = "level"
encoderConfig.NameKey = "logger"
encoderConfig.CallerKey = "caller"
encoderConfig.MessageKey = "msg"
encoderConfig.StacktraceKey = "StacktraceKey"
encoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05"))
}
consoleConfig := encoderConfig
consoleConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
atomicLevel = zap.NewAtomicLevel()
// init info level
atomicLevel.SetLevel(zapcore.Level(-1))
core := zapcore.NewTee(
zapcore.NewCore(zapcore.NewJSONEncoder(encoderConfig), zapcore.NewMultiWriteSyncer(zapcore.AddSync(&hook)), atomicLevel),
zapcore.NewCore(zapcore.NewConsoleEncoder(consoleConfig), zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), atomicLevel),
)
caller := zap.AddCaller()
development := zap.Development()
log = zap.New(core, caller, development, zap.AddCallerSkip(1), zap.AddStacktrace(zap.ErrorLevel))
defer log.Sync()
undo := zap.ReplaceGlobals(log)
defer undo()
logLevelSignal()
}

View File

@@ -0,0 +1,38 @@
// +build !windows
package logger
import (
"fmt"
"go.uber.org/zap/zapcore"
"os"
"os/signal"
"syscall"
)
func logLevelSignal() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGUSR1, syscall.SIGUSR2)
fmt.Println("notify receive signal")
go func() {
for s := range c {
fmt.Println("receive signal ", s.String())
switch s {
case syscall.SIGUSR1:
cur := atomicLevel.Level()
if (cur - 1) >= zapcore.DebugLevel {
atomicLevel.SetLevel(zapcore.Level(cur - 1))
}
case syscall.SIGUSR2:
cur := atomicLevel.Level()
if (cur + 1) <= zapcore.FatalLevel {
atomicLevel.SetLevel(zapcore.Level(cur + 1))
}
default:
}
fmt.Println("debug level change to ", atomicLevel.String())
}
}()
}

View File

@@ -0,0 +1,7 @@
// +build windows
package logger
func logLevelSignal() {
}

736
lib/pb/bridge.pb.go Normal file
View File

@@ -0,0 +1,736 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.19.1
// source: bridge.proto
package pb
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ConnType int32
const (
ConnType_tcp ConnType = 0
ConnType_udp ConnType = 1
ConnType_unix ConnType = 2
)
// Enum value maps for ConnType.
var (
ConnType_name = map[int32]string{
0: "tcp",
1: "udp",
2: "unix",
}
ConnType_value = map[string]int32{
"tcp": 0,
"udp": 1,
"unix": 2,
}
)
func (x ConnType) Enum() *ConnType {
p := new(ConnType)
*p = x
return p
}
func (x ConnType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ConnType) Descriptor() protoreflect.EnumDescriptor {
return file_bridge_proto_enumTypes[0].Descriptor()
}
func (ConnType) Type() protoreflect.EnumType {
return &file_bridge_proto_enumTypes[0]
}
func (x ConnType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ConnType.Descriptor instead.
func (ConnType) EnumDescriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{0}
}
type ConnRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"`
// Types that are assignable to ConnType:
// *ConnRequest_AppInfo
// *ConnRequest_NpcInfo
// *ConnRequest_SecretInfo
ConnType isConnRequest_ConnType `protobuf_oneof:"connType"`
}
func (x *ConnRequest) Reset() {
*x = ConnRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConnRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConnRequest) ProtoMessage() {}
func (x *ConnRequest) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConnRequest.ProtoReflect.Descriptor instead.
func (*ConnRequest) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{0}
}
func (x *ConnRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (m *ConnRequest) GetConnType() isConnRequest_ConnType {
if m != nil {
return m.ConnType
}
return nil
}
func (x *ConnRequest) GetAppInfo() *AppInfo {
if x, ok := x.GetConnType().(*ConnRequest_AppInfo); ok {
return x.AppInfo
}
return nil
}
func (x *ConnRequest) GetNpcInfo() *NpcInfo {
if x, ok := x.GetConnType().(*ConnRequest_NpcInfo); ok {
return x.NpcInfo
}
return nil
}
func (x *ConnRequest) GetSecretInfo() *SecretInfo {
if x, ok := x.GetConnType().(*ConnRequest_SecretInfo); ok {
return x.SecretInfo
}
return nil
}
type isConnRequest_ConnType interface {
isConnRequest_ConnType()
}
type ConnRequest_AppInfo struct {
AppInfo *AppInfo `protobuf:"bytes,2,opt,name=app_info,json=appInfo,proto3,oneof"`
}
type ConnRequest_NpcInfo struct {
NpcInfo *NpcInfo `protobuf:"bytes,3,opt,name=npc_info,json=npcInfo,proto3,oneof"`
}
type ConnRequest_SecretInfo struct {
SecretInfo *SecretInfo `protobuf:"bytes,4,opt,name=secret_info,json=secretInfo,proto3,oneof"`
}
func (*ConnRequest_AppInfo) isConnRequest_ConnType() {}
func (*ConnRequest_NpcInfo) isConnRequest_ConnType() {}
func (*ConnRequest_SecretInfo) isConnRequest_ConnType() {}
type ClientRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to ConnType:
// *ClientRequest_AppInfo
// *ClientRequest_Ping
ConnType isClientRequest_ConnType `protobuf_oneof:"connType"`
}
func (x *ClientRequest) Reset() {
*x = ClientRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientRequest) ProtoMessage() {}
func (x *ClientRequest) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientRequest.ProtoReflect.Descriptor instead.
func (*ClientRequest) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{1}
}
func (m *ClientRequest) GetConnType() isClientRequest_ConnType {
if m != nil {
return m.ConnType
}
return nil
}
func (x *ClientRequest) GetAppInfo() *AppInfo {
if x, ok := x.GetConnType().(*ClientRequest_AppInfo); ok {
return x.AppInfo
}
return nil
}
func (x *ClientRequest) GetPing() *Ping {
if x, ok := x.GetConnType().(*ClientRequest_Ping); ok {
return x.Ping
}
return nil
}
type isClientRequest_ConnType interface {
isClientRequest_ConnType()
}
type ClientRequest_AppInfo struct {
AppInfo *AppInfo `protobuf:"bytes,1,opt,name=app_info,json=appInfo,proto3,oneof"`
}
type ClientRequest_Ping struct {
Ping *Ping `protobuf:"bytes,2,opt,name=ping,proto3,oneof"`
}
func (*ClientRequest_AppInfo) isClientRequest_ConnType() {}
func (*ClientRequest_Ping) isClientRequest_ConnType() {}
type AppInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AppAddr string `protobuf:"bytes,1,opt,name=app_addr,json=appAddr,proto3" json:"app_addr,omitempty"`
NpcId string `protobuf:"bytes,2,opt,name=npc_id,json=npcId,proto3" json:"npc_id,omitempty"`
ConnType ConnType `protobuf:"varint,3,opt,name=conn_type,json=connType,proto3,enum=ConnType" json:"conn_type,omitempty"`
}
func (x *AppInfo) Reset() {
*x = AppInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppInfo) ProtoMessage() {}
func (x *AppInfo) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppInfo.ProtoReflect.Descriptor instead.
func (*AppInfo) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{2}
}
func (x *AppInfo) GetAppAddr() string {
if x != nil {
return x.AppAddr
}
return ""
}
func (x *AppInfo) GetNpcId() string {
if x != nil {
return x.NpcId
}
return ""
}
func (x *AppInfo) GetConnType() ConnType {
if x != nil {
return x.ConnType
}
return ConnType_tcp
}
type SecretInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
IsUdpConn bool `protobuf:"varint,1,opt,name=is_udp_conn,json=isUdpConn,proto3" json:"is_udp_conn,omitempty"`
AppAddr string `protobuf:"bytes,2,opt,name=app_addr,json=appAddr,proto3" json:"app_addr,omitempty"`
}
func (x *SecretInfo) Reset() {
*x = SecretInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SecretInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SecretInfo) ProtoMessage() {}
func (x *SecretInfo) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SecretInfo.ProtoReflect.Descriptor instead.
func (*SecretInfo) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{3}
}
func (x *SecretInfo) GetIsUdpConn() bool {
if x != nil {
return x.IsUdpConn
}
return false
}
func (x *SecretInfo) GetAppAddr() string {
if x != nil {
return x.AppAddr
}
return ""
}
type NpcInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TunnelId string `protobuf:"bytes,2,opt,name=tunnel_id,json=tunnelId,proto3" json:"tunnel_id,omitempty"`
IsControlTunnel bool `protobuf:"varint,3,opt,name=is_control_tunnel,json=isControlTunnel,proto3" json:"is_control_tunnel,omitempty"`
}
func (x *NpcInfo) Reset() {
*x = NpcInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NpcInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NpcInfo) ProtoMessage() {}
func (x *NpcInfo) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NpcInfo.ProtoReflect.Descriptor instead.
func (*NpcInfo) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{4}
}
func (x *NpcInfo) GetTunnelId() string {
if x != nil {
return x.TunnelId
}
return ""
}
func (x *NpcInfo) GetIsControlTunnel() bool {
if x != nil {
return x.IsControlTunnel
}
return false
}
type NpcResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *NpcResponse) Reset() {
*x = NpcResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NpcResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NpcResponse) ProtoMessage() {}
func (x *NpcResponse) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NpcResponse.ProtoReflect.Descriptor instead.
func (*NpcResponse) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{5}
}
func (x *NpcResponse) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
func (x *NpcResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
type Ping struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Now string `protobuf:"bytes,1,opt,name=now,proto3" json:"now,omitempty"`
}
func (x *Ping) Reset() {
*x = Ping{}
if protoimpl.UnsafeEnabled {
mi := &file_bridge_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Ping) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Ping) ProtoMessage() {}
func (x *Ping) ProtoReflect() protoreflect.Message {
mi := &file_bridge_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Ping.ProtoReflect.Descriptor instead.
func (*Ping) Descriptor() ([]byte, []int) {
return file_bridge_proto_rawDescGZIP(), []int{6}
}
func (x *Ping) GetNow() string {
if x != nil {
return x.Now
}
return ""
}
var File_bridge_proto protoreflect.FileDescriptor
var file_bridge_proto_rawDesc = []byte{
0x0a, 0x0c, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa7,
0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e,
0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x25,
0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x08, 0x2e, 0x41, 0x70, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x07, 0x61, 0x70,
0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x25, 0x0a, 0x08, 0x6e, 0x70, 0x63, 0x5f, 0x69, 0x6e, 0x66,
0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x4e, 0x70, 0x63, 0x49, 0x6e, 0x66,
0x6f, 0x48, 0x00, 0x52, 0x07, 0x6e, 0x70, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x0b,
0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x0b, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00,
0x52, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0a, 0x0a, 0x08,
0x63, 0x6f, 0x6e, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5f, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x61, 0x70, 0x70,
0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x41, 0x70,
0x70, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x07, 0x61, 0x70, 0x70, 0x49, 0x6e, 0x66, 0x6f,
0x12, 0x1b, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05,
0x2e, 0x70, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x0a, 0x0a,
0x08, 0x63, 0x6f, 0x6e, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x22, 0x64, 0x0a, 0x07, 0x41, 0x70, 0x70,
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x41, 0x64, 0x64, 0x72, 0x12,
0x15, 0x0a, 0x06, 0x6e, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x6e, 0x70, 0x63, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x63, 0x6f, 0x6e, 0x6e,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x22,
0x47, 0x0a, 0x0a, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a,
0x0b, 0x69, 0x73, 0x5f, 0x75, 0x64, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x55, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x19, 0x0a,
0x08, 0x61, 0x70, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x61, 0x70, 0x70, 0x41, 0x64, 0x64, 0x72, 0x22, 0x52, 0x0a, 0x07, 0x4e, 0x70, 0x63, 0x49,
0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64,
0x12, 0x2a, 0x0a, 0x11, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x74,
0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, 0x43,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x41, 0x0a, 0x0b,
0x4e, 0x70, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73,
0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75,
0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
0x18, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x6f, 0x77, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6e, 0x6f, 0x77, 0x2a, 0x27, 0x0a, 0x09, 0x63, 0x6f, 0x6e,
0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x74, 0x63, 0x70, 0x10, 0x00, 0x12,
0x07, 0x0a, 0x03, 0x75, 0x64, 0x70, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x78,
0x10, 0x02, 0x42, 0x15, 0x5a, 0x13, 0x65, 0x68, 0x61, 0x6e, 0x67, 0x2e, 0x69, 0x6f, 0x2f, 0x6e,
0x70, 0x73, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_bridge_proto_rawDescOnce sync.Once
file_bridge_proto_rawDescData = file_bridge_proto_rawDesc
)
func file_bridge_proto_rawDescGZIP() []byte {
file_bridge_proto_rawDescOnce.Do(func() {
file_bridge_proto_rawDescData = protoimpl.X.CompressGZIP(file_bridge_proto_rawDescData)
})
return file_bridge_proto_rawDescData
}
var file_bridge_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_bridge_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_bridge_proto_goTypes = []interface{}{
(ConnType)(0), // 0: conn_type
(*ConnRequest)(nil), // 1: ConnRequest
(*ClientRequest)(nil), // 2: ClientRequest
(*AppInfo)(nil), // 3: AppInfo
(*SecretInfo)(nil), // 4: SecretInfo
(*NpcInfo)(nil), // 5: NpcInfo
(*NpcResponse)(nil), // 6: NpcResponse
(*Ping)(nil), // 7: ping
}
var file_bridge_proto_depIdxs = []int32{
3, // 0: ConnRequest.app_info:type_name -> AppInfo
5, // 1: ConnRequest.npc_info:type_name -> NpcInfo
4, // 2: ConnRequest.secret_info:type_name -> SecretInfo
3, // 3: ClientRequest.app_info:type_name -> AppInfo
7, // 4: ClientRequest.ping:type_name -> ping
0, // 5: AppInfo.conn_type:type_name -> conn_type
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_bridge_proto_init() }
func file_bridge_proto_init() {
if File_bridge_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_bridge_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConnRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_bridge_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_bridge_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AppInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_bridge_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SecretInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_bridge_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NpcInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_bridge_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NpcResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_bridge_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Ping); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_bridge_proto_msgTypes[0].OneofWrappers = []interface{}{
(*ConnRequest_AppInfo)(nil),
(*ConnRequest_NpcInfo)(nil),
(*ConnRequest_SecretInfo)(nil),
}
file_bridge_proto_msgTypes[1].OneofWrappers = []interface{}{
(*ClientRequest_AppInfo)(nil),
(*ClientRequest_Ping)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_bridge_proto_rawDesc,
NumEnums: 1,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_bridge_proto_goTypes,
DependencyIndexes: file_bridge_proto_depIdxs,
EnumInfos: file_bridge_proto_enumTypes,
MessageInfos: file_bridge_proto_msgTypes,
}.Build()
File_bridge_proto = out.File
file_bridge_proto_rawDesc = nil
file_bridge_proto_goTypes = nil
file_bridge_proto_depIdxs = nil
}

51
lib/pb/bridge.proto Normal file
View File

@@ -0,0 +1,51 @@
syntax = "proto3";
option go_package = "ehang.io/nps/lib/pb";
message ConnRequest {
string Id = 1;
oneof connType {
AppInfo app_info = 2;
NpcInfo npc_info = 3;
SecretInfo secret_info = 4;
}
}
message ClientRequest {
oneof connType {
AppInfo app_info = 1;
ping ping = 2;
}
}
enum conn_type{
tcp = 0;
udp = 1 ;
unix = 2;
}
message AppInfo {
string app_addr = 1;
string npc_id = 2;
conn_type conn_type = 3;
}
message SecretInfo {
bool is_udp_conn = 1;
string app_addr = 2;
}
message NpcInfo {
string tunnel_id = 2;
bool is_control_tunnel = 3;
}
message NpcResponse {
bool success = 1;
string message = 2;
}
message ping{
string now = 1;
}

29
lib/pb/pb.go Normal file
View File

@@ -0,0 +1,29 @@
package pb
import (
"ehang.io/nps/lib/common"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
"io"
)
// WriteMessage is used to write a message to writer
func WriteMessage(w io.Writer, message proto.Message) (int, error) {
b, err := proto.Marshal(message)
if err != nil {
return 0, errors.Wrap(err, "proto Marshal")
}
n, err := common.WriteLenBytes(w, b)
return n, err
}
// ReadMessage is used to read a message from reader
func ReadMessage(r io.Reader, message proto.Message) (int, error) {
message.Reset()
b := make([]byte, 4096)
n, err := common.ReadLenBytes(r, b)
if err != nil {
return 0, errors.Wrap(err, "read proto message")
}
return n, proto.Unmarshal(b[:n], message)
}

25
lib/pb/pb_test.go Normal file
View File

@@ -0,0 +1,25 @@
package pb
import (
"bytes"
"github.com/stretchr/testify/assert"
"testing"
)
func TestMarshal(t *testing.T) {
app := &AppInfo{
ConnType: ConnType_udp,
AppAddr: "127.0.0.1:8080",
}
var buf []byte
b := bytes.NewBuffer(buf)
_, err := WriteMessage(b, app)
assert.NoError(t, err)
appRecv := &AppInfo{}
_, err = ReadMessage(b, appRecv)
assert.NoError(t, err)
assert.Equal(t, app.AppAddr, appRecv.AppAddr)
assert.Equal(t, app.ConnType, appRecv.ConnType)
}

76
lib/pool/goroutine.go Normal file
View File

@@ -0,0 +1,76 @@
package pool
import (
"ehang.io/nps/lib/common"
"github.com/panjf2000/ants/v2"
"io"
"net"
"sync"
)
var connBp = NewBufferPool(MaxReadSize)
var packetBp = NewBufferPool(1500)
const MaxReadSize = 32 * 1024
var CopyConnGoroutinePool *ants.PoolWithFunc
var CopyPacketGoroutinePool *ants.PoolWithFunc
type CopyConnGpParams struct {
Writer io.Writer
Reader io.Reader
Wg *sync.WaitGroup
}
type CopyPacketGpParams struct {
RPacket net.PacketConn
WPacket net.PacketConn
Wg *sync.WaitGroup
}
func init() {
var err error
CopyConnGoroutinePool, err = ants.NewPoolWithFunc(1000000, func(i interface{}) {
gpp, ok := i.(*CopyConnGpParams)
if !ok {
return
}
buf := connBp.Get()
_, _ = common.CopyBuffer(gpp.Writer, gpp.Reader, buf)
connBp.Put(buf)
gpp.Wg.Done()
if v, ok := gpp.Reader.(*net.TCPConn); ok {
_ = v.CloseWrite()
}
if v, ok := gpp.Writer.(*net.TCPConn); ok {
_ = v.CloseRead()
}
})
if err != nil {
panic(err)
}
CopyPacketGoroutinePool, err = ants.NewPoolWithFunc(1000000, func(i interface{}) {
cpp, ok := i.(*CopyPacketGpParams)
if !ok {
return
}
buf := connBp.Get()
for {
n, addr, err := cpp.RPacket.ReadFrom(buf)
if err != nil {
break
}
_, err = cpp.WPacket.WriteTo(buf[:n], addr)
if err != nil {
break
}
}
connBp.Put(buf)
_ = cpp.RPacket.Close()
_ = cpp.WPacket.Close()
cpp.Wg.Done()
})
if err != nil {
panic(err)
}
}

32
lib/pool/pool.go Normal file
View File

@@ -0,0 +1,32 @@
package pool
import "sync"
type BufferPool struct {
pool sync.Pool
poolSize int
}
func NewBufferPool(poolSize int) *BufferPool {
bp := &BufferPool{}
bp.pool = sync.Pool{
New: func() interface{} {
return make([]byte, poolSize, poolSize)
},
}
bp.poolSize = poolSize
return bp
}
func (bp *BufferPool) Get() []byte {
buf := bp.pool.Get().([]byte)
return buf[:bp.poolSize] // just like make a new slice, but data may not be 0
}
func (bp *BufferPool) Put(x []byte) {
if len(x) == bp.poolSize {
bp.pool.Put(x)
} else {
x = nil // buf is not full, not allowed, New method returns a full buf
}
}

111
lib/rate/rate.go Normal file
View File

@@ -0,0 +1,111 @@
package rate
import (
"errors"
"sync"
"sync/atomic"
"time"
)
// Rate is an implementation of the token bucket added regularly
type Rate struct {
bucketSize int64
bucketSurplusSize int64
bucketAddSize int64
stopChan chan bool
nowRate int64
cond *sync.Cond
hasStop bool
hasStart bool
}
// NewRate return token bucket with specified rate
func NewRate(addSize int64) *Rate {
r := &Rate{
bucketSize: addSize * 2,
bucketSurplusSize: 0,
bucketAddSize: addSize,
stopChan: make(chan bool),
cond: sync.NewCond(new(sync.Mutex)),
}
return r
}
// Start is used to add token regularly
func (r *Rate) Start() {
if !r.hasStart {
r.hasStart = true
go r.session()
}
}
func (r *Rate) add(size int64) {
if res := r.bucketSize - r.bucketSurplusSize; res < r.bucketAddSize {
atomic.AddInt64(&r.bucketSurplusSize, res)
return
}
atomic.AddInt64(&r.bucketSurplusSize, size)
}
// Write is called when add token to bucket
func (r *Rate) Write(size int64) {
r.add(size)
}
// Stop is called when not use the rate bucket
func (r *Rate) Stop() {
if r.hasStart {
r.stopChan <- true
r.hasStop = true
r.cond.Broadcast()
}
}
// Get is called when get token from bucket
func (r *Rate) Get(size int64) error {
if r.hasStop {
return errors.New("the rate has closed")
}
if r.bucketSurplusSize >= size {
atomic.AddInt64(&r.bucketSurplusSize, -size)
return nil
}
for {
r.cond.L.Lock()
r.cond.Wait()
if r.bucketSurplusSize >= size {
r.cond.L.Unlock()
atomic.AddInt64(&r.bucketSurplusSize, -size)
return nil
}
if r.hasStop {
return errors.New("the rate has closed")
}
r.cond.L.Unlock()
}
}
// GetNowRate returns the current rate
// Just a rough number
func (r *Rate) GetNowRate() int64 {
return r.nowRate
}
func (r *Rate) session() {
ticker := time.NewTicker(time.Second * 1)
for {
select {
case <-ticker.C:
if rs := r.bucketAddSize - r.bucketSurplusSize; rs > 0 {
r.nowRate = rs
} else {
r.nowRate = r.bucketSize - r.bucketSurplusSize
}
r.add(r.bucketAddSize)
r.cond.Broadcast()
case <-r.stopChan:
ticker.Stop()
return
}
}
}

52
lib/rate/rate_test.go Normal file
View File

@@ -0,0 +1,52 @@
package rate
import (
"math"
"testing"
"time"
)
func TestRate_GetWrite(t *testing.T) {
r := NewRate(1024)
r.Write(2048)
n := 0
go func() {
for {
r.Get(1024)
n += 1024
}
}()
select {
case <-time.After(time.Second):
r.Stop()
if n != 2048 {
t.Fatal("get token error", n)
}
}
}
func TestRate_StartGetRate(t *testing.T) {
r := NewRate(1024)
r.Start()
n := 0
go func() {
for {
err := r.Get(1024)
if err != nil {
return
}
n += 1024
}
}()
select {
case <-time.After(time.Second * 5):
r.Stop()
time.Sleep(time.Second * 2)
if n < 4*1024 || n > 1024*5 {
t.Fatal("get error", n)
}
if math.Abs(float64(r.GetNowRate()-1024)) > 100 {
t.Fatal("rate error", n)
}
}
}