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 MagicNNCPDv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'D', 0, 0, 1}
48 mcdIP = net.ParseIP("ff02::1")
49 mcdAddrLifetime = 2 * time.Minute
52 MCDAddrs map[NodeId][]*MCDAddr
53 MCDAddrsM sync.RWMutex
59 mcd := MCD{Sender: nodeId}
60 if _, err := xdr.Marshal(&buf, mcd); err != nil {
63 mcdPktSize = buf.Len()
65 MCDAddrs = make(map[NodeId][]*MCDAddr)
68 time.Sleep(time.Minute)
71 for nodeId, addrs := range MCDAddrs {
72 addrsAlive := make([]*MCDAddr, 0, len(addrs))
73 for _, addr := range addrs {
74 if !addr.lastSeen.Add(mcdAddrLifetime).Before(now) {
75 addrsAlive = append(addrsAlive, addr)
78 MCDAddrs[nodeId] = addrsAlive
85 func (ctx *Ctx) MCDRx(ifiName string) error {
86 ifi, err := net.InterfaceByName(ifiName)
90 addr := &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName}
91 conn, err := net.ListenMulticastUDP("udp", ifi, addr)
96 buf := make([]byte, mcdPktSize)
101 les := LEs{{"If", ifiName}}
102 n, addr, err = conn.ReadFromUDP(buf)
104 ctx.LogE("mcd", les, err, func(les LEs) string {
105 return fmt.Sprintf("MCD Rx %s/%d", ifiName, MCDPort)
110 ctx.LogD("mcd", les, func(les LEs) string {
112 "MCD Rx %s/%d: got packet with invalid size",
118 _, err = xdr.Unmarshal(bytes.NewReader(buf[:n]), &mcd)
120 ctx.LogD("mcd", les, func(les LEs) string {
122 "MCD Rx %s/%d: can not unmarshal: %s",
123 ifiName, MCDPort, err,
128 if mcd.Magic != MagicNNCPDv1 {
129 ctx.LogD("mcd", les, func(les LEs) string {
131 "MCD Rx %s/%d: unexpected magic: %s",
132 ifiName, MCDPort, hex.EncodeToString(mcd.Magic[:]),
137 node, known := ctx.Neigh[*mcd.Sender]
139 les = append(les, LE{"Node", node.Id})
140 ctx.LogD("mcd", les, func(les LEs) string {
142 "MCD Rx %s/%d: %s: node %s",
143 ifiName, MCDPort, addr, node.Name,
147 ctx.LogD("mcd", les, func(les LEs) string {
149 "MCD Rx %s/%d: %s: unknown node %s",
150 ifiName, MCDPort, addr, node.Id.String(),
156 for _, mcdAddr := range MCDAddrs[*mcd.Sender] {
157 if mcdAddr.Addr.IP.Equal(addr.IP) &&
158 mcdAddr.Addr.Port == addr.Port &&
159 mcdAddr.Addr.Zone == addr.Zone {
160 mcdAddr.lastSeen = time.Now()
167 MCDAddrs[*mcd.Sender] = append(
168 MCDAddrs[*mcd.Sender],
169 &MCDAddr{Addr: *addr, lastSeen: time.Now()},
172 ctx.LogI("mcd-add", les, func(les LEs) string {
173 return fmt.Sprintf("MCD discovered %s's address: %s", node.Name, addr)
180 func (ctx *Ctx) MCDTx(ifiName string, port int, interval time.Duration) error {
181 conn, err := net.DialUDP("udp",
182 &net.UDPAddr{Port: port, Zone: ifiName},
183 &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName},
189 mcd := MCD{Magic: MagicNNCPDv1, Sender: ctx.Self.Id}
190 if _, err := xdr.Marshal(&buf, mcd); err != nil {
194 _, err = conn.Write(buf.Bytes())
198 les := LEs{{"If", ifiName}}
200 ctx.LogD("mcd", les, func(les LEs) string {
203 ifiName, MCDPort, port,
206 _, err = conn.Write(buf.Bytes())
208 ctx.LogE("mcd", les, err, func(les LEs) string {
209 return fmt.Sprintf("MCD on %s/%d/%d", ifiName, MCDPort, port)