mirror of https://github.com/v2ray/v2ray-core
smart error propagation
parent
0f71305ee1
commit
e480091388
|
@ -11,6 +11,7 @@ import (
|
||||||
"v2ray.com/core/app/dispatcher"
|
"v2ray.com/core/app/dispatcher"
|
||||||
"v2ray.com/core/app/log"
|
"v2ray.com/core/app/log"
|
||||||
"v2ray.com/core/common/buf"
|
"v2ray.com/core/common/buf"
|
||||||
|
"v2ray.com/core/common/errors"
|
||||||
v2net "v2ray.com/core/common/net"
|
v2net "v2ray.com/core/common/net"
|
||||||
"v2ray.com/core/proxy"
|
"v2ray.com/core/proxy"
|
||||||
"v2ray.com/core/transport/internet"
|
"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.ContextWithInboundEntryPoint(ctx, v2net.TCPDestination(w.address, w.port))
|
||||||
ctx = proxy.ContextWithSource(ctx, v2net.DestinationFromAddr(conn.RemoteAddr()))
|
ctx = proxy.ContextWithSource(ctx, v2net.DestinationFromAddr(conn.RemoteAddr()))
|
||||||
if err := w.proxy.Process(ctx, v2net.Network_TCP, conn, w.dispatcher); err != nil {
|
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()
|
cancel()
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
@ -213,7 +219,12 @@ func (w *udpWorker) callback(b *buf.Buffer, source v2net.Destination, originalDe
|
||||||
ctx = proxy.ContextWithSource(ctx, source)
|
ctx = proxy.ContextWithSource(ctx, source)
|
||||||
ctx = proxy.ContextWithInboundEntryPoint(ctx, v2net.UDPDestination(w.address, w.port))
|
ctx = proxy.ContextWithInboundEntryPoint(ctx, v2net.UDPDestination(w.address, w.port))
|
||||||
if err := w.proxy.Process(ctx, v2net.Network_UDP, conn, w.dispatcher); err != nil {
|
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)
|
w.removeConn(source)
|
||||||
cancel()
|
cancel()
|
||||||
|
|
|
@ -67,7 +67,12 @@ func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
|
||||||
err := h.proxy.Process(ctx, outboundRay, h)
|
err := h.proxy.Process(ctx, outboundRay, h)
|
||||||
// Ensure outbound ray is properly closed.
|
// Ensure outbound ray is properly closed.
|
||||||
if err != nil && errors.Cause(err) != io.EOF {
|
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()
|
outboundRay.OutboundOutput().CloseError()
|
||||||
} else {
|
} else {
|
||||||
outboundRay.OutboundOutput().Close()
|
outboundRay.OutboundOutput().Close()
|
||||||
|
|
|
@ -12,10 +12,15 @@ type hasInnerError interface {
|
||||||
Inner() error
|
Inner() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type actionRequired interface {
|
||||||
|
ActionRequired() bool
|
||||||
|
}
|
||||||
|
|
||||||
// Error is an error object with underlying error.
|
// Error is an error object with underlying error.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
message string
|
message string
|
||||||
inner error
|
inner error
|
||||||
|
actionRequired bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implements error.Error().
|
// Error implements error.Error().
|
||||||
|
@ -31,6 +36,10 @@ func (v *Error) Inner() error {
|
||||||
return v.inner
|
return v.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Error) ActionRequired() bool {
|
||||||
|
return v.actionRequired
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a new error object with message formed from given arguments.
|
// New returns a new error object with message formed from given arguments.
|
||||||
func New(msg ...interface{}) error {
|
func New(msg ...interface{}) error {
|
||||||
return &Error{
|
return &Error{
|
||||||
|
@ -56,10 +65,7 @@ func Cause(err error) error {
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
inner, ok := err.(hasInnerError)
|
inner, ok := err.(hasInnerError)
|
||||||
if !ok {
|
if !ok || inner.Inner() == nil {
|
||||||
break
|
|
||||||
}
|
|
||||||
if inner.Inner() == nil {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err = inner.Inner()
|
err = inner.Inner()
|
||||||
|
@ -67,8 +73,28 @@ func Cause(err error) error {
|
||||||
return err
|
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 {
|
type ErrorBuilder struct {
|
||||||
error
|
error
|
||||||
|
actionRequired bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v ErrorBuilder) RequireUserAction() ErrorBuilder {
|
||||||
|
v.actionRequired = true
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message returns an error object with given message and base error.
|
// Message returns an error object with given message and base error.
|
||||||
|
@ -80,6 +106,7 @@ func (v ErrorBuilder) Message(msg ...interface{}) error {
|
||||||
return &Error{
|
return &Error{
|
||||||
message: serial.Concat(msg...) + " > " + v.error.Error(),
|
message: serial.Concat(msg...) + " > " + v.error.Error(),
|
||||||
inner: v.error,
|
inner: v.error,
|
||||||
|
actionRequired: v.actionRequired,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,5 +118,6 @@ func (v ErrorBuilder) Format(format string, values ...interface{}) error {
|
||||||
return &Error{
|
return &Error{
|
||||||
message: fmt.Sprintf(format, values...) + " > " + v.error.Error(),
|
message: fmt.Sprintf(format, values...) + " > " + v.error.Error(),
|
||||||
inner: v.error,
|
inner: v.error,
|
||||||
|
actionRequired: v.actionRequired,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != 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())
|
log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination())
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != 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()
|
defer conn.Close()
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package internet
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"v2ray.com/core/app/log"
|
||||||
"v2ray.com/core/common/errors"
|
"v2ray.com/core/common/errors"
|
||||||
v2net "v2ray.com/core/common/net"
|
v2net "v2ray.com/core/common/net"
|
||||||
"v2ray.com/core/common/retry"
|
"v2ray.com/core/common/retry"
|
||||||
|
@ -85,13 +86,21 @@ func (v *TCPHub) start() {
|
||||||
default:
|
default:
|
||||||
conn, err := v.listener.Accept()
|
conn, err := v.listener.Accept()
|
||||||
if err != nil {
|
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
|
newConn = conn
|
||||||
return nil
|
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)
|
go v.connCallback(newConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue