]> Cypherpunks.ru repositories - nncp.git/commitdiff
Merge branch 'develop' v5.3.0
authorSergey Matveev <stargrave@stargrave.org>
Sun, 22 Dec 2019 18:13:32 +0000 (21:13 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sun, 22 Dec 2019 18:13:32 +0000 (21:13 +0300)
57 files changed:
VERSION
doc/Makefile
doc/cmds.texi
doc/download.texi
doc/index.texi
doc/install.texi
doc/news.ru.texi
doc/news.texi
doc/sp.texi
doc/sp.txt
doc/spool.texi
doc/thanks.texi
makedist.sh
ports/nncp/Makefile
src/call.go
src/cfg.go
src/check.go
src/chunked.go
src/cmd/nncp-bundle/main.go
src/cmd/nncp-call/main.go
src/cmd/nncp-caller/main.go
src/cmd/nncp-cfgenc/main.go
src/cmd/nncp-cfgmin/main.go
src/cmd/nncp-cfgnew/main.go
src/cmd/nncp-check/main.go
src/cmd/nncp-daemon/main.go
src/cmd/nncp-exec/main.go
src/cmd/nncp-file/main.go
src/cmd/nncp-freq/main.go
src/cmd/nncp-log/main.go
src/cmd/nncp-pkt/main.go
src/cmd/nncp-reass/main.go
src/cmd/nncp-rm/main.go
src/cmd/nncp-stat/main.go
src/cmd/nncp-toss/main.go
src/cmd/nncp-xfer/main.go
src/ctx.go
src/eblob.go
src/go.mod
src/go.sum
src/humanizer.go
src/jobs.go
src/lockdir.go
src/log.go
src/nncp.go
src/node.go
src/pipe.go
src/pkt.go
src/pkt_test.go
src/progress.go
src/sp.go
src/tmp.go
src/toss.go
src/toss_test.go
src/tx.go
src/tx_test.go
src/via.go

diff --git a/VERSION b/VERSION
index 26d99a283f21aa125ccd146e50e76a9b643f54f1..03f488b076ae34efcfad44444186507b6415e8cc 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-5.2.1
+5.3.0
index 205c2b4ee40c99361eda25fe9a9493b64f77029b..c3af5d45e6c738334f98ff07db1658cb18c72553 100644 (file)
@@ -13,7 +13,7 @@ CSS != cat style.css
 nncp.html: *.texi sp.utxt pedro.txt
        rm -f nncp.html/*.html
        $(MAKEINFO) --html \
-               --set-customization-variable EXTRA_HEAD='<link rev="made" href="mailto:stargrave+webmaster@nncpgo.org">' \
+               --set-customization-variable EXTRA_HEAD='<link rev="made" href="mailto:webmaster@nncpgo.org">' \
                --set-customization-variable CSS_LINES='$(CSS)' \
                --set-customization-variable SHOW_TITLE=0 \
                --set-customization-variable USE_ACCESSKEY=0 \
index 2606b6ee12bd9e59c67726eb57a93c1ec5c0999a..c4c6d01f6de38728823a29473b875336320871ab 100644 (file)
@@ -250,10 +250,12 @@ can handle. @option{-bind} option specifies @option{addr:port} it must
 bind to and listen.
 
 It could be run as @command{inetd} service, by specifying
-@option{-inetd} option. Example inetd-entry:
+@option{-inetd} option. Pay attention that because it uses stdin/stdout,
+it can not effectively work with IO timeouts and connection closing can
+propagate up to 5 minutes in practice. Example inetd-entry:
 
 @verbatim
-uucp   stream  tcp6    nowait  nncpuser        /usr/local/bin/nncp-daemon      nncp-daemon -inetd
+uucp   stream  tcp6    nowait  nncpuser        /usr/local/bin/nncp-daemon      nncp-daemon -quiet -inetd
 @end verbatim
 
 @node nncp-exec
index 2eb52ff9641c74f42a05c72f80f22f59fdf07645..fd6c17d9a1910245bca8a06a031765db2a51be77 100644 (file)
@@ -24,6 +24,10 @@ Tarballs include all necessary required libraries:
 @multitable {XXXXX} {XXXX-XX-XX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
 @headitem Version @tab Date @tab Size @tab Tarball @tab SHA256 checksum
 
+@item @ref{Release 5.2.1, 5.2.1} @tab 2019-12-15 @tab 1109 KiB
+@tab @url{download/nncp-5.2.1.tar.xz, link} @url{download/nncp-5.2.1.tar.xz.sig, sign}
+@tab @code{983D1A8A 4398C281 76356AE1 C5541124 B0755555 D115063B D1388F85 9C4A6B3E}
+
 @item @ref{Release 5.2.0, 5.2.0} @tab 2019-12-14 @tab 1109 KiB
 @tab @url{download/nncp-5.2.0.tar.xz, link} @url{download/nncp-5.2.0.tar.xz.sig, sign}
 @tab @code{FFC55467 8B4ECCA6 92D90F42 ACC0286D 209E054E EA1CBF87 0307003E CF219610}
index a83ea31be352e50881770dd47b23e6262883cb4d..0278b86faa077d9e3e18ad890ed424772dc60240 100644 (file)
@@ -6,7 +6,7 @@
 This manual is for NNCP (Node to Node copy) --  collection of utilities
 simplifying secure store-and-forward files and mail exchanging.
 
-Copyright @copyright{} 2016-2019 @email{stargrave@@stargrave.org, Sergey Matveev}
+Copyright @copyright{} 2016-2020 @email{stargrave@@stargrave.org, Sergey Matveev}
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
index 1c8497e6f2ab6679a0d003e69e03d26779883849..5db01d04bbe4c770d1768a205e9befd393638b6b 100644 (file)
@@ -1,7 +1,7 @@
 @node Installation
 @unnumbered Installation
 
-@set VERSION 5.2.1
+@set VERSION 5.3.0
 
 Possibly NNCP package already exists for your distribution:
 
@@ -9,6 +9,8 @@ Possibly NNCP package already exists for your distribution:
 @item @url{https://www.freshports.org/net/nncp/, FreeBSD ports}
 @item @url{https://github.com/DragonFlyBSD/DPorts/tree/master/net/nncp, DragonFly BSD ports}
 @item @url{https://github.com/void-linux/void-packages/blob/master/srcpkgs/nncp/template, Void Linux}
+@item @url{https://qa.debian.org/developer.php?login=jgoerzen@@complete.org, Debian packages} (pending inclusion, maintainer's page)
+@item @url{https://github.com/NixOS/nixpkgs/pull/75772, NixOS packages} (pending inclusion, maintainer's page)
 @end itemize
 
 NNCP should run on any POSIX-compatible operating system.
index 2e5d927bdf90546a1bcd4194767b9b676a0c57c7..ba347167b8a4416a48c6fa79f943b5d3e8d0920b 100644 (file)
@@ -1,6 +1,38 @@
 @node Новости
 @section Новости
 
+@node Релиз 5.3.0
+@subsection Релиз 5.3.0
+@itemize
+
+@item
+Сообщения прогресса содержат префикс, поясняющий выполняемое действие.
+
+@item
+Исправлено не происходящее дополнение (padding) handshake сообщений.
+
+@item
+Завершать все порождаемые в SP протоколе горутины, меньше утечек памяти.
+
+@item
+SP протокол порождает меньше вызовов записей (соответственно, и TCP
+пакетов) в сокет.
+
+@item
+Проверять @option{onlinedeadline} и @option{maxonlinetime} ежесекундно,
+независимо от чтения из сокета (раз в 10 секунд в худшем случае).
+
+@item
+Раз в минуту, если нет более никакого другого трафика, посылаются PING
+пакеты в SP-соединении. Это позволит быстрее понимать что соединение
+более не работоспособно.
+
+@item
+@command{nncp-toss} использует lock-file для предотвращения
+одновременной обработки зашифрованных пакетов.
+
+@end itemize
+
 @node Релиз 5.2.1
 @subsection Релиз 5.2.1
 @itemize
index 6cdc9981afaf2033bc48a0c4e0adde26e929ae03..9d9e877d85548015168275447680c26bead33777 100644 (file)
@@ -3,6 +3,36 @@
 
 See also this page @ref{Новости, on russian}.
 
+@node Release 5.3.0
+@section Release 5.3.0
+@itemize
+
+@item
+Progress messages contain prefix, describing the running action.
+
+@item
+Fixed not occurring handshake messages padding.
+
+@item
+Finish all SP protocol related goroutines, less memory leak.
+
+@item
+SP protocol generates less socket write calls, thus generating less TCP
+packets.
+
+@item
+Check @option{onlinedeadline} and @option{maxonlinetime} options every
+second, independently from socket reads (up to 10 seconds).
+
+@item
+Once per minute, if no other traffic exists, PING packets are sent in
+SP-connection. That allows faster determining of connection unworkability.
+
+@item
+@command{nncp-toss} uses lock-file to prevent simultaneous tossing.
+
+@end itemize
+
 @node Release 5.2.1
 @section Release 5.2.1
 @itemize
index d6be2d927f7977aca6b750a2c22b2152ea6b1179..ef00f63404bc3b80221d3e62a2e4b9ec40f4289d 100644 (file)
@@ -61,6 +61,15 @@ just an unsigned integer telling what body structure follows.
 +------+
 @end verbatim
 
+@item PING
+    Dummy packet only used for determining workability of the connection.
+
+@verbatim
++------+
+| PING |
++------+
+@end verbatim
+
 @item INFO
     Information about the file we have for transmission.
 
@@ -195,13 +204,20 @@ then run background integrity checker on it. If check succeeds, then
 delete @file{.part} suffix from file's name and send @emph{DONE} packet.
 
 @item When @emph{DONE} packet received, delete corresponding file.
+
 @item When @emph{HALT} packet received, empty file sending queue.
 
 @item Each second, node checks: are there any new @emph{tx} packets
 appeared and queues corresponding @emph{INFO} packets.
 
-@item If no packets are sent and received during @ref{CfgOnlineDeadline,
-onlinedeadline} duration, then close the connection. There is no
-explicit indication that session is over.
+@item Each minute, if no packets were sent, node sends @emph{PING}
+packet.
+
+@item If no non-PING packets are sent and received during
+@ref{CfgOnlineDeadline, onlinedeadline} duration, then close the
+connection. There is no explicit indication that session is over.
+
+@item If no packets are received during two minutes (two PING timeouts),
+then close the connection.
 
 @end enumerate
index 461c95aaa045b8c5790295d2f13f1dc5b03a19b4..b86ee687b385cdb29e50e6e77bc22cd34008d988 100644 (file)
@@ -13,7 +13,7 @@ Initiator -> Responder : [e, es, s, ss], INFO..., HALT...
 Initiator <- Responder : [e, ee, se], INFO..., HALT...
 Initiator -> Responder : INFO..., FREQ..., DONE...
 Initiator <- Responder : INFO..., FREQ..., DONE...
-Initiator -> Responder : FILE..., INFO..., DONE...
-Initiator <- Responder : FILE..., INFO..., DONE...
+Initiator -> Responder : FILE..., INFO..., DONE..., PING
+Initiator <- Responder : FILE..., INFO..., DONE..., PING
 
 @enduml
index 98532ae803597b7784ec5eb8c9f0ae76cd4b6350..5e7812d50b6a0944356aed56ce12bcc488662b55 100644 (file)
@@ -10,6 +10,7 @@ spool/tmp/
 spool/2WHB...OABQ/rx.lock
 spool/2WHB...OABQ/rx/5ZIB...UMKW.part
 spool/2WHB...OABQ/tx.lock
+spool/2WHB...OABQ/toss.lock
 spool/BYRR...CG6Q/rx.lock
 spool/BYRR...CG6Q/rx/
 spool/BYRR...CG6Q/tx.lock
index d42954f34846fb0c0972c1efb4026313bfc94745..f118c0ba937cb0cd522aef1c2a3592e51fe66624 100644 (file)
@@ -4,8 +4,11 @@
 There are people deserving to be thanked for helping this project:
 
 @itemize
+
 @item Shawn K. Quinn for his descriptive instructions about building
 NNCP under Ubuntu GNU/Linux distributions and bug reports.
+
 @item @url{mailto:jgoerzen@@complete.org, John Goerzen} for his feature
 suggestions and Debian package maintenance.
+
 @end itemize
index 5e66e0abbd7da029c5a03680c674e2dc4246b945..d8ba2e8b0baec39ea56f8080c73caf857f4472d1 100755 (executable)
@@ -108,23 +108,23 @@ You can obtain releases source code prepared tarballs on
 @url{http://www.nncpgo.org/}.
 EOF
 perl -i -ne 'print unless /include pedro/' doc/index.texi doc/about.ru.texi
+perl -p -i -e 's/^(.verbatiminclude) .*$/$1 PUBKEY.asc/g' doc/integrity.texi
+mv doc/.well-known/openpgpkey/hu/i4cdqgcarfjdjnba6y4jnf498asg8c6p.asc PUBKEY.asc
+ln -s ../PUBKEY.asc doc
 make -C doc
 
 ########################################################################
 # Supplementary files autogeneration
 ########################################################################
-texi=`mktemp`
+texi=$(TMPDIR=doc mktemp)
 
 cat > $texi <<EOF
 \input texinfo
 @documentencoding UTF-8
 @settitle NEWS
-
 @node News
 @unnumbered News
-
 `sed -n '5,$p' < doc/news.texi`
-
 @bye
 EOF
 makeinfo --plaintext -o NEWS $texi
@@ -133,40 +133,30 @@ cat > $texi <<EOF
 \input texinfo
 @documentencoding UTF-8
 @settitle NEWS.RU
-
 @node Новости
 @unnumbered Новости
-
 `sed -n '3,$p' < doc/news.ru.texi | sed 's/^@subsection/@section/'`
-
 @bye
 EOF
 makeinfo --plaintext -o NEWS.RU $texi
 
 rm -f $texi
 
-texi=$(TMPDIR=doc mktemp)
 cat > $texi <<EOF
 \input texinfo
 @documentencoding UTF-8
 @settitle INSTALL
-
 @include install.texi
-
 @bye
 EOF
 makeinfo --plaintext -o INSTALL $texi
 rm -f $texi
 
-texi=`mktemp`
-
 cat > $texi <<EOF
 \input texinfo
 @documentencoding UTF-8
 @settitle THANKS
-
 `cat doc/thanks.texi`
-
 @bye
 EOF
 makeinfo --plaintext -o THANKS $texi
@@ -174,7 +164,6 @@ rm -f $texi
 
 ########################################################################
 
-mv doc/.well-known/openpgpkey/hu/i4cdqgcarfjdjnba6y4jnf498asg8c6p.asc PUBKEY.asc
 rm -r doc/.gitignore doc/.well-known doc/nncp.html/.well-known
 
 find . -type d -exec chmod 755 {} \;
index 6dca46acaaf714e7a90180959966a44eb38c4fe5..3b5109ba60f467b98edf963586992ebc2e38cdcd 100644 (file)
@@ -1,7 +1,7 @@
 # $FreeBSD: head/net/nncp/Makefile 517819 2019-11-17 11:51:56Z dmgk $
 
 PORTNAME=      nncp
-DISTVERSION=   5.2.1
+DISTVERSION=   5.3.0
 CATEGORIES=    net
 MASTER_SITES=  http://www.nncpgo.org/download/
 
index 034ba286884496da6f2a7384ef6c18e0652ded22..339549825004f97da322b5cd00a3d44eb6c0fb07 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -19,6 +19,7 @@ package nncp
 
 import (
        "net"
+       "time"
 
        "github.com/gorhill/cronexpr"
 )
@@ -30,8 +31,8 @@ type Call struct {
        RxRate         int
        TxRate         int
        Addr           *string
-       OnlineDeadline uint
-       MaxOnlineTime  uint
+       OnlineDeadline time.Duration
+       MaxOnlineTime  time.Duration
 }
 
 func (ctx *Ctx) CallNode(
@@ -40,7 +41,7 @@ func (ctx *Ctx) CallNode(
        nice uint8,
        xxOnly TRxTx,
        rxRate, txRate int,
-       onlineDeadline, maxOnlineTime uint,
+       onlineDeadline, maxOnlineTime time.Duration,
        listOnly bool,
        onlyPkts map[[32]byte]bool,
 ) (isGood bool) {
index 615e382410a6f52bd067e40717356a3b9c6e0950..f003dcb0bd85dcd2bc31585a69d1a03a515b860d 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -25,6 +25,7 @@ import (
        "os"
        "path"
        "strconv"
+       "time"
 
        "github.com/gorhill/cronexpr"
        "github.com/hjson/hjson-go"
@@ -116,13 +117,13 @@ type CfgJSON struct {
        Neigh map[string]NodeJSON `json:"neigh"`
 }
 
-func NewNode(name string, yml NodeJSON) (*Node, error) {
-       nodeId, err := NodeIdFromString(yml.Id)
+func NewNode(name string, cfg NodeJSON) (*Node, error) {
+       nodeId, err := NodeIdFromString(cfg.Id)
        if err != nil {
                return nil, err
        }
 
-       exchPub, err := FromBase32(yml.ExchPub)
+       exchPub, err := FromBase32(cfg.ExchPub)
        if err != nil {
                return nil, err
        }
@@ -130,7 +131,7 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
                return nil, errors.New("Invalid exchPub size")
        }
 
-       signPub, err := FromBase32(yml.SignPub)
+       signPub, err := FromBase32(cfg.SignPub)
        if err != nil {
                return nil, err
        }
@@ -139,8 +140,8 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
        }
 
        var noisePub []byte
-       if yml.NoisePub != nil {
-               noisePub, err = FromBase32(*yml.NoisePub)
+       if cfg.NoisePub != nil {
+               noisePub, err = FromBase32(*cfg.NoisePub)
                if err != nil {
                        return nil, err
                }
@@ -150,8 +151,8 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
        }
 
        var incoming *string
-       if yml.Incoming != nil {
-               inc := path.Clean(*yml.Incoming)
+       if cfg.Incoming != nil {
+               inc := path.Clean(*cfg.Incoming)
                if !path.IsAbs(inc) {
                        return nil, errors.New("Incoming path must be absolute")
                }
@@ -162,8 +163,8 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
        freqChunked := int64(MaxFileSize)
        var freqMinSize int64
        freqMaxSize := int64(MaxFileSize)
-       if yml.Freq != nil {
-               f := yml.Freq
+       if cfg.Freq != nil {
+               f := cfg.Freq
                if f.Path != nil {
                        fPath := path.Clean(*f.Path)
                        if !path.IsAbs(fPath) {
@@ -186,44 +187,44 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
        }
 
        defRxRate := 0
-       if yml.RxRate != nil && *yml.RxRate > 0 {
-               defRxRate = *yml.RxRate
+       if cfg.RxRate != nil && *cfg.RxRate > 0 {
+               defRxRate = *cfg.RxRate
        }
        defTxRate := 0
-       if yml.TxRate != nil && *yml.TxRate > 0 {
-               defTxRate = *yml.TxRate
+       if cfg.TxRate != nil && *cfg.TxRate > 0 {
+               defTxRate = *cfg.TxRate
        }
 
-       defOnlineDeadline := uint(DefaultDeadline)
-       if yml.OnlineDeadline != nil {
-               if *yml.OnlineDeadline <= 0 {
+       defOnlineDeadline := DefaultDeadline
+       if cfg.OnlineDeadline != nil {
+               if *cfg.OnlineDeadline <= 0 {
                        return nil, errors.New("OnlineDeadline must be at least 1 second")
                }
-               defOnlineDeadline = *yml.OnlineDeadline
+               defOnlineDeadline = time.Duration(*cfg.OnlineDeadline) * time.Second
        }
-       var defMaxOnlineTime uint
-       if yml.MaxOnlineTime != nil {
-               defMaxOnlineTime = *yml.MaxOnlineTime
+       var defMaxOnlineTime time.Duration
+       if cfg.MaxOnlineTime != nil {
+               defMaxOnlineTime = time.Duration(*cfg.MaxOnlineTime) * time.Second
        }
 
        var calls []*Call
-       for _, callYml := range yml.Calls {
-               expr, err := cronexpr.Parse(callYml.Cron)
+       for _, callCfg := range cfg.Calls {
+               expr, err := cronexpr.Parse(callCfg.Cron)
                if err != nil {
                        return nil, err
                }
 
                nice := uint8(255)
-               if callYml.Nice != nil {
-                       nice, err = NicenessParse(*callYml.Nice)
+               if callCfg.Nice != nil {
+                       nice, err = NicenessParse(*callCfg.Nice)
                        if err != nil {
                                return nil, err
                        }
                }
 
                var xx TRxTx
-               if callYml.Xx != nil {
-                       switch *callYml.Xx {
+               if callCfg.Xx != nil {
+                       switch *callCfg.Xx {
                        case "rx":
                                xx = TRx
                        case "tx":
@@ -234,34 +235,34 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
                }
 
                rxRate := defRxRate
-               if callYml.RxRate != nil {
-                       rxRate = *callYml.RxRate
+               if callCfg.RxRate != nil {
+                       rxRate = *callCfg.RxRate
                }
                txRate := defTxRate
-               if callYml.TxRate != nil {
-                       txRate = *callYml.TxRate
+               if callCfg.TxRate != nil {
+                       txRate = *callCfg.TxRate
                }
 
                var addr *string
-               if callYml.Addr != nil {
-                       if a, exists := yml.Addrs[*callYml.Addr]; exists {
+               if callCfg.Addr != nil {
+                       if a, exists := cfg.Addrs[*callCfg.Addr]; exists {
                                addr = &a
                        } else {
-                               addr = callYml.Addr
+                               addr = callCfg.Addr
                        }
                }
 
                onlineDeadline := defOnlineDeadline
-               if callYml.OnlineDeadline != nil {
-                       if *callYml.OnlineDeadline == 0 {
+               if callCfg.OnlineDeadline != nil {
+                       if *callCfg.OnlineDeadline == 0 {
                                return nil, errors.New("OnlineDeadline must be at least 1 second")
                        }
-                       onlineDeadline = *callYml.OnlineDeadline
+                       onlineDeadline = time.Duration(*callCfg.OnlineDeadline) * time.Second
                }
 
-               var maxOnlineTime uint
-               if callYml.MaxOnlineTime != nil {
-                       maxOnlineTime = *callYml.MaxOnlineTime
+               var maxOnlineTime time.Duration
+               if callCfg.MaxOnlineTime != nil {
+                       maxOnlineTime = time.Duration(*callCfg.MaxOnlineTime) * time.Second
                }
 
                calls = append(calls, &Call{
@@ -281,14 +282,14 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
                Id:             nodeId,
                ExchPub:        new([32]byte),
                SignPub:        ed25519.PublicKey(signPub),
-               Exec:           yml.Exec,
+               Exec:           cfg.Exec,
                Incoming:       incoming,
                FreqPath:       freqPath,
                FreqChunked:    freqChunked,
                FreqMinSize:    freqMinSize,
                FreqMaxSize:    freqMaxSize,
                Calls:          calls,
-               Addrs:          yml.Addrs,
+               Addrs:          cfg.Addrs,
                RxRate:         defRxRate,
                TxRate:         defTxRate,
                OnlineDeadline: defOnlineDeadline,
@@ -302,13 +303,13 @@ func NewNode(name string, yml NodeJSON) (*Node, error) {
        return &node, nil
 }
 
-func NewNodeOur(yml *NodeOurJSON) (*NodeOur, error) {
-       id, err := NodeIdFromString(yml.Id)
+func NewNodeOur(cfg *NodeOurJSON) (*NodeOur, error) {
+       id, err := NodeIdFromString(cfg.Id)
        if err != nil {
                return nil, err
        }
 
-       exchPub, err := FromBase32(yml.ExchPub)
+       exchPub, err := FromBase32(cfg.ExchPub)
        if err != nil {
                return nil, err
        }
@@ -316,7 +317,7 @@ func NewNodeOur(yml *NodeOurJSON) (*NodeOur, error) {
                return nil, errors.New("Invalid exchPub size")
        }
 
-       exchPrv, err := FromBase32(yml.ExchPrv)
+       exchPrv, err := FromBase32(cfg.ExchPrv)
        if err != nil {
                return nil, err
        }
@@ -324,7 +325,7 @@ func NewNodeOur(yml *NodeOurJSON) (*NodeOur, error) {
                return nil, errors.New("Invalid exchPrv size")
        }
 
-       signPub, err := FromBase32(yml.SignPub)
+       signPub, err := FromBase32(cfg.SignPub)
        if err != nil {
                return nil, err
        }
@@ -332,7 +333,7 @@ func NewNodeOur(yml *NodeOurJSON) (*NodeOur, error) {
                return nil, errors.New("Invalid signPub size")
        }
 
-       signPrv, err := FromBase32(yml.SignPrv)
+       signPrv, err := FromBase32(cfg.SignPrv)
        if err != nil {
                return nil, err
        }
@@ -340,7 +341,7 @@ func NewNodeOur(yml *NodeOurJSON) (*NodeOur, error) {
                return nil, errors.New("Invalid signPrv size")
        }
 
-       noisePub, err := FromBase32(yml.NoisePub)
+       noisePub, err := FromBase32(cfg.NoisePub)
        if err != nil {
                return nil, err
        }
@@ -348,7 +349,7 @@ func NewNodeOur(yml *NodeOurJSON) (*NodeOur, error) {
                return nil, errors.New("Invalid noisePub size")
        }
 
-       noisePrv, err := FromBase32(yml.NoisePrv)
+       noisePrv, err := FromBase32(cfg.NoisePrv)
        if err != nil {
                return nil, err
        }
index 4c1f542452420bda9a3446208c2dfc4b4a0a499c..ae5b80f0c4a0bd7d24d89feb2c044ab01a938fe7 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -32,7 +32,7 @@ func Check(src io.Reader, checksum []byte, sds SDS, showPrgrs bool) (bool, error
        if err != nil {
                log.Fatalln(err)
        }
-       if _, err = CopyProgressed(hsh, bufio.NewReader(src), sds, showPrgrs); err != nil {
+       if _, err = CopyProgressed(hsh, bufio.NewReader(src), "check", sds, showPrgrs); err != nil {
                return false, err
        }
        return bytes.Compare(hsh.Sum(nil), checksum) == 0, nil
index 2e5fb9e36682844923c1dba39ef4a57524de9e02..824f49a5c3bcaba4de0c055e4430a25b09d3ec60 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 0bca23f69c1ad5d502c05188ed416823b7079f91..76854283334c6015a01605472a5fbca877015df6 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -153,7 +153,7 @@ func main() {
                                        log.Fatalln("Error writing tar header:", err)
                                }
                                if _, err = nncp.CopyProgressed(
-                                       tarWr, job.Fd,
+                                       tarWr, job.Fd, "Tx",
                                        nncp.SdsAdd(sds, nncp.SDS{
                                                "pkt":      nncp.ToBase32(job.HshValue[:]),
                                                "fullsize": job.Size,
@@ -293,7 +293,7 @@ func main() {
                                        log.Fatalln("Error during writing:", err)
                                }
                                if _, err = nncp.CopyProgressed(
-                                       hsh, tarR,
+                                       hsh, tarR, "Rx",
                                        nncp.SdsAdd(sds, nncp.SDS{"fullsize": entry.Size}),
                                        ctx.ShowPrgrs,
                                ); err != nil {
@@ -341,7 +341,7 @@ func main() {
                                        if _, err = hsh.Write(pktEncBuf); err != nil {
                                                log.Fatalln("Error during writing:", err)
                                        }
-                                       if _, err = nncp.CopyProgressed(hsh, tarR, sds, ctx.ShowPrgrs); err != nil {
+                                       if _, err = nncp.CopyProgressed(hsh, tarR, "check", sds, ctx.ShowPrgrs); err != nil {
                                                log.Fatalln("Error during copying:", err)
                                        }
                                        if nncp.ToBase32(hsh.Sum(nil)) != pktName {
@@ -356,7 +356,7 @@ func main() {
                                        if _, err = tmp.W.Write(pktEncBuf); err != nil {
                                                log.Fatalln("Error during writing:", err)
                                        }
-                                       if _, err = nncp.CopyProgressed(tmp.W, tarR, sds, ctx.ShowPrgrs); err != nil {
+                                       if _, err = nncp.CopyProgressed(tmp.W, tarR, "check", sds, ctx.ShowPrgrs); err != nil {
                                                log.Fatalln("Error during copying:", err)
                                        }
                                        if err = tmp.W.Flush(); err != nil {
@@ -374,7 +374,7 @@ func main() {
                                }
                        } else {
                                if *dryRun {
-                                       if _, err = nncp.CopyProgressed(ioutil.Discard, tarR, sds, ctx.ShowPrgrs); err != nil {
+                                       if _, err = nncp.CopyProgressed(ioutil.Discard, tarR, "Rx", sds, ctx.ShowPrgrs); err != nil {
                                                log.Fatalln("Error during copying:", err)
                                        }
                                } else {
@@ -386,7 +386,7 @@ func main() {
                                        if _, err = bufTmp.Write(pktEncBuf); err != nil {
                                                log.Fatalln("Error during writing:", err)
                                        }
-                                       if _, err = nncp.CopyProgressed(bufTmp, tarR, sds, ctx.ShowPrgrs); err != nil {
+                                       if _, err = nncp.CopyProgressed(bufTmp, tarR, "Rx", sds, ctx.ShowPrgrs); err != nil {
                                                log.Fatalln("Error during copying:", err)
                                        }
                                        if err = bufTmp.Flush(); err != nil {
index 0072e982e22345fe250e49edb0e0dfdfca2644e1..ae6bffeb39b7f997e3cf5e45d952b3964c28a840 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -24,6 +24,7 @@ import (
        "log"
        "os"
        "strings"
+       "time"
 
        "go.cypherpunks.ru/nncp/v5"
 )
@@ -55,8 +56,8 @@ func main() {
                version     = flag.Bool("version", false, "Print version information")
                warranty    = flag.Bool("warranty", false, "Print warranty information")
 
-               onlineDeadline = flag.Uint("onlinedeadline", 0, "Override onlinedeadline option")
-               maxOnlineTime  = flag.Uint("maxonlinetime", 0, "Override maxonlinetime option")
+               onlineDeadlineSec = flag.Uint("onlinedeadline", 0, "Override onlinedeadline option")
+               maxOnlineTimeSec  = flag.Uint("maxonlinetime", 0, "Override maxonlinetime option")
        )
        flag.Usage = usage
        flag.Parse()
@@ -105,11 +106,13 @@ func main() {
                log.Fatalln("Node does not have online communication capability")
        }
 
-       if *onlineDeadline == 0 {
-               onlineDeadline = &node.OnlineDeadline
+       onlineDeadline := node.OnlineDeadline
+       if *onlineDeadlineSec != 0 {
+               onlineDeadline = time.Duration(*onlineDeadlineSec) * time.Second
        }
-       if *maxOnlineTime == 0 {
-               maxOnlineTime = &node.MaxOnlineTime
+       maxOnlineTime := node.MaxOnlineTime
+       if *maxOnlineTimeSec != 0 {
+               maxOnlineTime = time.Duration(*maxOnlineTimeSec) * time.Second
        }
 
        var xxOnly nncp.TRxTx
@@ -157,8 +160,8 @@ func main() {
                xxOnly,
                *rxRate,
                *txRate,
-               *onlineDeadline,
-               *maxOnlineTime,
+               onlineDeadline,
+               maxOnlineTime,
                *listOnly,
                onlyPkts,
        ) {
index 7297350d41b746efa23eb5380726eac15c19e2a9..81c90c4aff7b90a63ec594f439adeafdcdc62891 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 055b6443c4c3a7e1ad511267ffb817c5c1e21713..7cedca0d94204e5cf41ddf4cd7214485d3b2bbc2 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 43d5b3ef128d44fb9edf825067877a8faa956595..b8eae7ef3e29f2e39f0316d4b9411c12936d64dc 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 6f43b69dff9a31e54ab958337412e2d65e8e2443..ff638260ce0f945e459f0cf748a9ae02299e59f6 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 77fae4a87a515ff0cb1fd7718e739e235da389c6..252f79aa8bb5cafc875493e1d031e71f33989605 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 3fdba332684f1e0e0cdfecd5128ff60049256ae9..2d52fcf418a48ecac5cf8955c670d159592cc687 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -59,6 +59,10 @@ func (c InetdConn) SetWriteDeadline(t time.Time) error {
 }
 
 func (c InetdConn) Close() error {
+       if err := c.r.Close(); err != nil {
+               c.w.Close()
+               return err
+       }
        return c.w.Close()
 }
 
@@ -72,7 +76,7 @@ func performSP(ctx *nncp.Ctx, conn nncp.ConnDeadlined, nice uint8) {
                state.Wait()
                ctx.LogI("call-finish", nncp.SDS{
                        "node":     state.Node.Id,
-                       "duration": state.Duration.Seconds(),
+                       "duration": int64(state.Duration.Seconds()),
                        "rxbytes":  state.RxBytes,
                        "txbytes":  state.TxBytes,
                        "rxspeed":  state.RxSpeed,
@@ -139,6 +143,7 @@ func main() {
                os.Stderr.Close()
                conn := &InetdConn{os.Stdin, os.Stdout}
                performSP(ctx, conn, nice)
+               conn.Close()
                return
        }
 
index 805577e77373ffc2689e4d63bc5bde222d8a9f43..ddd3ffd9dc88a7eb6ba92acb5577cc444106798a 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 9d975f7cfc3bca1f872f0da421fda426d0d63731..9a69e6cce05f5e27a7749341e72165db1b3ff00b 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 62a851afd260b47867c209f0ab04abd5e751c39d..1bbcf9811c2c6263d19bcdf240a6ad4b695b79f2 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 883d06f416aa4ebfaedc2a83fcbaa75035258787..2535b89dc2ea8248057838fee13a58073da9f5d3 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index aaf0c2dd90c76337818314f4dd192e5cb1c877c1..3f42cd260e48a25c2f404b94ea769243f4be68db 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 75aaf5a0aa06b036373e8aff2b10c9efc45b41ab..f39d5ace3475a3af79600fca91bcd0fd3fd34d46 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -144,10 +144,14 @@ func process(ctx *nncp.Ctx, path string, keep, dryRun, stdout, dumpMeta bool) bo
                if err != nil {
                        log.Fatalln(err)
                }
-               if _, err = nncp.CopyProgressed(hsh, bufio.NewReader(fd), nncp.SDS{
-                       "pkt":      chunkPath,
-                       "fullsize": fi.Size(),
-               }, ctx.ShowPrgrs); err != nil {
+               if _, err = nncp.CopyProgressed(
+                       hsh, bufio.NewReader(fd), "check",
+                       nncp.SDS{
+                               "pkt":      chunkPath,
+                               "fullsize": fi.Size(),
+                       },
+                       ctx.ShowPrgrs,
+               ); err != nil {
                        log.Fatalln(err)
                }
                fd.Close()
@@ -195,10 +199,14 @@ func process(ctx *nncp.Ctx, path string, keep, dryRun, stdout, dumpMeta bool) bo
                if err != nil {
                        log.Fatalln("Can not stat file:", err)
                }
-               if _, err = nncp.CopyProgressed(dstW, bufio.NewReader(fd), nncp.SDS{
-                       "pkt":      chunkPath,
-                       "fullsize": fi.Size(),
-               }, ctx.ShowPrgrs); err != nil {
+               if _, err = nncp.CopyProgressed(
+                       dstW, bufio.NewReader(fd), "reass",
+                       nncp.SDS{
+                               "pkt":      chunkPath,
+                               "fullsize": fi.Size(),
+                       },
+                       ctx.ShowPrgrs,
+               ); err != nil {
                        log.Fatalln(err)
                }
                fd.Close()
index 31c04921881c0e7c739877e19b0c2b2a5a15d73c..911db6370b35ffc0d84ae2deeed65ea889f67562 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index f0588922d4ff5a351f339ec564ff6e670fc5e7fd..22eaca0af5376a54198a7dfaf9fa5dcaa1b3f142 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 5cf0a933496fc546ba679dec8314917033253134..89b94d9515a7b1c5210974701026450abdcead22 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index df7acd3b9cc3f0b2b881f4f85073ff51ec40e2b7..1a2351d4ed92526bd01c61eba8f58fad9efcc79a 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -215,10 +215,14 @@ func main() {
                                ctx.LogE("nncp-xfer", sds, err, "copy")
                                w.CloseWithError(err)
                        }()
-                       if _, err = nncp.CopyProgressed(tmp.W, r, nncp.SdsAdd(sds, nncp.SDS{
-                               "pkt":      filename,
-                               "fullsize": sds["size"],
-                       }), ctx.ShowPrgrs); err != nil {
+                       if _, err = nncp.CopyProgressed(
+                               tmp.W, r, "Rx",
+                               nncp.SdsAdd(sds, nncp.SDS{
+                                       "pkt":      filename,
+                                       "fullsize": sds["size"],
+                               }),
+                               ctx.ShowPrgrs,
+                       ); err != nil {
                                ctx.LogE("nncp-xfer", sds, err, "copy")
                                isBad = true
                        }
@@ -258,7 +262,7 @@ Tx:
                        ctx.LogD("nncp-xfer", sds, "skip")
                        continue
                }
-               dirLock, err := ctx.LockDir(&nodeId, nncp.TTx)
+               dirLock, err := ctx.LockDir(&nodeId, string(nncp.TTx))
                if err != nil {
                        continue
                }
@@ -333,8 +337,7 @@ Tx:
                        ctx.LogD("nncp-xfer", sds, "created")
                        bufW := bufio.NewWriter(tmp)
                        copied, err := nncp.CopyProgressed(
-                               bufW,
-                               bufio.NewReader(job.Fd),
+                               bufW, bufio.NewReader(job.Fd), "Tx",
                                nncp.SdsAdd(sds, nncp.SDS{"fullsize": job.Size}),
                                ctx.ShowPrgrs,
                        )
index 19c7b9c0177fb0e0abe86497f05ede78404d3719..c1625a1dc5642e8a6427fec5b8bc6a9a60066af2 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 0616c8402b87ffdfa6b8f3d335864902449c15a4..e1fd012e473e10df9ad955037fa99a2afd2f8c14 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index c7a3543f379d890d994ca197755343805544ef19..eca5fae734bea33c7f4e0ab0dcd51ffdc312346c 100644 (file)
@@ -9,10 +9,10 @@ require (
        github.com/hjson/hjson-go v3.0.1+incompatible
        github.com/klauspost/compress v1.9.2
        github.com/kr/pretty v0.1.0 // indirect
-       go.cypherpunks.ru/balloon v1.1.0
-       golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708
-       golang.org/x/net v0.0.0-20191112182307-2180aed22343
-       golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056
+       go.cypherpunks.ru/balloon v1.1.1
+       golang.org/x/crypto v0.0.0-20191219195013-becbf705a915
+       golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
+       golang.org/x/sys v0.0.0-20191219235734-af0d71d358ab
        gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
 )
 
index a0803fc0eaa6fd23a5fe0b9ae3e71d68a8796749..2a006d9d922976b29dd4de3ddd1315298d1b8b44 100644 (file)
@@ -17,19 +17,19 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-go.cypherpunks.ru/balloon v1.1.0 h1:tKwBeS1xrZYS/vn87Hm/4EvgNeHKyU1uC099aPRa2JQ=
-go.cypherpunks.ru/balloon v1.1.0/go.mod h1:k4s4ozrIrhpBjj78Z7LX8ZHxMQ+XE7DZUWl8gP2ojCo=
+go.cypherpunks.ru/balloon v1.1.1 h1:ypHM1DRf/XuCrp9pDkTHg00CqZX/Np/APb//iHvDJTA=
+go.cypherpunks.ru/balloon v1.1.1/go.mod h1:k4s4ozrIrhpBjj78Z7LX8ZHxMQ+XE7DZUWl8gP2ojCo=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4=
-golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 h1:aJ0ex187qoXrJHPo8ZasVTASQB7llQP6YeNzgDALPRk=
+golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343 h1:00ohfJ4K98s3m6BGUoBd8nyfp4Yl0GoIKvw5abItTjI=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191219235734-af0d71d358ab h1:j8r8g0V3tVdbo274kyTmC+yEsChru2GfvdiV84wm5T8=
+golang.org/x/sys v0.0.0-20191219235734-af0d71d358ab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
index 8ac19ea11ae7d44a62ccb1eea2a33256cab5ad54..1eded3cab7e474ad68e4e81766f590de96d2b67f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 705bb7e551f09c68e04e922a4570ba6e81b9c31b..16c95bfbbe2b7276499c912e0fb28a888c21c19c 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 50e90f4dfe0b33ddace932e657d0b100361b18c8..f87e6c6afbf67dd132d992b9eb144c1ea4fc8e17 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -24,9 +24,9 @@ import (
        "golang.org/x/sys/unix"
 )
 
-func (ctx *Ctx) LockDir(nodeId *NodeId, xx TRxTx) (*os.File, error) {
+func (ctx *Ctx) LockDir(nodeId *NodeId, lockCtx string) (*os.File, error) {
        ctx.ensureRxDir(nodeId)
-       lockPath := filepath.Join(ctx.Spool, nodeId.String(), string(xx)) + ".lock"
+       lockPath := filepath.Join(ctx.Spool, nodeId.String(), lockCtx) + ".lock"
        dirLock, err := os.OpenFile(
                lockPath,
                os.O_CREATE|os.O_WRONLY,
index bc91043e2198352f26c4c13249da790885c59284..a5bef48b9d5d7765da62213eb45c313b78b3e633 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 9ff5b6d73fbb2fc26259af42532379a116bf415d..93e4446aa6e87425fd09764a719219ef2d84970b 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -46,7 +46,7 @@ func VersionGet() string {
 
 func UsageHeader() string {
        return VersionGet() + `
-Copyright (C) 2016-2019 Sergey Matveev
+Copyright (C) 2016-2020 Sergey Matveev
 License GPLv3: GNU GPL version 3 <http://gnu.org/licenses/gpl.html>
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
index 65f5e9cde30cc7e8c4931f9c54384c89b9c8e9b2..7bfd0efda5723cb71d164410a4428a2fbf47627e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -21,6 +21,7 @@ import (
        "crypto/rand"
        "errors"
        "sync"
+       "time"
 
        "github.com/flynn/noise"
        "golang.org/x/crypto/blake2b"
@@ -50,8 +51,8 @@ type Node struct {
        Addrs          map[string]string
        RxRate         int
        TxRate         int
-       OnlineDeadline uint
-       MaxOnlineTime  uint
+       OnlineDeadline time.Duration
+       MaxOnlineTime  time.Duration
        Calls          []*Call
 
        Busy bool
index a5d8610e8209f2d4127d61b5c3630799e7e4324b..a250ceedd2b2548140ec69bae513ee5f1dfb3e50 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 8324ffbc0428450850779b9c1bdf215533fa9d33..6eb4ef201a5484b5a7a4e6421a4076dc22d8181f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index c69ba96e3b951b1ed1630799b3664a052c71c83e..d076b63587d774c50e6906a447aeca7d53bee3ea 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index d07185749dd812670e156fb1ff800444c2c3ad0d..546979a5d645b80133d19a1df676f71a9a69378f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -21,7 +21,6 @@ import (
        "fmt"
        "io"
        "os"
-       "strings"
        "sync"
        "time"
 
@@ -82,6 +81,7 @@ func (pb ProgressBar) Kill() {
 func CopyProgressed(
        dst io.Writer,
        src io.Reader,
+       prgrsPrefix string,
        sds SDS,
        showPrgrs bool,
 ) (written int64, err error) {
@@ -96,7 +96,7 @@ func CopyProgressed(
                                written += int64(nw)
                                if showPrgrs {
                                        sds["size"] = written
-                                       Progress(sds)
+                                       Progress(prgrsPrefix, sds)
                                }
                        }
                        if ew != nil {
@@ -118,13 +118,13 @@ func CopyProgressed(
        return
 }
 
-func Progress(sds SDS) {
-       pkt := sds["pkt"].(string)
+func Progress(prefix string, sds SDS) {
        var size int64
        if sizeI, exists := sds["size"]; exists {
                size = sizeI.(int64)
        }
        fullsize := sds["fullsize"].(int64)
+       pkt := sds["pkt"].(string)
        progressBarsLock.RLock()
        pb, exists := progressBars[pkt]
        progressBarsLock.RUnlock()
@@ -138,9 +138,7 @@ func Progress(sds SDS) {
        if len(what) >= 52 { // Base32 encoded
                what = what[:16] + ".." + what[len(what)-16:]
        }
-       if xx, exists := sds["xx"]; exists {
-               what = strings.Title(xx.(string)) + " " + what
-       }
+       what = prefix + " " + what
        pb.Render(what, size)
        if size >= fullsize {
                pb.Kill()
index fa853b033779d971c5d3e35299961d7c36064964..1297c414cb3d5c175720fc0178fe3e21224fec40 100644 (file)
--- a/src/sp.go
+++ b/src/sp.go
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -34,19 +34,19 @@ import (
 )
 
 const (
-       MaxSPSize       = 1<<16 - 256
-       PartSuffix      = ".part"
-       DefaultDeadline = 10
+       MaxSPSize      = 1<<16 - 256
+       PartSuffix     = ".part"
+       SPHeadOverhead = 4
 )
 
 var (
        MagicNNCPLv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'S', 0, 0, 1}
 
-       SPHeadOverhead    int
        SPInfoOverhead    int
        SPFreqOverhead    int
        SPFileOverhead    int
        SPHaltMarshalized []byte
+       SPPingMarshalized []byte
 
        NoiseCipherSuite noise.CipherSuite = noise.NewCipherSuite(
                noise.DH25519,
@@ -54,6 +54,9 @@ var (
                noise.HashBLAKE2b,
        )
 
+       DefaultDeadline = 10 * time.Second
+       PingTimeout     = time.Minute
+
        spWorkersGroup sync.WaitGroup
 )
 
@@ -65,6 +68,7 @@ const (
        SPTypeFile SPType = iota
        SPTypeDone SPType = iota
        SPTypeHalt SPType = iota
+       SPTypePing SPType = iota
 )
 
 type SPHead struct {
@@ -114,8 +118,16 @@ func init() {
        if _, err := xdr.Marshal(&buf, spHead); err != nil {
                panic(err)
        }
+       SPHaltMarshalized = make([]byte, SPHeadOverhead)
        copy(SPHaltMarshalized, buf.Bytes())
-       SPHeadOverhead = buf.Len()
+       buf.Reset()
+
+       spHead = SPHead{Type: SPTypePing}
+       if _, err := xdr.Marshal(&buf, spHead); err != nil {
+               panic(err)
+       }
+       SPPingMarshalized = make([]byte, SPHeadOverhead)
+       copy(SPPingMarshalized, buf.Bytes())
        buf.Reset()
 
        spInfo := SPInfo{Nice: 123, Size: 123, Hash: new([32]byte)}
@@ -141,11 +153,10 @@ func init() {
 
 func MarshalSP(typ SPType, sp interface{}) []byte {
        var buf bytes.Buffer
-       var err error
-       if _, err = xdr.Marshal(&buf, SPHead{typ}); err != nil {
+       if _, err := xdr.Marshal(&buf, SPHead{typ}); err != nil {
                panic(err)
        }
-       if _, err = xdr.Marshal(&buf, sp); err != nil {
+       if _, err := xdr.Marshal(&buf, sp); err != nil {
                panic(err)
        }
        return buf.Bytes()
@@ -171,21 +182,25 @@ type SPState struct {
        Ctx            *Ctx
        Node           *Node
        Nice           uint8
-       onlineDeadline uint
-       maxOnlineTime  uint
+       onlineDeadline time.Duration
+       maxOnlineTime  time.Duration
        hs             *noise.HandshakeState
        csOur          *noise.CipherState
        csTheir        *noise.CipherState
        payloads       chan []byte
+       pings          chan struct{}
        infosTheir     map[[32]byte]*SPInfo
        infosOurSeen   map[[32]byte]uint8
        queueTheir     []*FreqWithNice
        wg             sync.WaitGroup
        RxBytes        int64
        RxLastSeen     time.Time
+       RxLastNonPing  time.Time
        TxBytes        int64
        TxLastSeen     time.Time
+       TxLastNonPing  time.Time
        started        time.Time
+       mustFinishAt   time.Time
        Duration       time.Duration
        RxSpeed        int64
        TxSpeed        int64
@@ -194,22 +209,40 @@ type SPState struct {
        xxOnly         TRxTx
        rxRate         int
        txRate         int
-       isDead         bool
+       isDead         chan struct{}
        listOnly       bool
        onlyPkts       map[[32]byte]bool
+       writeSPBuf     bytes.Buffer
        sync.RWMutex
 }
 
-func (state *SPState) NotAlive() bool {
-       if state.isDead {
-               return true
+func (state *SPState) SetDead() {
+       state.Lock()
+       defer state.Unlock()
+       select {
+       case <-state.isDead:
+               // Already closed channel, dead
+               return
+       default:
        }
-       now := time.Now()
-       if state.maxOnlineTime > 0 && state.started.Add(time.Duration(state.maxOnlineTime)*time.Second).Before(now) {
+       close(state.isDead)
+       go func() {
+               for _ = range state.payloads {
+               }
+       }()
+       go func() {
+               for _ = range state.pings {
+               }
+       }()
+}
+
+func (state *SPState) NotAlive() bool {
+       select {
+       case <-state.isDead:
                return true
+       default:
        }
-       return uint(now.Sub(state.RxLastSeen).Seconds()) >= state.onlineDeadline &&
-               uint(now.Sub(state.TxLastSeen).Seconds()) >= state.onlineDeadline
+       return false
 }
 
 func (state *SPState) dirUnlock() {
@@ -217,11 +250,21 @@ func (state *SPState) dirUnlock() {
        state.Ctx.UnlockDir(state.txLock)
 }
 
-func (state *SPState) WriteSP(dst io.Writer, payload []byte) error {
-       n, err := xdr.Marshal(dst, SPRaw{Magic: MagicNNCPLv1, Payload: payload})
-       if err == nil {
+func (state *SPState) WriteSP(dst io.Writer, payload []byte, ping bool) error {
+       state.writeSPBuf.Reset()
+       n, err := xdr.Marshal(&state.writeSPBuf, SPRaw{
+               Magic:   MagicNNCPLv1,
+               Payload: payload,
+       })
+       if err != nil {
+               return err
+       }
+       if n, err = dst.Write(state.writeSPBuf.Bytes()); err == nil {
                state.TxLastSeen = time.Now()
                state.TxBytes += int64(n)
+               if !ping {
+                       state.TxLastNonPing = state.TxLastSeen
+               }
        }
        return err
 }
@@ -292,14 +335,14 @@ func (state *SPState) StartI(conn ConnDeadlined) error {
        }
        var rxLock *os.File
        if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TRx) {
-               rxLock, err = state.Ctx.LockDir(nodeId, TRx)
+               rxLock, err = state.Ctx.LockDir(nodeId, string(TRx))
                if err != nil {
                        return err
                }
        }
        var txLock *os.File
        if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TTx) {
-               txLock, err = state.Ctx.LockDir(nodeId, TTx)
+               txLock, err = state.Ctx.LockDir(nodeId, string(TTx))
                if err != nil {
                        return err
                }
@@ -321,6 +364,7 @@ func (state *SPState) StartI(conn ConnDeadlined) error {
        }
        state.hs = hs
        state.payloads = make(chan []byte)
+       state.pings = make(chan struct{})
        state.infosTheir = make(map[[32]byte]*SPInfo)
        state.infosOurSeen = make(map[[32]byte]uint8)
        state.started = started
@@ -349,14 +393,14 @@ func (state *SPState) StartI(conn ConnDeadlined) error {
        }
        sds := SDS{"node": nodeId, "nice": int(state.Nice)}
        state.Ctx.LogD("sp-start", sds, "sending first message")
-       conn.SetWriteDeadline(time.Now().Add(DefaultDeadline * time.Second))
-       if err = state.WriteSP(conn, buf); err != nil {
+       conn.SetWriteDeadline(time.Now().Add(DefaultDeadline))
+       if err = state.WriteSP(conn, buf, false); err != nil {
                state.Ctx.LogE("sp-start", sds, err, "")
                state.dirUnlock()
                return err
        }
        state.Ctx.LogD("sp-start", sds, "waiting for first message")
-       conn.SetReadDeadline(time.Now().Add(DefaultDeadline * time.Second))
+       conn.SetReadDeadline(time.Now().Add(DefaultDeadline))
        if buf, err = state.ReadSP(conn); err != nil {
                state.Ctx.LogE("sp-start", sds, err, "")
                state.dirUnlock()
@@ -373,7 +417,6 @@ func (state *SPState) StartI(conn ConnDeadlined) error {
        if err != nil {
                state.Ctx.LogE("sp-start", sds, err, "")
                state.dirUnlock()
-               return err
        }
        return err
 }
@@ -396,6 +439,7 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
        xxOnly := TRxTx("")
        state.hs = hs
        state.payloads = make(chan []byte)
+       state.pings = make(chan struct{})
        state.infosOurSeen = make(map[[32]byte]uint8)
        state.infosTheir = make(map[[32]byte]*SPInfo)
        state.started = started
@@ -403,7 +447,7 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
        var buf []byte
        var payload []byte
        state.Ctx.LogD("sp-start", SDS{"nice": int(state.Nice)}, "waiting for first message")
-       conn.SetReadDeadline(time.Now().Add(DefaultDeadline * time.Second))
+       conn.SetReadDeadline(time.Now().Add(DefaultDeadline))
        if buf, err = state.ReadSP(conn); err != nil {
                state.Ctx.LogE("sp-start", SDS{}, err, "")
                return err
@@ -437,7 +481,7 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
        }
        var rxLock *os.File
        if xxOnly == "" || xxOnly == TRx {
-               rxLock, err = state.Ctx.LockDir(node.Id, TRx)
+               rxLock, err = state.Ctx.LockDir(node.Id, string(TRx))
                if err != nil {
                        return err
                }
@@ -445,7 +489,7 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
        state.rxLock = rxLock
        var txLock *os.File
        if xxOnly == "" || xxOnly == TTx {
-               txLock, err = state.Ctx.LockDir(node.Id, TTx)
+               txLock, err = state.Ctx.LockDir(node.Id, string(TTx))
                if err != nil {
                        return err
                }
@@ -471,8 +515,8 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
                state.dirUnlock()
                return err
        }
-       conn.SetWriteDeadline(time.Now().Add(DefaultDeadline * time.Second))
-       if err = state.WriteSP(conn, buf); err != nil {
+       conn.SetWriteDeadline(time.Now().Add(DefaultDeadline))
+       if err = state.WriteSP(conn, buf, false); err != nil {
                state.Ctx.LogE("sp-start", sds, err, "")
                state.dirUnlock()
                return err
@@ -481,7 +525,6 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
        err = state.StartWorkers(conn, infosPayloads, payload)
        if err != nil {
                state.dirUnlock()
-               return err
        }
        return err
 }
@@ -489,9 +532,17 @@ func (state *SPState) StartR(conn ConnDeadlined) error {
 func (state *SPState) StartWorkers(
        conn ConnDeadlined,
        infosPayloads [][]byte,
-       payload []byte) error {
+       payload []byte,
+) error {
        sds := SDS{"node": state.Node.Id, "nice": int(state.Nice)}
+       state.isDead = make(chan struct{})
+       if state.maxOnlineTime > 0 {
+               state.mustFinishAt = state.started.Add(state.maxOnlineTime)
+       }
+
+       // Remaining handshake payload sending
        if len(infosPayloads) > 1 {
+               state.wg.Add(1)
                go func() {
                        for _, payload := range infosPayloads[1:] {
                                state.Ctx.LogD(
@@ -501,8 +552,11 @@ func (state *SPState) StartWorkers(
                                )
                                state.payloads <- payload
                        }
+                       state.wg.Done()
                }()
        }
+
+       // Processing of first payload and queueing its responses
        state.Ctx.LogD(
                "sp-work",
                SdsAdd(sds, SDS{"size": len(payload)}),
@@ -513,7 +567,7 @@ func (state *SPState) StartWorkers(
                state.Ctx.LogE("sp-work", sds, err, "")
                return err
        }
-
+       state.wg.Add(1)
        go func() {
                for _, reply := range replies {
                        state.Ctx.LogD(
@@ -523,42 +577,88 @@ func (state *SPState) StartWorkers(
                        )
                        state.payloads <- reply
                }
+               state.wg.Done()
+       }()
+
+       // Periodic jobs
+       state.wg.Add(1)
+       go func() {
+               deadlineTicker := time.NewTicker(time.Second)
+               pingTicker := time.NewTicker(PingTimeout)
+               for {
+                       select {
+                       case <-state.isDead:
+                               state.wg.Done()
+                               deadlineTicker.Stop()
+                               pingTicker.Stop()
+                               return
+                       case now := <-deadlineTicker.C:
+                               if (now.Sub(state.RxLastNonPing) >= state.onlineDeadline &&
+                                       now.Sub(state.TxLastNonPing) >= state.onlineDeadline) ||
+                                       (state.maxOnlineTime > 0 && state.mustFinishAt.Before(now)) ||
+                                       (now.Sub(state.RxLastSeen) >= 2*PingTimeout) {
+                                       state.SetDead()
+                                       conn.Close()
+                               }
+                       case now := <-pingTicker.C:
+                               if now.After(state.TxLastSeen.Add(PingTimeout)) {
+                                       state.wg.Add(1)
+                                       go func() {
+                                               state.pings <- struct{}{}
+                                               state.wg.Done()
+                                               state.Ctx.LogD("HERE", SDS{}, "PING GOROUTINE QUIT")
+                                       }()
+                               }
+                       }
+               }
        }()
 
+       // Spool checker and INFOs sender of appearing files
        if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TTx) {
+               state.wg.Add(1)
                go func() {
-                       for range time.Tick(time.Second) {
-                               if state.NotAlive() {
+                       ticker := time.NewTicker(time.Second)
+                       for {
+                               select {
+                               case <-state.isDead:
+                                       state.wg.Done()
+                                       ticker.Stop()
                                        return
-                               }
-                               for _, payload := range state.Ctx.infosOur(
-                                       state.Node.Id,
-                                       state.Nice,
-                                       &state.infosOurSeen,
-                               ) {
-                                       state.Ctx.LogD(
-                                               "sp-work",
-                                               SdsAdd(sds, SDS{"size": len(payload)}),
-                                               "queuing new info",
-                                       )
-                                       state.payloads <- payload
+                               case <-ticker.C:
+                                       for _, payload := range state.Ctx.infosOur(
+                                               state.Node.Id,
+                                               state.Nice,
+                                               &state.infosOurSeen,
+                                       ) {
+                                               state.Ctx.LogD(
+                                                       "sp-work",
+                                                       SdsAdd(sds, SDS{"size": len(payload)}),
+                                                       "queuing new info",
+                                               )
+                                               state.payloads <- payload
+                                       }
                                }
                        }
                }()
        }
 
+       // Sender
        state.wg.Add(1)
        go func() {
-               defer func() {
-                       state.isDead = true
-                       state.wg.Done()
-               }()
+               defer conn.Close()
+               defer state.SetDead()
+               defer state.wg.Done()
                for {
                        if state.NotAlive() {
                                return
                        }
                        var payload []byte
+                       var ping bool
                        select {
+                       case <-state.pings:
+                               state.Ctx.LogD("sp-xmit", sds, "got ping")
+                               payload = SPPingMarshalized
+                               ping = true
                        case payload = <-state.payloads:
                                state.Ctx.LogD(
                                        "sp-xmit",
@@ -566,22 +666,17 @@ func (state *SPState) StartWorkers(
                                        "got payload",
                                )
                        default:
-                       }
-                       if payload == nil {
                                state.RLock()
                                if len(state.queueTheir) == 0 {
-                                       state.Ctx.LogD("sp-xmit", sds, "file queue is empty")
                                        state.RUnlock()
                                        time.Sleep(100 * time.Millisecond)
                                        continue
                                }
                                freq := state.queueTheir[0].freq
                                state.RUnlock()
-
                                if state.txRate > 0 {
                                        time.Sleep(time.Second / time.Duration(state.txRate))
                                }
-
                                sdsp := SdsAdd(sds, SDS{
                                        "xx":   string(TTx),
                                        "pkt":  ToBase32(freq.Hash[:]),
@@ -596,12 +691,12 @@ func (state *SPState) StartWorkers(
                                ))
                                if err != nil {
                                        state.Ctx.LogE("sp-file", sdsp, err, "")
-                                       break
+                                       return
                                }
                                fi, err := fd.Stat()
                                if err != nil {
                                        state.Ctx.LogE("sp-file", sdsp, err, "")
-                                       break
+                                       return
                                }
                                fullSize := fi.Size()
                                var buf []byte
@@ -609,20 +704,16 @@ func (state *SPState) StartWorkers(
                                        state.Ctx.LogD("sp-file", sdsp, "seeking")
                                        if _, err = fd.Seek(int64(freq.Offset), io.SeekStart); err != nil {
                                                state.Ctx.LogE("sp-file", sdsp, err, "")
-                                               break
+                                               return
                                        }
                                        buf = make([]byte, MaxSPSize-SPHeadOverhead-SPFileOverhead)
                                        n, err := fd.Read(buf)
                                        if err != nil {
                                                state.Ctx.LogE("sp-file", sdsp, err, "")
-                                               break
+                                               return
                                        }
                                        buf = buf[:n]
-                                       state.Ctx.LogD(
-                                               "sp-file",
-                                               SdsAdd(sdsp, SDS{"size": n}),
-                                               "read",
-                                       )
+                                       state.Ctx.LogD("sp-file", SdsAdd(sdsp, SDS{"size": n}), "read")
                                }
                                fd.Close()
                                payload = MarshalSP(SPTypeFile, SPFile{
@@ -634,7 +725,7 @@ func (state *SPState) StartWorkers(
                                sdsp["size"] = int64(ourSize)
                                sdsp["fullsize"] = fullSize
                                if state.Ctx.ShowPrgrs {
-                                       Progress(sdsp)
+                                       Progress("Tx", sdsp)
                                }
                                state.Lock()
                                if len(state.queueTheir) > 0 && *state.queueTheir[0].freq.Hash == *freq.Hash {
@@ -653,31 +744,24 @@ func (state *SPState) StartWorkers(
                                }
                                state.Unlock()
                        }
-                       state.Ctx.LogD(
-                               "sp-xmit",
-                               SdsAdd(sds, SDS{"size": len(payload)}),
-                               "sending",
-                       )
-                       conn.SetWriteDeadline(time.Now().Add(DefaultDeadline * time.Second))
-                       if err := state.WriteSP(conn, state.csOur.Encrypt(nil, nil, payload)); err != nil {
+                       state.Ctx.LogD("sp-xmit", SdsAdd(sds, SDS{"size": len(payload)}), "sending")
+                       conn.SetWriteDeadline(time.Now().Add(DefaultDeadline))
+                       if err := state.WriteSP(conn, state.csOur.Encrypt(nil, nil, payload), ping); err != nil {
                                state.Ctx.LogE("sp-xmit", sds, err, "")
-                               break
+                               return
                        }
                }
        }()
 
+       // Receiver
        state.wg.Add(1)
        go func() {
-               defer func() {
-                       state.isDead = true
-                       state.wg.Done()
-               }()
                for {
                        if state.NotAlive() {
-                               return
+                               break
                        }
                        state.Ctx.LogD("sp-recv", sds, "waiting for payload")
-                       conn.SetReadDeadline(time.Now().Add(DefaultDeadline * time.Second))
+                       conn.SetReadDeadline(time.Now().Add(DefaultDeadline))
                        payload, err := state.ReadSP(conn)
                        if err != nil {
                                if err == io.EOF {
@@ -714,6 +798,7 @@ func (state *SPState) StartWorkers(
                                state.Ctx.LogE("sp-recv", sds, err, "")
                                break
                        }
+                       state.wg.Add(1)
                        go func() {
                                for _, reply := range replies {
                                        state.Ctx.LogD(
@@ -723,11 +808,16 @@ func (state *SPState) StartWorkers(
                                        )
                                        state.payloads <- reply
                                }
+                               state.wg.Done()
                        }()
                        if state.rxRate > 0 {
                                time.Sleep(time.Second / time.Duration(state.rxRate))
                        }
                }
+               state.SetDead()
+               state.wg.Done()
+               state.SetDead()
+               conn.Close()
        }()
 
        return nil
@@ -735,6 +825,8 @@ func (state *SPState) StartWorkers(
 
 func (state *SPState) Wait() {
        state.wg.Wait()
+       close(state.payloads)
+       close(state.pings)
        state.dirUnlock()
        state.Duration = time.Now().Sub(state.started)
        state.RxSpeed = state.RxBytes
@@ -763,6 +855,13 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
                        return nil, err
                }
                switch head.Type {
+               case SPTypeHalt:
+                       state.Ctx.LogD("sp-process", SdsAdd(sds, SDS{"type": "halt"}), "")
+                       state.Lock()
+                       state.queueTheir = nil
+                       state.Unlock()
+               case SPTypePing:
+                       state.Ctx.LogD("sp-process", SdsAdd(sds, SDS{"type": "ping"}), "")
                case SPTypeInfo:
                        infosGot = true
                        sdsp := SdsAdd(sds, SDS{"type": "info"})
@@ -873,19 +972,23 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
                                fd.Close()
                                return nil, err
                        }
-                       ourSize := file.Offset + uint64(len(file.Payload))
+                       ourSize := int64(file.Offset + uint64(len(file.Payload)))
+                       sdsp["size"] = ourSize
+                       fullsize := int64(0)
                        state.RLock()
-                       sdsp["size"] = int64(ourSize)
-                       sdsp["fullsize"] = int64(state.infosTheir[*file.Hash].Size)
+                       infoTheir, ok := state.infosTheir[*file.Hash]
+                       state.RUnlock()
+                       if ok {
+                               fullsize = int64(infoTheir.Size)
+                       }
+                       sdsp["fullsize"] = fullsize
                        if state.Ctx.ShowPrgrs {
-                               Progress(sdsp)
+                               Progress("Rx", sdsp)
                        }
-                       if state.infosTheir[*file.Hash].Size != ourSize {
-                               state.RUnlock()
+                       if fullsize != ourSize {
                                fd.Close()
                                continue
                        }
-                       state.RUnlock()
                        spWorkersGroup.Wait()
                        spWorkersGroup.Add(1)
                        go func() {
@@ -917,8 +1020,10 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
                                delete(state.infosTheir, *file.Hash)
                                state.Unlock()
                                spWorkersGroup.Done()
+                               state.wg.Add(1)
                                go func() {
                                        state.payloads <- MarshalSP(SPTypeDone, SPDone{file.Hash})
+                                       state.wg.Done()
                                }()
                        }()
                case SPTypeDone:
@@ -975,11 +1080,6 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
                        } else {
                                state.Ctx.LogD("sp-process", sdsp, "unknown")
                        }
-               case SPTypeHalt:
-                       state.Ctx.LogD("sp-process", SdsAdd(sds, SDS{"type": "halt"}), "")
-                       state.Lock()
-                       state.queueTheir = nil
-                       state.Unlock()
                default:
                        state.Ctx.LogE(
                                "sp-process",
@@ -989,6 +1089,9 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
                        )
                        return nil, BadPktType
                }
+               if head.Type != SPTypePing {
+                       state.RxLastNonPing = state.RxLastSeen
+               }
        }
        if infosGot {
                var pkts int
index 0784b996eea067656966f6e2b5bfb8a516f31242..32c3fdba1aed68b16a39477c9f810a73646a7a5e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 6abf278af8ab18cc61e785a80fb0c5565890bcca..0bedecae7a76440b3812519b5fe37c433e4fbcbd 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -68,6 +68,12 @@ func (ctx *Ctx) Toss(
        nice uint8,
        dryRun, doSeen, noFile, noFreq, noExec, noTrns bool,
 ) bool {
+       dirLock, err := ctx.LockDir(nodeId, "toss")
+       if err != nil {
+               ctx.LogE("rx", SDS{}, err, "lock")
+               return false
+       }
+       defer ctx.UnlockDir(dirLock)
        isBad := false
        sendmail := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
        decompressor, err := zstd.NewReader(nil)
@@ -224,8 +230,7 @@ func (ctx *Ctx) Toss(
                                ctx.LogD("rx", sds, "created")
                                bufW := bufio.NewWriter(tmp)
                                if _, err = CopyProgressed(
-                                       bufW,
-                                       pipeR,
+                                       bufW, pipeR, "Rx file",
                                        SdsAdd(sds, SDS{"fullsize": sds["size"]}),
                                        ctx.ShowPrgrs,
                                ); err != nil {
index 3a6f29fa36334c0f8924e3c53568e73a64058b69..b6df326256cf6c0eba277f9ff47b379463f85621 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index 67bb659a672426895919fcd5961633c75d455df9..831cb6fde721eac9eb982ab83c80a074d7ee79d7 100644 (file)
--- a/src/tx.go
+++ b/src/tx.go
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
@@ -108,8 +108,8 @@ func (ctx *Ctx) Tx(
        }
        go func() {
                _, err := CopyProgressed(
-                       tmp.W, pipeR,
-                       SDS{"xx": string(TTx), "pkt": pktName, "fullsize": curSize},
+                       tmp.W, pipeR, "Tx",
+                       SDS{"pkt": pktName, "fullsize": curSize},
                        ctx.ShowPrgrs,
                )
                errs <- err
@@ -532,11 +532,11 @@ func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error
        if err != nil {
                return err
        }
-       if _, err = CopyProgressed(tmp.W, src, SDS{
-               "xx":       string(TTx),
-               "pkt":      node.Id.String(),
-               "fullsize": size,
-       }, ctx.ShowPrgrs); err != nil {
+       if _, err = CopyProgressed(
+               tmp.W, src, "Tx trns",
+               SDS{"pkt": node.Id.String(), "fullsize": size},
+               ctx.ShowPrgrs,
+       ); err != nil {
                return err
        }
        nodePath := filepath.Join(ctx.Spool, node.Id.String())
index 46e5b1e98b12bab0a5dc2049cac62b516a928b74..9a16d9a8787b118c4a861cc12fc2d9dceeb73a7a 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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
index d8bdbbba0e73191e906e87511a1bde78128d3bc6..251af21c0c54d50ddeecdae44d00ecc874008802 100644 (file)
@@ -1,6 +1,6 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2020 Sergey Matveev <stargrave@stargrave.org>
 
 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