@section nncp-toss
@verbatim
-% nncp-toss [options] [-dryrun] [-cycle INT]
+% nncp-toss [options] [-dryrun] [-cycle INT] [-seen]
@end verbatim
Perform "tossing" operation on all inbound packets. This is the tool
@option{INT} seconds in an infinite loop. That can be useful when
running this command as a daemon.
+@option{-seen} option creates empty @file{XXX.seen} file after
+successful tossing of @file{XXX} packet. @ref{nncp-xfer} and
+@ref{nncp-bundle} commands skip inbound packets that has been already
+seen, processed and tossed. This is helpful to defeat duplicates.
+
@node nncp-xfer
@section nncp-xfer
методах передачи (например запись на CD-ROM без создания промежуточного
подготовленного ISO образа или работа с ленточными накопителями).
@item
+@command{nncp-toss} команда может создавать @file{.seen} файлы,
+предотвращая приём дублированных пакетов.
+@item
В команде @command{nncp-call} разрешается иметь только одного
обработчика контрольной суммы в фоне. Это полезно когда тысячи маленьких
входящих пакетов могут создать много горутин.
transmission methods (like writing to CD-ROM without intermediate
prepared ISO image and working with tape drives).
@item
+@command{nncp-toss} is able to create @file{.seen} files preventing
+duplicate packets receiving.
+@item
Single background checksum verifier worker is allowed in
@command{nncp-call}. This is helpful when thousands of small inbound
packets could create many goroutines.
spool/BYRR...CG6Q/rx.lock
spool/BYRR...CG6Q/rx/
spool/BYRR...CG6Q/tx.lock
+spool/BYRR...CG6Q/tx/AQUT...DGNT.seen
spool/BYRR...CG6Q/tx/NSYY...ZUU6
+spool/BYRR...CG6Q/tx/VCSR...3VXX.seen
spool/BYRR...CG6Q/tx/ZI5U...5RRQ
@end verbatim
can not contain partly written files -- they are moved atomically from
@file{tmp}.
+When @ref{nncp-toss} utility is called with @option{-seen} option, it
+will create empty @file{XXX.seen} files, telling that some kind of
+packet already was tossed sometime.
+
Only one process can work with @file{rx}/@file{tx} directories at once,
so there are corresponding lock files.
ctx.LogD("nncp-bundle", sds, "Packet already exists")
continue
}
+ if _, err = os.Stat(dstPath + nncp.SeenPostfix); err == nil || !os.IsNotExist(err) {
+ ctx.LogD("nncp-bundle", sds, "Packet already exists")
+ continue
+ }
if *doCheck {
tmp, err := ctx.NewTmpFileWHash()
if err != nil {
nodeRaw = flag.String("node", "", "Process only that node")
niceRaw = flag.Int("nice", 255, "Minimal required niceness")
dryRun = flag.Bool("dryrun", false, "Do not actually write any tossed data")
+ doSeen = flag.Bool("seen", false, "Create .seen files")
cycle = flag.Uint("cycle", 0, "Repeat tossing after N seconds in infinite loop")
quiet = flag.Bool("quiet", false, "Print only errors")
debug = flag.Bool("debug", false, "Print debug messages")
if nodeOnly != nil && nodeId != *nodeOnly.Id {
continue
}
- isBad = ctx.Toss(node.Id, nice, *dryRun)
+ isBad = ctx.Toss(node.Id, nice, *dryRun, *doSeen)
}
if *cycle > 0 {
time.Sleep(time.Duration(*cycle) * time.Second)
job.Fd.Close()
continue
}
+ if _, err = os.Stat(filepath.Join(dstPath, pktName)); err == nil || !os.IsNotExist(err) {
+ ctx.LogD("nncp-xfer", sds, "already exists")
+ job.Fd.Close()
+ continue
+ }
+ if _, err = os.Stat(filepath.Join(dstPath, pktName+nncp.SeenPostfix)); err == nil || !os.IsNotExist(err) {
+ ctx.LogD("nncp-xfer", sds, "already exists")
+ job.Fd.Close()
+ continue
+ }
tmp, err := ioutil.TempFile(dstPath, "nncp-xfer")
if err != nil {
ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "mktemp")
"golang.org/x/crypto/blake2b"
)
+const (
+ SeenPostfix = ".seen"
+)
+
func newNotification(fromTo *FromToYAML, subject string) io.Reader {
return strings.NewReader(fmt.Sprintf(
"From: %s\nTo: %s\nSubject: %s\n",
))
}
-func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
+func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun, doSeen bool) bool {
isBad := false
for job := range ctx.Jobs(nodeId, TRx) {
pktName := filepath.Base(job.Fd.Name())
}
ctx.LogI("rx", sds, "")
if !dryRun {
+ if doSeen {
+ if fd, err := os.Create(job.Fd.Name() + SeenPostfix); err == nil {
+ fd.Close()
+ }
+ }
if err = os.Remove(job.Fd.Name()); err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
isBad = true
}
ctx.LogI("rx", sds, "")
if !dryRun {
+ if doSeen {
+ if fd, err := os.Create(job.Fd.Name() + SeenPostfix); err == nil {
+ fd.Close()
+ }
+ }
if err = os.Remove(job.Fd.Name()); err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
isBad = true
}
ctx.LogI("rx", sds, "")
if !dryRun {
+ if doSeen {
+ if fd, err := os.Create(job.Fd.Name() + SeenPostfix); err == nil {
+ fd.Close()
+ }
+ }
if err = os.Remove(job.Fd.Name()); err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
isBad = true
}
ctx.LogI("rx", sds, "")
if !dryRun {
+ if doSeen {
+ if fd, err := os.Create(job.Fd.Name() + SeenPostfix); err == nil {
+ fd.Close()
+ }
+ }
if err = os.Remove(job.Fd.Name()); err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
isBad = true
if len(dirFiles(rxPath)) == 0 {
continue
}
- ctx.Toss(ctx.Self.Id, DefaultNiceMail-1, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceMail-1, false, false)
if len(dirFiles(rxPath)) == 0 {
return false
}
ctx.Neigh[*nodeOur.Id].Sendmail = []string{"/bin/sh", "-c", "false"}
- ctx.Toss(ctx.Self.Id, DefaultNiceMail, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false)
if len(dirFiles(rxPath)) == 0 {
return false
}
"/bin/sh", "-c",
fmt.Sprintf("cat >> %s", filepath.Join(spool, "mbox")),
}
- ctx.Toss(ctx.Self.Id, DefaultNiceMail, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false)
if len(dirFiles(rxPath)) != 0 {
return false
}
}
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, DefaultNiceFile, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
if len(dirFiles(rxPath)) == 0 {
return false
}
ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
- ctx.Toss(ctx.Self.Id, DefaultNiceFile, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
if len(dirFiles(rxPath)) != 0 {
return false
}
rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
- ctx.Toss(ctx.Self.Id, DefaultNiceFile, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
expected := make(map[string]struct{})
expected["samefile"] = struct{}{}
for i := 0; i < files-1; i++ {
txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
os.Rename(txPath, rxPath)
os.MkdirAll(txPath, os.FileMode(0700))
- ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
return false
}
ctx.Neigh[*nodeOur.Id].Freq = &spool
- ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
return false
}
panic(err)
}
}
- ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false)
+ ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
return false
}
panic(err)
}
}
- ctx.Toss(ctx.Self.Id, 123, false)
+ ctx.Toss(ctx.Self.Id, 123, false, false)
if len(dirFiles(rxPath)) != 0 {
return false
}