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