github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/wire/netaddress.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package wire
     7  
     8  import (
     9  	"encoding/binary"
    10  	"errors"
    11  	"io"
    12  	"net"
    13  	"time"
    14  )
    15  
    16  // ErrInvalidNetAddr describes an error that indicates the caller didn't specify
    17  // a TCP address as required.
    18  var ErrInvalidNetAddr = errors.New("provided net.Addr is not a net.TCPAddr")
    19  
    20  // maxNetAddressPayload returns the max payload size for a bitcoin NetAddress
    21  // based on the protocol version.
    22  func maxNetAddressPayload(pver uint32) uint32 {
    23  	// Services 8 bytes + ip 16 bytes + port 2 bytes.
    24  	plen := uint32(26)
    25  
    26  	// NetAddressTimeVersion added a timestamp field.
    27  	if pver >= NetAddressTimeVersion {
    28  		// Timestamp 4 bytes.
    29  		plen += 4
    30  	}
    31  
    32  	return plen
    33  }
    34  
    35  // NetAddress defines information about a peer on the network including the time
    36  // it was last seen, the services it supports, its IP address, and port.
    37  type NetAddress struct {
    38  	// Last time the address was seen.  This is, unfortunately, encoded as a
    39  	// uint32 on the wire and therefore is limited to 2106.  This field is
    40  	// not present in the bitcoin version message (MsgVersion) nor was it
    41  	// added until protocol version >= NetAddressTimeVersion.
    42  	Timestamp time.Time
    43  
    44  	// Bitfield which identifies the services supported by the address.
    45  	Services ServiceFlag
    46  
    47  	// IP address of the peer.
    48  	IP net.IP
    49  
    50  	// Port the peer is using.  This is encoded in big endian on the wire
    51  	// which differs from most everything else.
    52  	Port uint16
    53  }
    54  
    55  // HasService returns whether the specified service is supported by the address.
    56  func (na *NetAddress) HasService(service ServiceFlag) bool {
    57  	if na.Services&service == service {
    58  		return true
    59  	}
    60  	return false
    61  }
    62  
    63  // AddService adds service as a supported service by the peer generating the
    64  // message.
    65  func (na *NetAddress) AddService(service ServiceFlag) {
    66  	na.Services |= service
    67  }
    68  
    69  // SetAddress is a convenience function to set the IP address and port in one
    70  // call.
    71  func (na *NetAddress) SetAddress(ip net.IP, port uint16) {
    72  	na.IP = ip
    73  	na.Port = port
    74  }
    75  
    76  // NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
    77  // supported services with defaults for the remaining fields.
    78  func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
    79  	// Limit the timestamp to one second precision since the protocol
    80  	// doesn't support better.
    81  	na := NetAddress{
    82  		Timestamp: time.Unix(time.Now().Unix(), 0),
    83  		Services:  services,
    84  		IP:        ip,
    85  		Port:      port,
    86  	}
    87  	return &na
    88  }
    89  
    90  // NewNetAddress returns a new NetAddress using the provided TCP address and
    91  // supported services with defaults for the remaining fields.
    92  //
    93  // Note that addr must be a net.TCPAddr.  An ErrInvalidNetAddr is returned
    94  // if it is not.
    95  func NewNetAddress(addr net.Addr, services ServiceFlag) (*NetAddress, error) {
    96  	tcpAddr, ok := addr.(*net.TCPAddr)
    97  	if !ok {
    98  		return nil, ErrInvalidNetAddr
    99  	}
   100  
   101  	na := NewNetAddressIPPort(tcpAddr.IP, uint16(tcpAddr.Port), services)
   102  	return na, nil
   103  }
   104  
   105  // readNetAddress reads an encoded NetAddress from r depending on the protocol
   106  // version and whether or not the timestamp is included per ts.  Some messages
   107  // like version do not include the timestamp.
   108  func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
   109  	var services ServiceFlag
   110  	var ip [16]byte
   111  
   112  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
   113  	// stop working somewhere around 2106.  Also timestamp wasn't added until
   114  	// protocol version >= NetAddressTimeVersion
   115  	if ts && pver >= NetAddressTimeVersion {
   116  		err := readElement(r, (*uint32Time)(&na.Timestamp))
   117  		if err != nil {
   118  			return err
   119  		}
   120  	}
   121  
   122  	err := readElements(r, &services, &ip)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	// Sigh.  Bitcoin protocol mixes little and big endian.
   127  	port, err := binarySerializer.Uint16(r, bigEndian)
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	na.Services = services
   133  	na.SetAddress(net.IP(ip[:]), port)
   134  	return nil
   135  }
   136  
   137  // writeNetAddress serializes a NetAddress to w depending on the protocol
   138  // version and whether or not the timestamp is included per ts.  Some messages
   139  // like version do not include the timestamp.
   140  func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
   141  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
   142  	// stop working somewhere around 2106.  Also timestamp wasn't added until
   143  	// until protocol version >= NetAddressTimeVersion.
   144  	if ts && pver >= NetAddressTimeVersion {
   145  		err := writeElement(w, uint32(na.Timestamp.Unix()))
   146  		if err != nil {
   147  			return err
   148  		}
   149  	}
   150  
   151  	// Ensure to always write 16 bytes even if the ip is nil.
   152  	var ip [16]byte
   153  	if na.IP != nil {
   154  		copy(ip[:], na.IP.To16())
   155  	}
   156  	err := writeElements(w, na.Services, ip)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	// Sigh.  Bitcoin protocol mixes little and big endian.
   162  	err = binary.Write(w, bigEndian, na.Port)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	return nil
   168  }