2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 xdr "github.com/davecgh/go-xdr/xdr2"
34 "golang.org/x/crypto/blake2b"
41 func dirFiles(path string) []string {
42 dir, err := os.Open(path)
47 names, err := dir.Readdirnames(0)
54 func TestTossExec(t *testing.T) {
55 f := func(replyNice uint8, handleRaw uint32, recipients [16]uint8) bool {
56 handle := strconv.Itoa(int(handleRaw))
57 for i, recipient := range recipients {
58 recipients[i] = recipient % 8
60 spool, err := ioutil.TempDir("", "testtoss")
64 defer os.RemoveAll(spool)
65 nodeOur, err := NewNodeGenerate()
74 Neigh: make(map[NodeId]*Node),
75 Alias: make(map[string]*NodeId),
76 LogPath: filepath.Join(spool, "log.log"),
79 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
80 privates := make(map[uint8]*NodeOur)
81 for _, recipient := range recipients {
82 if _, exists := privates[recipient]; exists {
85 our, err := NewNodeGenerate()
90 privates[recipient] = our
91 ctx.Neigh[*our.Id] = our.Their()
93 for _, recipient := range recipients {
95 ctx.Neigh[*privates[recipient].Id],
99 []string{"arg0", "arg1"},
100 strings.NewReader("BODY\n"),
109 for _, recipient := range recipients {
110 ctx.Self = privates[recipient]
111 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
112 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
113 if len(dirFiles(rxPath)) == 0 {
116 ctx.Toss(ctx.Self.Id, DefaultNiceExec-1, false, false, false, false, false, false)
117 if len(dirFiles(rxPath)) == 0 {
120 ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
121 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
122 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
123 if len(dirFiles(rxPath)) == 0 {
126 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{
129 "echo $NNCP_NICE $0 $1 >> %s ; cat >> %s",
130 filepath.Join(spool, "mbox"),
131 filepath.Join(spool, "mbox"),
134 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
135 if len(dirFiles(rxPath)) != 0 {
139 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
143 expected := make([]byte, 0, 16)
144 for i := 0; i < 16; i++ {
147 []byte(fmt.Sprintf("%d arg0 arg1\n", replyNice))...,
149 expected = append(expected, []byte("BODY\n")...)
151 return bytes.Compare(mbox, expected) == 0
153 if err := quick.Check(f, nil); err != nil {
158 func TestTossFile(t *testing.T) {
159 f := func(fileSizes []uint8) bool {
160 if len(fileSizes) == 0 {
163 files := make(map[string][]byte)
164 for i, fileSize := range fileSizes {
165 data := make([]byte, fileSize)
166 if _, err := io.ReadFull(rand.Reader, data); err != nil {
169 files[strconv.Itoa(i)] = data
171 spool, err := ioutil.TempDir("", "testtoss")
175 defer os.RemoveAll(spool)
176 nodeOur, err := NewNodeGenerate()
185 Neigh: make(map[NodeId]*Node),
186 Alias: make(map[string]*NodeId),
187 LogPath: filepath.Join(spool, "log.log"),
190 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
191 incomingPath := filepath.Join(spool, "incoming")
192 for _, fileData := range files {
193 checksum := blake2b.Sum256(fileData)
194 fileName := Base32Codec.EncodeToString(checksum[:])
195 src := filepath.Join(spool, fileName)
196 if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
199 if err := ctx.TxFile(
200 ctx.Neigh[*nodeOur.Id],
212 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
213 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
214 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
215 if len(dirFiles(rxPath)) == 0 {
218 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
219 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
220 if len(dirFiles(rxPath)) != 0 {
223 for _, fileData := range files {
224 checksum := blake2b.Sum256(fileData)
225 fileName := Base32Codec.EncodeToString(checksum[:])
226 data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
230 if bytes.Compare(data, fileData) != 0 {
236 if err := quick.Check(f, nil); err != nil {
241 func TestTossFileSameName(t *testing.T) {
242 f := func(filesRaw uint8) bool {
243 files := int(filesRaw)%8 + 1
244 spool, err := ioutil.TempDir("", "testtoss")
248 defer os.RemoveAll(spool)
249 nodeOur, err := NewNodeGenerate()
258 Neigh: make(map[NodeId]*Node),
259 Alias: make(map[string]*NodeId),
260 LogPath: filepath.Join(spool, "log.log"),
263 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
264 srcPath := filepath.Join(spool, "junk")
265 if err = ioutil.WriteFile(
267 []byte("doesnotmatter"),
273 incomingPath := filepath.Join(spool, "incoming")
274 for i := 0; i < files; i++ {
275 if err := ctx.TxFile(
276 ctx.Neigh[*nodeOur.Id],
288 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
289 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
290 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
291 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
292 expected := make(map[string]struct{})
293 expected["samefile"] = struct{}{}
294 for i := 0; i < files-1; i++ {
295 expected["samefile."+strconv.Itoa(i)] = struct{}{}
297 for _, filename := range dirFiles(incomingPath) {
298 if _, exists := expected[filename]; !exists {
301 delete(expected, filename)
303 if len(expected) != 0 {
308 if err := quick.Check(f, nil); err != nil {
313 func TestTossFreq(t *testing.T) {
314 f := func(fileSizes []uint8, replyNice uint8) bool {
315 if len(fileSizes) == 0 {
318 spool, err := ioutil.TempDir("", "testtoss")
322 defer os.RemoveAll(spool)
323 nodeOur, err := NewNodeGenerate()
332 Neigh: make(map[NodeId]*Node),
333 Alias: make(map[string]*NodeId),
334 LogPath: filepath.Join(spool, "log.log"),
337 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
338 files := make(map[string][]byte)
339 for i, fileSize := range fileSizes {
340 fileData := make([]byte, fileSize)
341 if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
344 fileName := strconv.Itoa(i)
345 files[fileName] = fileData
346 if err := ctx.TxFreq(
347 ctx.Neigh[*nodeOur.Id],
358 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
359 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
360 os.Rename(txPath, rxPath)
361 os.MkdirAll(txPath, os.FileMode(0700))
362 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
363 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
366 ctx.Neigh[*nodeOur.Id].FreqPath = &spool
367 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
368 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
371 for fileName, fileData := range files {
372 if err := ioutil.WriteFile(
373 filepath.Join(spool, fileName),
380 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
381 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
384 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
386 _, _, err := PktEncRead(ctx.Self, ctx.Neigh, job.Fd, &buf)
392 if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
396 if pkt.Nice != replyNice {
399 dst := string(pkt.Path[:int(pkt.PathLen)])
400 if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
406 if err := quick.Check(f, nil); err != nil {
411 func TestTossTrns(t *testing.T) {
412 f := func(datumLens []uint8) bool {
413 if len(datumLens) == 0 {
416 datum := make(map[int][]byte)
417 for i, datumLen := range datumLens {
419 data := make([]byte, datumLen)
420 if _, err := io.ReadFull(rand.Reader, data); err != nil {
425 spool, err := ioutil.TempDir("", "testtoss")
429 defer os.RemoveAll(spool)
430 nodeOur, err := NewNodeGenerate()
439 Neigh: make(map[NodeId]*Node),
440 Alias: make(map[string]*NodeId),
441 LogPath: filepath.Join(spool, "log.log"),
444 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
445 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
446 os.MkdirAll(rxPath, os.FileMode(0700))
447 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
448 os.MkdirAll(txPath, os.FileMode(0700))
449 for _, data := range datum {
453 PathLen: blake2b.Size256,
455 copy(pktTrans.Path[:], nodeOur.Id[:])
457 if err := PktEncWrite(
459 ctx.Neigh[*nodeOur.Id],
464 bytes.NewReader(data),
470 checksum := blake2b.Sum256(dst.Bytes())
471 if err := ioutil.WriteFile(
472 filepath.Join(rxPath, Base32Codec.EncodeToString(checksum[:])),
479 ctx.Toss(ctx.Self.Id, 123, false, false, false, false, false, false)
480 if len(dirFiles(rxPath)) != 0 {
483 for _, filename := range dirFiles(txPath) {
484 dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
488 for k, data := range datum {
489 if bytes.Compare(dataRead, data) == 0 {
499 if err := quick.Check(f, nil); err != nil {