1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-22 10:08:15 -05:00
This commit is contained in:
Shelikhoo 2016-08-14 14:11:51 +08:00
parent a0fda39274
commit 49441a5050
No known key found for this signature in database
GPG Key ID: 7791BDB0709ABD21
5 changed files with 46 additions and 37 deletions

View File

@ -4,7 +4,6 @@ import (
"errors" "errors"
"io" "io"
"net" "net"
"reflect"
"time" "time"
) )
@ -96,15 +95,5 @@ func (this *Connection) SysFd() (int, error) {
} }
func getSysFd(conn net.Conn) (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 return 0, ErrInvalidConn
} }

View File

@ -3,6 +3,7 @@ package ws
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@ -44,7 +45,6 @@ func init() {
} }
func wsDial(src v2net.Address, dest v2net.Destination) (*wsconn, error) { func wsDial(src v2net.Address, dest v2net.Destination) (*wsconn, error) {
//internet.DialToDest(src, dest)
commonDial := func(network, addr string) (net.Conn, error) { commonDial := func(network, addr string) (net.Conn, error) {
return internet.DialToDest(src, dest) 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, if the port you are using is not well-known,
specify it to avoid this process. 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 80:
case 8080: 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 { uri := func(dst v2net.Destination, pto string, path string) string {
return fmt.Sprintf("%v://%v:%v/%v", pto, dst.NetAddr(), dst.Port(), path) return fmt.Sprintf("%v://%v:%v/%v", pto, dst.NetAddr(), dst.Port(), path)
}(dest, effpto, effectiveConfig.Path) }(dest, effpto, effectiveConfig.Path)
conn, _, err := dialer.Dial(uri, nil)
conn, resp, err := dialer.Dial(uri, nil)
if err != nil { if err != nil {
reason, reasonerr := ioutil.ReadAll(resp.Body)
log.Info(string(reason), reasonerr)
return nil, err return nil, err
} }
return func() internet.Connection { return func() internet.Connection {

View File

@ -62,7 +62,6 @@ func (wsl *WSListener) listenws(address v2net.Address, port v2net.Port) error {
con.Close() con.Close()
} }
} }
//con.retloc.Wait()
return return
}) })

View File

@ -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

View File

@ -18,7 +18,6 @@ type wsconn struct {
readBuffer *bufio.Reader readBuffer *bufio.Reader
connClosing bool connClosing bool
reusable bool reusable bool
retloc *sync.Cond
rlock *sync.Mutex rlock *sync.Mutex
wlock *sync.Mutex wlock *sync.Mutex
} }
@ -59,7 +58,6 @@ func (ws *wsconn) Read(b []byte) (n int, err error) {
if ws.readBuffer == nil { if ws.readBuffer == nil {
err = getNewBuffer() err = getNewBuffer()
if err != nil { if err != nil {
//ws.Close()
return 0, err return 0, err
} }
} }
@ -77,7 +75,6 @@ func (ws *wsconn) Read(b []byte) (n int, err error) {
} }
return n, nil return n, nil
} }
//ws.Close()
return n, err 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) { func (ws *wsconn) Write(b []byte) (n int, err error) {
ws.wlock.Lock() 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() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
fmt.Println("WS workaround: recover", r) fmt.Println("WS workaround: recover", r)
ws.wlock.Unlock() ws.wlock.Unlock()
} }
}() }()
//defer
//ws.checkifRWAfterClosing()
if ws.connClosing { if ws.connClosing {
return 0, io.EOF return 0, io.EOF
@ -111,12 +112,10 @@ func (ws *wsconn) Write(b []byte) (n int, err error) {
} }
n, err = wr.Write(b) n, err = wr.Write(b)
if err != nil { if err != nil {
//ws.Close()
return 0, err return 0, err
} }
err = wr.Close() err = wr.Close()
if err != nil { if err != nil {
//ws.Close()
return 0, err return 0, err
} }
return n, err return n, err
@ -129,7 +128,6 @@ func (ws *wsconn) Close() error {
ws.connClosing = true ws.connClosing = true
ws.wsc.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add((time.Second * 5))) ws.wsc.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add((time.Second * 5)))
err := ws.wsc.Close() err := ws.wsc.Close()
ws.retloc.Broadcast()
return err return err
} }
func (ws *wsconn) LocalAddr() net.Addr { func (ws *wsconn) LocalAddr() net.Addr {
@ -159,25 +157,12 @@ func (ws *wsconn) SetWriteDeadline(t time.Time) error {
return ws.wsc.SetWriteDeadline(t) 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() { func (ws *wsconn) setup() {
ws.connClosing = false ws.connClosing = false
ws.rlock = &sync.Mutex{} ws.rlock = &sync.Mutex{}
ws.wlock = &sync.Mutex{} ws.wlock = &sync.Mutex{}
initConnectedCond := func() {
rsl := &sync.Mutex{}
ws.retloc = sync.NewCond(rsl)
}
initConnectedCond()
ws.pingPong() ws.pingPong()
} }
@ -206,7 +191,6 @@ func (ws *wsconn) pingPong() {
select { select {
case <-pongRcv: case <-pongRcv:
//log.Debug("WS:Pong~" + ws.wsc.UnderlyingConn().RemoteAddr().String())
break break
case <-tick.C: case <-tick.C:
log.Debug("WS:Closing as ping is not responded~" + ws.wsc.UnderlyingConn().LocalAddr().String() + "-" + ws.wsc.UnderlyingConn().RemoteAddr().String()) log.Debug("WS:Closing as ping is not responded~" + ws.wsc.UnderlyingConn().LocalAddr().String() + "-" + ws.wsc.UnderlyingConn().RemoteAddr().String())