-
Notifications
You must be signed in to change notification settings - Fork 10
/
common.go
128 lines (114 loc) · 2.54 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package shadowsocks
import (
"context"
"encoding/base64"
"fmt"
"io"
"net"
"net/url"
"os"
"reflect"
"runtime"
"strings"
)
// isClosedConnError reports whether err is an error from use of a closed
// network connection.
func isClosedConnError(err error) bool {
if err == nil {
return false
}
str := err.Error()
if strings.Contains(str, "use of closed network connection") {
return true
}
if runtime.GOOS == "windows" {
if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
const WSAECONNABORTED = 10053
const WSAECONNRESET = 10054
if n := errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
return true
}
}
}
}
return false
}
func errno(v error) uintptr {
if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
return uintptr(rv.Uint())
}
return 0
}
// tunnel create tunnels for two io.ReadWriteCloser
func tunnel(ctx context.Context, c1, c2 io.ReadWriteCloser, buf1, buf2 []byte) error {
ctx, cancel := context.WithCancel(ctx)
var errs tunnelErr
go func() {
_, errs[0] = io.CopyBuffer(c1, c2, buf1)
cancel()
}()
go func() {
_, errs[1] = io.CopyBuffer(c2, c1, buf2)
cancel()
}()
<-ctx.Done()
errs[2] = c1.Close()
errs[3] = c2.Close()
errs[4] = ctx.Err()
if errs[4] == context.Canceled {
errs[4] = nil
}
return errs.FirstError()
}
type tunnelErr [5]error
func (t tunnelErr) FirstError() error {
for _, err := range t {
if err != nil {
return err
}
}
return nil
}
// BytesPool is an interface for getting and returning temporary
// bytes for use by io.CopyBuffer.
type BytesPool interface {
Get() []byte
Put([]byte)
}
func getBytes(p BytesPool) []byte {
if p != nil {
return p.Get()
}
return make([]byte, 32*1024)
}
func putBytes(p BytesPool, d []byte) {
if p != nil {
p.Put(d)
}
}
func decodeCipherAndPasswordFromBase64(str string) (cipher, password string, err error) {
data, err := base64.StdEncoding.DecodeString(str)
if err != nil {
return "", "", fmt.Errorf("can't support %q", str)
}
cp := strings.SplitN(string(data), ":", 2)
if len(cp) != 2 {
return cp[0], "", nil
}
return cp[0], cp[1], nil
}
func GetCipherAndPasswordFromUserinfo(user *url.Userinfo) (cipher, password string, err error) {
cipher = user.Username()
password, ok := user.Password()
if !ok && !IsCipher(cipher) {
cipher, password, err = decodeCipherAndPasswordFromBase64(cipher)
if err != nil {
return "", "", err
}
}
return cipher, password, nil
}
type Logger interface {
Println(v ...interface{})
}