From: Sergey Matveev Date: Sun, 24 Nov 2019 15:12:07 +0000 (+0300) Subject: exec notification, freq.maxsize, paxed directories X-Git-Tag: v5.1.0^0 X-Git-Url: http://www.git.cypherpunks.ru/?a=commitdiff_plain;h=2ac16acad8de20005793cbadd61068d38dc3b0ca;hp=dd887c15fa21071a2f4931f7248e10c4ab1029d2;p=nncp.git exec notification, freq.maxsize, paxed directories --- diff --git a/Makefile b/Makefile index 46ddcf0..fd65c25 100644 --- a/Makefile +++ b/Makefile @@ -49,9 +49,10 @@ all: $(ALL) $(ALL): mkdir -p $(BIN) - cd $(SRC) ; GOPATH=$(GOPATH) $(GO) build -ldflags "$(LDFLAGS)" \ + cd $(SRC) ; GOPATH=$(GOPATH) $(GO) build \ + -o $(BIN)/$$(basename $@) \ + -ldflags "$(LDFLAGS)" \ $(MOD)/cmd/$$(basename $@) - mv $(SRC)/$$(basename $@) $(BIN) test: cd $(SRC) ; GOPATH=$(GOPATH) $(GO) test -failfast $(MOD)/... diff --git a/VERSION b/VERSION index 0062ac9..831446c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0 +5.1.0 diff --git a/doc/building.texi b/doc/building.texi index 1489294..30493d1 100644 --- a/doc/building.texi +++ b/doc/building.texi @@ -11,16 +11,16 @@ Make sure that Go is installed. For example to install it from packages: @end table @verbatim -$ [fetch|wget] http://www.nncpgo.org/download/nncp-5.0.0.tar.xz -$ [fetch|wget] http://www.nncpgo.org/download/nncp-5.0.0.tar.xz.sig -$ gpg --verify nncp-5.0.0.tar.xz.sig nncp-5.0.0.tar.xz -$ xz --decompress --stdout nncp-5.0.0.tar.xz | tar xf - -$ make -C nncp-5.0.0 all +$ [fetch|wget] http://www.nncpgo.org/download/nncp-5.1.0.tar.xz +$ [fetch|wget] http://www.nncpgo.org/download/nncp-5.1.0.tar.xz.sig +$ gpg --verify nncp-5.1.0.tar.xz.sig nncp-5.1.0.tar.xz +$ xz --decompress --stdout nncp-5.1.0.tar.xz | tar xf - +$ make -C nncp-5.1.0 all @end verbatim There is @command{install} make-target respecting @env{DESTDIR}. It will install binaries and info-documentation: @verbatim -# make -C nncp-5.0.0 install PREFIX=/usr/local +# make -C nncp-5.1.0 install PREFIX=/usr/local @end verbatim diff --git a/doc/bundles.texi b/doc/bundles.texi index 8330cdf..21b3104 100644 --- a/doc/bundles.texi +++ b/doc/bundles.texi @@ -48,8 +48,8 @@ can contain mix of various recipients. @end itemize -Technically bundle is valid POSIX.1-2001 (pax) -@url{http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html, tar archive}, +Technically bundle is valid POSIX.1-2001 +@url{https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_01, pax archive} with directory/files hierarchy identical to that is used in @ref{nncp-xfer}: @file{NNCP/RECIPIENT/SENDER/PACKET}. So bundle can also be created by manual tar-ing of @command{nncp-xfer} resulting directory. diff --git a/doc/cfg.texi b/doc/cfg.texi index 0aca8f9..46fa5f3 100644 --- a/doc/cfg.texi +++ b/doc/cfg.texi @@ -18,6 +18,16 @@ Example @url{https://hjson.org/, Hjson} configuration file: from: nncp@localhost to: user+freq@example.com } + exec: { + "*.warcer": { + from: nncp@localhost + to: user+warcer@example.com + } + "eve.warcer": { + from: nncp@localhost + to: user+warcer-overriden@example.com + } + } } self: { @@ -67,9 +77,11 @@ Example @url{https://hjson.org/, Hjson} configuration file: warcer: ["/path/to/warcer.sh"] wgeter: ["/path/to/wgeter.sh"] } - freq: "/home/bob/pub" - freqchunked: 1024 - freqminsize: 2048 + freq: { + path: "/home/bob/pub" + chunked: 1024 + minsize: 2048 + } via: ["alice"] rxrate: 10 txrate: 20 @@ -88,12 +100,18 @@ override their umask to specified octal mask. Useful for using with @anchor{CfgNotify} @strong{notify} section contains notification settings for successfully -tossed file and freq packets. Corresponding @strong{from} and +tossed file, freq and exec packets. Corresponding @strong{from} and @strong{to} fields will be substituted in notification email message. -@emph{neigh/self/exec/sendmail} will be used as a local mailer. You can -omit either of those two @emph{from}/@emph{to} sections to omit +@code{neigh.self.exec.sendmail} will be used as a local mailer. You can +omit either of those two @code{from}/@code{to} sections to omit corresponding notifications, or the whole section at once. +@code{notify.exec} section is a mapping of exec handles and +corresponding @code{from}/@code{to} sections. Each handle has either +@code{NODE.HANDLE} or @code{*.HANDLE} syntax. You can override +notification options for some node with the first type of name. +Handle command's output will be included in notification messages. + @strong{self} section contains our node's private keypairs. @strong{exch*} and @strong{sign*} are used during @ref{Encrypted, encrypted} packet creation. @strong{noise*} are used during @ref{Sync, @@ -104,7 +122,7 @@ always has @strong{self} neighbour that is copy of our node's public data (public keys). It is useful for copy-paste sharing with your friends. Each section's key is a human-readable name of the neighbour. -Except for @emph{id}, @emph{exchpub} and @emph{signpub} each neighbour +Except for @code{id}, @code{exchpub} and @code{signpub} each neighbour node has the following fields: @table @strong @@ -141,24 +159,24 @@ Full path to directory where all file uploads will be saved. May be omitted to forbid file uploading on that node. @anchor{CfgFreq} -@item freq +@item freq.path Full path to directory from where file requests will queue files for transmission. May be omitted to forbid freqing from that node. -@item freqchunked +@item freq.chunked If set, then enable @ref{Chunked, chunked} file transmission during freqing. This is the desired chunk size in KiBs. -@item freqminsize +@item freq.minsize If set, then apply @ref{OptMinSize, -minsize} option during file transmission. @anchor{CfgVia} @item via An array of node identifiers that will be used as a relay to that node. -For example @verb{|[foo,bar]|} means that packet can reach current node -by transitioning through @emph{foo} and then @emph{bar} nodes. May be -omitted if direct connection exists and no relaying is required. +For example @verb{|["foo","bar"]|} means that packet can reach current +node by transitioning through @code{foo} and then @code{bar} nodes. May +be omitted if direct connection exists and no relaying is required. @anchor{CfgAddrs} @item addrs diff --git a/doc/cmds.texi b/doc/cmds.texi index 4247054..1910651 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -287,6 +287,9 @@ echo My message | /usr/sbin/sendmail -t root@localhost @end verbatim +If @ref{CfgNotify, notification} is enabled on the remote side for exec +handles, then it will sent simple letter after successful command +execution with its output in message body. @node nncp-file @section nncp-file @@ -315,6 +318,15 @@ variable. Encryption is performed in AEAD mode with algorithms. Data is splitted on 128 KiB blocks. Each block is encrypted with increasing nonce counter. +If @file{SRC} points to directory, then +@url{https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_01, pax archive} +will be created on the fly with directory contents and destination +filename @file{.tar} appended. It @strong{won't} contain any entities +metainformation, but modification time with the names. UID/GID are set +to zero. Directories have 777 permissions, files have 666, for being +friendly with @command{umask}. Also each entity will have comment like +@verb{|Autogenerated by NNCP version X.Y.Z built with goXXX|}. + If @option{-chunked} is specified, then source file will be split @ref{Chunked, on chunks}. @option{INT} is the desired chunk size in KiBs. This mode is more CPU hungry. Pay attention that chunk is saved in @@ -334,7 +346,7 @@ $ nncp-freq [options] NODE:SRC [DST] @end verbatim Send file request to @option{NODE}, asking it to send its @file{SRC} -file from @ref{CfgFreq, freq} directory to our node under @file{DST} +file from @ref{CfgFreq, freq.path} directory to our node under @file{DST} filename in our @ref{CfgIncoming, incoming} one. If @file{DST} is not specified, then last element of @file{SRC} will be used. diff --git a/doc/download.texi b/doc/download.texi index f25c62e..1cbd5c6 100644 --- a/doc/download.texi +++ b/doc/download.texi @@ -23,6 +23,11 @@ Tarballs include all necessary required libraries: @multitable {XXXXX} {XXXX-XX-XX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} @headitem Version @tab Date @tab Size @tab Tarball @tab SHA256 checksum +An entry for documentation: +@item @ref{Release 5.0.0, 5.0.0} @tab 2019-11-15 @tab 1099 KiB +@tab @url{download/nncp-5.0.0.tar.xz, link} @url{download/nncp-5.0.0.tar.xz.sig, sign} +@tab @code{3696D7EE B0783E91 87E5EEF4 EFC35235 10452353 7C51FA4C 9BD3CBEE A22678B3} + @item @ref{Release 4.1, 4.1} @tab 2019-05-01 @tab 1227 KiB @tab @url{download/nncp-4.1.tar.xz, link} @url{download/nncp-4.1.tar.xz.sig, sign} @tab @code{29AEC53D EC914906 D7C47194 0955A32E 2BF470E6 9B8E09D3 AF3B62D8 CC8E541E} diff --git a/doc/integrity.texi b/doc/integrity.texi index cc1e587..d4bd456 100644 --- a/doc/integrity.texi +++ b/doc/integrity.texi @@ -31,5 +31,5 @@ $ gpg --auto-key-locate wkd --locate-keys releases at nncpgo dot org Then you could verify tarballs signature: @verbatim -$ gpg --verify nncp-5.0.0.tar.xz.sig nncp-5.0.0.tar.xz +$ gpg --verify nncp-5.1.0.tar.xz.sig nncp-5.1.0.tar.xz @end verbatim diff --git a/doc/news.ru.texi b/doc/news.ru.texi index 828a3cd..3226116 100644 --- a/doc/news.ru.texi +++ b/doc/news.ru.texi @@ -1,6 +1,33 @@ @node Новости @section Новости +@node Релиз 5.1.0 +@subsection Релиз 5.1.0 +@itemize + +@item +@command{nncp-file} может отправлять директории, автоматически на лету +создавая pax архив. + +@item +Во время создания исходящих сообщений проверяется наличие свободного +места на файловой системе. + +@item +@option{freq}, @option{freqminsize}, @option{freqchunked} опции +конфигурационного файла заменены на структуру +@option{freq: @{path: ..., minsize: ..., chunked: ...@}}. + +@item +Добавлена @option{freq.maxsize} опция конфигурационного файл, +запрещающая ответ на файловый запрос больше заданного размера. + +@item +Возможность оповещения об успешно выполненных командах (exec) через +@option{notify.exec} опцию конфигурационного файла. + +@end itemize + @node Релиз 5.0.0 @subsection Релиз 5.0.0 @itemize @@ -8,7 +35,7 @@ @item @strong{Несовместимое} изменение формата конфигурационного файла: YAML заменён на Hjson, из-за его гораздо большей простоты, без -заметного потеря функционала и удобства. +заметной потери функционала и удобства. @item @strong{Несовместимое} изменение формата простых пакетов. Работа со diff --git a/doc/news.texi b/doc/news.texi index b57c5ea..bc7a6fc 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -3,6 +3,32 @@ See also this page @ref{Новости, on russian}. +@node Release 5.1.0 +@section Release 5.1.0 +@itemize + +@item +@command{nncp-file} can send directories, automatically creating pax +archive on the fly. + +@item +Free disk space is checked during outbound packets creation. + +@item +@option{freq}, @option{freqminsize}, @option{freqchunked} configuration +file options replaced with the structure: +@option{freq: @{path: ..., minsize: ..., chunked: ...@}}. + +@item +Added @option{freq.maxsize} configuration file option, forbidding of +freq sending larger than specified size. + +@item +Ability to notify about successfully executed commands (exec) with +@option{notify.exec} configuration file option. + +@end itemize + @node Release 5.0.0 @section Release 5.0.0 @itemize diff --git a/doc/thanks.texi b/doc/thanks.texi index 42f5df6..d42954f 100644 --- a/doc/thanks.texi +++ b/doc/thanks.texi @@ -6,4 +6,6 @@ There are people deserving to be thanked for helping this project: @itemize @item Shawn K. Quinn for his descriptive instructions about building NNCP under Ubuntu GNU/Linux distributions and bug reports. +@item @url{mailto:jgoerzen@@complete.org, John Goerzen} for his feature +suggestions and Debian package maintenance. @end itemize diff --git a/makedist.sh b/makedist.sh index cd79f6b..e326922 100755 --- a/makedist.sh +++ b/makedist.sh @@ -226,7 +226,7 @@ online TCP daemon with full-duplex resumable data transmission exists. The main improvements for that release are: -$(git cat-file -p $release | sed -n '6,/^.*BEGIN/p' | sed '$d') +$(git cat-file -p v$release | sed -n '6,/^.*BEGIN/p' | sed '$d') ------------------------ >8 ------------------------ @@ -274,7 +274,7 @@ NNCP (Node to Node copy) это набор утилит упрощающий б Основные усовершенствования в этом релизе: -$(git cat-file -p $release | sed -n '6,/^.*BEGIN/p' | sed '$d') +$(git cat-file -p v$release | sed -n '6,/^.*BEGIN/p' | sed '$d') ------------------------ >8 ------------------------ diff --git a/ports/nncp/Makefile b/ports/nncp/Makefile index b26f566..6cee3ef 100644 --- a/ports/nncp/Makefile +++ b/ports/nncp/Makefile @@ -1,8 +1,7 @@ -# $FreeBSD: head/net/nncp/Makefile 484628 2018-11-10 18:12:57Z bapt $ +# $FreeBSD: head/net/nncp/Makefile 517819 2019-11-17 11:51:56Z dmgk $ PORTNAME= nncp -DISTVERSION= 5.0.0 -PORTREVISION= 1 +DISTVERSION= 5.1.0 CATEGORIES= net MASTER_SITES= http://www.nncpgo.org/download/ @@ -12,19 +11,19 @@ COMMENT= Utilities for secure store-and-forward files, mail, command exchanging LICENSE= GPLv3 LICENSE_FILE= ${WRKSRC}/COPYING -BUILD_DEPENDS= go:lang/go +USES= go:no_targets tar:xz -USES= tar:xz USE_RC_SUBR= nncp-caller nncp-daemon nncp-toss + +MAKE_ARGS= INFODIR=${STAGEDIR}${PREFIX}/${INFO_PATH} INSTALL_TARGET= install-strip SUB_FILES= pkg-message pkg-install pkg-deinstall -OPTIONS_DEFINE= DOCS - -PORTDOCS= AUTHORS NEWS NEWS.RU README README.RU THANKS INFO= nncp -MAKE_ARGS= INFODIR=${STAGEDIR}${PREFIX}/${INFO_PATH} +PORTDOCS= AUTHORS NEWS NEWS.RU README README.RU THANKS + +OPTIONS_DEFINE= DOCS post-install: ${INSTALL_DATA} ${FILESDIR}/nncp.newsyslog.conf.sample ${STAGEDIR}${PREFIX}/etc/nncp.conf.sample diff --git a/ports/nncp/files/pkg-message.in b/ports/nncp/files/pkg-message.in index 6aa49a4..3d6ddd9 100644 --- a/ports/nncp/files/pkg-message.in +++ b/ports/nncp/files/pkg-message.in @@ -1,4 +1,6 @@ -====================================================================== +[ +{ type: install + message: < %%PREFIX%%/etc/nncp.hjson -====================================================================== +EOM +} +] diff --git a/src/cfg.go b/src/cfg.go index a4450e0..edc132a 100644 --- a/src/cfg.go +++ b/src/cfg.go @@ -46,17 +46,15 @@ var ( ) type NodeJSON struct { - Id string `json:"id"` - ExchPub string `json:"exchpub"` - SignPub string `json:"signpub"` - NoisePub *string `json:"noisepub,omitempty"` - Exec map[string][]string `json:"exec,omitempty"` - Incoming *string `json:"incoming,omitempty"` - Freq *string `json:"freq,omitempty"` - FreqChunked *uint64 `json:"freqchunked,omitempty"` - FreqMinSize *uint64 `json:"freqminsize,omitempty"` - Via []string `json:"via,omitempty"` - Calls []CallJSON `json:"calls,omitempty"` + Id string `json:"id"` + ExchPub string `json:"exchpub"` + SignPub string `json:"signpub"` + NoisePub *string `json:"noisepub,omitempty"` + Exec map[string][]string `json:"exec,omitempty"` + Incoming *string `json:"incoming,omitempty"` + Freq *NodeFreqJSON `json:"freq,omitempty"` + Via []string `json:"via,omitempty"` + Calls []CallJSON `json:"calls,omitempty"` Addrs map[string]string `json:"addrs,omitempty"` @@ -66,6 +64,13 @@ type NodeJSON struct { MaxOnlineTime *uint `json:"maxonlinetime,omitempty"` } +type NodeFreqJSON struct { + Path *string `json:"path,omitempty"` + Chunked *uint64 `json:"chunked,omitempty"` + MinSize *uint64 `json:"minsize,omitempty"` + MaxSize *uint64 `json:"maxsize,omitempty"` +} + type CallJSON struct { Cron string Nice *string `json:"nice,omitempty"` @@ -93,8 +98,9 @@ type FromToJSON struct { } type NotifyJSON struct { - File *FromToJSON `json:"file,omitempty"` - Freq *FromToJSON `json:"freq,omitempty"` + File *FromToJSON `json:"file,omitempty"` + Freq *FromToJSON `json:"freq,omitempty"` + Exec map[string]*FromToJSON `json:"exec,omitempty"` } type CfgJSON struct { @@ -150,24 +156,31 @@ func NewNode(name string, yml NodeJSON) (*Node, error) { incoming = &inc } - var freq *string + var freqPath *string + freqChunked := int64(MaxFileSize) + var freqMinSize int64 + freqMaxSize := int64(MaxFileSize) if yml.Freq != nil { - fr := path.Clean(*yml.Freq) - if !path.IsAbs(fr) { - return nil, errors.New("Freq path must be absolute") + f := yml.Freq + if f.Path != nil { + fPath := path.Clean(*f.Path) + if !path.IsAbs(fPath) { + return nil, errors.New("freq.path path must be absolute") + } + freqPath = &fPath } - freq = &fr - } - var freqChunked int64 - if yml.FreqChunked != nil { - if *yml.FreqChunked == 0 { - return nil, errors.New("freqchunked value must be greater than zero") + if f.Chunked != nil { + if *f.Chunked == 0 { + return nil, errors.New("freq.chunked value must be greater than zero") + } + freqChunked = int64(*f.Chunked) * 1024 + } + if f.MinSize != nil { + freqMinSize = int64(*f.MinSize) * 1024 + } + if f.MaxSize != nil { + freqMaxSize = int64(*f.MaxSize) * 1024 } - freqChunked = int64(*yml.FreqChunked) * 1024 - } - var freqMinSize int64 - if yml.FreqMinSize != nil { - freqMinSize = int64(*yml.FreqMinSize) * 1024 } defRxRate := 0 @@ -268,9 +281,10 @@ func NewNode(name string, yml NodeJSON) (*Node, error) { SignPub: ed25519.PublicKey(signPub), Exec: yml.Exec, Incoming: incoming, - Freq: freq, + FreqPath: freqPath, FreqChunked: freqChunked, FreqMinSize: freqMinSize, + FreqMaxSize: freqMaxSize, Calls: calls, Addrs: yml.Addrs, RxRate: defRxRate, @@ -424,6 +438,9 @@ func CfgParse(data []byte) (*Ctx, error) { if cfgJSON.Notify.Freq != nil { ctx.NotifyFreq = cfgJSON.Notify.Freq } + if cfgJSON.Notify.Exec != nil { + ctx.NotifyExec = cfgJSON.Notify.Exec + } } vias := make(map[NodeId][]string) for name, neighJSON := range cfgJSON.Neigh { diff --git a/src/cmd/nncp-bundle/main.go b/src/cmd/nncp-bundle/main.go index 4f5bca1..380b391 100644 --- a/src/cmd/nncp-bundle/main.go +++ b/src/cmd/nncp-bundle/main.go @@ -32,7 +32,7 @@ import ( "strconv" "strings" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "go.cypherpunks.ru/nncp/v5" "golang.org/x/crypto/blake2b" ) diff --git a/src/cmd/nncp-cfgenc/main.go b/src/cmd/nncp-cfgenc/main.go index 7adc6fa..055b644 100644 --- a/src/cmd/nncp-cfgenc/main.go +++ b/src/cmd/nncp-cfgenc/main.go @@ -27,7 +27,7 @@ import ( "log" "os" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "go.cypherpunks.ru/nncp/v5" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/ssh/terminal" diff --git a/src/cmd/nncp-cfgnew/main.go b/src/cmd/nncp-cfgnew/main.go index c7bb14e..e2eac99 100644 --- a/src/cmd/nncp-cfgnew/main.go +++ b/src/cmd/nncp-cfgnew/main.go @@ -113,6 +113,19 @@ func main() { # from: nncp@localhost # to: user+freq@example.com # } + # # Send some exec commands execution notifications + # exec: { + # # bob neighbour's "somehandle" notification + # bob.somehandle: { + # from: nncp+bob@localhost + # to: user+somehandle@example.com + # } + # # Any neighboor's "anotherhandle" + # *.anotherhandle: { + # from: nncp@localhost + # to: user+anotherhandle@example.com + # } + # } # } self: { @@ -148,50 +161,55 @@ func main() { # noisepub: UBM5K...VI42A # # # He is allowed to send email - # exec: {sendmail: ["/usr/sbin/sendmail"]} + # # exec: {sendmail: ["%s"]} # # # Allow incoming files saving in that directory - # incoming: "/home/alice/incoming" + # # incoming: "/home/alice/incoming" # # # Transitional nodes path - # via: ["bob", "eve"] + # # via: ["bob", "eve"] # # # Inactivity timeout when session with remote peer should be terminated - # onlinedeadline: 1800 + # # onlinedeadline: 1800 # # # Maximal online session lifetime - # maxonlinetime: 3600 + # # maxonlinetime: 3600 # - # # Allow freqing from that directory - # freq: "/home/bob/pub" - # # Send freqed files with chunks - # freqchunked: 1024 - # # Send freqed files with minumal chunk size - # freqminsize: 2048 + # # If neither freq section, nor freq.path exist, then no freqing allowed + # # freq: { + # # # Allow freqing from that directory + # # path: "/home/bob/pub" + # # # Send freqed files with chunks + # # # chunked: 1024 + # # # Send freqed files with minumal chunk size + # # # minsize: 2048 + # # # Maximal allowable freqing file size + # # # maxsize: 4096 + # # } # # # Set maximal packets per second receive and transmit rates - # rxrate: 10 - # txrate: 20 + # # rxrate: 10 + # # txrate: 20 # # # Address aliases - # addrs: { - # lan: "[fe80::1234%%igb0]:5400" - # internet: alice.com:3389 - # } + # # addrs: { + # # lan: "[fe80::1234%%igb0]:5400" + # # internet: alice.com:3389 + # # } # # # Calls configuration - # calls: [ - # { - # cron: "*/2 * * * *" - # onlinedeadline: 1800 - # maxonlinetime: 1750 - # nice: PRIORITY+10 - # rxrate: 10 - # txrate: 20 - # xx: rx - # addr: lan - # }, - # ] + # # calls: [ + # # { + # # cron: "*/2 * * * *" + # # onlinedeadline: 1800 + # # maxonlinetime: 1750 + # # nice: PRIORITY+10 + # # rxrate: 10 + # # txrate: 20 + # # xx: rx + # # addr: lan + # # }, + # # ] # } } }`, @@ -209,6 +227,7 @@ func main() { nncp.ToBase32(nodeOur.SignPub[:]), nncp.ToBase32(nodeOur.NoisePub[:]), nncp.DefaultSendmailPath, + nncp.DefaultSendmailPath, ) } if _, err = nncp.CfgParse([]byte(cfgRaw)); err != nil { diff --git a/src/cmd/nncp-file/main.go b/src/cmd/nncp-file/main.go index f3572ca..d7c0607 100644 --- a/src/cmd/nncp-file/main.go +++ b/src/cmd/nncp-file/main.go @@ -36,7 +36,7 @@ func usage() { fmt.Fprint(os.Stderr, ` If SRC equals to -, then read data from stdin to temporary file. --minsize/-chunked take NODE's FreqMinSize/FreqChunked configuration +-minsize/-chunked take NODE's freq.minsize/freq.chunked configuration options by default. You can forcefully turn them off by specifying 0 value. `) } @@ -109,25 +109,15 @@ func main() { chunkSize = *argChunkSize * 1024 } - if chunkSize == 0 { - err = ctx.TxFile( - node, - nice, - flag.Arg(0), - splitted[1], - minSize, - ) - } else { - err = ctx.TxFileChunked( - node, - nice, - flag.Arg(0), - splitted[1], - minSize, - chunkSize, - ) - } - if err != nil { + if err = ctx.TxFile( + node, + nice, + flag.Arg(0), + splitted[1], + chunkSize, + minSize, + nncp.MaxFileSize, + ); err != nil { log.Fatalln(err) } } diff --git a/src/cmd/nncp-freq/main.go b/src/cmd/nncp-freq/main.go index 4332ff1..2532887 100644 --- a/src/cmd/nncp-freq/main.go +++ b/src/cmd/nncp-freq/main.go @@ -24,7 +24,6 @@ import ( "log" "os" "path/filepath" - "strconv" "strings" "go.cypherpunks.ru/nncp/v5" @@ -41,7 +40,7 @@ func main() { var ( cfgPath = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file") niceRaw = flag.String("nice", nncp.NicenessFmt(nncp.DefaultNiceFreq), "Outbound packet niceness") - replyNiceRaw = flag.String("replynice", strconv.Itoa(nncp.DefaultNiceFile), "Reply file packet niceness") + replyNiceRaw = flag.String("replynice", nncp.NicenessFmt(nncp.DefaultNiceFile), "Reply file packet niceness") minSize = 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") diff --git a/src/cmd/nncp-pkt/main.go b/src/cmd/nncp-pkt/main.go index 1808e3a..cb9042a 100644 --- a/src/cmd/nncp-pkt/main.go +++ b/src/cmd/nncp-pkt/main.go @@ -27,7 +27,7 @@ import ( "log" "os" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "github.com/klauspost/compress/zstd" "go.cypherpunks.ru/nncp/v5" ) diff --git a/src/cmd/nncp-reass/main.go b/src/cmd/nncp-reass/main.go index 77a5f13..d7d79b0 100644 --- a/src/cmd/nncp-reass/main.go +++ b/src/cmd/nncp-reass/main.go @@ -32,7 +32,7 @@ import ( "strconv" "strings" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "github.com/dustin/go-humanize" "go.cypherpunks.ru/nncp/v5" "golang.org/x/crypto/blake2b" diff --git a/src/cmd/nncp-xfer/main.go b/src/cmd/nncp-xfer/main.go index fde1117..cfe16b7 100644 --- a/src/cmd/nncp-xfer/main.go +++ b/src/cmd/nncp-xfer/main.go @@ -28,7 +28,7 @@ import ( "path/filepath" "strconv" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "go.cypherpunks.ru/nncp/v5" ) diff --git a/src/ctx.go b/src/ctx.go index 3793bbb..8a1146e 100644 --- a/src/ctx.go +++ b/src/ctx.go @@ -24,8 +24,9 @@ import ( "os" "path/filepath" - "golang.org/x/sys/unix" "syscall" + + "golang.org/x/sys/unix" ) type Ctx struct { @@ -41,6 +42,7 @@ type Ctx struct { Debug bool NotifyFile *FromToJSON NotifyFreq *FromToJSON + NotifyExec map[string]*FromToJSON } func (ctx *Ctx) FindNode(id string) (*Node, error) { diff --git a/src/eblob.go b/src/eblob.go index 6432790..0616c84 100644 --- a/src/eblob.go +++ b/src/eblob.go @@ -22,7 +22,7 @@ import ( "crypto/rand" "hash" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "go.cypherpunks.ru/balloon" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/chacha20poly1305" diff --git a/src/go.mod b/src/go.mod index 77ef98a..c7a3543 100644 --- a/src/go.mod +++ b/src/go.mod @@ -15,3 +15,5 @@ require ( golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) + +go 1.10 diff --git a/src/jobs.go b/src/jobs.go index 080ec4a..49df07b 100644 --- a/src/jobs.go +++ b/src/jobs.go @@ -23,7 +23,7 @@ import ( "path/filepath" "strconv" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" ) type TRxTx string diff --git a/src/node.go b/src/node.go index ac78301..65f5e9c 100644 --- a/src/node.go +++ b/src/node.go @@ -42,9 +42,10 @@ type Node struct { NoisePub *[32]byte Exec map[string][]string Incoming *string - Freq *string + FreqPath *string FreqChunked int64 FreqMinSize int64 + FreqMaxSize int64 Via []*NodeId Addrs map[string]string RxRate int @@ -100,10 +101,12 @@ func NewNodeGenerate() (*NodeOur, error) { func (nodeOur *NodeOur) Their() *Node { return &Node{ - Name: "self", - Id: nodeOur.Id, - ExchPub: nodeOur.ExchPub, - SignPub: nodeOur.SignPub, + Name: "self", + Id: nodeOur.Id, + ExchPub: nodeOur.ExchPub, + SignPub: nodeOur.SignPub, + FreqChunked: MaxFileSize, + FreqMaxSize: MaxFileSize, } } diff --git a/src/pkt.go b/src/pkt.go index 2fab844..8324ffb 100644 --- a/src/pkt.go +++ b/src/pkt.go @@ -25,7 +25,7 @@ import ( "errors" "io" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/curve25519" diff --git a/src/pkt_test.go b/src/pkt_test.go index 678cbf4..c69ba96 100644 --- a/src/pkt_test.go +++ b/src/pkt_test.go @@ -22,7 +22,7 @@ import ( "testing" "testing/quick" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" ) func TestPktEncWrite(t *testing.T) { diff --git a/src/sp.go b/src/sp.go index 6dd724a..540e0e5 100644 --- a/src/sp.go +++ b/src/sp.go @@ -30,7 +30,7 @@ import ( "sync" "time" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "github.com/flynn/noise" ) diff --git a/src/toss.go b/src/toss.go index 0ce446a..586f378 100644 --- a/src/toss.go +++ b/src/toss.go @@ -20,6 +20,7 @@ package nncp import ( "bufio" "bytes" + "encoding/base64" "fmt" "io" "io/ioutil" @@ -32,7 +33,7 @@ import ( "strconv" "strings" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "github.com/dustin/go-humanize" "github.com/klauspost/compress/zstd" "golang.org/x/crypto/blake2b" @@ -43,13 +44,22 @@ const ( SeenSuffix = ".seen" ) -func newNotification(fromTo *FromToJSON, subject string) io.Reader { - return strings.NewReader(fmt.Sprintf( - "From: %s\nTo: %s\nSubject: %s\n", - fromTo.From, - fromTo.To, - mime.BEncoding.Encode("UTF-8", subject), - )) +func newNotification(fromTo *FromToJSON, subject string, body []byte) io.Reader { + lines := []string{ + "From: " + fromTo.From, + "To: " + fromTo.To, + "Subject: " + mime.BEncoding.Encode("UTF-8", subject), + } + if len(body) > 0 { + lines = append(lines, []string{ + "MIME-Version: 1.0", + "Content-Type: text/plain; charset=utf-8", + "Content-Transfer-Encoding: base64", + "", + base64.StdEncoding.EncodeToString(body), + }...) + } + return strings.NewReader(strings.Join(lines, "\n")) } func (ctx *Ctx) Toss( @@ -58,6 +68,7 @@ func (ctx *Ctx) Toss( dryRun, doSeen, noFile, noFreq, noExec, noTrns bool, ) bool { isBad := false + sendmail := ctx.Neigh[*ctx.SelfId].Exec["sendmail"] decompressor, err := zstd.NewReader(nil) if err != nil { panic(err) @@ -118,9 +129,10 @@ func (ctx *Ctx) Toss( for _, p := range path[1:] { args = append(args, string(p)) } + argsStr := strings.Join(append([]string{handle}, args...), " ") sds := SdsAdd(sds, SDS{ "type": "exec", - "dst": strings.Join(append([]string{handle}, args...), " "), + "dst": argsStr, }) sender := ctx.Neigh[*job.PktEnc.Sender] cmdline, exists := sender.Exec[handle] @@ -144,11 +156,28 @@ func (ctx *Ctx) Toss( "NNCP_NICE="+strconv.Itoa(int(pkt.Nice)), ) cmd.Stdin = decompressor - if err = cmd.Run(); err != nil { + output, err := cmd.Output() + if err != nil { ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "handle") isBad = true goto Closing } + if len(sendmail) > 0 && ctx.NotifyExec != nil { + notify, exists := ctx.NotifyExec[sender.Name+"."+handle] + if !exists { + notify, exists = ctx.NotifyExec["*."+handle] + } + if exists { + cmd := exec.Command( + sendmail[0], + append(sendmail[1:len(sendmail)], notify.To)..., + ) + cmd.Stdin = newNotification(notify, fmt.Sprintf( + "Exec from %s: %s", sender.Name, argsStr, + ), output) + cmd.Run() + } + } } ctx.LogI("rx", sds, "") if !dryRun { @@ -245,8 +274,7 @@ func (ctx *Ctx) Toss( ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove") isBad = true } - sendmail, exists := ctx.Neigh[*ctx.SelfId].Exec["sendmail"] - if exists && len(sendmail) > 0 && ctx.NotifyFile != nil { + if len(sendmail) > 0 && ctx.NotifyFile != nil { cmd := exec.Command( sendmail[0], append(sendmail[1:len(sendmail)], ctx.NotifyFile.To)..., @@ -256,7 +284,7 @@ func (ctx *Ctx) Toss( ctx.Neigh[*job.PktEnc.Sender].Name, dst, humanize.IBytes(uint64(pktSize)), - )) + ), nil) cmd.Run() } } @@ -280,31 +308,22 @@ func (ctx *Ctx) Toss( dst := string(dstRaw) sds["dst"] = dst sender := ctx.Neigh[*job.PktEnc.Sender] - freq := sender.Freq - if freq == nil { + freqPath := sender.FreqPath + if freqPath == nil { ctx.LogE("rx", sds, "freqing is not allowed") isBad = true goto Closing } if !dryRun { - if sender.FreqChunked == 0 { - err = ctx.TxFile( - sender, - pkt.Nice, - filepath.Join(*freq, src), - dst, - sender.FreqMinSize, - ) - } else { - err = ctx.TxFileChunked( - sender, - pkt.Nice, - filepath.Join(*freq, src), - dst, - sender.FreqMinSize, - sender.FreqChunked, - ) - } + err = ctx.TxFile( + sender, + pkt.Nice, + filepath.Join(*freqPath, src), + dst, + sender.FreqChunked, + sender.FreqMinSize, + sender.FreqMaxSize, + ) if err != nil { ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "tx file") isBad = true @@ -322,17 +341,14 @@ func (ctx *Ctx) Toss( ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove") isBad = true } - sendmail, exists := ctx.Neigh[*ctx.SelfId].Exec["sendmail"] - if exists && len(sendmail) > 0 && ctx.NotifyFreq != nil { + if len(sendmail) > 0 && ctx.NotifyFreq != nil { cmd := exec.Command( sendmail[0], append(sendmail[1:len(sendmail)], ctx.NotifyFreq.To)..., ) cmd.Stdin = newNotification(ctx.NotifyFreq, fmt.Sprintf( - "Freq from %s: %s", - ctx.Neigh[*job.PktEnc.Sender].Name, - src, - )) + "Freq from %s: %s", sender.Name, src, + ), nil) cmd.Run() } } diff --git a/src/toss_test.go b/src/toss_test.go index 4ccf4ea..3a6f29f 100644 --- a/src/toss_test.go +++ b/src/toss_test.go @@ -30,7 +30,7 @@ import ( "testing" "testing/quick" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "golang.org/x/crypto/blake2b" ) @@ -199,7 +199,9 @@ func TestTossFile(t *testing.T) { DefaultNiceFile, src, fileName, + MaxFileSize, 1<<15, + MaxFileSize, ); err != nil { t.Error(err) return false @@ -273,7 +275,9 @@ func TestTossFileSameName(t *testing.T) { DefaultNiceFile, srcPath, "samefile", + MaxFileSize, 1<<15, + MaxFileSize, ); err != nil { t.Error(err) return false @@ -357,7 +361,7 @@ func TestTossFreq(t *testing.T) { if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 { return false } - ctx.Neigh[*nodeOur.Id].Freq = &spool + ctx.Neigh[*nodeOur.Id].FreqPath = &spool ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false) if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 { return false diff --git a/src/tx.go b/src/tx.go index a509207..20853b0 100644 --- a/src/tx.go +++ b/src/tx.go @@ -18,6 +18,7 @@ along with this program. If not, see . package nncp import ( + "archive/tar" "bufio" "bytes" "crypto/rand" @@ -29,13 +30,21 @@ import ( "path/filepath" "strconv" "strings" + "time" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "github.com/klauspost/compress/zstd" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/chacha20poly1305" ) +const ( + MaxFileSize = 1 << 62 + + TarBlockSize = 512 + TarExt = ".tar" +) + func (ctx *Ctx) Tx( node *Node, pkt *Pkt, @@ -43,10 +52,6 @@ func (ctx *Ctx) Tx( size, minSize int64, src io.Reader, ) (*Node, error) { - tmp, err := ctx.NewTmpFileWHash() - if err != nil { - return nil, err - } hops := make([]*Node, 0, 1+len(node.Via)) hops = append(hops, node) lastNode := node @@ -62,6 +67,14 @@ func (ctx *Ctx) Tx( if padSize < 0 { padSize = 0 } + if !ctx.IsEnoughSpace(size + padSize) { + return nil, errors.New("is not enough space") + } + tmp, err := ctx.NewTmpFileWHash() + if err != nil { + return nil, err + } + errs := make(chan error) curSize := size pipeR, pipeW := io.Pipe() @@ -109,122 +122,198 @@ func (ctx *Ctx) Tx( return lastNode, err } -func prepareTxFile(srcPath string) (io.Reader, *os.File, int64, error) { - var reader io.Reader - var src *os.File - var fileSize int64 - var err error +type DummyCloser struct{} + +func (dc DummyCloser) Close() error { return nil } + +func prepareTxFile(srcPath string) (reader io.Reader, closer io.Closer, fileSize int64, archived bool, rerr error) { if srcPath == "-" { - src, err = ioutil.TempFile("", "nncp-file") + // Read content from stdin, saving to temporary file, encrypting + // on the fly + src, err := ioutil.TempFile("", "nncp-file") if err != nil { - return nil, nil, 0, err + rerr = err + return } os.Remove(src.Name()) tmpW := bufio.NewWriter(src) tmpKey := make([]byte, chacha20poly1305.KeySize) - if _, err = rand.Read(tmpKey[:]); err != nil { - return nil, nil, 0, err + if _, rerr = rand.Read(tmpKey[:]); rerr != nil { + return } aead, err := chacha20poly1305.New(tmpKey) if err != nil { - return nil, nil, 0, err + rerr = err + return } nonce := make([]byte, aead.NonceSize()) written, err := aeadProcess(aead, nonce, true, bufio.NewReader(os.Stdin), tmpW) if err != nil { - return nil, nil, 0, err + rerr = err + return } fileSize = int64(written) if err = tmpW.Flush(); err != nil { - return nil, nil, 0, err + return } src.Seek(0, io.SeekStart) r, w := io.Pipe() go func() { if _, err := aeadProcess(aead, nonce, false, bufio.NewReader(src), w); err != nil { - panic(err) + w.CloseWithError(err) } }() reader = r - } else { - src, err = os.Open(srcPath) - if err != nil { - return nil, nil, 0, err - } - srcStat, err := src.Stat() + closer = src + return + } + + srcStat, err := os.Stat(srcPath) + if err != nil { + rerr = err + return + } + mode := srcStat.Mode() + + if mode.IsRegular() { + // It is regular file, just send it + src, err := os.Open(srcPath) if err != nil { - return nil, nil, 0, err + rerr = err + return } fileSize = srcStat.Size() reader = bufio.NewReader(src) + closer = src + return } - return reader, src, fileSize, nil -} -func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize int64) error { - if dstPath == "" { - if srcPath == "-" { - return errors.New("Must provide destination filename") - } - dstPath = filepath.Base(srcPath) - } - dstPath = filepath.Clean(dstPath) - if filepath.IsAbs(dstPath) { - return errors.New("Relative destination path required") - } - pkt, err := NewPkt(PktTypeFile, nice, []byte(dstPath)) - if err != nil { - return err - } - reader, src, fileSize, err := prepareTxFile(srcPath) - if src != nil { - defer src.Close() + if !mode.IsDir() { + rerr = errors.New("unsupported file type") + return } + + // It is directory, create PAX archive with its contents + archived = true + basePath := filepath.Base(srcPath) + rootPath, err := filepath.Abs(srcPath) if err != nil { - return err + rerr = err + return } - _, err = ctx.Tx(node, pkt, nice, fileSize, minSize, reader) - sds := SDS{ - "type": "file", - "node": node.Id, - "nice": strconv.Itoa(int(nice)), - "src": srcPath, - "dst": dstPath, - "size": strconv.FormatInt(fileSize, 10), + type einfo struct { + path string + modTime time.Time + size int64 } - if err == nil { - ctx.LogI("tx", sds, "sent") - } else { - sds["err"] = err - ctx.LogE("tx", sds, "sent") + dirs := make([]einfo, 0, 1<<10) + files := make([]einfo, 0, 1<<10) + rerr = filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + // directory header, PAX record header+contents + fileSize += TarBlockSize + 2*TarBlockSize + dirs = append(dirs, einfo{path: path, modTime: info.ModTime()}) + } else { + // file header, PAX record header+contents, file content + fileSize += TarBlockSize + 2*TarBlockSize + info.Size() + if n := info.Size() % TarBlockSize; n != 0 { + fileSize += TarBlockSize - n // padding + } + files = append(files, einfo{ + path: path, + modTime: info.ModTime(), + size: info.Size(), + }) + } + return nil + }) + if rerr != nil { + return } - return err + + r, w := io.Pipe() + reader = r + closer = DummyCloser{} + fileSize += 2 * TarBlockSize // termination block + + go func() { + tarWr := tar.NewWriter(w) + hdr := tar.Header{ + Typeflag: tar.TypeDir, + Mode: 0777, + PAXRecords: map[string]string{ + "comment": "Autogenerated by " + VersionGet(), + }, + Format: tar.FormatPAX, + } + for _, e := range dirs { + hdr.Name = basePath + e.path[len(rootPath):] + hdr.ModTime = e.modTime + if err = tarWr.WriteHeader(&hdr); err != nil { + w.CloseWithError(err) + } + } + hdr.Typeflag = tar.TypeReg + hdr.Mode = 0666 + for _, e := range files { + hdr.Name = basePath + e.path[len(rootPath):] + hdr.ModTime = e.modTime + hdr.Size = e.size + if err = tarWr.WriteHeader(&hdr); err != nil { + w.CloseWithError(err) + } + fd, err := os.Open(e.path) + if err != nil { + w.CloseWithError(err) + } + _, err = io.Copy(tarWr, bufio.NewReader(fd)) + if err != nil { + w.CloseWithError(err) + } + fd.Close() + } + tarWr.Close() + w.Close() + }() + return } -func (ctx *Ctx) TxFileChunked( +func (ctx *Ctx) TxFile( node *Node, nice uint8, srcPath, dstPath string, - minSize int64, chunkSize int64, + minSize, maxSize int64, ) error { + dstPathSpecified := false if dstPath == "" { if srcPath == "-" { return errors.New("Must provide destination filename") } dstPath = filepath.Base(srcPath) + } else { + dstPathSpecified = true } dstPath = filepath.Clean(dstPath) if filepath.IsAbs(dstPath) { return errors.New("Relative destination path required") } - reader, src, fileSize, err := prepareTxFile(srcPath) - if src != nil { - defer src.Close() + reader, closer, fileSize, archived, err := prepareTxFile(srcPath) + if closer != nil { + defer closer.Close() } if err != nil { return err } + if fileSize > maxSize { + return errors.New("Too big than allowed") + } + if archived && !dstPathSpecified { + dstPath += TarExt + } if fileSize <= chunkSize { pkt, err := NewPkt(PktTypeFile, nice, []byte(dstPath)) @@ -243,8 +332,7 @@ func (ctx *Ctx) TxFileChunked( if err == nil { ctx.LogI("tx", sds, "sent") } else { - sds["err"] = err - ctx.LogE("tx", sds, "sent") + ctx.LogE("tx", SdsAdd(sds, SDS{"err": err}), "sent") } return err } @@ -299,8 +387,7 @@ func (ctx *Ctx) TxFileChunked( if err == nil { ctx.LogI("tx", sds, "sent") } else { - sds["err"] = err - ctx.LogE("tx", sds, "sent") + ctx.LogE("tx", SdsAdd(sds, SDS{"err": err}), "sent") return err } hsh.Sum(metaPkt.Checksums[chunkNum][:0]) @@ -333,8 +420,7 @@ func (ctx *Ctx) TxFileChunked( if err == nil { ctx.LogI("tx", sds, "sent") } else { - sds["err"] = err - ctx.LogE("tx", sds, "sent") + ctx.LogE("tx", SdsAdd(sds, SDS{"err": err}), "sent") } return err } @@ -370,8 +456,7 @@ func (ctx *Ctx) TxFreq( if err == nil { ctx.LogI("tx", sds, "sent") } else { - sds["err"] = err - ctx.LogE("tx", sds, "sent") + ctx.LogE("tx", SdsAdd(sds, SDS{"err": err}), "sent") } return err } @@ -419,8 +504,7 @@ func (ctx *Ctx) TxExec( if err == nil { ctx.LogI("tx", sds, "sent") } else { - sds["err"] = err - ctx.LogE("tx", sds, "sent") + ctx.LogE("tx", SdsAdd(sds, SDS{"err": err}), "sent") } return err } @@ -433,6 +517,11 @@ func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error "size": strconv.FormatInt(size, 10), } ctx.LogD("tx", sds, "taken") + if !ctx.IsEnoughSpace(size) { + err := errors.New("is not enough space") + ctx.LogE("tx", SdsAdd(sds, SDS{"err": err}), err.Error()) + return err + } tmp, err := ctx.NewTmpFileWHash() if err != nil { return err @@ -445,8 +534,7 @@ func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error if err == nil { ctx.LogI("tx", sds, "sent") } else { - sds["err"] = err - ctx.LogI("tx", sds, "sent") + ctx.LogI("tx", SdsAdd(sds, SDS{"err": err}), "sent") } os.Symlink(nodePath, filepath.Join(ctx.Spool, node.Name)) return err diff --git a/src/tx_test.go b/src/tx_test.go index bde218f..ca77d4c 100644 --- a/src/tx_test.go +++ b/src/tx_test.go @@ -27,7 +27,7 @@ import ( "testing" "testing/quick" - "github.com/davecgh/go-xdr/xdr2" + xdr "github.com/davecgh/go-xdr/xdr2" "golang.org/x/crypto/blake2b" )