2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 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"
46 mcdIP = net.ParseIP("ff02::4e4e:4350")
47 mcdAddrLifetime = 2 * time.Minute
50 MCDAddrs map[NodeId][]*MCDAddr
51 MCDAddrsM sync.RWMutex
57 mcd := MCD{Sender: nodeId}
58 if _, err := xdr.Marshal(&buf, mcd); err != nil {
61 mcdPktSize = buf.Len()
63 MCDAddrs = make(map[NodeId][]*MCDAddr)
66 time.Sleep(time.Minute)
69 for nodeId, addrs := range MCDAddrs {
70 addrsAlive := make([]*MCDAddr, 0, len(addrs))
71 for _, addr := range addrs {
72 if !addr.lastSeen.Add(mcdAddrLifetime).Before(now) {
73 addrsAlive = append(addrsAlive, addr)
76 MCDAddrs[nodeId] = addrsAlive
83 func (ctx *Ctx) MCDRx(ifiName string) error {
84 ifi, err := net.InterfaceByName(ifiName)
88 addr := &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName}
89 conn, err := net.ListenMulticastUDP("udp", ifi, addr)
94 buf := make([]byte, mcdPktSize)
99 les := LEs{{"If", ifiName}}
100 n, addr, err = conn.ReadFromUDP(buf)
102 ctx.LogE("mcd", les, err, func(les LEs) string {
103 return fmt.Sprintf("MCD Rx %s/%d", ifiName, MCDPort)
108 ctx.LogD("mcd", les, func(les LEs) string {
110 "MCD Rx %s/%d: got packet with invalid size",
116 _, err = xdr.Unmarshal(bytes.NewReader(buf[:n]), &mcd)
118 ctx.LogD("mcd", les, func(les LEs) string {
120 "MCD Rx %s/%d: can not unmarshal: %s",
121 ifiName, MCDPort, err,
126 if mcd.Magic != MagicNNCPDv1.B {
127 ctx.LogD("mcd", les, func(les LEs) string {
129 "MCD Rx %s/%d: unexpected magic: %s",
130 ifiName, MCDPort, hex.EncodeToString(mcd.Magic[:]),
135 node, known := ctx.Neigh[*mcd.Sender]
137 les = append(les, LE{"Node", node.Id})
138 ctx.LogD("mcd", les, func(les LEs) string {
140 "MCD Rx %s/%d: %s: node %s",
141 ifiName, MCDPort, addr, node.Name,
145 ctx.LogD("mcd", les, func(les LEs) string {
147 "MCD Rx %s/%d: %s: unknown node %s",
148 ifiName, MCDPort, addr, node.Id.String(),
154 for _, mcdAddr := range MCDAddrs[*mcd.Sender] {
155 if mcdAddr.Addr.IP.Equal(addr.IP) &&
156 mcdAddr.Addr.Port == addr.Port &&
157 mcdAddr.Addr.Zone == addr.Zone {
158 mcdAddr.lastSeen = time.Now()
165 MCDAddrs[*mcd.Sender] = append(
166 MCDAddrs[*mcd.Sender],
167 &MCDAddr{Addr: *addr, lastSeen: time.Now()},
170 ctx.LogI("mcd-add", les, func(les LEs) string {
171 return fmt.Sprintf("MCD discovered %s's address: %s", node.Name, addr)
178 func (ctx *Ctx) MCDTx(ifiName string, port int, interval time.Duration) error {
179 conn, err := net.DialUDP("udp",
180 &net.UDPAddr{Port: port, Zone: ifiName},
181 &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName},
187 mcd := MCD{Magic: MagicNNCPDv1.B, Sender: ctx.Self.Id}
188 if _, err := xdr.Marshal(&buf, mcd); err != nil {
192 _, err = conn.Write(buf.Bytes())
196 les := LEs{{"If", ifiName}}
198 ctx.LogD("mcd", les, func(les LEs) string {
201 ifiName, MCDPort, port,
204 _, err = conn.Write(buf.Bytes())
206 ctx.LogE("mcd", les, err, func(les LEs) string {
207 return fmt.Sprintf("MCD on %s/%d/%d", ifiName, MCDPort, port)