github.com/btcsuite/btcd@v0.24.0/wire/netaddress.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"io"
     9  	"net"
    10  	"time"
    11  )
    12  
    13  // maxNetAddressPayload returns the max payload size for a bitcoin NetAddress
    14  // based on the protocol version.
    15  func maxNetAddressPayload(pver uint32) uint32 {
    16  	// Services 8 bytes + ip 16 bytes + port 2 bytes.
    17  	plen := uint32(26)
    18  
    19  	// NetAddressTimeVersion added a timestamp field.
    20  	if pver >= NetAddressTimeVersion {
    21  		// Timestamp 4 bytes.
    22  		plen += 4
    23  	}
    24  
    25  	return plen
    26  }
    27  
    28  // NetAddress defines information about a peer on the network including the time
    29  // it was last seen, the services it supports, its IP address, and port.
    30  type NetAddress struct {
    31  	// Last time the address was seen.  This is, unfortunately, encoded as a
    32  	// uint32 on the wire and therefore is limited to 2106.  This field is
    33  	// not present in the bitcoin version message (MsgVersion) nor was it
    34  	// added until protocol version >= NetAddressTimeVersion.
    35  	Timestamp time.Time
    36  
    37  	// Bitfield which identifies the services supported by the address.
    38  	Services ServiceFlag
    39  
    40  	// IP address of the peer.
    41  	IP net.IP
    42  
    43  	// Port the peer is using.  This is encoded in big endian on the wire
    44  	// which differs from most everything else.
    45  	Port uint16
    46  }
    47  
    48  // HasService returns whether the specified service is supported by the address.
    49  func (na *NetAddress) HasService(service ServiceFlag) bool {
    50  	return na.Services&service == service
    51  }
    52  
    53  // AddService adds service as a supported service by the peer generating the
    54  // message.
    55  func (na *NetAddress) AddService(service ServiceFlag) {
    56  	na.Services |= service
    57  }
    58  
    59  // NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
    60  // supported services with defaults for the remaining fields.
    61  func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
    62  	return NewNetAddressTimestamp(time.Now(), services, ip, port)
    63  }
    64  
    65  // NewNetAddressTimestamp returns a new NetAddress using the provided
    66  // timestamp, IP, port, and supported services. The timestamp is rounded to
    67  // single second precision.
    68  func NewNetAddressTimestamp(
    69  	timestamp time.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress {
    70  	// Limit the timestamp to one second precision since the protocol
    71  	// doesn't support better.
    72  	na := NetAddress{
    73  		Timestamp: time.Unix(timestamp.Unix(), 0),
    74  		Services:  services,
    75  		IP:        ip,
    76  		Port:      port,
    77  	}
    78  	return &na
    79  }
    80  
    81  // NewNetAddress returns a new NetAddress using the provided TCP address and
    82  // supported services with defaults for the remaining fields.
    83  func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
    84  	return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services)
    85  }
    86  
    87  // readNetAddress reads an encoded NetAddress from r depending on the protocol
    88  // version and whether or not the timestamp is included per ts.  Some messages
    89  // like version do not include the timestamp.
    90  func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
    91  	buf := binarySerializer.Borrow()
    92  	defer binarySerializer.Return(buf)
    93  
    94  	err := readNetAddressBuf(r, pver, na, ts, buf)
    95  	return err
    96  }
    97  
    98  // readNetAddressBuf reads an encoded NetAddress from r depending on the
    99  // protocol version and whether or not the timestamp is included per ts.  Some
   100  // messages like version do not include the timestamp.
   101  //
   102  // If b is non-nil, the provided buffer will be used for serializing small
   103  // values.  Otherwise a buffer will be drawn from the binarySerializer's pool
   104  // and return when the method finishes.
   105  //
   106  // NOTE: b MUST either be nil or at least an 8-byte slice.
   107  func readNetAddressBuf(r io.Reader, pver uint32, na *NetAddress, ts bool,
   108  	buf []byte) error {
   109  
   110  	var (
   111  		timestamp time.Time
   112  		services  ServiceFlag
   113  		ip        [16]byte
   114  		port      uint16
   115  	)
   116  
   117  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
   118  	// stop working somewhere around 2106.  Also timestamp wasn't added until
   119  	// protocol version >= NetAddressTimeVersion
   120  	if ts && pver >= NetAddressTimeVersion {
   121  		if _, err := io.ReadFull(r, buf[:4]); err != nil {
   122  			return err
   123  		}
   124  		timestamp = time.Unix(int64(littleEndian.Uint32(buf[:4])), 0)
   125  	}
   126  
   127  	if _, err := io.ReadFull(r, buf); err != nil {
   128  		return err
   129  	}
   130  	services = ServiceFlag(littleEndian.Uint64(buf))
   131  
   132  	if _, err := io.ReadFull(r, ip[:]); err != nil {
   133  		return err
   134  	}
   135  
   136  	// Sigh.  Bitcoin protocol mixes little and big endian.
   137  	if _, err := io.ReadFull(r, buf[:2]); err != nil {
   138  		return err
   139  	}
   140  	port = bigEndian.Uint16(buf[:2])
   141  
   142  	*na = NetAddress{
   143  		Timestamp: timestamp,
   144  		Services:  services,
   145  		IP:        net.IP(ip[:]),
   146  		Port:      port,
   147  	}
   148  	return nil
   149  }
   150  
   151  // writeNetAddress serializes a NetAddress to w depending on the protocol
   152  // version and whether or not the timestamp is included per ts.  Some messages
   153  // like version do not include the timestamp.
   154  func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
   155  	buf := binarySerializer.Borrow()
   156  	defer binarySerializer.Return(buf)
   157  	err := writeNetAddressBuf(w, pver, na, ts, buf)
   158  
   159  	return err
   160  }
   161  
   162  // writeNetAddressBuf serializes a NetAddress to w depending on the protocol
   163  // version and whether or not the timestamp is included per ts.  Some messages
   164  // like version do not include the timestamp.
   165  //
   166  // If b is non-nil, the provided buffer will be used for serializing small
   167  // values.  Otherwise a buffer will be drawn from the binarySerializer's pool
   168  // and return when the method finishes.
   169  //
   170  // NOTE: b MUST either be nil or at least an 8-byte slice.
   171  func writeNetAddressBuf(w io.Writer, pver uint32, na *NetAddress, ts bool, buf []byte) error {
   172  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
   173  	// stop working somewhere around 2106.  Also timestamp wasn't added until
   174  	// until protocol version >= NetAddressTimeVersion.
   175  	if ts && pver >= NetAddressTimeVersion {
   176  		littleEndian.PutUint32(buf[:4], uint32(na.Timestamp.Unix()))
   177  		if _, err := w.Write(buf[:4]); err != nil {
   178  			return err
   179  		}
   180  	}
   181  
   182  	littleEndian.PutUint64(buf, uint64(na.Services))
   183  	if _, err := w.Write(buf); err != nil {
   184  		return err
   185  	}
   186  
   187  	// Ensure to always write 16 bytes even if the ip is nil.
   188  	var ip [16]byte
   189  	if na.IP != nil {
   190  		copy(ip[:], na.IP.To16())
   191  	}
   192  	if _, err := w.Write(ip[:]); err != nil {
   193  		return err
   194  	}
   195  
   196  	// Sigh.  Bitcoin protocol mixes little and big endian.
   197  	bigEndian.PutUint16(buf[:2], na.Port)
   198  	_, err := w.Write(buf[:2])
   199  
   200  	return err
   201  }