diff --git a/transport/internet/ws/connection.go b/transport/internet/ws/connection.go index 141fdb32d..2ba96df4f 100644 --- a/transport/internet/ws/connection.go +++ b/transport/internet/ws/connection.go @@ -4,7 +4,6 @@ import ( "errors" "io" "net" - "reflect" "time" ) @@ -96,15 +95,5 @@ func (this *Connection) SysFd() (int, error) { } func getSysFd(conn net.Conn) (int, error) { - cv := reflect.ValueOf(conn) - switch ce := cv.Elem(); ce.Kind() { - case reflect.Struct: - netfd := ce.FieldByName("conn").FieldByName("fd") - switch fe := netfd.Elem(); fe.Kind() { - case reflect.Struct: - fd := fe.FieldByName("sysfd") - return int(fd.Int()), nil - } - } return 0, ErrInvalidConn } diff --git a/transport/internet/ws/dialer.go b/transport/internet/ws/dialer.go index 480ec82e2..6b17dfeb8 100644 --- a/transport/internet/ws/dialer.go +++ b/transport/internet/ws/dialer.go @@ -3,6 +3,7 @@ package ws import ( "crypto/tls" "fmt" + "io/ioutil" "net" "github.com/gorilla/websocket" @@ -44,7 +45,6 @@ func init() { } func wsDial(src v2net.Address, dest v2net.Destination) (*wsconn, error) { - //internet.DialToDest(src, dest) commonDial := func(network, addr string) (net.Conn, error) { return internet.DialToDest(src, dest) } @@ -84,7 +84,7 @@ func wsDial(src v2net.Address, dest v2net.Destination) (*wsconn, error) { if the port you are using is not well-known, specify it to avoid this process. - We will re return "CRASH"turn "unknown" if we can't guess it, cause Dial to fail. + We will return "CRASH"turn "unknown" if we can't guess it, cause Dial to fail. */ case 80: case 8080: @@ -110,8 +110,11 @@ func wsDial(src v2net.Address, dest v2net.Destination) (*wsconn, error) { uri := func(dst v2net.Destination, pto string, path string) string { return fmt.Sprintf("%v://%v:%v/%v", pto, dst.NetAddr(), dst.Port(), path) }(dest, effpto, effectiveConfig.Path) - conn, _, err := dialer.Dial(uri, nil) + + conn, resp, err := dialer.Dial(uri, nil) if err != nil { + reason, reasonerr := ioutil.ReadAll(resp.Body) + log.Info(string(reason), reasonerr) return nil, err } return func() internet.Connection { diff --git a/transport/internet/ws/hub.go b/transport/internet/ws/hub.go index 412fb8950..16fd3df77 100644 --- a/transport/internet/ws/hub.go +++ b/transport/internet/ws/hub.go @@ -62,7 +62,6 @@ func (wsl *WSListener) listenws(address v2net.Address, port v2net.Port) error { con.Close() } } - //con.retloc.Wait() return }) diff --git a/transport/internet/ws/ws.go b/transport/internet/ws/ws.go new file mode 100644 index 000000000..156e7f3c6 --- /dev/null +++ b/transport/internet/ws/ws.go @@ -0,0 +1,34 @@ +/*Package ws implements Websocket transport + +Websocket transport implements a HTTP(S) compliable, surveillance proof transport method with plausible deniability. + +To configure such a listener, set streamSettings to be ws. A http(s) listener will be listening at the port you have configured. + +There is additional configure can be made at transport configure. + +"wsSettings":{ + "Path":"ws", // the path our ws handler bind + "Pto": "wss/ws", // the transport protocol we are using ws or wss(listen ws with tls) + "Cert":"cert.pem", // if you have configured to use wss, configure your cert here + "PrivKey":"priv.pem" //if you have configured to use wss, configure your privatekey here + } + + +To configure such a Dialer, set streamSettings to be ws. + +There is additional configure can be made at transport configure. + +"wsSettings":{ + "Path":"ws", // the path our ws handler bind + "Pto": "wss/ws", // the transport protocol we are using ws or wss(listen ws with tls) + } + +It is worth noting that accepting a non-valid cert is not supported as a self-signed or invalid cert can be a sign of a website that is not correctly configured and lead to additional investigation. + + +This transport was disscussed at +https://github.com/v2ray/v2ray-core/issues/224 +https://trello.com/c/3uCCeBkC/8-add-websocket-transport + +*/ +package ws diff --git a/transport/internet/ws/wsconn.go b/transport/internet/ws/wsconn.go index 9f86d8156..fa64ec88b 100644 --- a/transport/internet/ws/wsconn.go +++ b/transport/internet/ws/wsconn.go @@ -18,7 +18,6 @@ type wsconn struct { readBuffer *bufio.Reader connClosing bool reusable bool - retloc *sync.Cond rlock *sync.Mutex wlock *sync.Mutex } @@ -59,7 +58,6 @@ func (ws *wsconn) Read(b []byte) (n int, err error) { if ws.readBuffer == nil { err = getNewBuffer() if err != nil { - //ws.Close() return 0, err } } @@ -77,7 +75,6 @@ func (ws *wsconn) Read(b []byte) (n int, err error) { } return n, nil } - //ws.Close() return n, err } @@ -89,14 +86,18 @@ func (ws *wsconn) Read(b []byte) (n int, err error) { func (ws *wsconn) Write(b []byte) (n int, err error) { ws.wlock.Lock() + /* + process can crash as websocket report "concurrent write to websocket connection" + even if lock is persent. + + It is yet to know how to prevent this but a workaround is the only choice. + */ defer func() { if r := recover(); r != nil { fmt.Println("WS workaround: recover", r) ws.wlock.Unlock() } }() - //defer - //ws.checkifRWAfterClosing() if ws.connClosing { return 0, io.EOF @@ -111,12 +112,10 @@ func (ws *wsconn) Write(b []byte) (n int, err error) { } n, err = wr.Write(b) if err != nil { - //ws.Close() return 0, err } err = wr.Close() if err != nil { - //ws.Close() return 0, err } return n, err @@ -129,7 +128,6 @@ func (ws *wsconn) Close() error { ws.connClosing = true ws.wsc.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add((time.Second * 5))) err := ws.wsc.Close() - ws.retloc.Broadcast() return err } func (ws *wsconn) LocalAddr() net.Addr { @@ -159,25 +157,12 @@ func (ws *wsconn) SetWriteDeadline(t time.Time) error { return ws.wsc.SetWriteDeadline(t) } -func (ws *wsconn) checkifRWAfterClosing() { - if ws.connClosing { - log.Error("WS transport: Read or Write After Conn have been marked closing, this can be dangerous.") - //panic("WS transport: Read or Write After Conn have been marked closing. Please report this crash to developer.") - } -} - func (ws *wsconn) setup() { ws.connClosing = false ws.rlock = &sync.Mutex{} ws.wlock = &sync.Mutex{} - initConnectedCond := func() { - rsl := &sync.Mutex{} - ws.retloc = sync.NewCond(rsl) - } - - initConnectedCond() ws.pingPong() } @@ -206,7 +191,6 @@ func (ws *wsconn) pingPong() { select { case <-pongRcv: - //log.Debug("WS:Pong~" + ws.wsc.UnderlyingConn().RemoteAddr().String()) break case <-tick.C: log.Debug("WS:Closing as ping is not responded~" + ws.wsc.UnderlyingConn().LocalAddr().String() + "-" + ws.wsc.UnderlyingConn().RemoteAddr().String())