doc/call.texi | 6 ++++++ doc/cfg.texi | 11 +++++++++++ doc/cmds.texi | 5 ++++- doc/download.texi | 4 ++++ doc/index.texi | 2 ++ doc/integration.texi | 11 +++++++++-- doc/mcd.texi | 35 +++++++++++++++++++++++++++++++++++ doc/news.ru.texi | 17 ++++++++++++++++- doc/news.texi | 15 +++++++++++++++ src/call.go | 1 + src/cfg.go | 9 +++++++++ src/cmd/nncp-caller/main.go | 27 +++++++++++++++++++++++---- src/cmd/nncp-cfgnew/main.go | 7 +++++++ src/cmd/nncp-daemon/main.go | 25 +++++++++++++++++++++++++ src/ctx.go | 3 +++ src/mcd.go | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/nncp.go | 2 +- src/sp.go | 8 ++++++-- diff --git a/doc/call.texi b/doc/call.texi index 49bb81809abd291ed3361936ba1f309e2c830bc5a899fdf6bc16545a7e16adbd..eb938d3482ca78306ba14b32360b4d4e1434b9ac87ba399ada1ba29445b31f49 100644 --- a/doc/call.texi +++ b/doc/call.texi @@ -32,6 +32,7 @@ { cron: "*/5 * * * * * *" when-tx-exists: true nock: true + mcd-ignore: true }, ] @end verbatim @@ -95,5 +96,10 @@ simultaneous reading of the data for checksumming and writing of the received one, but just sequential writing of the file. Pay attention that you have to make a call to remote node after checksumming is done, to send notification about successful packet reception. + +@anchor{CfgMCDIgnore} +@item mcd-ignore +Ignore @ref{MCD} announcements: do not add MCD addresses for possible +connection attempts. @end table diff --git a/doc/cfg.texi b/doc/cfg.texi index bc53047df4dd5766bed9d2ee3c8deb510e04973857d93275b88c2d18840e2716..18110a868b8a195ffc3fc69558b1c62a90187ff29e869b4af7673397d8420631 100644 --- a/doc/cfg.texi +++ b/doc/cfg.texi @@ -11,6 +11,9 @@ umask: "022" noprogress: true nohdr: true + mcd-listen: ["em0", "igb1"] + mcd-send: {em0: 60, igb1: 5} + notify: { file: { from: nncp@localhost @@ -106,6 +109,14 @@ @option{-progress} command line option anyway. @anchor{CfgNoHdr} @strong{nohdr} option disables @ref{HdrFile, .hdr} files usage. + +@anchor{CfgMCDListen} +@strong{mcd-listen} specifies list of network interfaces +@ref{nncp-caller} will listen for incoming @ref{MCD} announcements. + +@anchor{CfgMCDSend} +@strong{mcd-send} specifies list of network interfaces, and intervals in +seconds, where @ref{nncp-daemon} will send @ref{MCD} announcements. @anchor{CfgNotify} @strong{notify} section contains notification settings for successfully diff --git a/doc/cmds.texi b/doc/cmds.texi index 9d806ec1c0075ec689ff9742812ed41c7a7e0f414c166bee0701cc3e0f64e0d7..1c43a086258ed26b29f88dacc3b167617edee4a612c204fd8c71ed3675343625 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -260,7 +260,7 @@ @example $ nncp-daemon [options] [-maxconn INT] [-bind ADDR] [-inetd] - [-autotoss*] [-nock] + [-autotoss*] [-nock] [-mcd-once] @end example Start listening TCP daemon, wait for incoming connections and run @@ -287,6 +287,9 @@ during the call. All @option{-autotoss-*} options is the same as in @ref{nncp-toss} command. Read @ref{CfgNoCK, more} about @option{-nock} option. + +@option{-mcd-once} option sends @ref{MCD} announcements once and quits. +Could be useful with inetd-based setup, where daemons are not running. @node nncp-exec @section nncp-exec diff --git a/doc/download.texi b/doc/download.texi index 61e24024e7c64014db0bf5defd042fd6e80ed671a5a8ed68d20f9a3f5ab48ce3..f840e477cb53dfe9daa3aaff6b79b00edc407db84b091640bf610bf7d31f3abe 100644 --- a/doc/download.texi +++ b/doc/download.texi @@ -25,6 +25,10 @@ @multitable {XXXXX} {XXXX-XX-XX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} @headitem Version @tab Date @tab Size @tab Tarball @tab SHA256 checksum +@item @ref{Release 6.5.0, 6.5.0} @tab 2021-05-30 @tab 1041 KiB +@tab @url{download/nncp-6.5.0.tar.xz, link} @url{download/nncp-6.5.0.tar.xz.sig, sign} +@tab @code{241D2AA7 27275CCF 86F06797 1AA8B3B8 D625C85C 4279DFDE 560216E3 38670B9A} + @item @ref{Release 6.4.0, 6.4.0} @tab 2021-04-22 @tab 1042 KiB @tab @url{download/nncp-6.4.0.tar.xz, link} @url{download/nncp-6.4.0.tar.xz.sig, sign} @tab @code{3D0D1156 D69AF698 D402663C F84E51CC 3D40A50D 300E34D1 105A6F75 32E4B99B} diff --git a/doc/index.texi b/doc/index.texi index 00bb5f078c74f3a9366fee38434a12a97b373db645bb24fffdcf384ac5852a2a..cda41bb16a296b0dd06e571726bc663715d4fce204a7951ec3157d5b02e2cb3e 100644 --- a/doc/index.texi +++ b/doc/index.texi @@ -53,6 +53,7 @@ * Spool directory: Spool. * Log format: Log. * Packet format: Packet. * Sync protocol: Sync. +* MultiCast Discovery: MCD. * EBlob format: EBlob. * Thanks:: * Contacts and feedback: Contacts. @@ -77,6 +78,7 @@ @include spool.texi @include log.texi @include pkt.texi @include sp.texi +@include mcd.texi @include eblob.texi @include thanks.texi @include contacts.texi diff --git a/doc/integration.texi b/doc/integration.texi index a3c4e14386fb9f3f2265eeb700201b3d6705a7b615e0eb3a126cad61a38210c8..8772ca91622de806a2d42eb7899db0f63312d19f3276534bd1d3462a7a487317 100644 --- a/doc/integration.texi +++ b/doc/integration.texi @@ -55,7 +55,7 @@ delivery via NNCP: @example /usr/local/etc/postfix/master.cf: nncp unix - n n - - pipe - flags=FRqhu user=nncp argv=nncp-exec -quiet $nexthop sendmail $recipient + flags=Rqhu user=nncp argv=nncp-exec -quiet $nexthop sendmail $recipient @end example This runs the @command{nncp-exec} command to place outgoing mail into @@ -67,7 +67,7 @@ shell meta characters in command-line parameters. Pay attention to @code{flags}, containing @code{R}, telling Postfix to include @code{Return-Path:} header. Otherwise that envelope sender -information will be lost. Possibly you will also need somehow to +information may be lost. Possibly you will also need somehow to preserve that header on the receiving side, because @command{sendmail} command will replace it. For example you can rename it before feeding to @command{sendmail} with @@ -75,6 +75,13 @@ @code{reformail -R Return-Path: X-Original-Return-Path: | sendmail}, or extract with: @verbatiminclude sendmail.sh + +Also pay attention that @command{maildrop} does not like @code{From_} +mbox-style header, so you possibly want: + +@example +mailbox_command = reformail -f0 | maildrop -d $@{USER@} +@end example @item Specify that mail for @emph{example.com}, should be delivered via NNCP, to a host named @emph{nncp-host}: diff --git a/doc/mcd.texi b/doc/mcd.texi new file mode 100644 index 0000000000000000000000000000000000000000..0501a76c9143bb0bf7392c60a0ab09be10bea4c4fa79a33e6961008460289799 --- /dev/null +++ b/doc/mcd.texi @@ -0,0 +1,35 @@ +@node MCD +@unnumbered MultiCast Discovery + +MCD is an addition to online @ref{Sync, synchronization protocol}, that +gives ability to make node discovery by sending multicast announcements +in local area network. It is very simple: + +@itemize +@item + @command{nncp-daemon} sends multicast messages about its presence + from time to time. + See @ref{CfgMCDSend, mcd-send} configuration option. +@item + When @command{nncp-caller} sees them, it adds them as the most + preferred addresses to already known ones. If MCD address + announcement was not refreshed after two minutes -- it is removed. + See @ref{CfgMCDListen, mcd-listen} and + @ref{CfgMCDIgnore, mcd-ignore} configuration options. +@end itemize + +MCD announcement is an XDR-encoded packet with only two fields: + +@verbatim ++----------------+ +| MAGIC | SENDER | ++----------------+ +@end verbatim + +Magic number is @verb{|N N C P D 0x00 0x00 0x01|} and sender is 32-byte +identifier of the node. It is sent as UDP packet on IPv6 @verb{|ff02::1|} +multicast address (all hosts in the network) and hard-coded @strong{5400} +port. Operating system will use IPv6 link-local address as a source one, +with the port taken from @command{nncp-daemon}'s @option{-bind} option. +That way, IP packet itself will carry the link-scope reachable address +of the daemon. diff --git a/doc/news.ru.texi b/doc/news.ru.texi index 98f1bebda2e757b8c904f244008e4a0e9c9b86ce43fa40315525eaeb8d5bafae..aa486e0c73ed9f68c8d469afb402ed1755462ff8291ec5ab07a7ddd1bec5f928 100644 --- a/doc/news.ru.texi +++ b/doc/news.ru.texi @@ -1,6 +1,21 @@ @node Новости @section Новости +@node Релиз 6.6.0 +@subsection Релиз 6.6.0 +@itemize + +@item +@command{nncp-daemon}, @command{nncp-call} и @command{nncp-caller} +ожидают завершения всех процессов фоновой проверки контрольных сумм, +после того как соединение закрыто. + +@item +Добавлена возможность определения адреса через multicast оповещение в +локальной сети, так называемый MCD (MultiCast Discovery). + +@end itemize + @node Релиз 6.5.0 @subsection Релиз 6.5.0 @itemize @@ -18,7 +33,7 @@ принятого фрагмента пакета. @item Убирать показ прогресса передачи пакетов когда вызов уже завершён в -@command{nncp-daemon}, @command{nncp-call} and @command{nncp-caller}. +@command{nncp-daemon}, @command{nncp-call} и @command{nncp-caller}. @end itemize diff --git a/doc/news.texi b/doc/news.texi index 4620d4817e41e807e3f364271e8ce25ff21243af1738d1932ec7072ca0576c97..68ad9150fcf96cff8027cf6aa81c3e0832bcda7aaa697c4624f4a7eaedfc3a4b 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -3,6 +3,21 @@ @unnumbered News See also this page @ref{Новости, on russian}. +@node Release 6.6.0 +@section Release 6.6.0 +@itemize + +@item +@command{nncp-daemon}, @command{nncp-call} and @command{nncp-caller} +commands wait for all background checksummers completion after +connection is finished. + +@item +Added possibility of address determining through multicast announcement +in local area network, so called MCD (MultiCast Discovery). + +@end itemize + @node Release 6.5.0 @section Release 6.5.0 @itemize diff --git a/src/call.go b/src/call.go index 55ddd8b75f0fb80c2e4eddfcf793e1b01e68be1e81d578da17e8cf51a60f1a4d..8df270d4ec26a0154244c3ed482baf349596e919644128b2e5cd749d90973531 100644 --- a/src/call.go +++ b/src/call.go @@ -37,6 +37,7 @@ OnlineDeadline time.Duration MaxOnlineTime time.Duration WhenTxExists bool NoCK bool + MCDIgnore bool AutoToss bool AutoTossDoSeen bool diff --git a/src/cfg.go b/src/cfg.go index 406d41532e34d0110cdc6d01f529d9efb499e7643654f50893fefce9bf53edaf..ba15c11c337307b6cff9067f1f6a04fff9ec38beb92acd4827d22defe5f505a6 100644 --- a/src/cfg.go +++ b/src/cfg.go @@ -83,6 +83,7 @@ OnlineDeadline *uint `json:"onlinedeadline,omitempty"` MaxOnlineTime *uint `json:"maxonlinetime,omitempty"` WhenTxExists *bool `json:"when-tx-exists,omitempty"` NoCK *bool `json:"nock"` + MCDIgnore *bool `json:"mcd-ignore"` AutoToss *bool `json:"autotoss,omitempty"` AutoTossDoSeen *bool `json:"autotoss-doseen,omitempty"` @@ -125,6 +126,9 @@ Notify *NotifyJSON `json:"notify,omitempty"` Self *NodeOurJSON `json:"self"` Neigh map[string]NodeJSON `json:"neigh"` + + MCDRxIfis []string `json:"mcd-listen"` + MCDTxIfis map[string]int `json:"mcd-send"` } func NewNode(name string, cfg NodeJSON) (*Node, error) { @@ -289,6 +293,9 @@ } if callCfg.NoCK != nil { call.NoCK = *callCfg.NoCK } + if callCfg.MCDIgnore != nil { + call.MCDIgnore = *callCfg.MCDIgnore + } if callCfg.AutoToss != nil { call.AutoToss = *callCfg.AutoToss } @@ -477,6 +484,8 @@ HdrUsage: hdrUsage, Self: self, Neigh: make(map[NodeId]*Node, len(cfgJSON.Neigh)), Alias: make(map[string]*NodeId), + MCDRxIfis: cfgJSON.MCDRxIfis, + MCDTxIfis: cfgJSON.MCDTxIfis, } if cfgJSON.Notify != nil { if cfgJSON.Notify.File != nil { diff --git a/src/cmd/nncp-caller/main.go b/src/cmd/nncp-caller/main.go index c641928428a48d0cacaa97df93ed2e4ae398660284c2aa3f37dbcd217f184bd4..f1ae32fb006956c170c616e7261134928552fd33abe62dca8069964d60a1f553 100644 --- a/src/cmd/nncp-caller/main.go +++ b/src/cmd/nncp-caller/main.go @@ -121,19 +121,25 @@ nodes = append(nodes, node) } } + for _, ifiName := range ctx.MCDRxIfis { + if err = ctx.MCDRx(ifiName); err != nil { + log.Fatalln("Can not run MCD reception:", err) + } + } + var wg sync.WaitGroup for _, node := range nodes { for i, call := range node.Calls { wg.Add(1) go func(node *nncp.Node, i int, call *nncp.Call) { defer wg.Done() - var addrs []string + var addrsFromCfg []string if call.Addr == nil { for _, addr := range node.Addrs { - addrs = append(addrs, addr) + addrsFromCfg = append(addrsFromCfg, addr) } } else { - addrs = append(addrs, *call.Addr) + addrsFromCfg = append(addrsFromCfg, *call.Addr) } les := nncp.LEs{{K: "Node", V: node.Id}, {K: "CallIndex", V: i}} logMsg := func(les nncp.LEs) string { @@ -197,9 +203,22 @@ call.AutoTossNoTrns || *autoTossNoTrns, ) } + var addrs []string + if !call.MCDIgnore { + nncp.MCDAddrsM.RLock() + for _, mcdAddr := range nncp.MCDAddrs[*node.Id] { + ctx.LogD("caller", les, func(les nncp.LEs) string { + return logMsg(les) + ": adding MCD address: " + + mcdAddr.Addr.String() + }) + addrs = append(addrs, mcdAddr.Addr.String()) + } + nncp.MCDAddrsM.RUnlock() + } + ctx.CallNode( node, - addrs, + append(addrs, addrsFromCfg...), call.Nice, call.Xx, call.RxRate, diff --git a/src/cmd/nncp-cfgnew/main.go b/src/cmd/nncp-cfgnew/main.go index b615a712955a9062a88fc1280329399404dbe3bcad36aa2b1ab2f147798f6de1..f2f20262512db557073e73563834be430d1feb1e685f562165246460fe7b1f5f 100644 --- a/src/cmd/nncp-cfgnew/main.go +++ b/src/cmd/nncp-cfgnew/main.go @@ -109,6 +109,12 @@ # noprogress: true # Do not use .hdr files # nohdr: true + # MultiCast Discovery: + # List of interfaces where to listen for MCD announcements + # mcd-listen: ["em0", "igb1"] + # Interfaces and intervals (in seconds) where to send MCD announcements + # mcd-send: {em0: 60, igb1: 5} + # Enable notification email sending # notify: { # file: { @@ -216,6 +222,7 @@ # # xx: rx # # addr: lan # # when-tx-exists: true # # nock: true + # # mcd-ignore: true # # # # autotoss: false # # autotoss-doseen: true diff --git a/src/cmd/nncp-daemon/main.go b/src/cmd/nncp-daemon/main.go index ac2f576498c21dd710799898a64d739b48a212259a95de82ac22cb1a5829d2f0..37da4684db1b30c6955818d23d38a732ef393f5d969da677c0f347ef00933384 100644 --- a/src/cmd/nncp-daemon/main.go +++ b/src/cmd/nncp-daemon/main.go @@ -24,6 +24,8 @@ "fmt" "log" "net" "os" + "strconv" + "strings" "time" "github.com/dustin/go-humanize" @@ -136,6 +138,7 @@ bind = flag.String("bind", "[::]:5400", "Address to bind to") inetd = flag.Bool("inetd", false, "Is it started as inetd service") maxConn = flag.Int("maxconn", 128, "Maximal number of simultaneous connections") noCK = flag.Bool("nock", false, "Do no checksum checking") + mcdOnce = flag.Bool("mcd-once", false, "Send MCDs once and quit") spoolPath = flag.String("spool", "", "Override path to spool") logPath = flag.String("log", "", "Override path to logfile") quiet = flag.Bool("quiet", false, "Print only errors") @@ -213,10 +216,32 @@ conn.Close() // #nosec G104 return } + cols := strings.Split(*bind, ":") + port, err := strconv.Atoi(cols[len(cols)-1]) + if err != nil { + log.Fatalln("Can not parse port:", err) + } + + if *mcdOnce { + for ifiName := range ctx.MCDTxIfis { + if err = ctx.MCDTx(ifiName, port, 0); err != nil { + log.Fatalln("Can not do MCD transmission:", err) + } + } + return + } + ln, err := net.Listen("tcp", *bind) if err != nil { log.Fatalln("Can not listen:", err) } + + for ifiName, secs := range ctx.MCDTxIfis { + if err = ctx.MCDTx(ifiName, port, time.Duration(secs)*time.Second); err != nil { + log.Fatalln("Can not run MCD transmission:", err) + } + } + ln = netutil.LimitListener(ln, *maxConn) for { conn, err := ln.Accept() diff --git a/src/ctx.go b/src/ctx.go index 30deaffa96e232c97421deefa3db792e826a8a5ff243de1f9b47039c4f76a7da..36e456e631ebf4c4c86337ada8624bb7c64e1e61823a80b26424c28fef048873 100644 --- a/src/ctx.go +++ b/src/ctx.go @@ -46,6 +46,9 @@ Debug bool NotifyFile *FromToJSON NotifyFreq *FromToJSON NotifyExec map[string]*FromToJSON + + MCDRxIfis []string + MCDTxIfis map[string]int } func (ctx *Ctx) FindNode(id string) (*Node, error) { diff --git a/src/mcd.go b/src/mcd.go new file mode 100644 index 0000000000000000000000000000000000000000..3d46ec1d39c587aecf9456a74f4fcb0585507fac26f093f0387dba3f8284fd3b --- /dev/null +++ b/src/mcd.go @@ -0,0 +1,216 @@ +/* +NNCP -- Node to Node copy, utilities for store-and-forward data exchange +Copyright (C) 2016-2021 Sergey Matveev + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +package nncp + +import ( + "bytes" + "encoding/hex" + "fmt" + "net" + "sync" + "time" + + xdr "github.com/davecgh/go-xdr/xdr2" +) + +const ( + MCDPort = 5400 +) + +type MCD struct { + Magic [8]byte + Sender *NodeId +} + +type MCDAddr struct { + Addr net.UDPAddr + lastSeen time.Time +} + +var ( + MagicNNCPDv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'D', 0, 0, 1} + + mcdIP = net.ParseIP("ff02::1") + mcdAddrLifetime = 2 * time.Minute + + mcdPktSize int + MCDAddrs map[NodeId][]*MCDAddr + MCDAddrsM sync.RWMutex +) + +func init() { + nodeId := new(NodeId) + var buf bytes.Buffer + mcd := MCD{Sender: nodeId} + if _, err := xdr.Marshal(&buf, mcd); err != nil { + panic(err) + } + mcdPktSize = buf.Len() + + MCDAddrs = make(map[NodeId][]*MCDAddr) + go func() { + for { + time.Sleep(time.Minute) + MCDAddrsM.Lock() + now := time.Now() + for nodeId, addrs := range MCDAddrs { + addrsAlive := make([]*MCDAddr, 0, len(addrs)) + for _, addr := range addrs { + if !addr.lastSeen.Add(mcdAddrLifetime).Before(now) { + addrsAlive = append(addrsAlive, addr) + } + } + MCDAddrs[nodeId] = addrsAlive + } + MCDAddrsM.Unlock() + } + }() +} + +func (ctx *Ctx) MCDRx(ifiName string) error { + ifi, err := net.InterfaceByName(ifiName) + if err != nil { + return err + } + addr := &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName} + conn, err := net.ListenMulticastUDP("udp", ifi, addr) + if err != nil { + return err + } + go func() { + buf := make([]byte, mcdPktSize) + var n int + var mcd MCD + ListenCycle: + for { + les := LEs{{"If", ifiName}} + n, addr, err = conn.ReadFromUDP(buf) + if err != nil { + ctx.LogE("mcd", les, err, func(les LEs) string { + return fmt.Sprintf("MCD Rx %s/%d", ifiName, MCDPort) + }) + continue + } + if n != mcdPktSize { + ctx.LogD("mcd", les, func(les LEs) string { + return fmt.Sprintf( + "MCD Rx %s/%d: got packet with invalid size", + ifiName, MCDPort, + ) + }) + continue + } + _, err = xdr.Unmarshal(bytes.NewReader(buf[:n]), &mcd) + if err != nil { + ctx.LogD("mcd", les, func(les LEs) string { + return fmt.Sprintf( + "MCD Rx %s/%d: can not unmarshal: %s", + ifiName, MCDPort, err, + ) + }) + continue + } + if mcd.Magic != MagicNNCPDv1 { + ctx.LogD("mcd", les, func(les LEs) string { + return fmt.Sprintf( + "MCD Rx %s/%d: unexpected magic: %s", + ifiName, MCDPort, hex.EncodeToString(mcd.Magic[:]), + ) + }) + continue + } + node, known := ctx.Neigh[*mcd.Sender] + if known { + les = append(les, LE{"Node", node.Id}) + ctx.LogD("mcd", les, func(les LEs) string { + return fmt.Sprintf( + "MCD Rx %s/%d: %s: node %s", + ifiName, MCDPort, addr, node.Name, + ) + }) + } else { + ctx.LogD("mcd", les, func(les LEs) string { + return fmt.Sprintf( + "MCD Rx %s/%d: %s: unknown node %s", + ifiName, MCDPort, addr, node.Id.String(), + ) + }) + continue + } + MCDAddrsM.RLock() + for _, mcdAddr := range MCDAddrs[*mcd.Sender] { + if mcdAddr.Addr.IP.Equal(addr.IP) && + mcdAddr.Addr.Port == addr.Port && + mcdAddr.Addr.Zone == addr.Zone { + mcdAddr.lastSeen = time.Now() + MCDAddrsM.RUnlock() + continue ListenCycle + } + } + MCDAddrsM.RUnlock() + MCDAddrsM.Lock() + MCDAddrs[*mcd.Sender] = append( + MCDAddrs[*mcd.Sender], + &MCDAddr{Addr: *addr, lastSeen: time.Now()}, + ) + MCDAddrsM.Unlock() + ctx.LogI("mcd-add", les, func(les LEs) string { + return fmt.Sprintf("MCD discovered %s's address: %s", node.Name, addr) + }) + } + }() + return nil +} + +func (ctx *Ctx) MCDTx(ifiName string, port int, interval time.Duration) error { + conn, err := net.DialUDP("udp", + &net.UDPAddr{Port: port, Zone: ifiName}, + &net.UDPAddr{IP: mcdIP, Port: MCDPort, Zone: ifiName}, + ) + if err != nil { + return err + } + var buf bytes.Buffer + mcd := MCD{Magic: MagicNNCPDv1, Sender: ctx.Self.Id} + if _, err := xdr.Marshal(&buf, mcd); err != nil { + panic(err) + } + if interval == 0 { + _, err = conn.Write(buf.Bytes()) + return err + } + go func() { + les := LEs{{"If", ifiName}} + for { + ctx.LogD("mcd", les, func(les LEs) string { + return fmt.Sprintf( + "MCD Tx %s/%d/%d", + ifiName, MCDPort, port, + ) + }) + _, err = conn.Write(buf.Bytes()) + if err != nil { + ctx.LogE("mcd", les, err, func(les LEs) string { + return fmt.Sprintf("MCD on %s/%d/%d", ifiName, MCDPort, port) + }) + } + time.Sleep(interval) + } + }() + return nil +} diff --git a/src/nncp.go b/src/nncp.go index 4330af9bf07f4b4199c4ac6718fe7ddccd0958f7938745681a1dbfb9d8f96eda..496beaa67609e0e37d46ee0db4f29f42222b92036db046c7cb761579003cc36a 100644 --- a/src/nncp.go +++ b/src/nncp.go @@ -40,7 +40,7 @@ const Base32Encoded32Len = 52 var ( - Version string = "6.5.0" + Version string = "6.6.0" Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding) ) diff --git a/src/sp.go b/src/sp.go index 20fac709de09e812b85a2b2affb5946ecc582c01f35fb8da494798291bc300cf..efaa4d146306c7aae501feb0f784c8ae681d5236f240ae06ca2ada1bc1eaca68 100644 --- a/src/sp.go +++ b/src/sp.go @@ -65,7 +65,8 @@ DefaultDeadline = 10 * time.Second PingTimeout = time.Minute - spCheckers = make(map[NodeId]*SPCheckerQueues) + spCheckers = make(map[NodeId]*SPCheckerQueues) + SPCheckersWg sync.WaitGroup ) type FdAndFullSize struct { @@ -282,6 +283,7 @@ {"XX", string(TRx)}, {"Node", nodeId}, {"Pkt", pktName}, } + SPCheckersWg.Add(1) ctx.LogD("sp-checker", les, func(les LEs) string { return fmt.Sprintf("Checksumming %s/rx/%s", ctx.NodeName(nodeId), pktName) }) @@ -302,6 +304,7 @@ "Packet %s is retreived (%s)", pktName, humanize.IBytes(uint64(size)), ) }) + SPCheckersWg.Done() go func(hsh *[32]byte) { checked <- hsh }(hshValue) } } @@ -1135,8 +1138,9 @@ func (state *SPState) Wait() { state.wg.Wait() close(state.payloads) close(state.pings) + state.Duration = time.Now().Sub(state.started) + SPCheckersWg.Wait() state.dirUnlock() - state.Duration = time.Now().Sub(state.started) state.RxSpeed = state.RxBytes state.TxSpeed = state.TxBytes rxDuration := int64(state.RxLastSeen.Sub(state.started).Seconds())