Projects STRLCPY SeaMoon Commits fe658ff9
🤬
  • fix: some websocket error optimization (#4)

    fix: websocket panic 
    fix: websocket error disable
    fix: s tools deploy
    fix: remove debug dependency
    chore: add debug pprof
  • Loading...
  • DVK committed with GitHub 10 months ago
    fe658ff9
    1 parent c3165272
  • ■ ■ ■ ■ ■ ■
    .gitignore
    skipped 26 lines
    27 27  .config
    28 28  .secret
    29 29  node_modules
     30 +bootstrap
     31 +.s/
  • ■ ■ ■ ■ ■ ■
    cmd/client.go
    1 1  package main
    2 2   
    3 3  import (
    4  - "github.com/DVKunion/SeaMoon/pkg/client"
    5  - "github.com/DVKunion/SeaMoon/pkg/consts"
     4 + "os"
     5 + 
    6 6   log "github.com/sirupsen/logrus"
    7 7   "github.com/spf13/cobra"
    8  - "os"
     8 + 
     9 + "github.com/DVKunion/SeaMoon/pkg/client"
     10 + "github.com/DVKunion/SeaMoon/pkg/consts"
    9 11  )
    10 12   
    11 13  var (
    skipped 39 lines
  • ■ ■ ■ ■ ■
    go.mod
    skipped 3 lines
    4 4   
    5 5  require (
    6 6   github.com/BurntSushi/toml v0.3.1
    7  - github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021
    8 7   github.com/gin-gonic/gin v1.8.1
    9 8   github.com/google/martian/v3 v3.3.2
    10 9   github.com/gorilla/websocket v1.4.2
    11 10   github.com/sirupsen/logrus v1.9.0
    12 11   github.com/spf13/cobra v1.5.0
    13  - github.com/stretchr/testify v1.7.1
    14 12   github.com/tg123/go-htpasswd v1.2.0
    15 13  )
    16 14   
    17 15  require (
    18 16   github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 // indirect
    19  - github.com/davecgh/go-spew v1.1.1 // indirect
    20 17   github.com/gin-contrib/sse v0.1.0 // indirect
    21 18   github.com/go-playground/locales v0.14.0 // indirect
    22 19   github.com/go-playground/universal-translator v0.18.0 // indirect
    skipped 6 lines
    29 26   github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
    30 27   github.com/modern-go/reflect2 v1.0.2 // indirect
    31 28   github.com/pelletier/go-toml/v2 v2.0.1 // indirect
    32  - github.com/pmezard/go-difflib v1.0.0 // indirect
    33 29   github.com/spf13/pflag v1.0.5 // indirect
    34 30   github.com/ugorji/go/codec v1.2.7 // indirect
    35 31   golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
    skipped 2 lines
    38 34   golang.org/x/text v0.3.6 // indirect
    39 35   google.golang.org/protobuf v1.28.0 // indirect
    40 36   gopkg.in/yaml.v2 v2.4.0 // indirect
    41  - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
    42 37  )
    43 38   
  • ■ ■ ■ ■ ■
    go.sum
    skipped 10 lines
    11 11  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
    12 12  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
    13 13  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
    14  -github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021 h1:EbF0UihnxWRcIMOwoVtqnAylsqcjzqpSvMdjF2Ud4rA=
    15  -github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
    16  -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
    17  -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
    18 14  github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
    19 15  github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
    20 16  github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
    skipped 67 lines
    88 84  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
    89 85  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
    90 86  github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
    91  -github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
    92 87  github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
    93 88  github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
    94 89  github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
    skipped 98 lines
  • ■ ■ ■ ■ ■
    pkg/client/client.go
    skipped 2 lines
    3 3  import (
    4 4   "bufio"
    5 5   "context"
    6  - "github.com/DVKunion/SeaMoon/pkg/consts"
    7  - "github.com/DVKunion/SeaMoon/static"
    8  - "github.com/gin-gonic/gin"
    9  - log "github.com/sirupsen/logrus"
    10 6   "html/template"
    11 7   "io"
    12 8   "net"
    13 9   "net/http"
    14 10   "os"
     11 + 
     12 + "github.com/gin-gonic/gin"
     13 + log "github.com/sirupsen/logrus"
     14 + 
     15 + "github.com/DVKunion/SeaMoon/pkg/consts"
     16 + "github.com/DVKunion/SeaMoon/static"
     17 + 
     18 + _ "net/http/pprof"
    15 19  )
    16 20   
    17 21  type Client struct {
    skipped 50 lines
    68 72   server.GET("/", func(ctx *gin.Context) {
    69 73   ctx.HTML(200, "index.html", Config())
    70 74   })
     75 + 
     76 + // pprof
     77 + if debug {
     78 + server.GET("/debug/pprof/*any", gin.WrapH(http.DefaultServeMux))
     79 + }
    71 80   
    72 81   // controller set
    73 82   server.POST("/", func(ctx *gin.Context) {
    skipped 16 lines
  • ■ ■ ■ ■ ■ ■
    pkg/client/socks.go
    skipped 2 lines
    3 3  import (
    4 4   "bufio"
    5 5   "context"
    6  - "github.com/DVKunion/SeaMoon/pkg/consts"
    7  - "github.com/DVKunion/SeaMoon/pkg/server"
    8  - "github.com/DVKunion/SeaMoon/pkg/utils"
    9  - "github.com/gorilla/websocket"
    10  - log "github.com/sirupsen/logrus"
    11 6   "net"
    12 7   "net/http"
    13 8   "strings"
     9 + "sync"
     10 + 
     11 + "github.com/gorilla/websocket"
     12 + log "github.com/sirupsen/logrus"
     13 + 
     14 + "github.com/DVKunion/SeaMoon/pkg/consts"
     15 + "github.com/DVKunion/SeaMoon/pkg/server"
     16 + "github.com/DVKunion/SeaMoon/pkg/utils"
    14 17  )
    15 18   
    16 19  type bufferedConn struct {
    skipped 53 lines
    70 73   }()
    71 74   go func() {
    72 75   for {
     76 + lock := &sync.Mutex{}
    73 77   conn, err := server.Accept()
    74 78   if err == nil {
    75 79   log.Debugf(consts.SOCKS5_ACCEPT_START, conn.RemoteAddr())
    skipped 3 lines
    79 83   log.Errorf(consts.CLIENT_PROTOCOL_UNSUPPORT_ERROR, err)
    80 84   return
    81 85   }
    82  - go Socks5Handler(&bufferedConn{conn, br}, proxyAddr)
     86 + go Socks5Handler(&bufferedConn{conn, br}, proxyAddr, lock)
    83 87   } else {
    84 88   if closeFlag {
    85 89   // except close
    skipped 7 lines
    93 97   <-ctx.Done()
    94 98  }
    95 99   
    96  -func Socks5Handler(conn net.Conn, raddr string) {
     100 +func Socks5Handler(conn net.Conn, raddr string, lock *sync.Mutex) {
    97 101   // select method
    98 102   _, err := utils.ReadMethods(conn)
    99 103   if err != nil {
    skipped 19 lines
    119 123   }
    120 124   switch request.Cmd {
    121 125   case utils.CmdConnect:
    122  - handleConnect(conn, request, raddr)
     126 + handleConnect(conn, request, raddr, lock)
    123 127   break
    124 128   case utils.CmdBind:
    125 129   log.Error("not support cmd bind")
    skipped 6 lines
    132 136   }
    133 137  }
    134 138   
    135  -func handleConnect(conn net.Conn, req *utils.Request, rAddr string) {
     139 +func handleConnect(conn net.Conn, req *utils.Request, rAddr string, lock *sync.Mutex) {
    136 140   
    137 141   log.Infof(consts.SOCKS5_CONNECT_SERVER, req.Addr, conn.RemoteAddr())
    138 142   
    skipped 8 lines
    147 151   return
    148 152   }
    149 153   
    150  - newConn := server.NewWebsocketServer(wsConn)
     154 + newConn := server.NewWebsocketServer(wsConn, lock)
    151 155   
    152 156   defer newConn.Close()
    153 157   
    skipped 14 lines
  • ■ ■ ■ ■
    pkg/consts/log.go
    skipped 42 lines
    43 43   SOCKS5_LISTEN_START string = "[Socks5] Client Start Listen At: %s"
    44 44   SOCKS5_LISTEN_STOP string = "[Socks5] Client Stop Listen"
    45 45   SOCKS5_ACCEPT_START string = "[Socks5] Client Accept Conn From: %s"
    46  - SOCKS5_CONNECT_SERVER string = "[Socks5] Server Connect %s For %s"
     46 + SOCKS5_CONNECT_SERVER string = "[Socks5] Server Connect %s From %s"
    47 47   SOCKS5_CONNECT_ESTAB string = "[Socks5] Connect Tunnel Established %s <-> %s"
    48 48   SOCKS5_CONNECT_DIS string = "[Socks5] Connect Tunnel Disconnected %s >-< %s"
    49 49   SOCKS5_BIND_SERVER string = "[Socks5] Bind For %s"
    skipped 15 lines
  • ■ ■ ■ ■ ■ ■
    pkg/server/socks.go
    skipped 1 lines
    2 2   
    3 3  import (
    4 4   "errors"
    5  - "github.com/DVKunion/SeaMoon/pkg/consts"
    6  - "github.com/DVKunion/SeaMoon/pkg/utils"
    7  - "github.com/gorilla/websocket"
    8  - log "github.com/sirupsen/logrus"
    9 5   "net"
    10 6   "net/http"
    11 7   "strconv"
    12 8   "strings"
     9 + "sync"
    13 10   "time"
     11 + 
     12 + "github.com/gorilla/websocket"
     13 + log "github.com/sirupsen/logrus"
     14 + 
     15 + "github.com/DVKunion/SeaMoon/pkg/consts"
     16 + "github.com/DVKunion/SeaMoon/pkg/utils"
    14 17  )
    15 18   
    16 19  type SocksServer struct {
    skipped 15 lines
    32 35  }
    33 36   
    34 37  func (s *SocksServer) Serve(w http.ResponseWriter, r *http.Request) {
     38 + lock := &sync.Mutex{}
    35 39   // socks upgrade websocket
    36  - var upGrader = websocket.Upgrader{
     40 + upGrader := websocket.Upgrader{
    37 41   CheckOrigin: func(r *http.Request) bool {
    38 42   return true
    39 43   },
    40 44   }
    41 45   
    42  - var conn, _ = upGrader.Upgrade(w, r, nil)
     46 + conn, err := upGrader.Upgrade(w, r, nil)
     47 + if err != nil {
     48 + log.Errorf("websocket upgrade error: %s", err)
     49 + return
     50 + }
    43 51   
    44  - wsConn := NewWebsocketServer(conn)
     52 + wsConn := NewWebsocketServer(conn, lock)
    45 53   defer wsConn.Close()
    46 54   
    47 55   switch s.request.Cmd {
    skipped 4 lines
    52 60   case utils.CmdUDPOverTCP:
    53 61   s.handleUDPOverTCP()
    54 62   default:
    55  - conn.WriteMessage(websocket.BinaryMessage, []byte("UnSupport Command"))
     63 + log.Errorf("UnSupport Command")
    56 64   }
    57 65  }
    58 66   
    skipped 64 lines
  • ■ ■ ■ ■ ■ ■
    pkg/server/websocket.go
    1 1  package server
    2 2   
    3 3  import (
    4  - "github.com/gorilla/websocket"
    5 4   "io"
    6 5   "net"
     6 + "sync"
     7 + 
     8 + "github.com/gorilla/websocket"
    7 9  )
    8 10   
    9 11  type WebsocketServer struct {
    10 12   net.Conn
    11  - wConn *websocket.Conn
     13 + wConn *websocket.Conn
     14 + writeLock *sync.Mutex
     15 + 
    12 16   messageType int
    13 17  }
    14 18   
    15  -func NewWebsocketServer(wConn *websocket.Conn) net.Conn {
     19 +func NewWebsocketServer(wConn *websocket.Conn, lock *sync.Mutex) net.Conn {
    16 20   return &WebsocketServer{
    17 21   wConn: wConn,
    18 22   messageType: websocket.BinaryMessage,
     23 + writeLock: lock,
    19 24   }
    20 25  }
    21 26   
    skipped 3 lines
    25 30   
    26 31  func (ws *WebsocketServer) Close() error {
    27 32   // ws need send close message first to avoid err : close 1006 (abnormal closure): unexpected EOF
    28  - // todo: panic - concurrent write to websocket connection
    29  - err := ws.wConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "close"))
     33 + err := ws.write(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "close"))
    30 34   if err != nil {
    31 35   return err
    32 36   }
    skipped 1 lines
    34 38  }
    35 39   
    36 40  func (ws *WebsocketServer) Write(b []byte) (n int, err error) {
    37  - err = ws.wConn.WriteMessage(ws.messageType, b)
     41 + err = ws.write(ws.messageType, b)
    38 42   if err != nil {
    39 43   return 0, err
    40 44   }
    41 45   return len(b), nil
     46 +}
     47 + 
     48 +func (ws *WebsocketServer) write(messageType int, data []byte) error {
     49 + ws.writeLock.TryLock()
     50 + defer ws.writeLock.Unlock()
     51 + return ws.wConn.WriteMessage(messageType, data)
    42 52  }
    43 53   
    44 54  func (ws *WebsocketServer) Read(b []byte) (n int, err error) {
    skipped 12 lines
  • ■ ■ ■ ■ ■ ■
    pkg/utils/socks.go
    skipped 11 lines
    12 12   "net"
    13 13   "strconv"
    14 14   "sync"
     15 + 
     16 + "github.com/gorilla/websocket"
    15 17  )
    16 18   
    17 19  // buffer pools
    skipped 5 lines
    23 25   } // small buff pool
    24 26   LPool = sync.Pool{
    25 27   New: func() interface{} {
    26  - return make([]byte, 64*1024+262)
     28 + return make([]byte, 32768)
    27 29   },
    28 30   } // large buff pool for udp
    29 31  )
    30 32   
    31 33  // Transport rw1 and rw2
    32 34  func Transport(rw1, rw2 io.ReadWriter) error {
    33  - errc := make(chan error, 1)
     35 + errC := make(chan error, 1)
    34 36   go func() {
    35  - b := LPool.Get().([]byte)
    36  - defer LPool.Put(b)
    37  - 
    38  - _, err := io.CopyBuffer(rw1, rw2, b)
    39  - errc <- err
     37 + _, err := io.CopyBuffer(rw1, rw2, nil)
     38 + errC <- err
    40 39   }()
    41 40   
    42 41   go func() {
    43  - b := LPool.Get().([]byte)
    44  - defer LPool.Put(b)
    45  - 
    46  - _, err := io.CopyBuffer(rw2, rw1, b)
    47  - errc <- err
     42 + _, err := io.CopyBuffer(rw2, rw1, nil)
     43 + errC <- err
    48 44   }()
    49 45   
    50  - if err := <-errc; err != nil && err != io.EOF {
     46 + if err := <-errC; err != nil && err != io.EOF && !websocket.IsUnexpectedCloseError(err) {
    51 47   return err
    52 48   }
    53 49   
    skipped 729 lines
  • ■ ■ ■ ■ ■ ■
    s.yaml
    1  -edition: 1.0.0 # 命令行YAML规范版本,遵循语义化版本(Semantic Versioning)规范
    2  -name: SeaMoonAPP
    3  -access: "default"
     1 +# 阿里云函数FC部署 serverless-devs 脚本
     2 +# 如需要部署其他云厂商, 请使用 `s deploy -t s.xxxx.yaml`
     3 +edition: 1.0.0 # 命令行YAML规范版本,遵循语义化版本(Semantic Versioning)规范
     4 +name: SeaMoon-Server
     5 +access: "default" # 默认使用 `s config add` 添加密钥时,accessID的默认值
    4 6   
    5 7  vars:
    6 8   region: cn-hongkong # 部署区域,请看docs/DEPLOY.md
    skipped 3 lines
    10 12   internetAccess: true
    11 13  # logConfig: auto # 开启日志,注意日志服务是收费的,每月只有500MB的免费额度,如不需要(非debug)可以注释掉。
    12 14   
     15 +actions:
     16 + pre-deploy:
     17 + - run: go mod tidy
     18 + path: ./
     19 + - run: GO111MODULE=on GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X github.com/DVKunion/SeaMoon/pkg/consts.Version=1.1.0" -o main cmd/aliyun_server.go
     20 + path: ./
     21 + - run: chmod +x main
     22 + path: ./
     23 + 
    13 24  services:
    14  - SeaMoon-HTTP-Proxy:
    15  - component: fc
    16  - actions:
    17  - pre-deploy:
    18  - - run: go mod tidy
    19  - path: ./
    20  - - run: GO111MODULE=on GOOS=linux CGO_ENABLED=0 go build -ldflags "-X github.com/DVKunion/SeaMoon/pkg/consts.Version=1.1.0" -o main cmd/aliyun_server.go
    21  - path: ./
    22  - - run: chmod +x main
    23  - path: ./
     25 + SeaMoon-FC-HTTP-Proxy:
     26 + component: devscomp/fc
    24 27   props:
    25 28   region: ${vars.region}
    26 29   service: ${vars.service}
    skipped 10 lines
    37 40   instanceType: e1
    38 41   memorySize: 512
    39 42   runtime: custom
    40  - timeout: 120
     43 + timeout: 600
    41 44   internetAccess: true
    42 45   triggers:
    43 46   - name: httpTrigger
    skipped 17 lines
    61 64   - PUT
    62 65   - DELETE
    63 66   - OPTIONS
    64  - SeaMoon-Socks-Proxy:
    65  - component: fc
    66  - actions:
    67  - pre-deploy:
    68  - - run: go mod tidy
    69  - path: ./
    70  - - run: GO111MODULE=on GOOS=linux CGO_ENABLED=0 go build -ldflags "-X github.com/DVKunion/SeaMoon/pkg/consts.Version=1.1.0" -o main cmd/aliyun_server.go
    71  - path: ./
    72  - - run: chmod +x main
    73  - path: ./
     67 + SeaMoon-FC-Socks-Proxy:
     68 + component: devscomp/fc
    74 69   props:
    75 70   region: ${vars.region}
    76 71   service: ${vars.service}
    skipped 10 lines
    87 82   instanceType: e1
    88 83   memorySize: 512
    89 84   runtime: custom
    90  - timeout: 120
     85 + timeout: 600
    91 86   internetAccess: true
    92 87   triggers:
    93 88   - name: httpTrigger
    skipped 18 lines
Please wait...
Page is in error, reload to recover