]> Cypherpunks.ru repositories - nncp.git/commitdiff
ACK
authorSergey Matveev <stargrave@stargrave.org>
Mon, 28 Feb 2022 13:29:20 +0000 (16:29 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Wed, 2 Mar 2022 10:59:15 +0000 (13:59 +0300)
23 files changed:
bin/cmd.list
doc/cmd/index.texi
doc/cmd/nncp-ack.texi [new file with mode: 0644]
doc/news.ru.texi
doc/news.texi
doc/pkt/plain.texi
doc/usecases.ru/nolink.texi
doc/usecases/nolink.texi
doc/workflow.texi
ports/nncp/Makefile
ports/nncp/pkg-plist
src/call.go
src/cmd/nncp-ack/main.go [new file with mode: 0644]
src/cmd/nncp-call/main.go
src/cmd/nncp-caller/main.go
src/cmd/nncp-daemon/main.go
src/cmd/nncp-pkt/main.go
src/cmd/nncp-toss/main.go
src/nncp.go
src/pkt.go
src/toss.go
src/toss_test.go
src/tx.go

index de2a35f2a07a4fc19d152c89fd15ec7974a2820b..8a50ab588623fe058841b7355cdf03bfcc1a8199 100644 (file)
@@ -1,3 +1,4 @@
+nncp-ack
 nncp-bundle
 nncp-call
 nncp-caller
 nncp-bundle
 nncp-call
 nncp-caller
index 9f3c887bfc316a6122ca9869ed4e45d58d3e4e89..fa2b38ee0394090d6f86cb44752a1e5484d559e9 100644 (file)
@@ -69,6 +69,7 @@ Packets creation commands
 * nncp-exec::
 * nncp-freq::
 * nncp-trns::
 * nncp-exec::
 * nncp-freq::
 * nncp-trns::
+* nncp-ack::
 
 Packets sharing commands
 
 
 Packets sharing commands
 
@@ -105,6 +106,7 @@ Maintenance, monitoring and debugging commands:
 @include cmd/nncp-exec.texi
 @include cmd/nncp-freq.texi
 @include cmd/nncp-trns.texi
 @include cmd/nncp-exec.texi
 @include cmd/nncp-freq.texi
 @include cmd/nncp-trns.texi
+@include cmd/nncp-ack.texi
 @include cmd/nncp-xfer.texi
 @include cmd/nncp-bundle.texi
 @include cmd/nncp-toss.texi
 @include cmd/nncp-xfer.texi
 @include cmd/nncp-bundle.texi
 @include cmd/nncp-toss.texi
diff --git a/doc/cmd/nncp-ack.texi b/doc/cmd/nncp-ack.texi
new file mode 100644 (file)
index 0000000..14feac3
--- /dev/null
@@ -0,0 +1,60 @@
+@node nncp-ack
+@cindex packet acknowledgement
+@pindex nncp-ack
+@section nncp-ack
+
+@example
+$ nncp-ack [options] NODE [PKT|rx]
+@end example
+
+Sent acknowledgement of successful @option{PKT} (Base32-encoded hash)
+packet receipt. If @option{rx} is specified instead, then all
+@option{NODE}'s existing @code{rx} packets will be acknowledged.
+
+General workflow with acknowledgement is following, assuming that
+Alice has some outbound packets for Bob:
+
+@itemize
+
+@item Transfer an encrypted packets, without deleting them locally:
+
+@example
+alice$ nncp-xfer -keep -tx -node bob /mnt/shared
+@end example
+
+@item On Bob's side retrieve those packets:
+
+@example
+bob$ nncp-xfer -rx /mnt/shared
+@end example
+
+That will also check if copied packets checksum is not mismatched.
+
+@item Create ACK packets of received ones:
+
+@example
+bob$ nncp-ack alice rx
+@end example
+
+@item Send those newly created packets back to Alice:
+
+@example
+bob$ nncp-xfer -tx /mnt/shared
+@end example
+
+@item Get those acknowledgement packets and @ref{nncp-toss, toss} them:
+
+@example
+alice$ nncp-xfer -rx /mnt/shared
+alice$ nncp-toss
+@end example
+
+Each ACK packet will remove kept corresponding outbound packets, because
+Bob explicitly confirmed their receipt.
+
+@end itemize
+
+Similarly you can use it with @command{@ref{nncp-bundle}}, but do not
+forget that by default it does not do checksumming of the packets, so
+you should either use its @option{-check} option, or run
+@command{@ref{nncp-check}} after.
index 9b19a52a8da16372f9cbf256510dc0817b4d80fb..abd4405b70bbd69f828e431ca0103e084f417e08 100644 (file)
@@ -9,6 +9,11 @@
 @command{nncp-xfer} проверяет сходится ли контрольная сумма
 скопированного локально пакета и исходного.
 
 @command{nncp-xfer} проверяет сходится ли контрольная сумма
 скопированного локально пакета и исходного.
 
+@item
+Появилась @command{nncp-ack} команда, которая отправляет явное
+подтверждение доставки пакета (ACK пакет). Это подтверждение удаляет
+упомянутый пакет из исходящего spool-а.
+
 @item
 Появилась возможность отключения @code{fsync} операции
 @env{$NNCPNOSYNC=1} переменной окружения.
 @item
 Появилась возможность отключения @code{fsync} операции
 @env{$NNCPNOSYNC=1} переменной окружения.
index 03c719710ca773210f666dfb7070769d9bcfe45e..c0a7912e30f643956b3ab2f0ad4a4527c82bf628 100644 (file)
@@ -12,6 +12,11 @@ See also this page @ref{Новости, on russian}.
 @command{nncp-xfer} checks if locally copied packet's checksum differs
 from the source's one.
 
 @command{nncp-xfer} checks if locally copied packet's checksum differs
 from the source's one.
 
+@item
+@command{nncp-ack} command appeared, that sends explicit packet receipt
+acknowledgement (ACK packet). That acknowledgement deletes referenced
+packet from the outbound spool.
+
 @item
 Ability to turn @code{fsync} operation off using @env{$NNCPNOSYNC=1}
 environment variable.
 @item
 Ability to turn @code{fsync} operation off using @env{$NNCPNOSYNC=1}
 environment variable.
index 7af4360f36171df73546aaeb03013e82aa6a72b0..235b8135286fbb9256ef9636b1cffe4245a7db9c 100644 (file)
@@ -28,6 +28,7 @@ drive.
     @item trns (transition)
     @item exec-fat (uncompressed exec)
     @item area (@ref{Multicast, multicast} area message)
     @item trns (transition)
     @item exec-fat (uncompressed exec)
     @item area (@ref{Multicast, multicast} area message)
+    @item ack (receipt acknowledgement)
     @end enumerate
 @item Niceness @tab
     unsigned integer @tab
     @end enumerate
 @item Niceness @tab
     unsigned integer @tab
@@ -44,6 +45,7 @@ drive.
     @item UTF-8 encoded, zero byte separated, exec's arguments
     @item Node's id the transition packet must be relayed on
     @item Multicast area's id
     @item UTF-8 encoded, zero byte separated, exec's arguments
     @item Node's id the transition packet must be relayed on
     @item Multicast area's id
+    @item Packet's id (its @ref{MTH} hash)
     @end itemize
 @end multitable
 
     @end itemize
 @end multitable
 
@@ -62,6 +64,7 @@ Depending on the packet's type, payload could store:
     compressed exec body
 @item Whole encrypted packet we need to relay on
 @item Multicast area message wrap with another encrypted packet inside
     compressed exec body
 @item Whole encrypted packet we need to relay on
 @item Multicast area message wrap with another encrypted packet inside
+@item Nothing, if it is acknowledgement packet
 @end itemize
 
 Also depending on packet's type, niceness level means:
 @end itemize
 
 Also depending on packet's type, niceness level means:
@@ -142,4 +145,15 @@ So plain packets can hold following paths and payloads:
 @end example
 See also @ref{Encrypted area, encrypted area packet}.
 
 @end example
 See also @ref{Encrypted area, encrypted area packet}.
 
+@item ack
+@example
+  +------- PATH --------+
+ /                       \
++-------------------------+
+|  PKT ID | 0x00 ... 0x00 |
++-------------------------+
+ \       /
+  PATHLEN
+@end example
+
 @end table
 @end table
index 6bc2d576a7f43b477554449c35f9e547c5b5db08..a74b4618a890104f957032a89a694359fa483b44 100644 (file)
@@ -37,3 +37,6 @@ $ nncp-xfer /media/usbstick
 чтобы найти все пакеты относящиеся к их узлу и локально скопируют для
 дальнейшей обработки. @command{@ref{nncp-xfer}} это единственная команда
 используемая с переносными устройствами хранения.
 чтобы найти все пакеты относящиеся к их узлу и локально скопируют для
 дальнейшей обработки. @command{@ref{nncp-xfer}} это единственная команда
 используемая с переносными устройствами хранения.
+
+Вы также можете опционально использовать явное подтверждение приёма
+пакетов, как описано в @command{@ref{nncp-ack}}.
index de3593c2ac240a8d67c4ea6317ba77d2551e0657..fc8a40bfa118a914a1c258a75e29964c7517276d 100644 (file)
@@ -36,3 +36,6 @@ $ nncp-xfer /media/usbstick
 to find all packets related to their node and copy them locally for
 further processing. @command{@ref{nncp-xfer}} is the only command used with
 removable devices.
 to find all packets related to their node and copy them locally for
 further processing. @command{@ref{nncp-xfer}} is the only command used with
 removable devices.
+
+You can also optionally wait for explicit packets receipt
+acknowledgement as described in @command{@ref{nncp-ack}}.
index 7b64f7f8e8cc6e335072f170d0fe202bc2556a1b..fbd3eea20d9efa60f59c92f98f6a2cf52fdbcce2 100644 (file)
@@ -41,6 +41,9 @@ time), run @command{@ref{nncp-toss}} for tossing (decrypting and
 processing) all inbound queues to receive exec messages, files, file
 requests and relay transition packets to other nodes.
 
 processing) all inbound queues to receive exec messages, files, file
 requests and relay transition packets to other nodes.
 
+@item Optionally do not forget about explicit receipt acknowledgement
+ability with @command{@ref{nncp-ack}}.
+
 @end enumerate
 
 @itemize
 @end enumerate
 
 @itemize
index 6ff741a63b4370ff472432d0bf6505a552ae0d74..05c0ad1bdaa4a3bab031dea295487e4ae90a2600 100644 (file)
@@ -1,5 +1,5 @@
 PORTNAME=      nncp
 PORTNAME=      nncp
-DISTVERSION=   7.6.0
+DISTVERSION=   8.6.0
 CATEGORIES=    net
 MASTER_SITES=  http://www.nncpgo.org/download/
 
 CATEGORIES=    net
 MASTER_SITES=  http://www.nncpgo.org/download/
 
index e360a4ac72023754517d660e825aaac58cd360d4..e89c748f3046da33a7a479f9f20fb90bbe31e7a1 100644 (file)
@@ -1,3 +1,4 @@
+bin/nncp-ack
 bin/nncp-bundle
 bin/nncp-call
 bin/nncp-caller
 bin/nncp-bundle
 bin/nncp-call
 bin/nncp-caller
index c4e04cbd9d2a1a47a1e5c5f27a62410b159d0a0c..295e7c8805c62eaee4cf0d3fd5051e4e86fb2251 100644 (file)
@@ -50,6 +50,7 @@ type Call struct {
        AutoTossNoExec bool
        AutoTossNoTrns bool
        AutoTossNoArea bool
        AutoTossNoExec bool
        AutoTossNoTrns bool
        AutoTossNoArea bool
+       AutoTossNoACK  bool
 }
 
 func (ctx *Ctx) CallNode(
 }
 
 func (ctx *Ctx) CallNode(
diff --git a/src/cmd/nncp-ack/main.go b/src/cmd/nncp-ack/main.go
new file mode 100644 (file)
index 0000000..df912f1
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+NNCP -- Node to Node copy, utilities for store-and-forward data exchange
+Copyright (C) 2016-2022 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/>.
+*/
+
+// Send packet receipt acknowledgement via NNCP.
+package main
+
+import (
+       "flag"
+       "fmt"
+       "log"
+       "os"
+       "path/filepath"
+
+       "go.cypherpunks.ru/nncp/v8"
+)
+
+func usage() {
+       fmt.Fprintf(os.Stderr, nncp.UsageHeader())
+       fmt.Fprintf(os.Stderr, "nncp-ack -- send packet receipt acknowledgement\n\n")
+       fmt.Fprintf(os.Stderr, "Usage: %s [options] NODE [PKT|rx]\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.DefaultNiceFreq), "Outbound packet niceness")
+               minSizeRaw  = flag.Uint64("minsize", 0, "Minimal required resulting packet size, in KiB")
+               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() != 2 {
+               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")
+       }
+
+       node, err := ctx.FindNode(flag.Arg(0))
+       if err != nil {
+               log.Fatalln("Invalid NODE specified:", err)
+       }
+
+       nncp.ViaOverride(*viaOverride, ctx, node)
+       ctx.Umask()
+       minSize := int64(*minSizeRaw) * 1024
+
+       if flag.Arg(1) == string(nncp.TRx) {
+               for job := range ctx.Jobs(node.Id, nncp.TRx) {
+                       pktName := filepath.Base(job.Path)
+                       if err = ctx.TxACK(node, nice, pktName, minSize); err != nil {
+                               log.Fatalln(err)
+                       }
+               }
+       } else {
+               if err = ctx.TxACK(node, nice, flag.Arg(1), minSize); err != nil {
+                       log.Fatalln(err)
+               }
+       }
+}
index 82cec19987583b888932f6a25bed2259906a5b1c..4d8fb0648a3eaf547b4d635bec8cf0a584e70a16 100644 (file)
@@ -71,6 +71,7 @@ func main() {
                autoTossNoExec = flag.Bool("autotoss-noexec", false, "Do not process \"exec\" packets during tossing")
                autoTossNoTrns = flag.Bool("autotoss-notrns", false, "Do not process \"trns\" packets during tossing")
                autoTossNoArea = flag.Bool("autotoss-noarea", false, "Do not process \"area\" packets during tossing")
                autoTossNoExec = flag.Bool("autotoss-noexec", false, "Do not process \"exec\" packets during tossing")
                autoTossNoTrns = flag.Bool("autotoss-notrns", false, "Do not process \"trns\" packets during tossing")
                autoTossNoArea = flag.Bool("autotoss-noarea", false, "Do not process \"area\" packets during tossing")
+               autoTossNoACK  = flag.Bool("autotoss-noack", false, "Do not process \"ack\" packets during tossing")
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -217,6 +218,7 @@ func main() {
                        *autoTossNoExec,
                        *autoTossNoTrns,
                        *autoTossNoArea,
                        *autoTossNoExec,
                        *autoTossNoTrns,
                        *autoTossNoArea,
+                       *autoTossNoACK,
                )
        }
 
                )
        }
 
index 690244141eaf87e151112c3822b7c8ff9c637ff0..50d9bf4fc8b85aa8737cc48f2fd428b53bffa89d 100644 (file)
@@ -59,6 +59,7 @@ func main() {
                autoTossNoExec = flag.Bool("autotoss-noexec", false, "Do not process \"exec\" packets during tossing")
                autoTossNoTrns = flag.Bool("autotoss-notrns", false, "Do not process \"trns\" packets during tossing")
                autoTossNoArea = flag.Bool("autotoss-noarea", false, "Do not process \"area\" packets during tossing")
                autoTossNoExec = flag.Bool("autotoss-noexec", false, "Do not process \"exec\" packets during tossing")
                autoTossNoTrns = flag.Bool("autotoss-notrns", false, "Do not process \"trns\" packets during tossing")
                autoTossNoArea = flag.Bool("autotoss-noarea", false, "Do not process \"area\" packets during tossing")
+               autoTossNoACK  = flag.Bool("autotoss-noack", false, "Do not process \"ack\" packets during tossing")
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -219,6 +220,7 @@ func main() {
                                                                call.AutoTossNoExec || *autoTossNoExec,
                                                                call.AutoTossNoTrns || *autoTossNoTrns,
                                                                call.AutoTossNoArea || *autoTossNoArea,
                                                                call.AutoTossNoExec || *autoTossNoExec,
                                                                call.AutoTossNoTrns || *autoTossNoTrns,
                                                                call.AutoTossNoArea || *autoTossNoArea,
+                                                               call.AutoTossNoACK || *autoTossNoACK,
                                                        )
                                                }
 
                                                        )
                                                }
 
index 5fd6f6d0353f5cc0e7e5e5212234e9bd4def05ea..710b687826fbb7b73f8a818ec1332779d9a08efa 100644 (file)
@@ -158,6 +158,7 @@ func main() {
                autoTossNoExec = flag.Bool("autotoss-noexec", false, "Do not process \"exec\" packets during tossing")
                autoTossNoTrns = flag.Bool("autotoss-notrns", false, "Do not process \"trns\" packets during tossing")
                autoTossNoArea = flag.Bool("autotoss-noarea", false, "Do not process \"area\" packets during tossing")
                autoTossNoExec = flag.Bool("autotoss-noexec", false, "Do not process \"exec\" packets during tossing")
                autoTossNoTrns = flag.Bool("autotoss-notrns", false, "Do not process \"trns\" packets during tossing")
                autoTossNoArea = flag.Bool("autotoss-noarea", false, "Do not process \"area\" packets during tossing")
+               autoTossNoACK  = flag.Bool("autotoss-noack", false, "Do not process \"ack\" packets during tossing")
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -217,6 +218,7 @@ func main() {
                                *autoTossNoExec,
                                *autoTossNoTrns,
                                *autoTossNoArea,
                                *autoTossNoExec,
                                *autoTossNoTrns,
                                *autoTossNoArea,
+                               *autoTossNoACK,
                        )
                }
                <-nodeIdC // call completion
                        )
                }
                <-nodeIdC // call completion
@@ -303,6 +305,7 @@ func main() {
                                        *autoTossNoExec,
                                        *autoTossNoTrns,
                                        *autoTossNoArea,
                                        *autoTossNoExec,
                                        *autoTossNoTrns,
                                        *autoTossNoArea,
+                                       *autoTossNoACK,
                                )
                        }
                        <-nodeIdC // call completion
                                )
                        }
                        <-nodeIdC // call completion
index 54844dc4daecacbd5d60b761349698f0f8da8fa6..d40b8c5f859a969296acab7d012dc53fdb123721 100644 (file)
@@ -74,6 +74,8 @@ func doPlain(ctx *nncp.Ctx, pkt nncp.Pkt, dump, decompress bool) {
                payloadType = "exec uncompressed"
        case nncp.PktTypeArea:
                payloadType = "area"
                payloadType = "exec uncompressed"
        case nncp.PktTypeArea:
                payloadType = "area"
+       case nncp.PktTypeACK:
+               payloadType = "acknowledgement"
        }
        var path string
        switch pkt.Type {
        }
        var path string
        switch pkt.Type {
@@ -92,6 +94,8 @@ func doPlain(ctx *nncp.Ctx, pkt nncp.Pkt, dump, decompress bool) {
                if areaId, err := nncp.AreaIdFromString(path); err == nil {
                        path = fmt.Sprintf("%s (%s)", path, ctx.AreaName(areaId))
                }
                if areaId, err := nncp.AreaIdFromString(path); err == nil {
                        path = fmt.Sprintf("%s (%s)", path, ctx.AreaName(areaId))
                }
+       case nncp.PktTypeACK:
+               path = nncp.Base32Codec.EncodeToString(pkt.Path[:pkt.PathLen])
        default:
                path = string(pkt.Path[:pkt.PathLen])
        }
        default:
                path = string(pkt.Path[:pkt.PathLen])
        }
index 4eca181635d2281eef161407fed31e93dd347214..76bb7653b2e97f177e0313d1005b33b8f3ef9d84 100644 (file)
@@ -49,6 +49,7 @@ func main() {
                noExec    = flag.Bool("noexec", false, "Do not process \"exec\" packets")
                noTrns    = flag.Bool("notrns", false, "Do not process \"transitional\" packets")
                noArea    = flag.Bool("noarea", false, "Do not process \"area\" packets")
                noExec    = flag.Bool("noexec", false, "Do not process \"exec\" packets")
                noTrns    = flag.Bool("notrns", false, "Do not process \"transitional\" packets")
                noArea    = flag.Bool("noarea", false, "Do not process \"area\" packets")
+               noACK     = flag.Bool("noack", false, "Do not process \"ack\" packets")
                spoolPath = flag.String("spool", "", "Override path to spool")
                logPath   = flag.String("log", "", "Override path to logfile")
                quiet     = flag.Bool("quiet", false, "Print only errors")
                spoolPath = flag.String("spool", "", "Override path to spool")
                logPath   = flag.String("log", "", "Override path to logfile")
                quiet     = flag.Bool("quiet", false, "Print only errors")
@@ -110,14 +111,14 @@ func main() {
                                node.Id,
                                nncp.TRx,
                                nice,
                                node.Id,
                                nncp.TRx,
                                nice,
-                               *dryRun, *doSeen, *noFile, *noFreq, *noExec, *noTrns, *noArea,
+                               *dryRun, *doSeen, *noFile, *noFreq, *noExec, *noTrns, *noArea, *noACK,
                        ) || isBad
                        if nodeId == *ctx.SelfId {
                                isBad = ctx.Toss(
                                        node.Id,
                                        nncp.TTx,
                                        nice,
                        ) || isBad
                        if nodeId == *ctx.SelfId {
                                isBad = ctx.Toss(
                                        node.Id,
                                        nncp.TTx,
                                        nice,
-                                       *dryRun, false, true, true, true, true, *noArea,
+                                       *dryRun, false, true, true, true, true, *noArea, *noACK,
                                ) || isBad
                        }
                }
                                ) || isBad
                        }
                }
@@ -150,14 +151,14 @@ func main() {
                        nodeId,
                        nncp.TRx,
                        nice,
                        nodeId,
                        nncp.TRx,
                        nice,
-                       *dryRun, *doSeen, *noFile, *noFreq, *noExec, *noTrns, *noArea,
+                       *dryRun, *doSeen, *noFile, *noFreq, *noExec, *noTrns, *noArea, *noACK,
                )
                if *nodeId == *ctx.SelfId {
                        ctx.Toss(
                                nodeId,
                                nncp.TTx,
                                nice,
                )
                if *nodeId == *ctx.SelfId {
                        ctx.Toss(
                                nodeId,
                                nncp.TTx,
                                nice,
-                               *dryRun, false, true, true, true, true, *noArea,
+                               *dryRun, false, true, true, true, true, *noArea, *noACK,
                        )
                }
        }
                        )
                }
        }
index b2303c0d7aa55424a481421ab6e1367ac6e55496..0ae34704f120f803c720949b4cceda35dee49c9c 100644 (file)
@@ -40,7 +40,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.`
 const Base32Encoded32Len = 52
 
 var (
 const Base32Encoded32Len = 52
 
 var (
-       Version string = "8.5.0"
+       Version string = "8.6.0"
 
        Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
 )
 
        Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
 )
index 26c59e51e6d17cb4a9a46ca6f1f724c61b577ebb..ba711a30a86e2708803716db371dcf42ff3ed68e 100644 (file)
@@ -44,6 +44,7 @@ const (
        PktTypeTrns    PktType = iota
        PktTypeExecFat PktType = iota
        PktTypeArea    PktType = iota
        PktTypeTrns    PktType = iota
        PktTypeExecFat PktType = iota
        PktTypeArea    PktType = iota
+       PktTypeACK     PktType = iota
 
        MaxPathSize = 1<<8 - 1
 
 
        MaxPathSize = 1<<8 - 1
 
index e383257db77c43e31ddd8127160276526376983e..ebe20fbf0dd159c626d7b91801e814ddbc34ce0b 100644 (file)
@@ -91,7 +91,7 @@ func jobProcess(
        pktSize uint64,
        jobPath string,
        decompressor *zstd.Decoder,
        pktSize uint64,
        jobPath string,
        decompressor *zstd.Decoder,
-       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea bool,
+       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK bool,
 ) error {
        defer pipeR.Close()
        sendmail := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
 ) error {
        defer pipeR.Close()
        sendmail := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
@@ -858,7 +858,7 @@ func jobProcess(
                                        uint64(pktSizeWithoutEnc(int64(pktSize))),
                                        "",
                                        decompressor,
                                        uint64(pktSizeWithoutEnc(int64(pktSize))),
                                        "",
                                        decompressor,
-                                       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea,
+                                       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK,
                                )
                        }()
                        _, _, _, err = PktEncRead(
                                )
                        }()
                        _, _, _, err = PktEncRead(
@@ -908,6 +908,64 @@ func jobProcess(
                        }
                }
 
                        }
                }
 
+       case PktTypeACK:
+               if noACK {
+                       return nil
+               }
+               hsh := Base32Codec.EncodeToString(pkt.Path[:MTHSize])
+               les := append(les, LE{"Type", "ack"}, LE{"Pkt", hsh})
+               logMsg := func(les LEs) string {
+                       return fmt.Sprintf("Tossing ack %s/%s: %s", sender.Name, pktName, hsh)
+               }
+               ctx.LogD("rx-ack", les, logMsg)
+               pktPath := filepath.Join(ctx.Spool, sender.Id.String(), string(TTx), hsh)
+               if _, err := os.Stat(pktPath); err == nil {
+                       if !dryRun {
+                               if err = os.Remove(pktPath); err != nil {
+                                       ctx.LogE("rx-ack", les, err, func(les LEs) string {
+                                               return logMsg(les) + ": removing packet"
+                                       })
+                                       return err
+                               }
+                       }
+               } else {
+                       ctx.LogD("rx-ack", les, func(les LEs) string {
+                               return logMsg(les) + ": already disappeared"
+                       })
+               }
+               if !dryRun && doSeen {
+                       if err := ensureDir(filepath.Dir(jobPath), SeenDir); err != nil {
+                               return err
+                       }
+                       if fd, err := os.Create(jobPath2Seen(jobPath)); err == nil {
+                               fd.Close()
+                               if err = DirSync(filepath.Dir(jobPath)); err != nil {
+                                       ctx.LogE("rx-dirsync", les, err, func(les LEs) string {
+                                               return fmt.Sprintf(
+                                                       "Tossing file %s/%s (%s): %s: dirsyncing",
+                                                       sender.Name, pktName,
+                                                       humanize.IBytes(pktSize),
+                                                       filepath.Base(jobPath),
+                                               )
+                                       })
+                                       return err
+                               }
+                       }
+               }
+               if !dryRun {
+                       if err = os.Remove(jobPath); err != nil {
+                               ctx.LogE("rx", les, err, func(les LEs) string {
+                                       return logMsg(les) + ": removing job"
+                               })
+                               return err
+                       } else if ctx.HdrUsage {
+                               os.Remove(JobPath2Hdr(jobPath))
+                       }
+               }
+               ctx.LogI("rx", les, func(les LEs) string {
+                       return fmt.Sprintf("Got ACK packet from %s of %s", sender.Name, hsh)
+               })
+
        default:
                err = errors.New("unknown type")
                ctx.LogE(
        default:
                err = errors.New("unknown type")
                ctx.LogE(
@@ -928,7 +986,7 @@ func (ctx *Ctx) Toss(
        nodeId *NodeId,
        xx TRxTx,
        nice uint8,
        nodeId *NodeId,
        xx TRxTx,
        nice uint8,
-       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea bool,
+       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK bool,
 ) bool {
        dirLock, err := ctx.LockDir(nodeId, "toss")
        if err != nil {
 ) bool {
        dirLock, err := ctx.LockDir(nodeId, "toss")
        if err != nil {
@@ -996,7 +1054,7 @@ func (ctx *Ctx) Toss(
                                uint64(pktSizeWithoutEnc(job.Size)),
                                job.Path,
                                decompressor,
                                uint64(pktSizeWithoutEnc(job.Size)),
                                job.Path,
                                decompressor,
-                               dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea,
+                               dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK,
                        )
                }()
                pipeWB := bufio.NewWriter(pipeW)
                        )
                }()
                pipeWB := bufio.NewWriter(pipeW)
@@ -1046,7 +1104,7 @@ func (ctx *Ctx) Toss(
 func (ctx *Ctx) AutoToss(
        nodeId *NodeId,
        nice uint8,
 func (ctx *Ctx) AutoToss(
        nodeId *NodeId,
        nice uint8,
-       doSeen, noFile, noFreq, noExec, noTrns, noArea bool,
+       doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK bool,
 ) (chan struct{}, chan bool) {
        dw, err := ctx.NewDirWatcher(
                filepath.Join(ctx.Spool, nodeId.String(), string(TRx)),
 ) (chan struct{}, chan bool) {
        dw, err := ctx.NewDirWatcher(
                filepath.Join(ctx.Spool, nodeId.String(), string(TRx)),
@@ -1068,7 +1126,7 @@ func (ctx *Ctx) AutoToss(
                        case <-dw.C:
                                bad = !ctx.Toss(
                                        nodeId, TRx, nice, false,
                        case <-dw.C:
                                bad = !ctx.Toss(
                                        nodeId, TRx, nice, false,
-                                       doSeen, noFile, noFreq, noExec, noTrns, noArea) || bad
+                                       doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK) || bad
                        }
                }
        }()
                        }
                }
        }()
index 6cb68ebbc3f4fb0531f7910a451da27690425031..000653d7be96cf60c8b0fd4a09961836bea880d8 100644 (file)
@@ -113,14 +113,14 @@ func TestTossExec(t *testing.T) {
                                continue
                        }
                        ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec-1,
                                continue
                        }
                        ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec-1,
-                               false, false, false, false, false, false, false)
+                               false, false, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
                        ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
                        ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
                        ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec,
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
                        ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
                        ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
                        ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec,
-                               false, false, false, false, false, false, false)
+                               false, false, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
@@ -133,7 +133,7 @@ func TestTossExec(t *testing.T) {
                                ),
                        }
                        ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec,
                                ),
                        }
                        ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec,
-                               false, false, false, false, false, false, false)
+                               false, false, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) != 0 {
                                return false
                        }
                        if len(dirFiles(rxPath)) != 0 {
                                return false
                        }
@@ -220,13 +220,13 @@ func TestTossFile(t *testing.T) {
                rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
                os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
                rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
                os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
-                       false, false, false, false, false, false, false)
+                       false, false, false, false, false, false, false, false)
                if len(dirFiles(rxPath)) == 0 {
                        return false
                }
                ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
                if ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
                if len(dirFiles(rxPath)) == 0 {
                        return false
                }
                ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
                if ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
-                       false, false, false, false, false, false, false) {
+                       false, false, false, false, false, false, false, false) {
                        return false
                }
                if len(dirFiles(rxPath)) != 0 {
                        return false
                }
                if len(dirFiles(rxPath)) != 0 {
@@ -303,7 +303,7 @@ func TestTossFileSameName(t *testing.T) {
                os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
                ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
                os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
                ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
-                       false, false, false, false, false, false, false)
+                       false, false, false, false, false, false, false, false)
                expected := make(map[string]struct{})
                expected["samefile"] = struct{}{}
                for i := 0; i < files-1; i++ {
                expected := make(map[string]struct{})
                expected["samefile"] = struct{}{}
                for i := 0; i < files-1; i++ {
@@ -379,13 +379,13 @@ func TestTossFreq(t *testing.T) {
                os.Rename(txPath, rxPath)
                os.MkdirAll(txPath, os.FileMode(0700))
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
                os.Rename(txPath, rxPath)
                os.MkdirAll(txPath, os.FileMode(0700))
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
-                       false, false, false, false, false, false, false)
+                       false, false, false, false, false, false, false, false)
                if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
                        return false
                }
                ctx.Neigh[*nodeOur.Id].FreqPath = &spool
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
                if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
                        return false
                }
                ctx.Neigh[*nodeOur.Id].FreqPath = &spool
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
-                       false, false, false, false, false, false, false)
+                       false, false, false, false, false, false, false, false)
                if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
                        return false
                }
                if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
                        return false
                }
@@ -399,7 +399,7 @@ func TestTossFreq(t *testing.T) {
                        }
                }
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
                        }
                }
                ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
-                       false, false, false, false, false, false, false)
+                       false, false, false, false, false, false, false, false)
                if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
                        return false
                }
                if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
                        return false
                }
@@ -504,7 +504,7 @@ func TestTossTrns(t *testing.T) {
                        }
                }
                ctx.Toss(ctx.Self.Id, TRx, 123,
                        }
                }
                ctx.Toss(ctx.Self.Id, TRx, 123,
-                       false, false, false, false, false, false, false)
+                       false, false, false, false, false, false, false, false)
                if len(dirFiles(rxPath)) != 0 {
                        return false
                }
                if len(dirFiles(rxPath)) != 0 {
                        return false
                }
index f9da81b03093f6c82d500da82d5f492dfa056f33..6e13f2ef3fbeb9e4f97fe61b99d1897f6a8f6c09 100644 (file)
--- a/src/tx.go
+++ b/src/tx.go
@@ -729,3 +729,39 @@ func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error
        os.Symlink(nodePath, filepath.Join(ctx.Spool, node.Name))
        return err
 }
        os.Symlink(nodePath, filepath.Join(ctx.Spool, node.Name))
        return err
 }
+
+func (ctx *Ctx) TxACK(
+       node *Node,
+       nice uint8,
+       hsh string,
+       minSize int64,
+) error {
+       hshRaw, err := Base32Codec.DecodeString(hsh)
+       if err != nil {
+               return err
+       }
+       if len(hshRaw) != MTHSize {
+               return errors.New("Invalid packet id size")
+       }
+       pkt, err := NewPkt(PktTypeACK, nice, []byte(hshRaw))
+       if err != nil {
+               return err
+       }
+       src := bytes.NewReader([]byte{})
+       _, _, err = ctx.Tx(node, pkt, nice, 0, minSize, MaxFileSize, src, hsh, nil)
+       les := LEs{
+               {"Type", "ack"},
+               {"Node", node.Id},
+               {"Nice", int(nice)},
+               {"Pkt", hsh},
+       }
+       logMsg := func(les LEs) string {
+               return fmt.Sprintf("ACK to %s of %s is sent", ctx.NodeName(node.Id), hsh)
+       }
+       if err == nil {
+               ctx.LogI("tx", les, logMsg)
+       } else {
+               ctx.LogE("tx", les, err, logMsg)
+       }
+       return err
+}