]> Cypherpunks.ru repositories - nncp.git/commitdiff
Merge branch 'develop' v7.2.0
authorSergey Matveev <stargrave@stargrave.org>
Thu, 8 Jul 2021 17:14:46 +0000 (20:14 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Thu, 8 Jul 2021 17:14:46 +0000 (20:14 +0300)
20 files changed:
bin/cmd.list
doc/cmd/index.texi
doc/cmd/nncp-trns.texi [new file with mode: 0644]
doc/download.texi
doc/multicast.texi
doc/news.ru.texi
doc/news.texi
doc/nncp.html.do
ports/nncp/Makefile
ports/nncp/pkg-plist
src/check.go
src/cmd/nncp-hash/main.go
src/cmd/nncp-pkt/main.go
src/cmd/nncp-trns/main.go [new file with mode: 0644]
src/ctx.go
src/mth.go
src/mth_test.go
src/nncp.go
src/sp.go
src/toss.go

index b85cb2a2ba575cb4850a1491192f56614dd2c32a..693027a1fdc4f52c61d4911f60bbd1b977bf93e6 100644 (file)
@@ -17,4 +17,5 @@ nncp-reass
 nncp-rm
 nncp-stat
 nncp-toss
+nncp-trns
 nncp-xfer
index cb815438048b3c87388934d02aadc28108c4ec22..a360e28e882b3fbabff16cf89c4f447ee8dc3afb 100644 (file)
@@ -54,6 +54,7 @@ Packets creation commands
 * nncp-file::
 * nncp-exec::
 * nncp-freq::
+* nncp-trns::
 
 Packets sharing commands
 
@@ -88,6 +89,7 @@ Maintenance, monitoring and debugging commands:
 @include cmd/nncp-file.texi
 @include cmd/nncp-exec.texi
 @include cmd/nncp-freq.texi
+@include cmd/nncp-trns.texi
 @include cmd/nncp-xfer.texi
 @include cmd/nncp-bundle.texi
 @include cmd/nncp-toss.texi
diff --git a/doc/cmd/nncp-trns.texi b/doc/cmd/nncp-trns.texi
new file mode 100644 (file)
index 0000000..8e66205
--- /dev/null
@@ -0,0 +1,13 @@
+@node nncp-trns
+@section nncp-trns
+
+@example
+$ nncp-trns [options] -via NODEx[,...] NODE:PKT
+$ nncp-trns [options] -via NODEx[,...] /path/to/PKT
+
+@end example
+
+Transit specified encrypted packet via another @option{NODEx}es.
+Just manual transition packets creator. Normally you should not use that
+command at all, preferring automatic wrapping in transitional packets
+using the general @option{-via} option and configuration's files one.
index 30de1737f4ad5580f4c078713142a1ebecc91f29..28fbda84e773ea20ba224a3abd8eecf9f0b77081 100644 (file)
@@ -28,6 +28,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 7_1_1, 7.1.1} @tab 2021-07-06 @tab 1132 KiB
+@tab @url{download/nncp-7.1.1.tar.xz, link} @url{download/nncp-7.1.1.tar.xz.sig, sign}
+@tab @code{B741C9E3 EC3DB342 893FE081 888C40E4 B94E4298 E5C1A8E0 BA4D179C C239CCCA}
+
 @item @ref{Release 7_1_0, 7.1.0} @tab 2021-07-04 @tab 1142 KiB
 @tab @url{download/nncp-7.1.0.tar.xz, link} @url{download/nncp-7.1.0.tar.xz.sig, sign}
 @tab @code{D3BC010F 5D86BB59 E07A2A84 2FF9C73B 4C2F780B 807EF25C E4BC477C E40764A6}
index c33042644f40c8d555bdc7e8c3fb835d7b95a242..36e8bf9d53390523881d81337294c1e9105cf658 100644 (file)
@@ -100,7 +100,7 @@ A -- B -- C
 @end example
 
 @example
-$ nncp-file nodelist-20210704.rec area:nodelist-updates:
+$ nncp-file nodelist-20210704.rec.zst area:nodelist-updates:
 $ nncp-toss -node self
 @end example
 
@@ -126,7 +126,7 @@ not read area's message because it lacks the keys.
 
 @item
 @code{nodeC} does not relay it to anyone. Just stores
-@file{nodelist-20210704.rec} in the incoming directory.
+@file{nodelist-20210704.rec.zst} in the incoming directory.
 
 @item
 @code{nodeD} receives packets from both @code{nodeA} and @code{nodeB}.
@@ -137,9 +137,6 @@ If @code{nodeD} will receive packet from the @code{nodeB} first, it will
 relay it to the @code{nodeA} also, that will silently remove it when
 tossing, because it was already seen.
 
-@strong{TODO}: we must not relay packet to the node also presenting as
-the sender of the area's message. Obviously it has seen it.
-
 @item
 When @code{nodeC} sends message to the area, then @code{nodeA} will
 receive it twice from @code{nodeB} and @code{nodeD}, ignoring one of
index 86b0ccc1d4ba151eef55a2d713e5c60da60fb088..eeaca1ec4101f1603f1f7f527d6fde044753e93b 100644 (file)
@@ -1,6 +1,28 @@
 @node Новости
 @section Новости
 
+@node Релиз 7.2.0
+@subsection Релиз 7.2.0
+@itemize
+
+@item
+Появилась @command{nncp-trns} команда для ручного создания транзитных пакетов.
+
+@item
+Если у целевой ноды транзитного пакета задан @option{via} маршрут, то
+использовать его, а не игнорировать.
+
+@item
+Не отправлять multicast пакет оригинатору сообщения, очевидно точно
+видящего свой собственный пакет.
+
+@item
+Намного меньшее потребление памяти во время MTH хэширования когда
+смещение равно нулю: когда пакет не является докачиванием, а например
+проверяется @command{nncp-check} командой.
+
+@end itemize
+
 @node Релиз 7.1.1
 @subsection Релиз 7.1.1
 @itemize
index 731d8ef53d00f0a7aa0736f7270f7deedb947497..adf538b1d8c4079d29dd6f000901a21f8249e289 100644 (file)
@@ -3,12 +3,35 @@
 
 See also this page @ref{Новости, on russian}.
 
+@node Release 7_2_0
+@section Release 7.2.0
+@itemize
+
+@item
+@command{nncp-trns} command appeared for manual transition packets creation.
+
+@item
+If destination node of transitional packet has non empty @option{via}
+route, then do not ignore, but use it.
+
+@item
+Do not relay multicast packet to area message's originator, that
+obviously has seen its own packet.
+
+@item
+Much less memory usage during MTH hashing when offset is zero: when
+packet is not resumed, but for example checked with @command{nncp-check}
+command.
+
+@end itemize
+
 @node Release 7_1_1
 @section Release 7.1.1
 @itemize
 
 @item
 Fixed failing directories fsync after @file{.seen} file creation.
+
 @end itemize
 
 @node Release 7_1_0
index 17b042bc2aadbdb5a8cb37cfa2d56410ea7fc9ec..2a123c4c4fc8fce1d138ca5110e21d806a25a5d3 100644 (file)
@@ -1,5 +1,6 @@
 rm -fr nncp.html
 MAKEINFO_OPTS="$MAKEINFO_OPTS --html --css-include style.css"
+MAKEINFO_OPTS="$MAKEINFO_OPTS --set-customization-variable FORMAT_MENU=menu"
 MAKEINFO_OPTS="$MAKEINFO_OPTS --set-customization-variable SHOW_TITLE=0"
 MAKEINFO_OPTS="$MAKEINFO_OPTS --set-customization-variable DATE_IN_HEADER=1"
 MAKEINFO_OPTS="$MAKEINFO_OPTS --set-customization-variable TOP_NODE_UP_URL=index.html"
index e2f61665f1cfb67db9bb312dfe16a24888479ba5..7aed8a6005c5a6ba803a5c3fc95a5ea3840b665b 100644 (file)
@@ -1,5 +1,5 @@
 PORTNAME=      nncp
-DISTVERSION=   7.1.0
+DISTVERSION=   7.2.0
 CATEGORIES=    net
 MASTER_SITES=  http://www.nncpgo.org/download/
 
index 6c422ad005b034a7037bd15af48fde4670bb1a3c..268e547f49c009fac380ac0248d407538958adb8 100644 (file)
@@ -17,6 +17,7 @@ bin/nncp-reass
 bin/nncp-rm
 bin/nncp-stat
 bin/nncp-toss
+bin/nncp-trns
 bin/nncp-xfer
 @dir etc/newsyslog.conf.d
 @sample etc/nncp.conf.sample etc/newsyslog.conf.d/nncp.conf
index 4f0a081479c9e12b3e6a56beae33028ac12c7155..7a3d5b8041a42a11059b763a5a2ac3e285c54646 100644 (file)
@@ -79,7 +79,7 @@ func (ctx *Ctx) Check(nodeId *NodeId) bool {
        return !(ctx.checkXxIsBad(nodeId, TRx) || ctx.checkXxIsBad(nodeId, TTx))
 }
 
-func (ctx *Ctx) CheckNoCK(nodeId *NodeId, hshValue *[MTHSize]byte, mth *MTH) (int64, error) {
+func (ctx *Ctx) CheckNoCK(nodeId *NodeId, hshValue *[MTHSize]byte, mth MTH) (int64, error) {
        dirToSync := filepath.Join(ctx.Spool, nodeId.String(), string(TRx))
        pktName := Base32Codec.EncodeToString(hshValue[:])
        pktPath := filepath.Join(dirToSync, pktName)
@@ -103,7 +103,7 @@ func (ctx *Ctx) CheckNoCK(nodeId *NodeId, hshValue *[MTHSize]byte, mth *MTH) (in
        if mth == nil {
                gut, err = Check(fd, size, hshValue[:], les, ctx.ShowPrgrs)
        } else {
-               mth.PktName = pktName
+               mth.SetPktName(pktName)
                if _, err = mth.PrependFrom(bufio.NewReaderSize(fd, MTHSize)); err != nil {
                        return 0, err
                }
index ba0723221bc856e2f2a8822e46aa484ebb8c9a74..8b90ab9c0cc5eda0dbf6e1b3bcf309f96fc6c4f7 100644 (file)
@@ -42,6 +42,7 @@ func main() {
        var (
                fn        = flag.String("file", "", "Read the file instead of stdin")
                seek      = flag.Uint64("seek", 0, "Seek the file, hash, rewind, hash remaining")
+               forceFat  = flag.Bool("force-fat", false, "Force MTHFat implementation usage")
                showPrgrs = flag.Bool("progress", false, "Progress showing")
                debug     = flag.Bool("debug", false, "Print MTH steps calculations")
                version   = flag.Bool("version", false, "Print version information")
@@ -75,15 +76,20 @@ func main() {
                }
                size = fi.Size()
        }
-       mth := nncp.MTHNew(size, int64(*seek))
+       var mth nncp.MTH
+       if *forceFat {
+               mth = nncp.MTHFatNew(size, int64(*seek))
+       } else {
+               mth = nncp.MTHNew(size, int64(*seek))
+       }
        var debugger sync.WaitGroup
        if *debug {
                fmt.Println("Leaf BLAKE3 key:", hex.EncodeToString(nncp.MTHLeafKey[:]))
                fmt.Println("Node BLAKE3 key:", hex.EncodeToString(nncp.MTHNodeKey[:]))
-               mth.Events = make(chan nncp.MTHEvent)
+               events := mth.Events()
                debugger.Add(1)
                go func() {
-                       for e := range mth.Events {
+                       for e := range events {
                                var t string
                                switch e.Type {
                                case nncp.MTHEventAppend:
@@ -121,7 +127,7 @@ func main() {
                        log.Fatalln(err)
                }
                if *showPrgrs {
-                       mth.PktName = *fn
+                       mth.SetPktName(*fn)
                }
                if _, err = mth.PrependFrom(bufio.NewReaderSize(fd, nncp.MTHBlockSize)); err != nil {
                        log.Fatalln(err)
index 3cd59ecb8c6813e430e9becb1dcd3add024b90f8..58a45997af2645fa20a0bf89dbe14019f59ed33d 100644 (file)
@@ -84,7 +84,7 @@ func doPlain(ctx *nncp.Ctx, pkt nncp.Pkt, dump, decompress bool) {
        case nncp.PktTypeTrns:
                path = nncp.Base32Codec.EncodeToString(pkt.Path[:pkt.PathLen])
                node, err := ctx.FindNode(path)
-               if err != nil {
+               if err == nil {
                        path = fmt.Sprintf("%s (%s)", path, node.Name)
                }
        case nncp.PktTypeArea:
@@ -119,7 +119,9 @@ func doEncrypted(
        recipientNode := ctx.Neigh[*pktEnc.Recipient]
        if recipientNode == nil {
                area = ctx.AreaId2Area[nncp.AreaId(*pktEnc.Recipient)]
-               recipientName = "area " + area.Name
+               if area != nil {
+                       recipientName = "area " + area.Name
+               }
        } else {
                recipientName = recipientNode.Name
        }
diff --git a/src/cmd/nncp-trns/main.go b/src/cmd/nncp-trns/main.go
new file mode 100644 (file)
index 0000000..6c6e3d4
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+NNCP -- Node to Node copy, utilities for store-and-forward data exchange
+Copyright (C) 2016-2021 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
+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 <http://www.gnu.org/licenses/>.
+*/
+
+// Wrap existing encrypted packet to transition ones.
+package main
+
+import (
+       "flag"
+       "fmt"
+       "io"
+       "log"
+       "os"
+       "path/filepath"
+       "strings"
+
+       "go.cypherpunks.ru/nncp/v7"
+)
+
+func usage() {
+       fmt.Fprintf(os.Stderr, nncp.UsageHeader())
+       fmt.Fprintf(os.Stderr, "nncp-trns -- transit existing encrypted packet\n\n")
+       fmt.Fprintf(os.Stderr, "Usage: %s [options] -via NODEx[,...] NODE:PKT\n", os.Args[0])
+       fmt.Fprintf(os.Stderr, "       (to transit SPOOL/NODE/tx/PKT)\n")
+       fmt.Fprintf(os.Stderr, "       %s [options] -via NODEx[,...] /path/to/PKT\nOptions:\n",
+               os.Args[0])
+       flag.PrintDefaults()
+}
+
+func main() {
+       var (
+               cfgPath     = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
+               niceRaw     = flag.String("nice", nncp.NicenessFmt(nncp.DefaultNiceFile), "Outbound packet niceness")
+               viaOverride = flag.String("via", "", "Override Via path to destination node")
+               spoolPath   = flag.String("spool", "", "Override path to spool")
+               logPath     = flag.String("log", "", "Override path to logfile")
+               quiet       = flag.Bool("quiet", false, "Print only errors")
+               showPrgrs   = flag.Bool("progress", false, "Force progress showing")
+               omitPrgrs   = flag.Bool("noprogress", false, "Omit progress showing")
+               debug       = flag.Bool("debug", false, "Print debug messages")
+               version     = flag.Bool("version", false, "Print version information")
+               warranty    = flag.Bool("warranty", false, "Print warranty information")
+       )
+       log.SetFlags(log.Lshortfile)
+       flag.Usage = usage
+       flag.Parse()
+       if *warranty {
+               fmt.Println(nncp.Warranty)
+               return
+       }
+       if *version {
+               fmt.Println(nncp.VersionGet())
+               return
+       }
+       if flag.NArg() != 1 {
+               usage()
+               os.Exit(1)
+       }
+       nice, err := nncp.NicenessParse(*niceRaw)
+       if err != nil {
+               log.Fatalln(err)
+       }
+
+       ctx, err := nncp.CtxFromCmdline(
+               *cfgPath,
+               *spoolPath,
+               *logPath,
+               *quiet,
+               *showPrgrs,
+               *omitPrgrs,
+               *debug,
+       )
+       if err != nil {
+               log.Fatalln("Error during initialization:", err)
+       }
+       if ctx.Self == nil {
+               log.Fatalln("Config lacks private keys")
+       }
+       ctx.Umask()
+
+       var pktPath string
+       var pktName string
+       if _, err = os.Stat(flag.Arg(0)); err == nil {
+               pktPath = flag.Arg(0)
+               pktName = filepath.Base(pktPath)
+       } else {
+               splitted := strings.Split(flag.Arg(0), ":")
+               if len(splitted) != 2 {
+                       log.Fatalln("Invalid NODE:PKT specification")
+               }
+               node, err := ctx.FindNode(splitted[0])
+               if err != nil {
+                       log.Fatalln("Invalid NODE specified:", err)
+               }
+               pktPath = filepath.Join(
+                       ctx.Spool, node.Id.String(), string(nncp.TTx), splitted[1],
+               )
+               pktName = filepath.Base(splitted[1])
+       }
+
+       fd, err := os.Open(pktPath)
+       if err != nil {
+               log.Fatalln(err)
+       }
+       fi, err := fd.Stat()
+       if err != nil {
+               log.Fatalln(err)
+       }
+       pktEnc, _, err := ctx.HdrRead(fd)
+       if err != nil {
+               log.Fatalln(err)
+       }
+       if _, err = fd.Seek(0, io.SeekStart); err != nil {
+               log.Fatalln(err)
+       }
+
+       node := ctx.Neigh[*pktEnc.Recipient]
+       nncp.ViaOverride(*viaOverride, ctx, node)
+       via := node.Via[:len(node.Via)-1]
+       node = ctx.Neigh[*node.Via[len(node.Via)-1]]
+       node.Via = via
+
+       pktTrns, err := nncp.NewPkt(nncp.PktTypeTrns, 0, pktEnc.Recipient[:])
+       if err != nil {
+               panic(err)
+       }
+       if _, err = ctx.Tx(node, pktTrns, nice, fi.Size(), 0, fd, pktName, nil); err != nil {
+               log.Fatalln(err)
+       }
+}
index 63d1fc27353dac5682fee2ce24b0d0adde87fdf9..cb5c4282b868627e32691fe1e78aff346891bfa5 100644 (file)
@@ -138,7 +138,7 @@ func CtxFromCmdline(
 func (ctx *Ctx) IsEnoughSpace(want int64) bool {
        var s unix.Statfs_t
        if err := unix.Statfs(ctx.Spool, &s); err != nil {
-               log.Fatalln(err)
+               log.Fatalln("Can not stat spool:", err)
        }
        return int64(s.Bavail)*int64(s.Bsize) > want
 }
index 6cb1f3640b6f180fa363f6b8c9b7664f4ff0787a..a766925cee3b6e9b3db90a679486bc97d5fc3103 100644 (file)
@@ -20,6 +20,7 @@ package nncp
 import (
        "bytes"
        "errors"
+       "hash"
        "io"
 
        "lukechampine.com/blake3"
@@ -50,21 +51,29 @@ type MTHEvent struct {
        Hsh   []byte
 }
 
-type MTH struct {
+type MTH interface {
+       hash.Hash
+       PrependFrom(r io.Reader) (int, error)
+       SetPktName(n string)
+       PrependSize() int64
+       Events() chan MTHEvent
+}
+
+type MTHFat struct {
        size        int64
-       PrependSize int64
+       prependSize int64
        skip        int64
        skipped     bool
        hasher      *blake3.Hasher
        hashes      [][MTHSize]byte
        buf         *bytes.Buffer
        finished    bool
-       Events      chan MTHEvent
-       PktName     string
+       events      chan MTHEvent
+       pktName     string
 }
 
-func MTHNew(size, offset int64) *MTH {
-       mth := MTH{
+func MTHFatNew(size, offset int64) MTH {
+       mth := MTHFat{
                hasher: blake3.New(MTHSize, MTHLeafKey[:]),
                buf:    bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
        }
@@ -86,19 +95,28 @@ func MTHNew(size, offset int64) *MTH {
                skip = size - offset
        }
        mth.size = size
-       mth.PrependSize = prependSize
+       mth.prependSize = prependSize
        mth.skip = skip
        mth.hashes = make([][MTHSize]byte, prepends, 1+size/MTHBlockSize)
        return &mth
 }
 
-func (mth *MTH) Reset() { panic("not implemented") }
+func (mth *MTHFat) Events() chan MTHEvent {
+       mth.events = make(chan MTHEvent)
+       return mth.events
+}
+
+func (mth *MTHFat) SetPktName(pktName string) { mth.pktName = pktName }
+
+func (mth *MTHFat) PrependSize() int64 { return mth.prependSize }
 
-func (mth *MTH) Size() int { return MTHSize }
+func (mth *MTHFat) Reset() { panic("not implemented") }
 
-func (mth *MTH) BlockSize() int { return MTHBlockSize }
+func (mth *MTHFat) Size() int { return MTHSize }
 
-func (mth *MTH) Write(data []byte) (int, error) {
+func (mth *MTHFat) BlockSize() int { return MTHBlockSize }
+
+func (mth *MTHFat) Write(data []byte) (int, error) {
        if mth.finished {
                return 0, errors.New("already Sum()ed")
        }
@@ -118,8 +136,8 @@ func (mth *MTH) Write(data []byte) (int, error) {
                mth.hasher.Sum(h[:0])
                mth.hasher.Reset()
                mth.hashes = append(mth.hashes, *h)
-               if mth.Events != nil {
-                       mth.Events <- MTHEvent{
+               if mth.events != nil {
+                       mth.events <- MTHEvent{
                                MTHEventAppend,
                                0, len(mth.hashes) - 1,
                                mth.hashes[len(mth.hashes)-1][:],
@@ -129,19 +147,19 @@ func (mth *MTH) Write(data []byte) (int, error) {
        return n, err
 }
 
-func (mth *MTH) PrependFrom(r io.Reader) (int, error) {
+func (mth *MTHFat) PrependFrom(r io.Reader) (int, error) {
        if mth.finished {
                return 0, errors.New("already Sum()ed")
        }
        var err error
        buf := make([]byte, MTHBlockSize)
        var i, n, read int
-       fullsize := mth.PrependSize
-       les := LEs{{"Pkt", mth.PktName}, {"FullSize", fullsize}, {"Size", 0}}
-       for mth.PrependSize >= MTHBlockSize {
+       fullsize := mth.prependSize
+       les := LEs{{"Pkt", mth.pktName}, {"FullSize", fullsize}, {"Size", 0}}
+       for mth.prependSize >= MTHBlockSize {
                n, err = io.ReadFull(r, buf)
                read += n
-               mth.PrependSize -= MTHBlockSize
+               mth.prependSize -= MTHBlockSize
                if err != nil {
                        return read, err
                }
@@ -150,30 +168,30 @@ func (mth *MTH) PrependFrom(r io.Reader) (int, error) {
                }
                mth.hasher.Sum(mth.hashes[i][:0])
                mth.hasher.Reset()
-               if mth.Events != nil {
-                       mth.Events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
+               if mth.events != nil {
+                       mth.events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
                }
-               if mth.PktName != "" {
+               if mth.pktName != "" {
                        les[len(les)-1].V = int64(read)
                        Progress("check", les)
                }
                i++
        }
-       if mth.PrependSize > 0 {
-               n, err = io.ReadFull(r, buf[:mth.PrependSize])
+       if mth.prependSize > 0 {
+               n, err = io.ReadFull(r, buf[:mth.prependSize])
                read += n
                if err != nil {
                        return read, err
                }
-               if _, err = mth.hasher.Write(buf[:mth.PrependSize]); err != nil {
+               if _, err = mth.hasher.Write(buf[:mth.prependSize]); err != nil {
                        panic(err)
                }
                mth.hasher.Sum(mth.hashes[i][:0])
                mth.hasher.Reset()
-               if mth.Events != nil {
-                       mth.Events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
+               if mth.events != nil {
+                       mth.events <- MTHEvent{MTHEventPrepend, 0, i, mth.hashes[i][:]}
                }
-               if mth.PktName != "" {
+               if mth.pktName != "" {
                        les[len(les)-1].V = fullsize
                        Progress("check", les)
                }
@@ -181,7 +199,7 @@ func (mth *MTH) PrependFrom(r io.Reader) (int, error) {
        return read, nil
 }
 
-func (mth *MTH) Sum(b []byte) []byte {
+func (mth *MTHFat) Sum(b []byte) []byte {
        if mth.finished {
                return append(b, mth.hashes[0][:]...)
        }
@@ -194,8 +212,8 @@ func (mth *MTH) Sum(b []byte) []byte {
                mth.hasher.Sum(h[:0])
                mth.hasher.Reset()
                mth.hashes = append(mth.hashes, *h)
-               if mth.Events != nil {
-                       mth.Events <- MTHEvent{
+               if mth.events != nil {
+                       mth.events <- MTHEvent{
                                MTHEventAppend,
                                0, len(mth.hashes) - 1,
                                mth.hashes[len(mth.hashes)-1][:],
@@ -211,14 +229,14 @@ func (mth *MTH) Sum(b []byte) []byte {
                mth.hasher.Sum(h[:0])
                mth.hasher.Reset()
                mth.hashes = append(mth.hashes, *h)
-               if mth.Events != nil {
-                       mth.Events <- MTHEvent{MTHEventAppend, 0, 0, mth.hashes[0][:]}
+               if mth.events != nil {
+                       mth.events <- MTHEvent{MTHEventAppend, 0, 0, mth.hashes[0][:]}
                }
                fallthrough
        case 1:
                mth.hashes = append(mth.hashes, mth.hashes[0])
-               if mth.Events != nil {
-                       mth.Events <- MTHEvent{MTHEventAppend, 0, 1, mth.hashes[1][:]}
+               if mth.events != nil {
+                       mth.events <- MTHEvent{MTHEventAppend, 0, 1, mth.hashes[1][:]}
                }
        }
        mth.hasher = blake3.New(MTHSize, MTHNodeKey[:])
@@ -237,8 +255,8 @@ func (mth *MTH) Sum(b []byte) []byte {
                        mth.hasher.Sum(h[:0])
                        mth.hasher.Reset()
                        hashesUp = append(hashesUp, *h)
-                       if mth.Events != nil {
-                               mth.Events <- MTHEvent{
+                       if mth.events != nil {
+                               mth.events <- MTHEvent{
                                        MTHEventFold,
                                        level, len(hashesUp) - 1,
                                        hashesUp[len(hashesUp)-1][:],
@@ -247,8 +265,8 @@ func (mth *MTH) Sum(b []byte) []byte {
                }
                if len(mth.hashes)%2 == 1 {
                        hashesUp = append(hashesUp, mth.hashes[len(mth.hashes)-1])
-                       if mth.Events != nil {
-                               mth.Events <- MTHEvent{
+                       if mth.events != nil {
+                               mth.events <- MTHEvent{
                                        MTHEventAppend,
                                        level, len(hashesUp) - 1,
                                        hashesUp[len(hashesUp)-1][:],
@@ -259,8 +277,170 @@ func (mth *MTH) Sum(b []byte) []byte {
                level++
        }
        mth.finished = true
-       if mth.Events != nil {
-               close(mth.Events)
+       if mth.events != nil {
+               close(mth.events)
        }
        return append(b, mth.hashes[0][:]...)
 }
+
+type MTHSeqEnt struct {
+       l int
+       h [MTHSize]byte
+}
+
+type MTHSeq struct {
+       hasherLeaf *blake3.Hasher
+       hasherNode *blake3.Hasher
+       hashes     []MTHSeqEnt
+       buf        *bytes.Buffer
+       events     chan MTHEvent
+       ctrs       []int
+       finished   bool
+}
+
+func MTHSeqNew() *MTHSeq {
+       mth := MTHSeq{
+               hasherLeaf: blake3.New(MTHSize, MTHLeafKey[:]),
+               hasherNode: blake3.New(MTHSize, MTHNodeKey[:]),
+               buf:        bytes.NewBuffer(make([]byte, 0, 2*MTHBlockSize)),
+               ctrs:       make([]int, 1, 2),
+       }
+       return &mth
+}
+
+func (mth *MTHSeq) Reset() { panic("not implemented") }
+
+func (mth *MTHSeq) Size() int { return MTHSize }
+
+func (mth *MTHSeq) BlockSize() int { return MTHBlockSize }
+
+func (mth *MTHSeq) PrependFrom(r io.Reader) (int, error) {
+       panic("must not reach that code")
+}
+
+func (mth *MTHSeq) Events() chan MTHEvent {
+       mth.events = make(chan MTHEvent)
+       return mth.events
+}
+
+func (mth *MTHSeq) SetPktName(pktName string) {}
+
+func (mth *MTHSeq) PrependSize() int64 { return 0 }
+
+func (mth *MTHSeq) leafAdd() {
+       ent := MTHSeqEnt{l: 0}
+       mth.hasherLeaf.Sum(ent.h[:0])
+       mth.hasherLeaf.Reset()
+       mth.hashes = append(mth.hashes, ent)
+       if mth.events != nil {
+               mth.events <- MTHEvent{
+                       MTHEventAppend, 0, mth.ctrs[0],
+                       mth.hashes[len(mth.hashes)-1].h[:],
+               }
+       }
+       mth.ctrs[0]++
+}
+
+func (mth *MTHSeq) incr(l int) {
+       if len(mth.ctrs) <= l {
+               mth.ctrs = append(mth.ctrs, 0)
+       } else {
+               mth.ctrs[l]++
+       }
+}
+
+func (mth *MTHSeq) fold() {
+       for len(mth.hashes) >= 2 {
+               if mth.hashes[len(mth.hashes)-2].l != mth.hashes[len(mth.hashes)-1].l {
+                       break
+               }
+               if _, err := mth.hasherNode.Write(mth.hashes[len(mth.hashes)-2].h[:]); err != nil {
+                       panic(err)
+               }
+               if _, err := mth.hasherNode.Write(mth.hashes[len(mth.hashes)-1].h[:]); err != nil {
+                       panic(err)
+               }
+               mth.hashes = mth.hashes[:len(mth.hashes)-1]
+               end := &mth.hashes[len(mth.hashes)-1]
+               end.l++
+               mth.incr(end.l)
+               mth.hasherNode.Sum(end.h[:0])
+               mth.hasherNode.Reset()
+               if mth.events != nil {
+                       mth.events <- MTHEvent{MTHEventFold, end.l, mth.ctrs[end.l], end.h[:]}
+               }
+       }
+}
+
+func (mth *MTHSeq) Write(data []byte) (int, error) {
+       if mth.finished {
+               return 0, errors.New("already Sum()ed")
+       }
+       n, err := mth.buf.Write(data)
+       if err != nil {
+               return n, err
+       }
+       for mth.buf.Len() >= MTHBlockSize {
+               if _, err = mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
+                       return n, err
+               }
+               mth.leafAdd()
+               mth.fold()
+       }
+       return n, err
+}
+
+func (mth *MTHSeq) Sum(b []byte) []byte {
+       if mth.finished {
+               return append(b, mth.hashes[0].h[:]...)
+       }
+       if mth.buf.Len() > 0 {
+               if _, err := mth.hasherLeaf.Write(mth.buf.Next(MTHBlockSize)); err != nil {
+                       panic(err)
+               }
+               mth.leafAdd()
+               mth.fold()
+       }
+       switch mth.ctrs[0] {
+       case 0:
+               if _, err := mth.hasherLeaf.Write(nil); err != nil {
+                       panic(err)
+               }
+               mth.leafAdd()
+               fallthrough
+       case 1:
+               mth.hashes = append(mth.hashes, mth.hashes[0])
+               mth.ctrs[0]++
+               if mth.events != nil {
+                       mth.events <- MTHEvent{
+                               MTHEventAppend, 0, mth.ctrs[0],
+                               mth.hashes[len(mth.hashes)-1].h[:],
+                       }
+               }
+               mth.fold()
+       }
+       for len(mth.hashes) >= 2 {
+               l := mth.hashes[len(mth.hashes)-2].l
+               mth.incr(l)
+               mth.hashes[len(mth.hashes)-1].l = l
+               if mth.events != nil {
+                       mth.events <- MTHEvent{
+                               MTHEventAppend, l, mth.ctrs[l],
+                               mth.hashes[len(mth.hashes)-1].h[:],
+                       }
+               }
+               mth.fold()
+       }
+       mth.finished = true
+       if mth.events != nil {
+               close(mth.events)
+       }
+       return append(b, mth.hashes[0].h[:]...)
+}
+
+func MTHNew(size, offset int64) MTH {
+       if offset == 0 {
+               return MTHSeqNew()
+       }
+       return MTHFatNew(size, offset)
+}
index 2d36f07a95067eb8f3eb9b52cf0cc50d3ce34acd..a4737c09d7efbf6399420ecefc25d04eed074703 100644 (file)
@@ -26,7 +26,7 @@ import (
        "lukechampine.com/blake3"
 )
 
-func TestMTHSymmetric(t *testing.T) {
+func TestMTHFatSymmetric(t *testing.T) {
        xof := blake3.New(32, nil).XOF()
        f := func(size uint32, offset uint32) bool {
                size %= 2 * 1024 * 1024
@@ -36,13 +36,13 @@ func TestMTHSymmetric(t *testing.T) {
                }
                offset = offset % size
 
-               mth := MTHNew(int64(size), 0)
+               mth := MTHFatNew(int64(size), 0)
                if _, err := io.Copy(mth, bytes.NewReader(data)); err != nil {
                        panic(err)
                }
                hsh0 := mth.Sum(nil)
 
-               mth = MTHNew(int64(size), int64(offset))
+               mth = MTHFatNew(int64(size), int64(offset))
                if _, err := io.Copy(mth, bytes.NewReader(data[int(offset):])); err != nil {
                        panic(err)
                }
@@ -53,14 +53,14 @@ func TestMTHSymmetric(t *testing.T) {
                        return false
                }
 
-               mth = MTHNew(0, 0)
+               mth = MTHFatNew(0, 0)
                mth.Write(data)
                if bytes.Compare(hsh0, mth.Sum(nil)) != 0 {
                        return false
                }
 
                data = append(data, 0)
-               mth = MTHNew(int64(size)+1, 0)
+               mth = MTHFatNew(int64(size)+1, 0)
                if _, err := io.Copy(mth, bytes.NewReader(data)); err != nil {
                        panic(err)
                }
@@ -69,7 +69,7 @@ func TestMTHSymmetric(t *testing.T) {
                        return false
                }
 
-               mth = MTHNew(int64(size)+1, int64(offset))
+               mth = MTHFatNew(int64(size)+1, int64(offset))
                if _, err := io.Copy(mth, bytes.NewReader(data[int(offset):])); err != nil {
                        panic(err)
                }
@@ -80,7 +80,7 @@ func TestMTHSymmetric(t *testing.T) {
                        return false
                }
 
-               mth = MTHNew(0, 0)
+               mth = MTHFatNew(0, 0)
                mth.Write(data)
                if bytes.Compare(hsh00, mth.Sum(nil)) != 0 {
                        return false
@@ -93,10 +93,42 @@ func TestMTHSymmetric(t *testing.T) {
        }
 }
 
+func TestMTHSeqAndFatEqual(t *testing.T) {
+       xof := blake3.New(32, nil).XOF()
+       f := func(size uint32, offset uint32) bool {
+               size %= 10 * 1024 * 1024
+               data := make([]byte, int(size), int(size)+1)
+               if _, err := io.ReadFull(xof, data); err != nil {
+                       panic(err)
+               }
+               fat := MTHFatNew(int64(size), 0)
+               if _, err := io.Copy(fat, bytes.NewReader(data)); err != nil {
+                       panic(err)
+               }
+               hshFat := fat.Sum(nil)
+               seq := MTHSeqNew()
+               if _, err := io.Copy(seq, bytes.NewReader(data)); err != nil {
+                       panic(err)
+               }
+               return bytes.Compare(hshFat, seq.Sum(nil)) == 0
+       }
+       if err := quick.Check(f, nil); err != nil {
+               t.Error(err)
+       }
+}
+
 func TestMTHNull(t *testing.T) {
-       mth := MTHNew(0, 0)
-       if _, err := mth.Write(nil); err != nil {
+       fat := MTHFatNew(0, 0)
+       if _, err := fat.Write(nil); err != nil {
                t.Error(err)
        }
-       mth.Sum(nil)
+       hshFat := fat.Sum(nil)
+
+       seq := MTHSeqNew()
+       if _, err := seq.Write(nil); err != nil {
+               t.Error(err)
+       }
+       if bytes.Compare(hshFat, seq.Sum(nil)) != 0 {
+               t.FailNow()
+       }
 }
index d2042c37f945c30af8c1f659ce5835f959fb9e81..4e0eb667aa72b7cbb34286d046c25b06c676a0b7 100644 (file)
@@ -40,7 +40,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.`
 const Base32Encoded32Len = 52
 
 var (
-       Version string = "7.1.1"
+       Version string = "7.2.0"
 
        Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
 )
index a1f51ebf80276b143675159248c97514ba621494..1bb8f75d6e628b4b294f0b931dbdaf6d7af6b33c 100644 (file)
--- a/src/sp.go
+++ b/src/sp.go
@@ -41,14 +41,14 @@ const (
 )
 
 type MTHAndOffset struct {
-       mth    *MTH
+       mth    MTH
        offset uint64
 }
 
 type SPCheckerTask struct {
        nodeId *NodeId
        hsh    *[MTHSize]byte
-       mth    *MTH
+       mth    MTH
        done   chan []byte
 }
 
@@ -1439,7 +1439,7 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
                        }
                        if hasherAndOffset != nil {
                                delete(state.fileHashers, filePath)
-                               if hasherAndOffset.mth.PrependSize == 0 {
+                               if hasherAndOffset.mth.PrependSize() == 0 {
                                        if bytes.Compare(hasherAndOffset.mth.Sum(nil), file.Hash[:]) != 0 {
                                                state.Ctx.LogE(
                                                        "sp-file-bad-checksum", lesp,
index 69ad45536e2ba0427e2ba90b5b9d104e6b924301..dc5573bd675527fb63084b5b2be2972dfbee130c 100644 (file)
@@ -588,11 +588,35 @@ func jobProcess(
                }
                ctx.LogD("rx-tx", les, logMsg)
                if !dryRun {
-                       if err = ctx.TxTrns(node, nice, int64(pktSize), pipeR); err != nil {
-                               ctx.LogE("rx", les, err, func(les LEs) string {
-                                       return logMsg(les) + ": txing"
-                               })
-                               return err
+                       if len(node.Via) == 0 {
+                               if err = ctx.TxTrns(node, nice, int64(pktSize), pipeR); err != nil {
+                                       ctx.LogE("rx", les, err, func(les LEs) string {
+                                               return logMsg(les) + ": txing"
+                                       })
+                                       return err
+                               }
+                       } else {
+                               via := node.Via[:len(node.Via)-1]
+                               node = ctx.Neigh[*node.Via[len(node.Via)-1]]
+                               node = &Node{Id: node.Id, Via: via, ExchPub: node.ExchPub}
+                               pktTrns, err := NewPkt(PktTypeTrns, 0, nodeId[:])
+                               if err != nil {
+                                       panic(err)
+                               }
+                               if _, err = ctx.Tx(
+                                       node,
+                                       pktTrns,
+                                       nice,
+                                       int64(pktSize), 0,
+                                       pipeR,
+                                       pktName,
+                                       nil,
+                               ); err != nil {
+                                       ctx.LogE("rx", les, err, func(les LEs) string {
+                                               return logMsg(les) + ": txing"
+                                       })
+                                       return err
+                               }
                        }
                }
                ctx.LogI("rx", les, func(les LEs) string {
@@ -705,7 +729,7 @@ func jobProcess(
                                        })
                                        continue
                                }
-                               if nodeId != sender.Id {
+                               if nodeId != sender.Id && nodeId != pktEnc.Sender {
                                        ctx.LogI("rx-area-echo", lesEcho, logMsgNode)
                                        if _, err = ctx.Tx(
                                                node, &pkt, nice, int64(pktSize), 0, fullPipeR, pktName, nil,
@@ -820,7 +844,7 @@ func jobProcess(
                        )
                        if err != nil {
                                pipeW.CloseWithError(err)
-                               go func() { <-errs }()
+                               <-errs
                                return err
                        }
                        pipeW.Close()
@@ -917,6 +941,18 @@ func (ctx *Ctx) Toss(
                        isBad = true
                        continue
                }
+               sender := ctx.Neigh[*job.PktEnc.Sender]
+               if sender == nil {
+                       err := errors.New("unknown node")
+                       ctx.LogE("rx-open", les, err, func(les LEs) string {
+                               return fmt.Sprintf(
+                                       "Tossing %s/%s",
+                                       ctx.NodeName(job.PktEnc.Sender), pktName,
+                               )
+                       })
+                       isBad = true
+                       continue
+               }
                errs := make(chan error, 1)
                var sharedKey []byte
        Retry:
@@ -927,7 +963,7 @@ func (ctx *Ctx) Toss(
                                pipeR,
                                pktName,
                                les,
-                               ctx.Neigh[*job.PktEnc.Sender],
+                               sender,
                                job.PktEnc.Nice,
                                uint64(pktSizeWithoutEnc(job.Size)),
                                job.Path,
@@ -955,7 +991,7 @@ func (ctx *Ctx) Toss(
                if err != nil {
                        isBad = true
                        fd.Close()
-                       go func() { <-errs }()
+                       <-errs
                        continue
                }
                if err = <-errs; err == JobRepeatProcess {