frp/utils/net/websocket.go

106 lines
1.9 KiB
Go
Raw Normal View History

2018-08-03 19:41:54 +08:00
package net
import (
2018-08-10 11:43:08 +08:00
"errors"
2018-08-03 19:41:54 +08:00
"fmt"
"net"
"net/http"
"net/url"
"time"
"github.com/fatedier/frp/utils/log"
2018-08-10 11:43:08 +08:00
2018-08-03 19:41:54 +08:00
"golang.org/x/net/websocket"
)
2018-08-10 11:43:08 +08:00
var (
ErrWebsocketListenerClosed = errors.New("websocket listener closed")
)
const (
2018-08-10 14:44:14 +08:00
FrpWebsocketPath = "/~!frp"
2018-08-10 11:43:08 +08:00
)
2018-08-03 19:41:54 +08:00
type WebsocketListener struct {
2018-08-10 11:43:08 +08:00
net.Addr
ln net.Listener
accept chan Conn
2018-08-03 19:41:54 +08:00
log.Logger
2018-08-10 11:43:08 +08:00
2018-08-03 19:41:54 +08:00
server *http.Server
httpMutex *http.ServeMux
}
2018-08-10 11:43:08 +08:00
// ln: tcp listener for websocket connections
func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
wl = &WebsocketListener{
Addr: ln.Addr(),
accept: make(chan Conn),
Logger: log.NewPrefixLogger(""),
2018-08-03 19:41:54 +08:00
}
2018-08-10 11:43:08 +08:00
muxer := http.NewServeMux()
muxer.Handle(FrpWebsocketPath, websocket.Handler(func(c *websocket.Conn) {
notifyCh := make(chan struct{})
conn := WrapCloseNotifyConn(c, func() {
close(notifyCh)
})
wl.accept <- conn
<-notifyCh
2018-08-03 19:41:54 +08:00
}))
2018-08-10 11:43:08 +08:00
wl.server = &http.Server{
Addr: ln.Addr().String(),
Handler: muxer,
2018-08-03 19:41:54 +08:00
}
2018-08-10 11:43:08 +08:00
go wl.server.Serve(ln)
2018-08-03 19:41:54 +08:00
return
}
2018-08-10 11:43:08 +08:00
func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error) {
tcpLn, err := net.Listen("tcp", fmt.Sprintf("%s:%d", bindAddr, bindPort))
2018-08-03 19:41:54 +08:00
if err != nil {
2018-08-10 11:43:08 +08:00
return nil, err
2018-08-03 19:41:54 +08:00
}
2018-08-10 11:43:08 +08:00
l := NewWebsocketListener(tcpLn)
return l, nil
2018-08-03 19:41:54 +08:00
}
func (p *WebsocketListener) Accept() (Conn, error) {
2018-08-10 11:43:08 +08:00
c, ok := <-p.accept
if !ok {
return nil, ErrWebsocketListenerClosed
}
2018-08-03 19:41:54 +08:00
return c, nil
}
func (p *WebsocketListener) Close() error {
2018-08-10 11:43:08 +08:00
return p.server.Close()
2018-08-03 19:41:54 +08:00
}
2018-08-10 11:43:08 +08:00
// addr: domain:port
func ConnectWebsocketServer(addr string) (Conn, error) {
addr = "ws://" + addr + FrpWebsocketPath
2018-08-03 19:41:54 +08:00
uri, err := url.Parse(addr)
if err != nil {
2018-08-10 11:43:08 +08:00
return nil, err
2018-08-03 19:41:54 +08:00
}
origin := "http://" + uri.Host
cfg, err := websocket.NewConfig(addr, origin)
if err != nil {
2018-08-10 11:43:08 +08:00
return nil, err
2018-08-03 19:41:54 +08:00
}
cfg.Dialer = &net.Dialer{
2018-08-10 11:43:08 +08:00
Timeout: 10 * time.Second,
2018-08-03 19:41:54 +08:00
}
conn, err := websocket.DialConfig(cfg)
if err != nil {
2018-08-10 11:43:08 +08:00
return nil, err
2018-08-03 19:41:54 +08:00
}
2018-08-10 11:43:08 +08:00
c := WrapConn(conn)
return c, nil
2018-08-03 19:41:54 +08:00
}