gnunet-go

GNUnet Bindings for Go
Log | Files | Refs | README | LICENSE

msg_hello.go (6017B)


      1 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
      2 // Copyright (C) 2019-2022 Bernd Fix  >Y<
      3 //
      4 // gnunet-go is free software: you can redistribute it and/or modify it
      5 // under the terms of the GNU Affero General Public License as published
      6 // by the Free Software Foundation, either version 3 of the License,
      7 // or (at your option) any later version.
      8 //
      9 // gnunet-go is distributed in the hope that it will be useful, but
     10 // WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12 // Affero General Public License for more details.
     13 //
     14 // You should have received a copy of the GNU Affero General Public License
     15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 //
     17 // SPDX-License-Identifier: AGPL3.0-or-later
     18 
     19 package message
     20 
     21 import (
     22 	"bytes"
     23 	"encoding/binary"
     24 	"fmt"
     25 	"gnunet/enums"
     26 	"gnunet/util"
     27 	"io"
     28 	"time"
     29 
     30 	"github.com/bfix/gospel/logger"
     31 )
     32 
     33 //----------------------------------------------------------------------
     34 
     35 // HelloAddress represents a (generic) peer address with expiration date:
     36 type HelloAddress struct {
     37 	transport string            // Name of transport
     38 	addrSize  uint16            // Size of address entry
     39 	expires   util.AbsoluteTime // Expiry date
     40 	address   []byte            // Address specification
     41 }
     42 
     43 // NewHelloAddress create a new HELLO address from the given address
     44 func NewHelloAddress(a *util.Address) *HelloAddress {
     45 	// use default expiration time, but adjust it if address expires earlier
     46 	exp := util.NewAbsoluteTime(time.Now().Add(HelloAddressExpiration))
     47 	if exp.Compare(a.Expire) > 0 {
     48 		exp = a.Expire
     49 	}
     50 	// convert address
     51 	addr := &HelloAddress{
     52 		transport: a.Netw,
     53 		addrSize:  uint16(len(a.Address)),
     54 		expires:   exp,
     55 		address:   make([]byte, len(a.Address)),
     56 	}
     57 	copy(addr.address, a.Address)
     58 	return addr
     59 }
     60 
     61 // ParseHelloAddress from reader
     62 func ParseHelloAddr(rdr io.Reader) (a *HelloAddress, err error) {
     63 	// parse \0-terminated transport
     64 	var (
     65 		transport []byte
     66 		buf       = make([]byte, 1)
     67 	)
     68 	for {
     69 		if _, err = rdr.Read(buf); err != nil {
     70 			return
     71 		}
     72 		if buf[0] == 0 {
     73 			break
     74 		}
     75 		transport = append(transport, buf[0])
     76 	}
     77 	// parse address size
     78 	var asize uint16
     79 	if err = binary.Read(rdr, binary.BigEndian, &asize); err != nil {
     80 		return
     81 	}
     82 	// parse expiration time
     83 	var exp uint64
     84 	if err = binary.Read(rdr, binary.BigEndian, &exp); err != nil {
     85 		return
     86 	}
     87 	// get address data
     88 	adata := make([]byte, asize)
     89 	if _, err = rdr.Read(adata); err != nil {
     90 		return
     91 	}
     92 	// assemble HELLO address
     93 	a = &HelloAddress{
     94 		transport: string(transport),
     95 		addrSize:  asize,
     96 		expires:   util.AbsoluteTime{Val: exp},
     97 		address:   adata,
     98 	}
     99 	return
    100 }
    101 
    102 // Wrap a HelloAddress into a uitl.Address
    103 func (a *HelloAddress) Wrap() (addr *util.Address) {
    104 	addr = util.NewAddress(a.transport, string(a.address))
    105 	addr.Expire = a.expires
    106 	return
    107 }
    108 
    109 // String returns a human-readable representation of the message.
    110 func (a *HelloAddress) String() string {
    111 	return fmt.Sprintf("Address{%s,expire=%s}",
    112 		util.URI(a.transport, a.address), a.expires)
    113 }
    114 
    115 // Bytes returns the binary representation of a HelloAddress
    116 func (a *HelloAddress) Bytes() []byte {
    117 	buf := new(bytes.Buffer)
    118 	_, err := buf.Write([]byte(a.transport))
    119 	if err == nil {
    120 		if err = buf.WriteByte(0); err == nil {
    121 			if err = binary.Write(buf, binary.BigEndian, a.addrSize); err == nil {
    122 				if err = binary.Write(buf, binary.BigEndian, a.expires.Val); err != nil {
    123 					_, err = buf.Write(a.address)
    124 				}
    125 			}
    126 		}
    127 	}
    128 	if err != nil {
    129 		logger.Printf(logger.ERROR, "[HelloAddress] failed: %s", err.Error())
    130 	}
    131 	return buf.Bytes()
    132 }
    133 
    134 //----------------------------------------------------------------------
    135 // HELLO
    136 //
    137 // A HELLO message is used to exchange information about transports with
    138 // other peers. This struct is always followed by the actual network
    139 // addresses of type "HelloAddress"
    140 //----------------------------------------------------------------------
    141 
    142 // HelloMsg is a message send by peers to announce their presence
    143 type HelloMsg struct {
    144 	MsgHeader
    145 	FriendsOnly uint32       `order:"big"` // Do not gossip this HELLO message
    146 	Peer        *util.PeerID ``            // peer identifier for addresses
    147 	AddrList    []byte       `size:"*"`    // List of end-point addresses (HelloAddress)
    148 
    149 	// transient state
    150 	addresses []*HelloAddress // list of converted addresses
    151 }
    152 
    153 // Init called after unmarshalling a message to setup internal state
    154 func (m *HelloMsg) Init() (err error) {
    155 	// check for initialized state
    156 	if m.addresses != nil {
    157 		return nil
    158 	}
    159 	// convert addresses
    160 	m.addresses = make([]*HelloAddress, 0)
    161 	rdr := bytes.NewReader(m.AddrList)
    162 	var addr *HelloAddress
    163 	for {
    164 		// parse address from stream
    165 		if addr, err = ParseHelloAddr(rdr); err != nil {
    166 			// end of stream: no more addresses
    167 			if err == io.EOF {
    168 				err = nil
    169 			}
    170 			return
    171 		}
    172 		m.addresses = append(m.addresses, addr)
    173 	}
    174 }
    175 
    176 // NewHelloMsg creates a new HELLO msg for a given peer.
    177 func NewHelloMsg(peer *util.PeerID) *HelloMsg {
    178 	// allocate peer id if none is specified
    179 	if peer == nil {
    180 		peer = util.NewPeerID(nil)
    181 	}
    182 	// return empty HelloMessage
    183 	return &HelloMsg{
    184 		MsgHeader:   MsgHeader{40, enums.MSG_HELLO},
    185 		FriendsOnly: 0,               // not used here
    186 		Peer:        peer,            // associated peer
    187 		AddrList:    make([]byte, 0), // list of addresses
    188 	}
    189 }
    190 
    191 // Addresses returns the list of HelloAddress
    192 func (m *HelloMsg) Addresses() (list []*HelloAddress, err error) {
    193 	if m.addresses == nil {
    194 		return
    195 	}
    196 	return m.addresses, nil
    197 }
    198 
    199 // String returns a human-readable representation of the message.
    200 func (m *HelloMsg) String() string {
    201 	return fmt.Sprintf("HelloMsg{%s: addrs=%d}", m.Peer, len(m.AddrList))
    202 }
    203 
    204 // SetAddresses adds addresses to the HELLO message.
    205 func (m *HelloMsg) SetAddresses(list []*HelloAddress) {
    206 	wrt := new(bytes.Buffer)
    207 	for _, addr := range list {
    208 		n, _ := wrt.Write(addr.Bytes())
    209 		m.MsgSize += uint16(n)
    210 	}
    211 	m.AddrList = wrt.Bytes()
    212 }