2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2023 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 xdr "github.com/davecgh/go-xdr/xdr2"
44 mcdIP = net.ParseIP("ff02::4e4e:4350")
45 mcdAddrLifetime = 2 * time.Minute
48 MCDAddrs map[NodeId][]*MCDAddr
49 MCDAddrsM sync.RWMutex
55 mcd := MCD{Sender: nodeId}
56 if _, err := xdr.Marshal(&buf, mcd); err != nil {
59 mcdPktSize = buf.Len()
61 MCDAddrs = make(map[NodeId][]*MCDAddr)
64 time.Sleep(time.Minute)
67 for nodeId, addrs := range MCDAddrs {
68 addrsAlive := make([]*MCDAddr, 0, len(addrs))
69 for _, addr := range addrs {
70 if !addr.lastSeen.Add(mcdAddrLifetime).Before(now) {
71 addrsAlive = append(addrsAlive, addr)
74 MCDAddrs[nodeId] = addrsAlive
81 func (ctx *Ctx) MCDRx(ifiName string) error {
82 ifi, err := net.InterfaceByName(ifiName)
86 addr := &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName}
87 conn, err := net.ListenMulticastUDP("udp", ifi, addr)
92 buf := make([]byte, mcdPktSize)
97 les := LEs{{"If", ifiName}}
98 n, addr, err = conn.ReadFromUDP(buf)
100 ctx.LogE("mcd", les, err, func(les LEs) string {
101 return fmt.Sprintf("MCD Rx %s/%d", ifiName, MCDPort)
106 ctx.LogD("mcd", les, func(les LEs) string {
108 "MCD Rx %s/%d: got packet with invalid size",
114 _, err = xdr.Unmarshal(bytes.NewReader(buf[:n]), &mcd)
116 ctx.LogD("mcd", les, func(les LEs) string {
118 "MCD Rx %s/%d: can not unmarshal: %s",
119 ifiName, MCDPort, err,
124 if mcd.Magic != MagicNNCPDv1.B {
125 ctx.LogD("mcd", les, func(les LEs) string {
127 "MCD Rx %s/%d: unexpected magic: %s",
128 ifiName, MCDPort, hex.EncodeToString(mcd.Magic[:]),
133 node, known := ctx.Neigh[*mcd.Sender]
135 les = append(les, LE{"Node", node.Id})
136 ctx.LogD("mcd", les, func(les LEs) string {
138 "MCD Rx %s/%d: %s: node %s",
139 ifiName, MCDPort, addr, node.Name,
143 ctx.LogD("mcd", les, func(les LEs) string {
145 "MCD Rx %s/%d: %s: unknown node %s",
146 ifiName, MCDPort, addr, node.Id.String(),
152 for _, mcdAddr := range MCDAddrs[*mcd.Sender] {
153 if mcdAddr.Addr.IP.Equal(addr.IP) &&
154 mcdAddr.Addr.Port == addr.Port &&
155 mcdAddr.Addr.Zone == addr.Zone {
156 mcdAddr.lastSeen = time.Now()
163 MCDAddrs[*mcd.Sender] = append(
164 MCDAddrs[*mcd.Sender],
165 &MCDAddr{Addr: *addr, lastSeen: time.Now()},
168 ctx.LogI("mcd-add", les, func(les LEs) string {
169 return fmt.Sprintf("MCD discovered %s's address: %s", node.Name, addr)
176 func (ctx *Ctx) MCDTx(ifiName string, port int, interval time.Duration) error {
177 ifi, err := net.InterfaceByName(ifiName)
181 addr := &net.UDPAddr{IP: mcdIP, Port: port, Zone: ifiName}
182 conn, err := net.ListenMulticastUDP("udp", ifi, addr)
187 dst := &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName}
189 mcd := MCD{Magic: MagicNNCPDv1.B, Sender: ctx.Self.Id}
190 if _, err := xdr.Marshal(&buf, mcd); err != nil {
194 _, err = conn.WriteTo(buf.Bytes(), dst)
198 les := LEs{{"If", ifiName}}
200 ctx.LogD("mcd", les, func(les LEs) string {
203 ifiName, MCDPort, port,
206 _, err = conn.WriteTo(buf.Bytes(), dst)
208 ctx.LogE("mcd", les, err, func(les LEs) string {
209 return fmt.Sprintf("MCD on %s/%d/%d", ifiName, MCDPort, port)