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"
40 func dirFiles(path string) []string {
41 dir, err := os.Open(path)
46 names, err := dir.Readdirnames(0)
53 func TestTossExec(t *testing.T) {
54 f := func(replyNice uint8, handleRaw uint32, recipients [16]uint8) bool {
55 handle := strconv.Itoa(int(handleRaw))
56 for i, recipient := range recipients {
57 recipients[i] = recipient % 8
59 spool, err := ioutil.TempDir("", "testtoss")
63 defer os.RemoveAll(spool)
64 nodeOur, err := NewNodeGenerate()
73 Neigh: make(map[NodeId]*Node),
74 Alias: make(map[string]*NodeId),
75 LogPath: filepath.Join(spool, "log.log"),
78 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
79 privates := make(map[uint8]*NodeOur)
80 for _, recipient := range recipients {
81 if _, exists := privates[recipient]; exists {
84 our, err := NewNodeGenerate()
89 privates[recipient] = our
90 ctx.Neigh[*our.Id] = our.Their()
92 for _, recipient := range recipients {
94 ctx.Neigh[*privates[recipient].Id],
98 []string{"arg0", "arg1"},
99 strings.NewReader("BODY\n"),
108 for _, recipient := range recipients {
109 ctx.Self = privates[recipient]
110 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
111 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
112 if len(dirFiles(rxPath)) == 0 {
115 ctx.Toss(ctx.Self.Id, DefaultNiceExec-1, false, false, false, false, false, false)
116 if len(dirFiles(rxPath)) == 0 {
119 ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
120 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
121 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
122 if len(dirFiles(rxPath)) == 0 {
125 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{
128 "echo $NNCP_NICE $0 $1 >> %s ; cat >> %s",
129 filepath.Join(spool, "mbox"),
130 filepath.Join(spool, "mbox"),
133 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
134 if len(dirFiles(rxPath)) != 0 {
138 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
142 expected := make([]byte, 0, 16)
143 for i := 0; i < 16; i++ {
146 []byte(fmt.Sprintf("%d arg0 arg1\n", replyNice))...,
148 expected = append(expected, []byte("BODY\n")...)
150 return bytes.Compare(mbox, expected) == 0
152 if err := quick.Check(f, nil); err != nil {
157 func TestTossFile(t *testing.T) {
158 f := func(fileSizes []uint8) bool {
159 if len(fileSizes) == 0 {
162 files := make(map[string][]byte)
163 for i, fileSize := range fileSizes {
164 data := make([]byte, fileSize)
165 if _, err := io.ReadFull(rand.Reader, data); err != nil {
168 files[strconv.Itoa(i)] = data
170 spool, err := ioutil.TempDir("", "testtoss")
174 defer os.RemoveAll(spool)
175 nodeOur, err := NewNodeGenerate()
184 Neigh: make(map[NodeId]*Node),
185 Alias: make(map[string]*NodeId),
186 LogPath: filepath.Join(spool, "log.log"),
189 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
190 incomingPath := filepath.Join(spool, "incoming")
191 for _, fileData := range files {
192 hasher := MTHNew(0, 0)
193 hasher.Write(fileData)
194 fileName := Base32Codec.EncodeToString(hasher.Sum(nil))
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 hasher := MTHNew(0, 0)
225 hasher.Write(fileData)
226 fileName := Base32Codec.EncodeToString(hasher.Sum(nil))
227 data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
231 if bytes.Compare(data, fileData) != 0 {
237 if err := quick.Check(f, nil); err != nil {
242 func TestTossFileSameName(t *testing.T) {
243 f := func(filesRaw uint8) bool {
244 files := int(filesRaw)%8 + 1
245 spool, err := ioutil.TempDir("", "testtoss")
249 defer os.RemoveAll(spool)
250 nodeOur, err := NewNodeGenerate()
259 Neigh: make(map[NodeId]*Node),
260 Alias: make(map[string]*NodeId),
261 LogPath: filepath.Join(spool, "log.log"),
264 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
265 srcPath := filepath.Join(spool, "junk")
266 if err = ioutil.WriteFile(
268 []byte("doesnotmatter"),
274 incomingPath := filepath.Join(spool, "incoming")
275 for i := 0; i < files; i++ {
276 if err := ctx.TxFile(
277 ctx.Neigh[*nodeOur.Id],
289 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
290 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
291 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
292 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
293 expected := make(map[string]struct{})
294 expected["samefile"] = struct{}{}
295 for i := 0; i < files-1; i++ {
296 expected["samefile."+strconv.Itoa(i)] = struct{}{}
298 for _, filename := range dirFiles(incomingPath) {
299 if _, exists := expected[filename]; !exists {
302 delete(expected, filename)
304 if len(expected) != 0 {
309 if err := quick.Check(f, nil); err != nil {
314 func TestTossFreq(t *testing.T) {
315 f := func(fileSizes []uint8, replyNice uint8) bool {
316 if len(fileSizes) == 0 {
319 spool, err := ioutil.TempDir("", "testtoss")
323 defer os.RemoveAll(spool)
324 nodeOur, err := NewNodeGenerate()
333 Neigh: make(map[NodeId]*Node),
334 Alias: make(map[string]*NodeId),
335 LogPath: filepath.Join(spool, "log.log"),
338 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
339 files := make(map[string][]byte)
340 for i, fileSize := range fileSizes {
341 fileData := make([]byte, fileSize)
342 if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
345 fileName := strconv.Itoa(i)
346 files[fileName] = fileData
347 if err := ctx.TxFreq(
348 ctx.Neigh[*nodeOur.Id],
359 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
360 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
361 os.Rename(txPath, rxPath)
362 os.MkdirAll(txPath, os.FileMode(0700))
363 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
364 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
367 ctx.Neigh[*nodeOur.Id].FreqPath = &spool
368 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
369 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
372 for fileName, fileData := range files {
373 if err := ioutil.WriteFile(
374 filepath.Join(spool, fileName),
381 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
382 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
385 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
387 fd, err := os.Open(job.Path)
392 _, _, err = PktEncRead(ctx.Self, ctx.Neigh, fd, &buf)
398 if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
402 if pkt.Nice != replyNice {
405 dst := string(pkt.Path[:int(pkt.PathLen)])
406 if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
412 if err := quick.Check(f, nil); err != nil {
417 func TestTossTrns(t *testing.T) {
418 f := func(datumLens []uint8) bool {
419 if len(datumLens) == 0 {
422 datum := make(map[int][]byte)
423 for i, datumLen := range datumLens {
425 data := make([]byte, datumLen)
426 if _, err := io.ReadFull(rand.Reader, data); err != nil {
431 spool, err := ioutil.TempDir("", "testtoss")
435 defer os.RemoveAll(spool)
436 nodeOur, err := NewNodeGenerate()
445 Neigh: make(map[NodeId]*Node),
446 Alias: make(map[string]*NodeId),
447 LogPath: filepath.Join(spool, "log.log"),
450 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
451 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
452 os.MkdirAll(rxPath, os.FileMode(0700))
453 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
454 os.MkdirAll(txPath, os.FileMode(0700))
455 for _, data := range datum {
457 Magic: MagicNNCPPv3.B,
461 copy(pktTrans.Path[:], nodeOur.Id[:])
463 if _, err := PktEncWrite(
465 ctx.Neigh[*nodeOur.Id],
470 bytes.NewReader(data),
476 hasher := MTHNew(0, 0)
477 hasher.Write(dst.Bytes())
478 if err := ioutil.WriteFile(
479 filepath.Join(rxPath, Base32Codec.EncodeToString(hasher.Sum(nil))),
486 ctx.Toss(ctx.Self.Id, 123, false, false, false, false, false, false)
487 if len(dirFiles(rxPath)) != 0 {
490 for _, filename := range dirFiles(txPath) {
491 dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
495 for k, data := range datum {
496 if bytes.Compare(dataRead, data) == 0 {
506 if err := quick.Check(f, nil); err != nil {