netaddress.go raw

   1  package wire
   2  
   3  import (
   4  	"encoding/binary"
   5  	"io"
   6  	"net"
   7  	"time"
   8  )
   9  
  10  // maxNetAddressPayload returns the max payload size for a bitcoin NetAddress
  11  // based on the protocol version.
  12  func maxNetAddressPayload(pver uint32) uint32 {
  13  	// Services 8 bytes + ip 16 bytes + port 2 bytes.
  14  	plen := uint32(26)
  15  	// NetAddressTimeVersion added a timestamp field.
  16  	if pver >= NetAddressTimeVersion {
  17  		// Timestamp 4 bytes.
  18  		plen += 4
  19  	}
  20  	return plen
  21  }
  22  
  23  // NetAddress defines information about a peer on the network including the time
  24  // it was last seen, the services it supports, its IP address, and port.
  25  type NetAddress struct {
  26  	// Last time the address was seen. This is, unfortunately, encoded as a uint32
  27  	// on the wire and therefore is limited to 2106. This field is not present in
  28  	// the bitcoin version message (MsgVersion) nor was it added until protocol
  29  	// version >= NetAddressTimeVersion.
  30  	Timestamp time.Time
  31  	// Bitfield which identifies the services supported by the address.
  32  	Services ServiceFlag
  33  	// IP address of the peer.
  34  	IP net.IP
  35  	// Port the peer is using. This is encoded in big endian on the wire which
  36  	// differs from most everything else.
  37  	Port uint16
  38  }
  39  
  40  // HasService returns whether the specified service is supported by the address.
  41  func (na *NetAddress) HasService(service ServiceFlag) bool {
  42  	return na.Services&service == service
  43  }
  44  
  45  // AddService adds service as a supported service by the peer generating the
  46  // message.
  47  func (na *NetAddress) AddService(service ServiceFlag) {
  48  	na.Services |= service
  49  }
  50  
  51  // NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
  52  // supported services with defaults for the remaining fields.
  53  func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
  54  	return NewNetAddressTimestamp(time.Now(), services, ip, port)
  55  }
  56  
  57  // NewNetAddressTimestamp returns a new NetAddress using the provided timestamp,
  58  // IP, port, and supported services. The timestamp is rounded to single second
  59  // precision.
  60  func NewNetAddressTimestamp(timestamp time.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress {
  61  	// Limit the timestamp to one second precision since the protocol doesn't support better.
  62  	na := NetAddress{
  63  		Timestamp: time.Unix(timestamp.Unix(), 0),
  64  		Services:  services,
  65  		IP:        ip,
  66  		Port:      port,
  67  	}
  68  	return &na
  69  }
  70  
  71  // NewNetAddress returns a new NetAddress using the provided TCP address and
  72  // supported services with defaults for the remaining fields.
  73  func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
  74  	return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services)
  75  }
  76  
  77  // readNetAddress reads an encoded NetAddress from r depending on the protocol
  78  // version and whether or not the timestamp is included per ts. Some messages
  79  // like version do not include the timestamp.
  80  func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) (e error) {
  81  	var ip [16]byte
  82  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will stop
  83  	// working somewhere around 2106. Also timestamp wasn't added until protocol
  84  	// version >= NetAddressTimeVersion
  85  	if ts && pver >= NetAddressTimeVersion {
  86  		if e = readElement(r, (*uint32Time)(&na.Timestamp)); E.Chk(e) {
  87  			return
  88  		}
  89  	}
  90  	if e = readElements(r, &na.Services, &ip); E.Chk(e) {
  91  		return
  92  	}
  93  	// Sigh.  Bitcoin protocol mixes little and big endian.
  94  	var port uint16
  95  	if port, e = binarySerializer.Uint16(r, bigEndian); E.Chk(e) {
  96  		return
  97  	}
  98  	*na = NetAddress{
  99  		Timestamp: na.Timestamp,
 100  		Services:  na.Services,
 101  		IP:        ip[:],
 102  		Port:      port,
 103  	}
 104  	return nil
 105  }
 106  
 107  // writeNetAddress serializes a NetAddress to w depending on the protocol
 108  // version and whether or not the timestamp is included per ts. Some messages
 109  // like version do not include the timestamp.
 110  func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) (e error) {
 111  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will stop
 112  	// working somewhere around 2106. Also timestamp wasn't added until until
 113  	// protocol version >= NetAddressTimeVersion.
 114  	if ts && pver >= NetAddressTimeVersion {
 115  		if e = writeElement(w, uint32(na.Timestamp.Unix())); E.Chk(e) {
 116  			return
 117  		}
 118  	}
 119  	// Ensure to always write 16 bytes even if the ip is nil.
 120  	var ip [16]byte
 121  	if na.IP != nil {
 122  		copy(ip[:], na.IP.To16())
 123  	}
 124  	if e = writeElements(w, na.Services, ip); E.Chk(e) {
 125  		return
 126  	}
 127  	// Sigh.  Bitcoin protocol mixes little and big endian.
 128  	return binary.Write(w, bigEndian, na.Port)
 129  }
 130