--- /dev/null
+@node ACK
+@cindex ACKnowledgements
+@cindex packet acknowledgement
+@unnumbered ACKnowledgements
+
+There is possibility to explicitly acknowledge the receipt of the
+encrypted packet, by generating the reply of @code{ACK}-type which
+contains the packet identifier.
+
+ACK packets can be generated explicitly by @command{@ref{nncp-ack}}
+command, or during the tossing procedure if @option{-gen-ack} option
+is specified.
+
+General workflow with acknowledgement is following, assuming that
+Alice has some outbound packets for Bob:
+
+@itemize
+
+@item Transfer 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, saving the list of encrypted
+ ACK packets:
+
+@example
+bob$ nncp-ack -node alice 4>acks
+@end example
+
+@item Send those newly created packets back to Alice:
+
+@example
+bob$ nncp-xfer [-keep] -tx /mnt/shared
+@end example
+
+@item Remove them from outbound spool, because we expect no
+ acknowledgement for them:
+
+@example
+bob$ nncp-rm -node alice -pkt <acks
+@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.
+
+If you generate ACK packet during the tossing, then the list of ACK
+packets is saved as empty files directly in the @ref{Spool, spool}.
+You can remove transferred ACK packets with @command{nncp-rm -ack}.
autotoss: true
autotoss-doseen: true
+ autotoss-gen-ack: true
}
{
cron: "30 * * * SAT,SUN"
configuration option when calling.
@vindex autotoss
-@item autotoss, -doseen, -nofile, -nofreq, -noexec, -notrns
+@item autotoss, -doseen, -nofile, -nofreq, -noexec, -notrns, -noack, -gen-ack
Optionally enable auto tossing: run tosser on node's spool every second
during the call. You can control either are @file{seen/} files must be
-created, or skip any kind of packet processing.
+created, or skip any kind of packet processing, or enable @ref{ACK}
+packets generation.
@vindex when-tx-exists
@item when-tx-exists
chunked: 1024
minsize: 2048
}
+ ack: {
+ nice: FLASH
+ minsize: 2048
+ }
via: ["alice"]
rxrate: 10
txrate: 20
transmission.
@end table
+@vindex ack
+@anchor{CfgACK}
+@item ack
+ Options applied to automatically generated @ref{ACK} packets during tossing.
+
+ @table @code
+ @item nice
+ Use that @ref{Niceness, niceness} for generated packets (255 is used
+ otherwise).
+
+ @item minsize
+ If set, then apply @ref{OptMinSize, -minsize} option during file
+ transmission.
+ @end table
+
@vindex via
@anchor{CfgVia}
@item via
@node nncp-ack
-@cindex packet acknowledgement
@pindex nncp-ack
@section nncp-ack
$ nncp-ack [@dots{}] 4>&1 >&2 | nncp-rm [@dots{}] -pkt
@end example
-Send acknowledgement of successful @option{PKT} (Base32-encoded hash)
-packet receipt from @option{NODE} node. If no @option{-pkt} is
-specified, then acknowledge all packet in node's @code{rx} spool.
-If @option{-all} is specified, then do that for all nodes.
+Send @ref{ACK, acknowledgement} of successful @option{PKT}
+(Base32-encoded hash) packet receipt from @option{NODE} node. If no
+@option{-pkt} is specified, then acknowledge all packet in node's
+@code{rx} spool. If @option{-all} is specified, then do that for all
+nodes.
That commands outputs list of created encrypted ACK packets
(@code{NODE/PKT}) to @strong{4}th file descriptor. That output can be
passed for example to @command{@ref{nncp-rm}} to remove them after
transmission to not wait for acknowledgement and retransmission.
-
-General workflow with acknowledgement is following, assuming that
-Alice has some outbound packets for Bob:
-
-@itemize
-
-@item Transfer 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, saving the list of encrypted
- ACK packets:
-
-@example
-bob$ nncp-ack -node alice 4>acks
-@end example
-
-@item Send those newly created packets back to Alice:
-
-@example
-bob$ nncp-xfer [-keep] -tx /mnt/shared
-@end example
-
-@item Remove them from outbound spool, because we expect no
- acknowledgement for them:
-
-@example
-bob$ nncp-rm -node alice -pkt <acks
-@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.
$ nncp-rm [options] [-older X] @{-all|-node NODE@} -nock
$ nncp-rm [options] [-older X] @{-all|-node NODE@} -area
$ nncp-rm [options] [-older X] @{-all|-node NODE@} @{-rx|-tx@} [-hdr]
-$ nncp-rm [options] [-older X] @{-all|-node NODE@} -pkt <<EOF
+$ nncp-rm [options] @{-all|-node NODE@} -pkt <<EOF
+$ nncp-rm [options] @{-all|-node NODE@} -ack
PKT1
PKT2
NODEx/PKT3
[-node NODE]
[-dryrun]
[-cycle INT]
- [-seen]
- [-nofile] [-nofreq] [-noexec] [-notrns] [-noarea]
+ [-seen] [-gen-ack]
+ [-nofile] [-nofreq] [-noexec] [-notrns] [-noarea] [-noack]
@end example
Perform "tossing" operation on all inbound packets. This is the tool
duplicates.
@option{-nofile}, @option{-nofreq}, @option{-noexec}, @option{-notrns},
-@option{-noarea} options allow disabling any kind of packet types processing.
+@option{-noarea}, @option{-noack} options allow disabling any kind of
+packet types processing.
+
+@option{-gen-ack} option tells to automatically generate @ref{ACK}
+outbound packets when tossing each packet, saving corresponding list of
+generated packets inside the special directory in the @ref{ACKFile, spool}.
@include niceness.texi
@include chunked.texi
@include bundles.texi
+@include ack.texi
@include spool.texi
@include log.texi
@include pkt/index.texi
@node Новости
@section Новости
-@node Релиз 8.8.4
-@subsection Релиз 8.8.4
+@node Релиз 8.9.0
+@subsection Релиз 8.9.0
@itemize
@item
-Избавиться от @command{redo} системы сборки при установке, так как по сути
-нет зависимостей, только компиляция Go кода.
+@command{nncp-toss} команда имеет @option{-gen-ack} опцию.
+@command{nncp-daemon}, @command{nncp-caller}, @command{nncp-call}
+команды имеют @option{-autotoss-gen-ack} опцию. Они автоматически
+генерируют ACK пакеты и сохраняют соответствующие @file{spoo/tx/ack/}
+ссылки на них, чтобы их можно было удалить после передачи.
+
+@item
+@code{autotoss-gen-ack} появился в конфигурации call.
+@code{ack} секция появилась в конфигурации ноды.
+
+@item
+@command{nncp-rm} команда имеет @option{-ack} опцию для удаления пакетов
+на которые ссылаются @file{spool/tx/ack/} файлы созданные во время toss.
+
+@item
+@command{redo} система сборки более не требуется при установке, так как
+по сути нет зависимостей, только компиляция Go кода.
+
+@item
+Обновлены некоторые зависимости.
@end itemize
See also this page @ref{Новости, on russian}.
-@node Release 8_8_4
-@section Release 8.8.4
+@node Release 8_9_0
+@section Release 8.9.0
@itemize
+@item
+@command{nncp-toss} command has @option{-gen-ack} option.
+@command{nncp-daemon}, @command{nncp-caller}, @command{nncp-call}
+commands have @option{-autotoss-gen-ack} option. They automatically
+generate ACK packets and store corresponding @file{spool/tx/ack/}
+references to them, to be able to remove them after the transfer.
+
+@item
+@code{autotoss-gen-ack} appeared in call configuration.
+@code{ack} section appeared in neighbour configuration.
+
+@item
+@command{nncp-rm} command has @option{-ack} option to remove packets
+referenced by stored @file{spool/tx/ack/} files generated during tossing.
+
@item
Get rid of @command{redo} build system during installation, as there are
virtually none dependencies, just only compilation of the Go code.
+@item
+Updated some dependencies.
+
@end itemize
@node Release 8_8_3
allocated more or less linearly on the disk, decreasing listing time
even more.
+@cindex ack files
+@anchor{ACKFile}
+@item tx/ack/LYT64MWSNDK34CVYOO7TA6ZCJ3NWI2OUDBBMX2A4QWF34FIRY4DQ
+If tossing was performed with @option{-gen-ack} option, then for each
+generated @ref{ACK} packet there will be corresponding empty @file{ack/}
+file. ACK outbound packets needs to be deleted after the transmission,
+but since they are stored encrypted in the spool, there needs to be some
+kind of knowledge what packets are ACK ones. Both ACK and corresponding
+@file{ack/} files are removed by @command{@ref{nncp-rm} -ack} command.
+
@end table
AutoTossNoTrns bool
AutoTossNoArea bool
AutoTossNoACK bool
+ AutoTossGenACK bool
}
func (ctx *Ctx) CallNode(
Incoming *string `json:"incoming,omitempty"`
Exec map[string][]string `json:"exec,omitempty"`
Freq *NodeFreqJSON `json:"freq,omitempty"`
+ ACK *NodeACKJSON `json:"ack,omitempty"`
Via []string `json:"via,omitempty"`
Calls []CallJSON `json:"calls,omitempty"`
MaxSize *uint64 `json:"maxsize,omitempty"`
}
+type NodeACKJSON struct {
+ MinSize *uint64 `json:"minsize,omitempty"`
+ Nice *string `json:"nice,omitempty"`
+}
+
type CallJSON struct {
Cron string `json:"cron"`
Nice *string `json:"nice,omitempty"`
AutoTossNoExec bool `json:"autotoss-noexec,omitempty"`
AutoTossNoTrns bool `json:"autotoss-notrns,omitempty"`
AutoTossNoArea bool `json:"autotoss-noarea,omitempty"`
+ AutoTossNoACK bool `json:"autotoss-noack,omitempty"`
+ AutoTossGenACK bool `json:"autotoss-gen-ack,omitempty"`
}
type NodeOurJSON struct {
}
}
+ ackNice := uint8(255)
+ var ackMinSize int64
+ if cfg.ACK != nil {
+ if cfg.ACK.Nice != nil {
+ ackNice, err = NicenessParse(*cfg.ACK.Nice)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if cfg.ACK.MinSize != nil {
+ ackMinSize = int64(*cfg.ACK.MinSize) * 1024
+ }
+ }
+
defRxRate := 0
if cfg.RxRate != nil && *cfg.RxRate > 0 {
defRxRate = *cfg.RxRate
call.AutoTossNoExec = callCfg.AutoTossNoExec
call.AutoTossNoTrns = callCfg.AutoTossNoTrns
call.AutoTossNoArea = callCfg.AutoTossNoArea
+ call.AutoTossNoACK = callCfg.AutoTossNoACK
+ call.AutoTossGenACK = callCfg.AutoTossGenACK
calls = append(calls, &call)
}
FreqChunked: freqChunked,
FreqMinSize: freqMinSize,
FreqMaxSize: freqMaxSize,
+ ACKNice: ackNice,
+ ACKMinSize: ackMinSize,
Calls: calls,
Addrs: cfg.Addrs,
RxRate: defRxRate,
}
}
+ if n.ACK != nil {
+ if err = cfgDirMkdir(dst, "neigh", name, "ack"); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ n.ACK.MinSize,
+ dst, "neigh", name, "ack", "minsize",
+ ); err != nil {
+ return
+ }
+ if err = cfgDirSave(
+ n.ACK.Nice,
+ dst, "neigh", name, "ack", "nice",
+ ); err != nil {
+ return
+ }
+ }
+
if len(n.Via) > 0 {
if err = cfgDirSave(
strings.Join(n.Via, "\n"),
return
}
}
+ if call.AutoTossNoACK {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-noack"); err != nil {
+ return
+ }
+ }
+ if call.AutoTossGenACK {
+ if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-gen-ack"); err != nil {
+ return
+ }
+ }
}
}
}
}
+ if cfgDirExists(src, "neigh", n, "ack") {
+ node.ACK = &NodeACKJSON{}
+ i64, err := cfgDirLoadIntOpt(src, "neigh", n, "ack", "minsize")
+ if err != nil {
+ return nil, err
+ }
+ if i64 != nil {
+ i := uint64(*i64)
+ node.ACK.MinSize = &i
+ }
+ if node.ACK.Nice, err = cfgDirLoadOpt(
+ src, "neigh", n, "ack", "nice",
+ ); err != nil {
+ return nil, err
+ }
+ }
+
via, err := cfgDirLoadOpt(src, "neigh", n, "via")
if err != nil {
return nil, err
if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noarea") {
call.AutoTossNoArea = true
}
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noack") {
+ call.AutoTossNoACK = true
+ }
+ if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-gen-ack") {
+ call.AutoTossGenACK = true
+ }
node.Calls = append(node.Calls, call)
}
cfg.Neigh[n] = node
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")
+ minSizeRaw = flag.Int64("minsize", -1, "Minimal required resulting packet size, in KiB")
viaOverride = flag.String("via", "", "Override Via path to destination node (ignored with -all)")
spoolPath = flag.String("spool", "", "Override path to spool")
logPath = flag.String("log", "", "Override path to logfile")
}
ctx.Umask()
- minSize := int64(*minSizeRaw) * 1024
var nodes []*nncp.Node
if *nodesRaw != "" {
os.Exit(1)
}
nncp.ViaOverride(*viaOverride, ctx, nodes[0])
+
+ var minSize int64
+ if *minSizeRaw < 0 {
+ minSize = nodes[0].ACKMinSize
+ } else if *minSizeRaw > 0 {
+ minSize = *minSizeRaw * 1024
+ }
+
pktName, err := ctx.TxACK(nodes[0], nice, *pktRaw, minSize)
if err != nil {
log.Fatalln(err)
isBad := false
for _, node := range nodes {
+ var minSize int64
+ if *minSizeRaw < 0 {
+ minSize = node.ACKMinSize
+ } else if *minSizeRaw > 0 {
+ minSize = *minSizeRaw * 1024
+ }
for job := range ctx.Jobs(node.Id, nncp.TRx) {
pktName := filepath.Base(job.Path)
sender := ctx.Neigh[*job.PktEnc.Sender]
"Do not process \"area\" packets during tossing")
autoTossNoACK = flag.Bool("autotoss-noack", false,
"Do not process \"ack\" packets during tossing")
+ autoTossGenACK = flag.Bool("autotoss-gen-ack", false,
+ "Generate ACK packets")
)
log.SetFlags(log.Lshortfile)
flag.Usage = usage
NoTrns: *autoTossNoTrns,
NoArea: *autoTossNoArea,
NoACK: *autoTossNoACK,
+ GenACK: *autoTossGenACK,
},
)
}
"Do not process \"area\" packets during tossing")
autoTossNoACK = flag.Bool("autotoss-noack", false,
"Do not process \"ack\" packets during tossing")
+ autoTossGenACK = flag.Bool("autotoss-gen-ack", false,
+ "Generate ACK packets")
)
log.SetFlags(log.Lshortfile)
flag.Usage = usage
NoTrns: call.AutoTossNoTrns || *autoTossNoTrns,
NoArea: call.AutoTossNoArea || *autoTossNoArea,
NoACK: call.AutoTossNoACK || *autoTossNoACK,
+ GenACK: call.AutoTossGenACK || *autoTossGenACK,
},
)
}
"Do not process \"area\" packets during tossing")
autoTossNoACK = flag.Bool("autotoss-noack", false,
"Do not process \"ack\" packets during tossing")
+ autoTossGenACK = flag.Bool("autotoss-gen-ack", false,
+ "Generate ACK packets")
)
log.SetFlags(log.Lshortfile)
flag.Usage = usage
NoTrns: *autoTossNoTrns,
NoArea: *autoTossNoArea,
NoACK: *autoTossNoACK,
+ GenACK: *autoTossGenACK,
},
)
}
NoTrns: *autoTossNoTrns,
NoArea: *autoTossNoArea,
NoACK: *autoTossNoACK,
+ GenACK: *autoTossGenACK,
},
)
}
fmt.Fprintf(os.Stderr, " %s [options] [-older X] {-all|-node NODE} -nock\n", os.Args[0])
fmt.Fprintf(os.Stderr, " %s [options] [-older X] {-all|-node NODE} -area\n", os.Args[0])
fmt.Fprintf(os.Stderr, " %s [options] [-older X] {-all|-node NODE} {-rx|-tx} [-hdr]\n", os.Args[0])
- fmt.Fprintf(os.Stderr, " %s [options] [-older X] {-all|-node NODE} -pkt < ...\n", os.Args[0])
+ fmt.Fprintf(os.Stderr, " %s [options] {-all|-node NODE} -pkt < ...\n", os.Args[0])
+ fmt.Fprintf(os.Stderr, " %s [options] {-all|-node NODE} -ack\n", os.Args[0])
fmt.Fprintln(os.Stderr, "-older option's time units are: (s)econds, (m)inutes, (h)ours, (d)ays")
fmt.Fprintln(os.Stderr, "Options:")
flag.PrintDefaults()
older = flag.String("older", "", "XXX{smhd}: only older than XXX number of time units")
dryRun = flag.Bool("dryrun", false, "Do not actually remove files")
doPkt = flag.Bool("pkt", false, "Remove only that packets")
+ doACK = flag.Bool("ack", false, "Remove ACK packets from outbound")
spoolPath = flag.String("spool", "", "Override path to spool")
quiet = flag.Bool("quiet", false, "Print only errors")
debug = flag.Bool("debug", false, "Print debug messages")
log.Fatalln("Can not remove:", err)
}
}
+ if *doACK {
+ dirPath := filepath.Join(
+ ctx.Spool, node.Id.String(), string(nncp.TTx), nncp.ACKDir)
+ dir, err := os.Open(dirPath)
+ if err != nil {
+ continue
+ }
+ for {
+ fis, err := dir.ReadDir(1 << 10)
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ log.Fatalln("Can not read directory:", err)
+ }
+ for _, fi := range fis {
+ for _, pth := range []string{
+ filepath.Join(
+ ctx.Spool,
+ node.Id.String(),
+ string(nncp.TTx),
+ fi.Name(),
+ ),
+ filepath.Join(dirPath, fi.Name()),
+ } {
+ if err = os.Remove(pth); err == nil {
+ ctx.LogI(
+ "rm",
+ nncp.LEs{{K: "File", V: pth}},
+ func(les nncp.LEs) string {
+ return fmt.Sprintf("File %s: removed", pth)
+ },
+ )
+ } else if !errors.Is(err, fs.ErrNotExist) {
+ log.Fatalln("Can not remove:", pth, ":", err)
+ }
+ }
+ }
+ }
+ dir.Close()
+ }
}
}
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")
+ genACK = flag.Bool("gen-ack", false, "Generate 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")
NoTrns: *noTrns,
NoArea: *noArea,
NoACK: *noACK,
+ GenACK: *genACK,
},
) || isBad
if nodeId == *ctx.SelfId {
NoTrns: *noTrns,
NoArea: *noArea,
NoACK: *noACK,
+ GenACK: *genACK,
},
)
if *nodeId == *ctx.SelfId {
)
var (
- Version string = "8.8.4"
+ Version string = "8.9.0"
Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
)
FreqChunked int64
FreqMinSize int64
FreqMaxSize int64
+ ACKNice uint8
+ ACKMinSize int64
Via []*NodeId
Addrs map[string]string
RxRate int
const (
SeenDir = "seen"
+ ACKDir = "ack"
)
type TossOpts struct {
NoTrns bool
NoArea bool
NoACK bool
+ GenACK bool
}
func jobPath2Seen(jobPath string) string {
humanize.IBytes(pktSize),
)
})
+ if opts.GenACK && pkt.Type != PktTypeACK {
+ newPktName, err := ctx.TxACK(
+ sender, sender.ACKNice, pktName, sender.ACKMinSize,
+ )
+ if err != nil {
+ ctx.LogE("rx-unmarshal", les, err, func(les LEs) string {
+ return fmt.Sprintf("Tossing %s/%s: generating ACK", sender.Name, pktName)
+ })
+ return err
+ }
+ ackDir := filepath.Join(ctx.Spool, sender.Id.String(), string(TTx), ACKDir)
+ os.MkdirAll(ackDir, os.FileMode(0777))
+ if fd, err := os.Create(filepath.Join(ackDir, newPktName)); err == nil {
+ fd.Close()
+ if err = DirSync(ackDir); err != nil {
+ ctx.LogE("rx-genack", les, err, func(les LEs) string {
+ return fmt.Sprintf("Tossing %s/%s: genACK", sender.Name, pktName)
+ })
+ return err
+ }
+ } else {
+ ctx.LogE("rx-genack", les, err, func(les LEs) string {
+ return fmt.Sprintf("Tossing %s/%s: genACK", sender.Name, pktName)
+ })
+ return err
+ }
+ }
switch pkt.Type {
case PktTypeExec, PktTypeExecFat:
if opts.NoExec {