Compare commits

..

4 Commits

Author SHA1 Message Date
Darien Raymond
0a2547b285 cleanup handler functions 2017-04-14 10:03:10 +02:00
Darien Raymond
f57260c358 refactor 2017-04-13 22:17:58 +02:00
Darien Raymond
94c6acea43 remove docker def 2017-04-13 22:02:52 +02:00
Darien Raymond
2cf809021b force close session manage when main connection is finished 2017-04-13 20:56:32 +02:00
16 changed files with 237 additions and 277 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +0,0 @@
#!/bin/bash
docker build --rm=true --tag=$USER/v2ray ./

View File

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

View File

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

View File

@@ -1,3 +0,0 @@
#!/bin/bash
docker run -d --name=v2ray -p 27183:27183/tcp $USER/v2ray

View File

@@ -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",
},

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
}
}

View File

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

View File

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