From 2e59e1d8da61bc5dee797d351e50e8ed114aa4c7 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Mon, 28 Feb 2022 16:29:20 +0300 Subject: [PATCH] ACK --- bin/cmd.list | 1 + doc/cmd/index.texi | 2 + doc/cmd/nncp-ack.texi | 60 ++++++++++++++++++++ doc/news.ru.texi | 5 ++ doc/news.texi | 5 ++ doc/pkt/plain.texi | 14 +++++ doc/usecases.ru/nolink.texi | 3 + doc/usecases/nolink.texi | 3 + doc/workflow.texi | 3 + ports/nncp/Makefile | 2 +- ports/nncp/pkg-plist | 1 + src/call.go | 1 + src/cmd/nncp-ack/main.go | 110 ++++++++++++++++++++++++++++++++++++ src/cmd/nncp-call/main.go | 2 + src/cmd/nncp-caller/main.go | 2 + src/cmd/nncp-daemon/main.go | 3 + src/cmd/nncp-pkt/main.go | 4 ++ src/cmd/nncp-toss/main.go | 9 +-- src/nncp.go | 2 +- src/pkt.go | 1 + src/toss.go | 70 +++++++++++++++++++++-- src/toss_test.go | 20 +++---- src/tx.go | 36 ++++++++++++ 23 files changed, 337 insertions(+), 22 deletions(-) create mode 100644 doc/cmd/nncp-ack.texi create mode 100644 src/cmd/nncp-ack/main.go diff --git a/bin/cmd.list b/bin/cmd.list index de2a35f..8a50ab5 100644 --- a/bin/cmd.list +++ b/bin/cmd.list @@ -1,3 +1,4 @@ +nncp-ack nncp-bundle nncp-call nncp-caller diff --git a/doc/cmd/index.texi b/doc/cmd/index.texi index 9f3c887..fa2b38e 100644 --- a/doc/cmd/index.texi +++ b/doc/cmd/index.texi @@ -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 index 0000000..14feac3 --- /dev/null +++ b/doc/cmd/nncp-ack.texi @@ -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. diff --git a/doc/news.ru.texi b/doc/news.ru.texi index 9b19a52..abd4405 100644 --- a/doc/news.ru.texi +++ b/doc/news.ru.texi @@ -9,6 +9,11 @@ @command{nncp-xfer} проверяет сходится ли контрольная сумма скопированного локально пакета и исходного. +@item +Появилась @command{nncp-ack} команда, которая отправляет явное +подтверждение доставки пакета (ACK пакет). Это подтверждение удаляет +упомянутый пакет из исходящего spool-а. + @item Появилась возможность отключения @code{fsync} операции @env{$NNCPNOSYNC=1} переменной окружения. diff --git a/doc/news.texi b/doc/news.texi index 03c7197..c0a7912 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -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. diff --git a/doc/pkt/plain.texi b/doc/pkt/plain.texi index 7af4360..235b813 100644 --- a/doc/pkt/plain.texi +++ b/doc/pkt/plain.texi @@ -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 diff --git a/doc/usecases.ru/nolink.texi b/doc/usecases.ru/nolink.texi index 6bc2d57..a74b461 100644 --- a/doc/usecases.ru/nolink.texi +++ b/doc/usecases.ru/nolink.texi @@ -37,3 +37,6 @@ $ nncp-xfer /media/usbstick чтобы найти все пакеты относящиеся к их узлу и локально скопируют для дальнейшей обработки. @command{@ref{nncp-xfer}} это единственная команда используемая с переносными устройствами хранения. + +Вы также можете опционально использовать явное подтверждение приёма +пакетов, как описано в @command{@ref{nncp-ack}}. diff --git a/doc/usecases/nolink.texi b/doc/usecases/nolink.texi index de3593c..fc8a40b 100644 --- a/doc/usecases/nolink.texi +++ b/doc/usecases/nolink.texi @@ -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}}. diff --git a/doc/workflow.texi b/doc/workflow.texi index 7b64f7f..fbd3eea 100644 --- a/doc/workflow.texi +++ b/doc/workflow.texi @@ -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 diff --git a/ports/nncp/Makefile b/ports/nncp/Makefile index 6ff741a..05c0ad1 100644 --- a/ports/nncp/Makefile +++ b/ports/nncp/Makefile @@ -1,5 +1,5 @@ PORTNAME= nncp -DISTVERSION= 7.6.0 +DISTVERSION= 8.6.0 CATEGORIES= net MASTER_SITES= http://www.nncpgo.org/download/ diff --git a/ports/nncp/pkg-plist b/ports/nncp/pkg-plist index e360a4a..e89c748 100644 --- a/ports/nncp/pkg-plist +++ b/ports/nncp/pkg-plist @@ -1,3 +1,4 @@ +bin/nncp-ack bin/nncp-bundle bin/nncp-call bin/nncp-caller diff --git a/src/call.go b/src/call.go index c4e04cb..295e7c8 100644 --- a/src/call.go +++ b/src/call.go @@ -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 index 0000000..df912f1 --- /dev/null +++ b/src/cmd/nncp-ack/main.go @@ -0,0 +1,110 @@ +/* +NNCP -- Node to Node copy, utilities for store-and-forward data exchange +Copyright (C) 2016-2022 Sergey Matveev + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +// 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) + } + } +} diff --git a/src/cmd/nncp-call/main.go b/src/cmd/nncp-call/main.go index 82cec19..4d8fb06 100644 --- a/src/cmd/nncp-call/main.go +++ b/src/cmd/nncp-call/main.go @@ -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, ) } diff --git a/src/cmd/nncp-caller/main.go b/src/cmd/nncp-caller/main.go index 6902441..50d9bf4 100644 --- a/src/cmd/nncp-caller/main.go +++ b/src/cmd/nncp-caller/main.go @@ -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, ) } diff --git a/src/cmd/nncp-daemon/main.go b/src/cmd/nncp-daemon/main.go index 5fd6f6d..710b687 100644 --- a/src/cmd/nncp-daemon/main.go +++ b/src/cmd/nncp-daemon/main.go @@ -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 diff --git a/src/cmd/nncp-pkt/main.go b/src/cmd/nncp-pkt/main.go index 54844dc..d40b8c5 100644 --- a/src/cmd/nncp-pkt/main.go +++ b/src/cmd/nncp-pkt/main.go @@ -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]) } diff --git a/src/cmd/nncp-toss/main.go b/src/cmd/nncp-toss/main.go index 4eca181..76bb765 100644 --- a/src/cmd/nncp-toss/main.go +++ b/src/cmd/nncp-toss/main.go @@ -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, ) } } diff --git a/src/nncp.go b/src/nncp.go index b2303c0..0ae3470 100644 --- a/src/nncp.go +++ b/src/nncp.go @@ -40,7 +40,7 @@ along with this program. If not, see .` const Base32Encoded32Len = 52 var ( - Version string = "8.5.0" + Version string = "8.6.0" Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding) ) diff --git a/src/pkt.go b/src/pkt.go index 26c59e5..ba711a3 100644 --- a/src/pkt.go +++ b/src/pkt.go @@ -44,6 +44,7 @@ const ( PktTypeTrns PktType = iota PktTypeExecFat PktType = iota PktTypeArea PktType = iota + PktTypeACK PktType = iota MaxPathSize = 1<<8 - 1 diff --git a/src/toss.go b/src/toss.go index e383257..ebe20fb 100644 --- a/src/toss.go +++ b/src/toss.go @@ -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 } } }() diff --git a/src/toss_test.go b/src/toss_test.go index 6cb68eb..000653d 100644 --- a/src/toss_test.go +++ b/src/toss_test.go @@ -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 } diff --git a/src/tx.go b/src/tx.go index f9da81b..6e13f2e 100644 --- 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 +} -- 2.44.0