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"),
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, TRx, DefaultNiceExec-1,
117 false, false, false, false, false, false, false)
118 if len(dirFiles(rxPath)) == 0 {
121 ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
122 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
123 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec,
124 false, false, false, false, false, false, false)
125 if len(dirFiles(rxPath)) == 0 {
128 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{
131 "echo $NNCP_NICE $0 $1 >> %s ; cat >> %s",
132 filepath.Join(spool, "mbox"),
133 filepath.Join(spool, "mbox"),
136 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceExec,
137 false, false, false, false, false, false, false)
138 if len(dirFiles(rxPath)) != 0 {
142 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
146 expected := make([]byte, 0, 16)
147 for i := 0; i < 16; i++ {
150 []byte(fmt.Sprintf("%d arg0 arg1\n", replyNice))...,
152 expected = append(expected, []byte("BODY\n")...)
154 return bytes.Compare(mbox, expected) == 0
156 if err := quick.Check(f, nil); err != nil {
161 func TestTossFile(t *testing.T) {
162 f := func(fileSizes []uint8) bool {
163 if len(fileSizes) == 0 {
166 files := make(map[string][]byte)
167 for i, fileSize := range fileSizes {
168 data := make([]byte, fileSize)
169 if _, err := io.ReadFull(rand.Reader, data); err != nil {
172 files[strconv.Itoa(i)] = data
174 spool, err := ioutil.TempDir("", "testtoss")
178 defer os.RemoveAll(spool)
179 nodeOur, err := NewNodeGenerate()
188 Neigh: make(map[NodeId]*Node),
189 Alias: make(map[string]*NodeId),
190 LogPath: filepath.Join(spool, "log.log"),
193 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
194 incomingPath := filepath.Join(spool, "incoming")
195 for _, fileData := range files {
196 hasher := MTHNew(0, 0)
197 hasher.Write(fileData)
198 fileName := Base32Codec.EncodeToString(hasher.Sum(nil))
199 src := filepath.Join(spool, fileName)
200 if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
203 if err := ctx.TxFile(
204 ctx.Neigh[*nodeOur.Id],
217 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
218 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
219 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
220 false, false, false, false, false, false, false)
221 if len(dirFiles(rxPath)) == 0 {
224 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
225 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
226 false, false, false, false, false, false, false)
227 if len(dirFiles(rxPath)) != 0 {
230 for _, fileData := range files {
231 hasher := MTHNew(0, 0)
232 hasher.Write(fileData)
233 fileName := Base32Codec.EncodeToString(hasher.Sum(nil))
234 data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
238 if bytes.Compare(data, fileData) != 0 {
244 if err := quick.Check(f, nil); err != nil {
249 func TestTossFileSameName(t *testing.T) {
250 f := func(filesRaw uint8) bool {
251 files := int(filesRaw)%8 + 1
252 spool, err := ioutil.TempDir("", "testtoss")
256 defer os.RemoveAll(spool)
257 nodeOur, err := NewNodeGenerate()
266 Neigh: make(map[NodeId]*Node),
267 Alias: make(map[string]*NodeId),
268 LogPath: filepath.Join(spool, "log.log"),
271 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
272 srcPath := filepath.Join(spool, "junk")
273 if err = ioutil.WriteFile(
275 []byte("doesnotmatter"),
281 incomingPath := filepath.Join(spool, "incoming")
282 for i := 0; i < files; i++ {
283 if err := ctx.TxFile(
284 ctx.Neigh[*nodeOur.Id],
297 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
298 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
299 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
300 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFile,
301 false, false, false, false, false, false, false)
302 expected := make(map[string]struct{})
303 expected["samefile"] = struct{}{}
304 for i := 0; i < files-1; i++ {
305 expected["samefile."+strconv.Itoa(i)] = struct{}{}
307 for _, filename := range dirFiles(incomingPath) {
308 if _, exists := expected[filename]; !exists {
311 delete(expected, filename)
313 if len(expected) != 0 {
318 if err := quick.Check(f, nil); err != nil {
323 func TestTossFreq(t *testing.T) {
324 f := func(fileSizes []uint8, replyNice uint8) bool {
325 if len(fileSizes) == 0 {
328 spool, err := ioutil.TempDir("", "testtoss")
332 defer os.RemoveAll(spool)
333 nodeOur, err := NewNodeGenerate()
342 Neigh: make(map[NodeId]*Node),
343 Alias: make(map[string]*NodeId),
344 LogPath: filepath.Join(spool, "log.log"),
347 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
348 files := make(map[string][]byte)
349 for i, fileSize := range fileSizes {
350 fileData := make([]byte, fileSize)
351 if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
354 fileName := strconv.Itoa(i)
355 files[fileName] = fileData
356 if err := ctx.TxFreq(
357 ctx.Neigh[*nodeOur.Id],
368 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
369 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
370 os.Rename(txPath, rxPath)
371 os.MkdirAll(txPath, os.FileMode(0700))
372 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
373 false, false, false, false, false, false, false)
374 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
377 ctx.Neigh[*nodeOur.Id].FreqPath = &spool
378 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
379 false, false, false, false, false, false, false)
380 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
383 for fileName, fileData := range files {
384 if err := ioutil.WriteFile(
385 filepath.Join(spool, fileName),
392 ctx.Toss(ctx.Self.Id, TRx, DefaultNiceFreq,
393 false, false, false, false, false, false, false)
394 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
397 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
399 fd, err := os.Open(job.Path)
404 _, _, _, err = PktEncRead(ctx.Self, ctx.Neigh, fd, &buf, true, nil)
410 if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
414 if pkt.Nice != replyNice {
417 dst := string(pkt.Path[:int(pkt.PathLen)])
418 if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
424 if err := quick.Check(f, nil); err != nil {
429 func TestTossTrns(t *testing.T) {
430 f := func(datumLens []uint8) bool {
431 if len(datumLens) == 0 {
434 datum := make(map[int][]byte)
435 for i, datumLen := range datumLens {
437 data := make([]byte, datumLen)
438 if _, err := io.ReadFull(rand.Reader, data); err != nil {
443 spool, err := ioutil.TempDir("", "testtoss")
447 defer os.RemoveAll(spool)
448 nodeOur, err := NewNodeGenerate()
457 Neigh: make(map[NodeId]*Node),
458 Alias: make(map[string]*NodeId),
459 LogPath: filepath.Join(spool, "log.log"),
462 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
463 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
464 os.MkdirAll(rxPath, os.FileMode(0700))
465 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
466 os.MkdirAll(txPath, os.FileMode(0700))
467 for _, data := range datum {
469 Magic: MagicNNCPPv3.B,
473 copy(pktTrans.Path[:], nodeOur.Id[:])
475 if _, err := PktEncWrite(
477 ctx.Neigh[*nodeOur.Id],
482 bytes.NewReader(data),
488 hasher := MTHNew(0, 0)
489 hasher.Write(dst.Bytes())
490 if err := ioutil.WriteFile(
491 filepath.Join(rxPath, Base32Codec.EncodeToString(hasher.Sum(nil))),
498 ctx.Toss(ctx.Self.Id, TRx, 123,
499 false, false, false, false, false, false, false)
500 if len(dirFiles(rxPath)) != 0 {
503 for _, filename := range dirFiles(txPath) {
504 dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
508 for k, data := range datum {
509 if bytes.Compare(dataRead, data) == 0 {
519 if err := quick.Check(f, nil); err != nil {