1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 18:00:43 +00:00

smart error propagation

This commit is contained in:
Darien Raymond 2017-02-21 23:14:07 +01:00
parent 0f71305ee1
commit e480091388
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
7 changed files with 96 additions and 17 deletions

View File

@ -11,6 +11,7 @@ import (
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/log"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
@ -53,7 +54,12 @@ func (w *tcpWorker) callback(conn internet.Connection) {
ctx = proxy.ContextWithInboundEntryPoint(ctx, v2net.TCPDestination(w.address, w.port))
ctx = proxy.ContextWithSource(ctx, v2net.DestinationFromAddr(conn.RemoteAddr()))
if err := w.proxy.Process(ctx, v2net.Network_TCP, conn, w.dispatcher); err != nil {
log.Info("Proxyman|TCPWorker: Connection ends with ", err)
err := errors.Base(err).Message("Proxyman|TCPWorker: Connection ends.")
if errors.IsActionRequired(err) {
log.Warning(err)
} else {
log.Info(err)
}
}
cancel()
conn.Close()
@ -213,7 +219,12 @@ func (w *udpWorker) callback(b *buf.Buffer, source v2net.Destination, originalDe
ctx = proxy.ContextWithSource(ctx, source)
ctx = proxy.ContextWithInboundEntryPoint(ctx, v2net.UDPDestination(w.address, w.port))
if err := w.proxy.Process(ctx, v2net.Network_UDP, conn, w.dispatcher); err != nil {
log.Info("Proxyman|UDPWorker: Connection ends with ", err)
err = errors.Base(err).Message("Proxyman|UDPWorker: Connection ends.")
if errors.IsActionRequired(err) {
log.Warning(err)
} else {
log.Info(err)
}
}
w.removeConn(source)
cancel()

View File

@ -67,7 +67,12 @@ func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
err := h.proxy.Process(ctx, outboundRay, h)
// Ensure outbound ray is properly closed.
if err != nil && errors.Cause(err) != io.EOF {
log.Info("Proxyman|OutboundHandler: Failed to process outbound traffic: ", err)
err = errors.Base(err).Message("Proxyman|OutboundHandler: Failed to process outbound traffic.")
if errors.IsActionRequired(err) {
log.Warning(err)
} else {
log.Info(err)
}
outboundRay.OutboundOutput().CloseError()
} else {
outboundRay.OutboundOutput().Close()

View File

@ -12,10 +12,15 @@ type hasInnerError interface {
Inner() error
}
type actionRequired interface {
ActionRequired() bool
}
// Error is an error object with underlying error.
type Error struct {
message string
inner error
message string
inner error
actionRequired bool
}
// Error implements error.Error().
@ -31,6 +36,10 @@ func (v *Error) Inner() error {
return v.inner
}
func (v *Error) ActionRequired() bool {
return v.actionRequired
}
// New returns a new error object with message formed from given arguments.
func New(msg ...interface{}) error {
return &Error{
@ -56,10 +65,7 @@ func Cause(err error) error {
}
for {
inner, ok := err.(hasInnerError)
if !ok {
break
}
if inner.Inner() == nil {
if !ok || inner.Inner() == nil {
break
}
err = inner.Inner()
@ -67,8 +73,28 @@ func Cause(err error) error {
return err
}
func IsActionRequired(err error) bool {
for err != nil {
if ar, ok := err.(actionRequired); ok && ar.ActionRequired() {
return true
}
inner, ok := err.(hasInnerError)
if !ok || inner.Inner() == nil {
break
}
err = inner.Inner()
}
return false
}
type ErrorBuilder struct {
error
actionRequired bool
}
func (v ErrorBuilder) RequireUserAction() ErrorBuilder {
v.actionRequired = true
return v
}
// Message returns an error object with given message and base error.
@ -78,8 +104,9 @@ func (v ErrorBuilder) Message(msg ...interface{}) error {
}
return &Error{
message: serial.Concat(msg...) + " > " + v.error.Error(),
inner: v.error,
message: serial.Concat(msg...) + " > " + v.error.Error(),
inner: v.error,
actionRequired: v.actionRequired,
}
}
@ -89,7 +116,8 @@ func (v ErrorBuilder) Format(format string, values ...interface{}) error {
return nil
}
return &Error{
message: fmt.Sprintf(format, values...) + " > " + v.error.Error(),
inner: v.error,
message: fmt.Sprintf(format, values...) + " > " + v.error.Error(),
inner: v.error,
actionRequired: v.actionRequired,
}
}

View File

@ -0,0 +1,26 @@
package errors_test
import (
"io"
"testing"
. "v2ray.com/core/common/errors"
"v2ray.com/core/testing/assert"
)
func TestActionRequired(t *testing.T) {
assert := assert.On(t)
err := New("TestError")
assert.Bool(IsActionRequired(err)).IsFalse()
err = Base(io.EOF).Message("TestError2")
assert.Bool(IsActionRequired(err)).IsFalse()
err = Base(io.EOF).RequireUserAction().Message("TestError3")
assert.Bool(IsActionRequired(err)).IsTrue()
err = Base(io.EOF).RequireUserAction().Message("TestError4")
err = Base(err).Message("TestError5")
assert.Bool(IsActionRequired(err)).IsTrue()
}

View File

@ -60,7 +60,7 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
return nil
})
if err != nil {
return errors.Base(err).Message("Shadowsocks|Client: Failed to find an available destination.")
return errors.Base(err).RequireUserAction().Message("Shadowsocks|Client: Failed to find an available destination.")
}
log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination())

View File

@ -61,7 +61,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
return nil
})
if err != nil {
return errors.Base(err).Message("VMess|Outbound: Failed to find an available destination.")
return errors.Base(err).RequireUserAction().Message("VMess|Outbound: Failed to find an available destination.")
}
defer conn.Close()

View File

@ -3,6 +3,7 @@ package internet
import (
"net"
"v2ray.com/core/app/log"
"v2ray.com/core/common/errors"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/retry"
@ -85,13 +86,21 @@ func (v *TCPHub) start() {
default:
conn, err := v.listener.Accept()
if err != nil {
return errors.Base(err).Message("Internet|Listener: Failed to accept new TCP connection.")
return errors.Base(err).RequireUserAction().Message("Internet|Listener: Failed to accept new TCP connection.")
}
newConn = conn
return nil
}
})
if err == nil && newConn != nil {
if err != nil {
if errors.IsActionRequired(err) {
log.Warning(err)
} else {
log.Info(err)
}
continue
}
if newConn != nil {
go v.connCallback(newConn)
}
}