Files
bt/krpc/addr.go
2023-03-01 22:50:46 +08:00

313 lines
7.7 KiB
Go

// Copyright 2023 xgfone
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package krpc
import (
"bytes"
"encoding"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"strconv"
"github.com/xgfone/bt/bencode"
)
// Addr represents an address based on ip and port,
// which implements "Compact IP-address/port info".
//
// See http://bittorrent.org/beps/bep_0005.html.
type Addr struct {
IP net.IP // For IPv4, its length must be 4.
Port uint16
// The original network address, which is only used by the DHT server.
Orig net.Addr
}
// ParseAddrs parses the address from the string s with the format "IP:PORT".
func ParseAddrs(s string) (addrs []Addr, err error) {
_ip, _port, err := net.SplitHostPort(s)
if err != nil {
return
}
port, err := strconv.ParseUint(_port, 10, 16)
if err != nil {
return
}
ip := net.ParseIP(_ip)
if ip != nil {
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
}
return []Addr{NewAddr(ip, uint16(port))}, nil
}
ips, err := net.LookupIP(_ip)
if err != nil {
return nil, err
}
addrs = make([]Addr, len(ips))
for i, ip := range ips {
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
}
addrs[i] = NewAddr(ip, uint16(port))
}
return
}
// NewAddr returns a new Addr with ip and port.
func NewAddr(ip net.IP, port uint16) Addr {
return Addr{IP: ip, Port: port}
}
// NewAddrFromUDPAddr converts *net.UDPAddr to a new Addr.
func NewAddrFromUDPAddr(ua *net.UDPAddr) Addr {
return Addr{IP: ua.IP, Port: uint16(ua.Port), Orig: ua}
}
// Valid reports whether the addr is valid.
func (a Addr) Valid() bool {
return len(a.IP) > 0 && a.Port > 0
}
// Equal reports whether a is equal to o.
func (a Addr) Equal(o Addr) bool {
return a.Port == o.Port && a.IP.Equal(o.IP)
}
// UDPAddr converts itself to *net.UDPAddr.
func (a Addr) UDPAddr() *net.UDPAddr {
return &net.UDPAddr{IP: a.IP, Port: int(a.Port)}
}
var _ net.Addr = Addr{}
// Network implements the interface net.Addr#Network.
func (a Addr) Network() string {
return "krpc"
}
func (a Addr) String() string {
if a.Port == 0 {
return a.IP.String()
}
return net.JoinHostPort(a.IP.String(), strconv.FormatUint(uint64(a.Port), 10))
}
// WriteBinary is the same as MarshalBinary, but writes the result into w
// instead of returning.
func (a Addr) WriteBinary(w io.Writer) (n int, err error) {
if n, err = w.Write(a.IP); err == nil {
if err = binary.Write(w, binary.BigEndian, a.Port); err == nil {
n += 2
}
}
return
}
var (
_ encoding.BinaryMarshaler = new(Addr)
_ encoding.BinaryUnmarshaler = new(Addr)
)
// MarshalBinary implements the interface encoding.BinaryMarshaler,
func (a Addr) MarshalBinary() (data []byte, err error) {
buf := bytes.NewBuffer(nil)
buf.Grow(18)
if _, err = a.WriteBinary(buf); err == nil {
data = buf.Bytes()
}
return
}
// UnmarshalBinary implements the interface encoding.BinaryUnmarshaler.
func (a *Addr) UnmarshalBinary(data []byte) error {
_len := len(data) - 2
switch _len {
case net.IPv4len, net.IPv6len:
default:
return errors.New("invalid compact ip-address/port info")
}
a.IP = make(net.IP, _len)
copy(a.IP, data[:_len])
a.Port = binary.BigEndian.Uint16(data[_len:])
return nil
}
var (
_ bencode.Marshaler = new(Addr)
_ bencode.Unmarshaler = new(Addr)
)
// MarshalBencode implements the interface bencode.Marshaler.
func (a Addr) MarshalBencode() (b []byte, err error) {
if b, err = a.MarshalBinary(); err == nil {
b, err = bencode.EncodeBytes(b)
}
return
}
// UnmarshalBencode implements the interface bencode.Unmarshaler.
func (a *Addr) UnmarshalBencode(b []byte) (err error) {
var data []byte
if err = bencode.DecodeBytes(b, &data); err == nil {
err = a.UnmarshalBinary(data)
}
return
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
var (
_ bencode.Marshaler = new(CompactIPv4Addrs)
_ bencode.Unmarshaler = new(CompactIPv4Addrs)
_ encoding.BinaryMarshaler = new(CompactIPv4Addrs)
_ encoding.BinaryUnmarshaler = new(CompactIPv4Addrs)
)
// CompactIPv4Addrs is a set of IPv4 Addrs.
type CompactIPv4Addrs []Addr
// MarshalBinary implements the interface encoding.BinaryMarshaler.
func (cas CompactIPv4Addrs) MarshalBinary() ([]byte, error) {
buf := bytes.NewBuffer(nil)
buf.Grow(6 * len(cas))
for _, addr := range cas {
if addr.IP = addr.IP.To4(); len(addr.IP) == 0 {
continue
}
if n, err := addr.WriteBinary(buf); err != nil {
return nil, err
} else if n != 6 {
panic(fmt.Errorf("CompactIPv4Nodes: the invalid node info length '%d'", n))
}
}
return buf.Bytes(), nil
}
// UnmarshalBinary implements the interface encoding.BinaryUnmarshaler.
func (cas *CompactIPv4Addrs) UnmarshalBinary(b []byte) (err error) {
_len := len(b)
if _len%6 != 0 {
return fmt.Errorf("CompactIPv4Addrs: invalid addr info length '%d'", _len)
}
addrs := make(CompactIPv4Addrs, 0, _len/6)
for i := 0; i < _len; i += 6 {
var addr Addr
if err = addr.UnmarshalBinary(b[i : i+6]); err != nil {
return
}
addrs = append(addrs, addr)
}
*cas = addrs
return
}
// MarshalBencode implements the interface bencode.Marshaler.
func (cas CompactIPv4Addrs) MarshalBencode() (b []byte, err error) {
if b, err = cas.MarshalBinary(); err == nil {
b, err = bencode.EncodeBytes(b)
}
return
}
// UnmarshalBencode implements the interface bencode.Unmarshaler.
func (cas *CompactIPv4Addrs) UnmarshalBencode(b []byte) (err error) {
var data []byte
if err = bencode.DecodeBytes(b, &data); err == nil {
err = cas.UnmarshalBinary(data)
}
return
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
var (
_ bencode.Marshaler = new(CompactIPv6Addrs)
_ bencode.Unmarshaler = new(CompactIPv6Addrs)
_ encoding.BinaryMarshaler = new(CompactIPv6Addrs)
_ encoding.BinaryUnmarshaler = new(CompactIPv6Addrs)
)
// CompactIPv6Addrs is a set of IPv6 Addrs.
type CompactIPv6Addrs []Addr
// MarshalBinary implements the interface encoding.BinaryMarshaler.
func (cas CompactIPv6Addrs) MarshalBinary() ([]byte, error) {
buf := bytes.NewBuffer(nil)
buf.Grow(18 * len(cas))
for _, addr := range cas {
if addr.IP = addr.IP.To4(); len(addr.IP) == 0 {
continue
}
if n, err := addr.WriteBinary(buf); err != nil {
return nil, err
} else if n != 18 {
panic(fmt.Errorf("CompactIPv4Nodes: the invalid node info length '%d'", n))
}
}
return buf.Bytes(), nil
}
// UnmarshalBinary implements the interface encoding.BinaryUnmarshaler.
func (cas *CompactIPv6Addrs) UnmarshalBinary(b []byte) (err error) {
_len := len(b)
if _len%18 != 0 {
return fmt.Errorf("CompactIPv4Addrs: invalid addr info length '%d'", _len)
}
addrs := make(CompactIPv6Addrs, 0, _len/18)
for i := 0; i < _len; i += 18 {
var addr Addr
if err = addr.UnmarshalBinary(b[i : i+18]); err != nil {
return
}
addrs = append(addrs, addr)
}
*cas = addrs
return
}
// MarshalBencode implements the interface bencode.Marshaler.
func (cas CompactIPv6Addrs) MarshalBencode() (b []byte, err error) {
if b, err = cas.MarshalBinary(); err == nil {
b, err = bencode.EncodeBytes(b)
}
return
}
// UnmarshalBencode implements the interface bencode.Unmarshaler.
func (cas *CompactIPv6Addrs) UnmarshalBencode(b []byte) (err error) {
var data []byte
if err = bencode.DecodeBytes(b, &data); err == nil {
err = cas.UnmarshalBinary(data)
}
return
}