Split Address struct to save some bytes

pull/27/head
V2Ray 2015-09-20 16:55:45 +02:00
parent b319704282
commit 823cbf1509
4 changed files with 131 additions and 61 deletions

View File

@ -3,66 +3,142 @@ package net
import ( import (
"net" "net"
"strconv" "strconv"
"github.com/v2ray/v2ray-core/common/log"
) )
const ( type Address interface {
AddrTypeIP = byte(0x01) IP() net.IP
AddrTypeDomain = byte(0x03) Domain() string
) Port() uint16
PortBytes() []byte
type Address struct { IsIPv4() bool
Type byte IsIPv6() bool
IP net.IP IsDomain() bool
Domain string
Port uint16 String() string
} }
func IPAddress(ip []byte, port uint16) Address { func IPAddress(ip []byte, port uint16) Address {
ipCopy := make([]byte, len(ip)) switch len(ip) {
copy(ipCopy, ip) case net.IPv4len:
// TODO: check IP length return IPv4Address{
return Address{ PortAddress: PortAddress{port: port},
Type: AddrTypeIP, ip: [4]byte{ip[0], ip[1], ip[2], ip[3]},
IP: net.IP(ipCopy), }
Domain: "", case net.IPv6len:
Port: port, return IPv6Address{
PortAddress: PortAddress{port: port},
ip: [16]byte{ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]},
}
default:
panic(log.Error("Unknown IP format: %v", ip))
} }
} }
func DomainAddress(domain string, port uint16) Address { func DomainAddress(domain string, port uint16) Address {
return Address{ return DomainAddressImpl{
Type: AddrTypeDomain, domain: domain,
IP: nil, PortAddress: PortAddress{port: port},
Domain: domain,
Port: port,
} }
} }
func (addr Address) IsIPv4() bool { type PortAddress struct {
return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv4len port uint16
} }
func (addr Address) IsIPv6() bool { func (addr PortAddress) Port() uint16 {
return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv6len return addr.port
} }
func (addr Address) IsDomain() bool { func (addr PortAddress) PortBytes() []byte {
return addr.Type == AddrTypeDomain return []byte{byte(addr.port >> 8), byte(addr.port)}
} }
func (addr Address) String() string { type IPv4Address struct {
var host string PortAddress
switch addr.Type { ip [4]byte
case AddrTypeIP: }
host = addr.IP.String()
if len(addr.IP) == net.IPv6len { func (addr IPv4Address) IP() net.IP {
host = "[" + host + "]" return net.IP(addr.ip[:])
} }
case AddrTypeDomain: func (addr IPv4Address) Domain() string {
host = addr.Domain panic("Calling Domain() on an IPv4Address.")
default: }
panic("Unknown Address Type " + strconv.Itoa(int(addr.Type)))
} func (addr IPv4Address) IsIPv4() bool {
return host + ":" + strconv.Itoa(int(addr.Port)) return true
}
func (addr IPv4Address) IsIPv6() bool {
return false
}
func (addr IPv4Address) IsDomain() bool {
return false
}
func (addr IPv4Address) String() string {
return addr.IP().String() + ":" + strconv.Itoa(int(addr.PortAddress.port))
}
type IPv6Address struct {
PortAddress
ip [16]byte
}
func (addr IPv6Address) IP() net.IP {
return net.IP(addr.ip[:])
}
func (addr IPv6Address) Domain() string {
panic("Calling Domain() on an IPv6Address.")
}
func (addr IPv6Address) IsIPv4() bool {
return false
}
func (addr IPv6Address) IsIPv6() bool {
return true
}
func (addr IPv6Address) IsDomain() bool {
return false
}
func (addr IPv6Address) String() string {
return "[" + addr.IP().String() + "]:" + strconv.Itoa(int(addr.PortAddress.port))
}
type DomainAddressImpl struct {
PortAddress
domain string
}
func (addr DomainAddressImpl) IP() net.IP {
panic("Calling IP() on a DomainAddress.")
}
func (addr DomainAddressImpl) Domain() string {
return addr.domain
}
func (addr DomainAddressImpl) IsIPv4() bool {
return false
}
func (addr DomainAddressImpl) IsIPv6() bool {
return false
}
func (addr DomainAddressImpl) IsDomain() bool {
return true
}
func (addr DomainAddressImpl) String() string {
return addr.domain + ":" + strconv.Itoa(int(addr.PortAddress.port))
} }

View File

@ -13,10 +13,9 @@ func TestIPv4Address(t *testing.T) {
port := uint16(80) port := uint16(80)
addr := IPAddress(ip, port) addr := IPAddress(ip, port)
assert.Byte(addr.Type).Equals(AddrTypeIP)
assert.Bool(addr.IsIPv4()).IsTrue() assert.Bool(addr.IsIPv4()).IsTrue()
assert.Bytes(addr.IP).Equals(ip) assert.Bytes(addr.IP()).Equals(ip)
assert.Uint16(addr.Port).Equals(port) assert.Uint16(addr.Port()).Equals(port)
assert.String(addr.String()).Equals("1.2.3.4:80") assert.String(addr.String()).Equals("1.2.3.4:80")
} }
@ -32,10 +31,9 @@ func TestIPv6Address(t *testing.T) {
port := uint16(443) port := uint16(443)
addr := IPAddress(ip, port) addr := IPAddress(ip, port)
assert.Byte(addr.Type).Equals(AddrTypeIP)
assert.Bool(addr.IsIPv6()).IsTrue() assert.Bool(addr.IsIPv6()).IsTrue()
assert.Bytes(addr.IP).Equals(ip) assert.Bytes(addr.IP()).Equals(ip)
assert.Uint16(addr.Port).Equals(port) assert.Uint16(addr.Port()).Equals(port)
assert.String(addr.String()).Equals("[102:304:102:304:102:304:102:304]:443") assert.String(addr.String()).Equals("[102:304:102:304:102:304:102:304]:443")
} }
@ -46,9 +44,8 @@ func TestDomainAddress(t *testing.T) {
port := uint16(443) port := uint16(443)
addr := DomainAddress(domain, port) addr := DomainAddress(domain, port)
assert.Byte(addr.Type).Equals(AddrTypeDomain)
assert.Bool(addr.IsDomain()).IsTrue() assert.Bool(addr.IsDomain()).IsTrue()
assert.String(addr.Domain).Equals(domain) assert.String(addr.Domain()).Equals(domain)
assert.Uint16(addr.Port).Equals(port) assert.Uint16(addr.Port()).Equals(port)
assert.String(addr.String()).Equals("v2ray.com:443") assert.String(addr.String()).Equals("v2ray.com:443")
} }

View File

@ -211,22 +211,19 @@ func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 u
buffer = append(buffer, request.RequestKey[:]...) buffer = append(buffer, request.RequestKey[:]...)
buffer = append(buffer, request.ResponseHeader[:]...) buffer = append(buffer, request.ResponseHeader[:]...)
buffer = append(buffer, request.Command) buffer = append(buffer, request.Command)
buffer = append(buffer, request.Address.PortBytes()...)
portBytes := make([]byte, 2)
binary.BigEndian.PutUint16(portBytes, request.Address.Port)
buffer = append(buffer, portBytes...)
switch { switch {
case request.Address.IsIPv4(): case request.Address.IsIPv4():
buffer = append(buffer, addrTypeIPv4) buffer = append(buffer, addrTypeIPv4)
buffer = append(buffer, request.Address.IP...) buffer = append(buffer, request.Address.IP()...)
case request.Address.IsIPv6(): case request.Address.IsIPv6():
buffer = append(buffer, addrTypeIPv6) buffer = append(buffer, addrTypeIPv6)
buffer = append(buffer, request.Address.IP...) buffer = append(buffer, request.Address.IP()...)
case request.Address.IsDomain(): case request.Address.IsDomain():
buffer = append(buffer, addrTypeDomain) buffer = append(buffer, addrTypeDomain)
buffer = append(buffer, byte(len(request.Address.Domain))) buffer = append(buffer, byte(len(request.Address.Domain())))
buffer = append(buffer, []byte(request.Address.Domain)...) buffer = append(buffer, []byte(request.Address.Domain())...)
} }
paddingLength := mrand.Intn(32) + 1 paddingLength := mrand.Intn(32) + 1

View File

@ -72,7 +72,7 @@ func startCommunicate(request *protocol.VMessRequest, dest *v2net.Destination, r
input := ray.OutboundInput() input := ray.OutboundInput()
output := ray.OutboundOutput() output := ray.OutboundOutput()
conn, err := net.DialTCP(dest.Network(), nil, &net.TCPAddr{dest.Address().IP, int(dest.Address().Port), ""}) conn, err := net.DialTCP(dest.Network(), nil, &net.TCPAddr{dest.Address().IP(), int(dest.Address().Port()), ""})
if err != nil { if err != nil {
log.Error("Failed to open tcp (%s): %v", dest.String(), err) log.Error("Failed to open tcp (%s): %v", dest.String(), err)
close(output) close(output)