]> 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
index 9f3c887bfc316a6122ca9869ed4e45d58d3e4e89..fa2b38ee0394090d6f86cb44752a1e5484d559e9 100644 (file)
@@ -69,6 +69,7 @@ Packets creation commands
 * nncp-exec::
 * nncp-freq::
 * nncp-trns::
+* nncp-ack::
 
 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-ack.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} проверяет сходится ли контрольная сумма
 скопированного локально пакета и исходного.
 
+@item
+Появилась @command{nncp-ack} команда, которая отправляет явное
+подтверждение доставки пакета (ACK пакет). Это подтверждение удаляет
+упомянутый пакет из исходящего spool-а.
+
 @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.
 
+@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.
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 ack (receipt acknowledgement)
     @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 Packet's id (its @ref{MTH} hash)
     @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
+@item Nothing, if it is acknowledgement packet
 @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}.
 
+@item ack
+@example
+  +------- PATH --------+
+ /                       \
++-------------------------+
+|  PKT ID | 0x00 ... 0x00 |
++-------------------------+
+ \       /
+  PATHLEN
+@end example
+
 @end table
index 6bc2d576a7f43b477554449c35f9e547c5b5db08..a74b4618a890104f957032a89a694359fa483b44 100644 (file)
@@ -37,3 +37,6 @@ $ nncp-xfer /media/usbstick
 чтобы найти все пакеты относящиеся к их узлу и локально скопируют для
 дальнейшей обработки. @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.
+
+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.
 
+@item Optionally do not forget about explicit receipt acknowledgement
+ability with @command{@ref{nncp-ack}}.
+
 @end enumerate
 
 @itemize
index 6ff741a63b4370ff472432d0bf6505a552ae0d74..05c0ad1bdaa4a3bab031dea295487e4ae90a2600 100644 (file)
@@ -1,5 +1,5 @@
 PORTNAME=      nncp
-DISTVERSION=   7.6.0
+DISTVERSION=   8.6.0
 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
index c4e04cbd9d2a1a47a1e5c5f27a62410b159d0a0c..295e7c8805c62eaee4cf0d3fd5051e4e86fb2251 100644 (file)
@@ -50,6 +50,7 @@ type Call struct {
        AutoTossNoExec bool
        AutoTossNoTrns bool
        AutoTossNoArea bool
+       AutoTossNoACK  bool
 }
 
 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")
+               autoTossNoACK  = flag.Bool("autotoss-noack", false, "Do not process \"ack\" packets during tossing")
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -217,6 +218,7 @@ func main() {
                        *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")
+               autoTossNoACK  = flag.Bool("autotoss-noack", false, "Do not process \"ack\" packets during tossing")
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -219,6 +220,7 @@ func main() {
                                                                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")
+               autoTossNoACK  = flag.Bool("autotoss-noack", false, "Do not process \"ack\" packets during tossing")
        )
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -217,6 +218,7 @@ func main() {
                                *autoTossNoExec,
                                *autoTossNoTrns,
                                *autoTossNoArea,
+                               *autoTossNoACK,
                        )
                }
                <-nodeIdC // call completion
@@ -303,6 +305,7 @@ func main() {
                                        *autoTossNoExec,
                                        *autoTossNoTrns,
                                        *autoTossNoArea,
+                                       *autoTossNoACK,
                                )
                        }
                        <-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"
+       case nncp.PktTypeACK:
+               payloadType = "acknowledgement"
        }
        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))
                }
+       case nncp.PktTypeACK:
+               path = nncp.Base32Codec.EncodeToString(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")
+               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")
@@ -110,14 +111,14 @@ func main() {
                                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,
-                                       *dryRun, false, true, true, true, true, *noArea,
+                                       *dryRun, false, true, true, true, true, *noArea, *noACK,
                                ) || isBad
                        }
                }
@@ -150,14 +151,14 @@ func main() {
                        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,
-                               *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 (
-       Version string = "8.5.0"
+       Version string = "8.6.0"
 
        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
+       PktTypeACK     PktType = iota
 
        MaxPathSize = 1<<8 - 1
 
index e383257db77c43e31ddd8127160276526376983e..ebe20fbf0dd159c626d7b91801e814ddbc34ce0b 100644 (file)
@@ -91,7 +91,7 @@ func jobProcess(
        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"]
@@ -858,7 +858,7 @@ func jobProcess(
                                        uint64(pktSizeWithoutEnc(int64(pktSize))),
                                        "",
                                        decompressor,
-                                       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea,
+                                       dryRun, doSeen, noFile, noFreq, noExec, noTrns, noArea, noACK,
                                )
                        }()
                        _, _, _, 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(
@@ -928,7 +986,7 @@ func (ctx *Ctx) Toss(
        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 {
@@ -996,7 +1054,7 @@ func (ctx *Ctx) Toss(
                                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)
@@ -1046,7 +1104,7 @@ func (ctx *Ctx) Toss(
 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)),
@@ -1068,7 +1126,7 @@ func (ctx *Ctx) AutoToss(
                        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,
-                               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,
-                               false, false, false, false, false, false, false)
+                               false, false, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
@@ -133,7 +133,7 @@ func TestTossExec(t *testing.T) {
                                ),
                        }
                        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
                        }
@@ -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,
-                       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,
-                       false, false, false, false, false, false, false) {
+                       false, false, false, false, false, false, false, false) {
                        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,
-                       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++ {
@@ -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,
-                       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,
-                       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
                }
@@ -399,7 +399,7 @@ func TestTossFreq(t *testing.T) {
                        }
                }
                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
                }
@@ -504,7 +504,7 @@ func TestTossTrns(t *testing.T) {
                        }
                }
                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
                }
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
 }
+
+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
+}