You've already forked v2ray-core
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a2547b285 | ||
|
|
f57260c358 | ||
|
|
94c6acea43 | ||
|
|
2cf809021b |
@@ -121,6 +121,7 @@ func (m *Client) monitor() {
|
||||
for {
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
m.sessionManager.Close()
|
||||
m.inboundRay.InboundInput().Close()
|
||||
m.inboundRay.InboundOutput().CloseError()
|
||||
return
|
||||
@@ -206,11 +207,46 @@ func pipe(reader *Reader, writer buf.Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) handleStatueKeepAlive(meta *FrameMetadata, reader *Reader) error {
|
||||
if meta.Option.Has(OptionData) {
|
||||
return drain(reader)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) handleStatusNew(meta *FrameMetadata, reader *Reader) error {
|
||||
if meta.Option.Has(OptionData) {
|
||||
return drain(reader)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) handleStatusKeep(meta *FrameMetadata, reader *Reader) error {
|
||||
if !meta.Option.Has(OptionData) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s, found := m.sessionManager.Get(meta.SessionID); found {
|
||||
return pipe(reader, s.output)
|
||||
}
|
||||
return drain(reader)
|
||||
}
|
||||
|
||||
func (m *Client) handleStatusEnd(meta *FrameMetadata, reader *Reader) error {
|
||||
if s, found := m.sessionManager.Get(meta.SessionID); found {
|
||||
s.CloseDownlink()
|
||||
s.output.Close()
|
||||
}
|
||||
if meta.Option.Has(OptionData) {
|
||||
return drain(reader)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) fetchOutput() {
|
||||
defer m.cancel()
|
||||
|
||||
reader := NewReader(m.inboundRay.InboundOutput())
|
||||
L:
|
||||
for {
|
||||
meta, err := reader.ReadMetadata()
|
||||
if err != nil {
|
||||
@@ -218,35 +254,23 @@ L:
|
||||
break
|
||||
}
|
||||
|
||||
var drainData bool
|
||||
switch meta.SessionStatus {
|
||||
case SessionStatusKeepAlive:
|
||||
drainData = true
|
||||
err = m.handleStatueKeepAlive(meta, reader)
|
||||
case SessionStatusEnd:
|
||||
if s, found := m.sessionManager.Get(meta.SessionID); found {
|
||||
s.CloseDownlink()
|
||||
s.output.Close()
|
||||
}
|
||||
drainData = true
|
||||
err = m.handleStatusEnd(meta, reader)
|
||||
case SessionStatusNew:
|
||||
drainData = true
|
||||
err = m.handleStatusNew(meta, reader)
|
||||
case SessionStatusKeep:
|
||||
if !meta.Option.Has(OptionData) {
|
||||
break
|
||||
}
|
||||
if s, found := m.sessionManager.Get(meta.SessionID); found {
|
||||
if err := pipe(reader, s.output); err != nil {
|
||||
log.Trace(newError("failed to pipe data").Base(err))
|
||||
break L
|
||||
}
|
||||
}
|
||||
err = m.handleStatusKeep(meta, reader)
|
||||
default:
|
||||
log.Trace(newError("unknown status: ", meta.SessionStatus).AtWarning())
|
||||
return
|
||||
}
|
||||
|
||||
if drainData && meta.Option.Has(OptionData) {
|
||||
if err := drain(reader); err != nil {
|
||||
log.Trace(newError("failed to drain data").Base(err))
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Trace(newError("failed to process data").Base(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,10 +323,63 @@ func handle(ctx context.Context, s *Session, output buf.Writer) {
|
||||
s.CloseDownlink()
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *Reader) error {
|
||||
if meta.Option.Has(OptionData) {
|
||||
return drain(reader)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *Reader) error {
|
||||
log.Trace(newError("received request for ", meta.Target))
|
||||
inboundRay, err := w.dispatcher.Dispatch(ctx, meta.Target)
|
||||
if err != nil {
|
||||
if meta.Option.Has(OptionData) {
|
||||
drain(reader)
|
||||
}
|
||||
return newError("failed to dispatch request.").Base(err)
|
||||
}
|
||||
s := &Session{
|
||||
input: inboundRay.InboundOutput(),
|
||||
output: inboundRay.InboundInput(),
|
||||
parent: w.sessionManager,
|
||||
ID: meta.SessionID,
|
||||
}
|
||||
w.sessionManager.Add(s)
|
||||
go handle(ctx, s, w.outboundRay.OutboundOutput())
|
||||
if meta.Option.Has(OptionData) {
|
||||
return pipe(reader, s.output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *Reader) error {
|
||||
if !meta.Option.Has(OptionData) {
|
||||
return nil
|
||||
}
|
||||
if s, found := w.sessionManager.Get(meta.SessionID); found {
|
||||
return pipe(reader, s.output)
|
||||
}
|
||||
return drain(reader)
|
||||
}
|
||||
|
||||
func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *Reader) error {
|
||||
if s, found := w.sessionManager.Get(meta.SessionID); found {
|
||||
s.CloseUplink()
|
||||
s.output.Close()
|
||||
}
|
||||
if meta.Option.Has(OptionData) {
|
||||
return drain(reader)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *ServerWorker) run(ctx context.Context) {
|
||||
input := w.outboundRay.OutboundInput()
|
||||
reader := NewReader(input)
|
||||
L:
|
||||
|
||||
defer w.sessionManager.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -316,56 +393,23 @@ L:
|
||||
return
|
||||
}
|
||||
|
||||
var drainData bool
|
||||
switch meta.SessionStatus {
|
||||
case SessionStatusKeepAlive:
|
||||
drainData = true
|
||||
err = w.handleStatusKeepAlive(meta, reader)
|
||||
case SessionStatusEnd:
|
||||
if s, found := w.sessionManager.Get(meta.SessionID); found {
|
||||
s.CloseUplink()
|
||||
s.output.Close()
|
||||
}
|
||||
drainData = true
|
||||
err = w.handleStatusEnd(meta, reader)
|
||||
case SessionStatusNew:
|
||||
log.Trace(newError("received request for ", meta.Target))
|
||||
inboundRay, err := w.dispatcher.Dispatch(ctx, meta.Target)
|
||||
if err != nil {
|
||||
log.Trace(newError("failed to dispatch request.").Base(err))
|
||||
drainData = true
|
||||
break
|
||||
}
|
||||
s := &Session{
|
||||
input: inboundRay.InboundOutput(),
|
||||
output: inboundRay.InboundInput(),
|
||||
parent: w.sessionManager,
|
||||
ID: meta.SessionID,
|
||||
}
|
||||
w.sessionManager.Add(s)
|
||||
go handle(ctx, s, w.outboundRay.OutboundOutput())
|
||||
if !meta.Option.Has(OptionData) {
|
||||
break
|
||||
}
|
||||
if err := pipe(reader, s.output); err != nil {
|
||||
log.Trace(newError("failed to read data").Base(err))
|
||||
break L
|
||||
}
|
||||
err = w.handleStatusNew(ctx, meta, reader)
|
||||
case SessionStatusKeep:
|
||||
if !meta.Option.Has(OptionData) {
|
||||
break
|
||||
}
|
||||
if s, found := w.sessionManager.Get(meta.SessionID); found {
|
||||
if err := pipe(reader, s.output); err != nil {
|
||||
log.Trace(newError("failed to read data").Base(err))
|
||||
break L
|
||||
}
|
||||
}
|
||||
err = w.handleStatusKeep(meta, reader)
|
||||
default:
|
||||
log.Trace(newError("unknown status: ", meta.SessionStatus).AtWarning())
|
||||
return
|
||||
}
|
||||
|
||||
if meta.Option.Has(OptionData) && drainData {
|
||||
if err := drain(reader); err != nil {
|
||||
log.Trace(newError("failed to drain data").Base(err))
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Trace(newError("failed to process data").Base(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,10 +74,26 @@ func (m *SessionManager) CloseIfNoSession() bool {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
if m.closed {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(m.sessions) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
m.closed = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *SessionManager) Close() {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
if m.closed {
|
||||
return
|
||||
}
|
||||
|
||||
m.closed = true
|
||||
|
||||
for _, s := range m.sessions {
|
||||
@@ -86,8 +102,6 @@ func (m *SessionManager) CloseIfNoSession() bool {
|
||||
}
|
||||
|
||||
m.sessions = make(map[uint16]*Session)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
FROM golang:latest
|
||||
|
||||
RUN go get -u v2ray.com/core/... \
|
||||
&& rm -f $GOPATH/bin/build \
|
||||
&& go install v2ray.com/core/tools/build \
|
||||
&& build \
|
||||
&& mv bin/v2ray-custom-linux-64/v2ray bin \
|
||||
&& rm -rf pkg src
|
||||
|
||||
EXPOSE 27183
|
||||
COPY gen-server-cfg.sh /go/gen-server-cfg.sh
|
||||
COPY docker-entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["v2ray", "--config=/go/server-cfg.json"]
|
||||
@@ -1,36 +0,0 @@
|
||||
Docker build for v2ray
|
||||
=======================
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To build the image:
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
|
||||
Then spin up a v2ray instance with:
|
||||
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
|
||||
The docker image will generate a server config file with random user id on first run.
|
||||
You can get see it with:
|
||||
|
||||
```bash
|
||||
docker logs v2ray
|
||||
```
|
||||
|
||||
You can also specify config file by manual with:
|
||||
|
||||
```bash
|
||||
docker run -d --name=v2ray -p 27183:27183 -v /config/file.json:/go/server-config.json $USER/v2ray
|
||||
```
|
||||
|
||||
To tail the access log, run:
|
||||
|
||||
```bash
|
||||
docker exec v2ray tail -F /go/access.log
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build --rm=true --tag=$USER/v2ray ./
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$1" = 'v2ray' ]; then
|
||||
if [ ! -e "server-cfg.json" ]; then
|
||||
./gen-server-cfg.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
PORT=27183
|
||||
|
||||
rand_str () {
|
||||
cat /dev/urandom | tr -dc 'a-f0-9' | fold -w $1 | head -n 1
|
||||
}
|
||||
|
||||
ID="$(rand_str 8)-$(rand_str 4)-$(rand_str 4)-$(rand_str 4)-$(rand_str 12)"
|
||||
echo "Generated client ID: $ID"
|
||||
|
||||
cat <<EOF > server-cfg.json
|
||||
{
|
||||
"log" : {
|
||||
"access": "/go/access.log"
|
||||
},
|
||||
"inbound": {
|
||||
"port": $PORT,
|
||||
"protocol": "vmess",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{"id": "$ID"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"outbound": {
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker run -d --name=v2ray -p 27183:27183/tcp $USER/v2ray
|
||||
@@ -95,13 +95,13 @@ func NewHeaderWriter(header *buf.Buffer) *HeaderWriter {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *HeaderWriter) Write(writer io.Writer) error {
|
||||
if v.header == nil {
|
||||
func (w *HeaderWriter) Write(writer io.Writer) error {
|
||||
if w.header == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := writer.Write(v.header.Bytes())
|
||||
v.header.Release()
|
||||
v.header = nil
|
||||
_, err := writer.Write(w.header.Bytes())
|
||||
w.header.Release()
|
||||
w.header = nil
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -123,49 +123,49 @@ func NewHttpConn(conn net.Conn, reader Reader, writer Writer, errorWriter Writer
|
||||
}
|
||||
}
|
||||
|
||||
func (v *HttpConn) Read(b []byte) (int, error) {
|
||||
if v.oneTimeReader != nil {
|
||||
buffer, err := v.oneTimeReader.Read(v.Conn)
|
||||
func (c *HttpConn) Read(b []byte) (int, error) {
|
||||
if c.oneTimeReader != nil {
|
||||
buffer, err := c.oneTimeReader.Read(c.Conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
v.readBuffer = buffer
|
||||
v.oneTimeReader = nil
|
||||
c.readBuffer = buffer
|
||||
c.oneTimeReader = nil
|
||||
}
|
||||
|
||||
if v.readBuffer.Len() > 0 {
|
||||
nBytes, err := v.readBuffer.Read(b)
|
||||
if nBytes == v.readBuffer.Len() {
|
||||
v.readBuffer.Release()
|
||||
v.readBuffer = nil
|
||||
if c.readBuffer.Len() > 0 {
|
||||
nBytes, err := c.readBuffer.Read(b)
|
||||
if nBytes == c.readBuffer.Len() {
|
||||
c.readBuffer.Release()
|
||||
c.readBuffer = nil
|
||||
}
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
return v.Conn.Read(b)
|
||||
return c.Conn.Read(b)
|
||||
}
|
||||
|
||||
func (v *HttpConn) Write(b []byte) (int, error) {
|
||||
if v.oneTimeWriter != nil {
|
||||
err := v.oneTimeWriter.Write(v.Conn)
|
||||
v.oneTimeWriter = nil
|
||||
func (c *HttpConn) Write(b []byte) (int, error) {
|
||||
if c.oneTimeWriter != nil {
|
||||
err := c.oneTimeWriter.Write(c.Conn)
|
||||
c.oneTimeWriter = nil
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return v.Conn.Write(b)
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
|
||||
// Close implements net.Conn.Close().
|
||||
func (v *HttpConn) Close() error {
|
||||
if v.oneTimeWriter != nil && v.errorWriter != nil {
|
||||
func (c *HttpConn) Close() error {
|
||||
if c.oneTimeWriter != nil && c.errorWriter != nil {
|
||||
// Connection is being closed but header wasn't sent. This means the client request
|
||||
// is probably not valid. Sending back a server error header in this case.
|
||||
v.errorWriter.Write(v.Conn)
|
||||
c.errorWriter.Write(c.Conn)
|
||||
}
|
||||
|
||||
return v.Conn.Close()
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func formResponseHeader(config *ResponseConfig) *HeaderWriter {
|
||||
@@ -193,9 +193,9 @@ type HttpAuthenticator struct {
|
||||
config *Config
|
||||
}
|
||||
|
||||
func (v HttpAuthenticator) GetClientWriter() *HeaderWriter {
|
||||
func (a HttpAuthenticator) GetClientWriter() *HeaderWriter {
|
||||
header := buf.NewSmall()
|
||||
config := v.config.Request
|
||||
config := a.config.Request
|
||||
header.AppendSupplier(serial.WriteString(strings.Join([]string{config.GetMethodValue(), config.PickUri(), config.GetFullVersion()}, " ")))
|
||||
header.AppendSupplier(writeCRLF)
|
||||
|
||||
@@ -210,31 +210,31 @@ func (v HttpAuthenticator) GetClientWriter() *HeaderWriter {
|
||||
}
|
||||
}
|
||||
|
||||
func (v HttpAuthenticator) GetServerWriter() *HeaderWriter {
|
||||
return formResponseHeader(v.config.Response)
|
||||
func (a HttpAuthenticator) GetServerWriter() *HeaderWriter {
|
||||
return formResponseHeader(a.config.Response)
|
||||
}
|
||||
|
||||
func (v HttpAuthenticator) Client(conn net.Conn) net.Conn {
|
||||
if v.config.Request == nil && v.config.Response == nil {
|
||||
func (a HttpAuthenticator) Client(conn net.Conn) net.Conn {
|
||||
if a.config.Request == nil && a.config.Response == nil {
|
||||
return conn
|
||||
}
|
||||
var reader Reader = new(NoOpReader)
|
||||
if v.config.Request != nil {
|
||||
if a.config.Request != nil {
|
||||
reader = new(HeaderReader)
|
||||
}
|
||||
|
||||
var writer Writer = new(NoOpWriter)
|
||||
if v.config.Response != nil {
|
||||
writer = v.GetClientWriter()
|
||||
if a.config.Response != nil {
|
||||
writer = a.GetClientWriter()
|
||||
}
|
||||
return NewHttpConn(conn, reader, writer, new(NoOpWriter))
|
||||
}
|
||||
|
||||
func (v HttpAuthenticator) Server(conn net.Conn) net.Conn {
|
||||
if v.config.Request == nil && v.config.Response == nil {
|
||||
func (a HttpAuthenticator) Server(conn net.Conn) net.Conn {
|
||||
if a.config.Request == nil && a.config.Response == nil {
|
||||
return conn
|
||||
}
|
||||
return NewHttpConn(conn, new(HeaderReader), v.GetServerWriter(), formResponseHeader(&ResponseConfig{
|
||||
return NewHttpConn(conn, new(HeaderReader), a.GetServerWriter(), formResponseHeader(&ResponseConfig{
|
||||
Version: &Version{
|
||||
Value: "1.1",
|
||||
},
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
|
||||
type NoOpHeader struct{}
|
||||
|
||||
func (v NoOpHeader) Size() int {
|
||||
func (NoOpHeader) Size() int {
|
||||
return 0
|
||||
}
|
||||
func (v NoOpHeader) Write([]byte) (int, error) {
|
||||
func (NoOpHeader) Write([]byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ type SRTP struct {
|
||||
number uint16
|
||||
}
|
||||
|
||||
func (v *SRTP) Size() int {
|
||||
func (*SRTP) Size() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (v *SRTP) Write(b []byte) (int, error) {
|
||||
v.number++
|
||||
serial.Uint16ToBytes(v.number, b[:0])
|
||||
serial.Uint16ToBytes(v.number, b[:2])
|
||||
func (s *SRTP) Write(b []byte) (int, error) {
|
||||
s.number++
|
||||
serial.Uint16ToBytes(s.number, b[:0])
|
||||
serial.Uint16ToBytes(s.number, b[:2])
|
||||
return 4, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,18 @@ type UTP struct {
|
||||
connectionId uint16
|
||||
}
|
||||
|
||||
func (v *UTP) Size() int {
|
||||
func (*UTP) Size() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (v *UTP) Write(b []byte) (int, error) {
|
||||
serial.Uint16ToBytes(v.connectionId, b[:0])
|
||||
b[2] = v.header
|
||||
b[3] = v.extension
|
||||
func (u *UTP) Write(b []byte) (int, error) {
|
||||
serial.Uint16ToBytes(u.connectionId, b[:0])
|
||||
b[2] = u.header
|
||||
b[3] = u.extension
|
||||
return 4, nil
|
||||
}
|
||||
|
||||
// NewUTP creates a new UTP header for the given config.
|
||||
func NewUTP(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
return &UTP{
|
||||
header: 1,
|
||||
|
||||
@@ -16,17 +16,17 @@ func NewSimpleAuthenticator() cipher.AEAD {
|
||||
}
|
||||
|
||||
// NonceSize implements cipher.AEAD.NonceSize().
|
||||
func (v *SimpleAuthenticator) NonceSize() int {
|
||||
func (*SimpleAuthenticator) NonceSize() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Overhead implements cipher.AEAD.NonceSize().
|
||||
func (v *SimpleAuthenticator) Overhead() int {
|
||||
func (*SimpleAuthenticator) Overhead() int {
|
||||
return 6
|
||||
}
|
||||
|
||||
// Seal implements cipher.AEAD.Seal().
|
||||
func (v *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {
|
||||
func (a *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {
|
||||
dst = append(dst, 0, 0, 0, 0)
|
||||
dst = serial.Uint16ToBytes(uint16(len(plain)), dst)
|
||||
dst = append(dst, plain...)
|
||||
@@ -48,7 +48,7 @@ func (v *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {
|
||||
}
|
||||
|
||||
// Open implements cipher.AEAD.Open().
|
||||
func (v *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {
|
||||
func (a *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {
|
||||
dst = append(dst, cipherText...)
|
||||
dstLen := len(dst)
|
||||
xtra := 4 - dstLen%4
|
||||
|
||||
@@ -29,75 +29,75 @@ type ClientConnection struct {
|
||||
writer PacketWriter
|
||||
}
|
||||
|
||||
func (o *ClientConnection) Overhead() int {
|
||||
o.RLock()
|
||||
defer o.RUnlock()
|
||||
if o.writer == nil {
|
||||
func (c *ClientConnection) Overhead() int {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
if c.writer == nil {
|
||||
return 0
|
||||
}
|
||||
return o.writer.Overhead()
|
||||
return c.writer.Overhead()
|
||||
}
|
||||
|
||||
func (o *ClientConnection) Write(b []byte) (int, error) {
|
||||
o.RLock()
|
||||
defer o.RUnlock()
|
||||
func (c *ClientConnection) Write(b []byte) (int, error) {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
if o.writer == nil {
|
||||
if c.writer == nil {
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
return o.writer.Write(b)
|
||||
return c.writer.Write(b)
|
||||
}
|
||||
|
||||
func (o *ClientConnection) Read([]byte) (int, error) {
|
||||
func (*ClientConnection) Read([]byte) (int, error) {
|
||||
panic("KCP|ClientConnection: Read should not be called.")
|
||||
}
|
||||
|
||||
func (o *ClientConnection) Close() error {
|
||||
return o.Conn.Close()
|
||||
func (c *ClientConnection) Close() error {
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func (o *ClientConnection) Reset(inputCallback func([]Segment)) {
|
||||
o.Lock()
|
||||
o.input = inputCallback
|
||||
o.Unlock()
|
||||
func (c *ClientConnection) Reset(inputCallback func([]Segment)) {
|
||||
c.Lock()
|
||||
c.input = inputCallback
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
func (o *ClientConnection) ResetSecurity(header internet.PacketHeader, security cipher.AEAD) {
|
||||
o.Lock()
|
||||
if o.reader == nil {
|
||||
o.reader = new(KCPPacketReader)
|
||||
func (c *ClientConnection) ResetSecurity(header internet.PacketHeader, security cipher.AEAD) {
|
||||
c.Lock()
|
||||
if c.reader == nil {
|
||||
c.reader = new(KCPPacketReader)
|
||||
}
|
||||
o.reader.(*KCPPacketReader).Header = header
|
||||
o.reader.(*KCPPacketReader).Security = security
|
||||
if o.writer == nil {
|
||||
o.writer = new(KCPPacketWriter)
|
||||
c.reader.(*KCPPacketReader).Header = header
|
||||
c.reader.(*KCPPacketReader).Security = security
|
||||
if c.writer == nil {
|
||||
c.writer = new(KCPPacketWriter)
|
||||
}
|
||||
o.writer.(*KCPPacketWriter).Header = header
|
||||
o.writer.(*KCPPacketWriter).Security = security
|
||||
o.writer.(*KCPPacketWriter).Writer = o.Conn
|
||||
c.writer.(*KCPPacketWriter).Header = header
|
||||
c.writer.(*KCPPacketWriter).Security = security
|
||||
c.writer.(*KCPPacketWriter).Writer = c.Conn
|
||||
|
||||
o.Unlock()
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
func (o *ClientConnection) Run() {
|
||||
func (c *ClientConnection) Run() {
|
||||
payload := buf.NewSmall()
|
||||
defer payload.Release()
|
||||
|
||||
for {
|
||||
err := payload.Reset(buf.ReadFrom(o.Conn))
|
||||
err := payload.Reset(buf.ReadFrom(c.Conn))
|
||||
if err != nil {
|
||||
payload.Release()
|
||||
return
|
||||
}
|
||||
o.RLock()
|
||||
if o.input != nil {
|
||||
segments := o.reader.Read(payload.Bytes())
|
||||
c.RLock()
|
||||
if c.input != nil {
|
||||
segments := c.reader.Read(payload.Bytes())
|
||||
if len(segments) > 0 {
|
||||
o.input(segments)
|
||||
c.input(segments)
|
||||
}
|
||||
}
|
||||
o.RUnlock()
|
||||
c.RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@ type KCPPacketReader struct {
|
||||
Header internet.PacketHeader
|
||||
}
|
||||
|
||||
func (v *KCPPacketReader) Read(b []byte) []Segment {
|
||||
if v.Header != nil {
|
||||
b = b[v.Header.Size():]
|
||||
func (r *KCPPacketReader) Read(b []byte) []Segment {
|
||||
if r.Header != nil {
|
||||
b = b[r.Header.Size():]
|
||||
}
|
||||
if v.Security != nil {
|
||||
nonceSize := v.Security.NonceSize()
|
||||
out, err := v.Security.Open(b[nonceSize:nonceSize], b[:nonceSize], b[nonceSize:], nil)
|
||||
if r.Security != nil {
|
||||
nonceSize := r.Security.NonceSize()
|
||||
out, err := r.Security.Open(b[nonceSize:nonceSize], b[:nonceSize], b[nonceSize:], nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -54,39 +54,39 @@ type KCPPacketWriter struct {
|
||||
buffer [32 * 1024]byte
|
||||
}
|
||||
|
||||
func (v *KCPPacketWriter) Overhead() int {
|
||||
func (w *KCPPacketWriter) Overhead() int {
|
||||
overhead := 0
|
||||
if v.Header != nil {
|
||||
overhead += v.Header.Size()
|
||||
if w.Header != nil {
|
||||
overhead += w.Header.Size()
|
||||
}
|
||||
if v.Security != nil {
|
||||
overhead += v.Security.Overhead()
|
||||
if w.Security != nil {
|
||||
overhead += w.Security.Overhead()
|
||||
}
|
||||
return overhead
|
||||
}
|
||||
|
||||
func (v *KCPPacketWriter) Write(b []byte) (int, error) {
|
||||
x := v.buffer[:]
|
||||
func (w *KCPPacketWriter) Write(b []byte) (int, error) {
|
||||
x := w.buffer[:]
|
||||
size := 0
|
||||
if v.Header != nil {
|
||||
nBytes, _ := v.Header.Write(x)
|
||||
if w.Header != nil {
|
||||
nBytes, _ := w.Header.Write(x)
|
||||
size += nBytes
|
||||
x = x[nBytes:]
|
||||
}
|
||||
if v.Security != nil {
|
||||
nonceSize := v.Security.NonceSize()
|
||||
if w.Security != nil {
|
||||
nonceSize := w.Security.NonceSize()
|
||||
var nonce []byte
|
||||
if nonceSize > 0 {
|
||||
nonce = x[:nonceSize]
|
||||
rand.Read(nonce)
|
||||
x = x[nonceSize:]
|
||||
}
|
||||
x = v.Security.Seal(x[:0], nonce, b, nil)
|
||||
x = w.Security.Seal(x[:0], nonce, b, nil)
|
||||
size += nonceSize + len(x)
|
||||
} else {
|
||||
size += copy(x, b)
|
||||
}
|
||||
|
||||
_, err := v.Writer.Write(v.buffer[:size])
|
||||
_, err := w.Writer.Write(w.buffer[:size])
|
||||
return len(b), err
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package ray_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"context"
|
||||
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/testing/assert"
|
||||
. "v2ray.com/core/transport/ray"
|
||||
|
||||
Reference in New Issue
Block a user