2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2019 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/>.
32 "github.com/davecgh/go-xdr/xdr2"
33 "golang.org/x/crypto/blake2b"
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"},
106 for _, recipient := range recipients {
107 ctx.Self = privates[recipient]
108 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
109 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
110 if len(dirFiles(rxPath)) == 0 {
113 ctx.Toss(ctx.Self.Id, DefaultNiceExec-1, false, false, false, false, false, false)
114 if len(dirFiles(rxPath)) == 0 {
117 ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
118 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
119 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
120 if len(dirFiles(rxPath)) == 0 {
123 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{
126 "echo $NNCP_NICE $0 $1 >> %s ; cat >> %s",
127 filepath.Join(spool, "mbox"),
128 filepath.Join(spool, "mbox"),
131 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
132 if len(dirFiles(rxPath)) != 0 {
136 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
140 expected := make([]byte, 0, 16)
141 for i := 0; i < 16; i++ {
144 []byte(fmt.Sprintf("%d arg0 arg1\n", replyNice))...,
146 expected = append(expected, []byte("BODY\n")...)
148 return bytes.Compare(mbox, expected) == 0
150 if err := quick.Check(f, nil); err != nil {
155 func TestTossFile(t *testing.T) {
156 f := func(fileSizes []uint8) bool {
157 if len(fileSizes) == 0 {
160 files := make(map[string][]byte)
161 for i, fileSize := range fileSizes {
162 data := make([]byte, fileSize)
163 if _, err := io.ReadFull(rand.Reader, data); err != nil {
166 files[strconv.Itoa(i)] = data
168 spool, err := ioutil.TempDir("", "testtoss")
172 defer os.RemoveAll(spool)
173 nodeOur, err := NewNodeGenerate()
182 Neigh: make(map[NodeId]*Node),
183 Alias: make(map[string]*NodeId),
184 LogPath: filepath.Join(spool, "log.log"),
187 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
188 incomingPath := filepath.Join(spool, "incoming")
189 for _, fileData := range files {
190 checksum := blake2b.Sum256(fileData)
191 fileName := ToBase32(checksum[:])
192 src := filepath.Join(spool, fileName)
193 if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
196 if err := ctx.TxFile(
197 ctx.Neigh[*nodeOur.Id],
207 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
208 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
209 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
210 if len(dirFiles(rxPath)) == 0 {
213 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
214 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
215 if len(dirFiles(rxPath)) != 0 {
218 for _, fileData := range files {
219 checksum := blake2b.Sum256(fileData)
220 fileName := ToBase32(checksum[:])
221 data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
225 if bytes.Compare(data, fileData) != 0 {
231 if err := quick.Check(f, nil); err != nil {
236 func TestTossFileSameName(t *testing.T) {
237 f := func(filesRaw uint8) bool {
238 files := int(filesRaw)%8 + 1
239 spool, err := ioutil.TempDir("", "testtoss")
243 defer os.RemoveAll(spool)
244 nodeOur, err := NewNodeGenerate()
253 Neigh: make(map[NodeId]*Node),
254 Alias: make(map[string]*NodeId),
255 LogPath: filepath.Join(spool, "log.log"),
258 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
259 srcPath := filepath.Join(spool, "junk")
260 if err = ioutil.WriteFile(
262 []byte("doesnotmatter"),
268 incomingPath := filepath.Join(spool, "incoming")
269 for i := 0; i < files; i++ {
270 if err := ctx.TxFile(
271 ctx.Neigh[*nodeOur.Id],
281 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
282 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
283 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
284 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
285 expected := make(map[string]struct{})
286 expected["samefile"] = struct{}{}
287 for i := 0; i < files-1; i++ {
288 expected["samefile."+strconv.Itoa(i)] = struct{}{}
290 for _, filename := range dirFiles(incomingPath) {
291 if _, exists := expected[filename]; !exists {
294 delete(expected, filename)
296 if len(expected) != 0 {
301 if err := quick.Check(f, nil); err != nil {
306 func TestTossFreq(t *testing.T) {
307 f := func(fileSizes []uint8, replyNice uint8) bool {
308 if len(fileSizes) == 0 {
311 spool, err := ioutil.TempDir("", "testtoss")
315 defer os.RemoveAll(spool)
316 nodeOur, err := NewNodeGenerate()
325 Neigh: make(map[NodeId]*Node),
326 Alias: make(map[string]*NodeId),
327 LogPath: filepath.Join(spool, "log.log"),
330 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
331 files := make(map[string][]byte)
332 for i, fileSize := range fileSizes {
333 fileData := make([]byte, fileSize)
334 if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
337 fileName := strconv.Itoa(i)
338 files[fileName] = fileData
339 if err := ctx.TxFreq(
340 ctx.Neigh[*nodeOur.Id],
351 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
352 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
353 os.Rename(txPath, rxPath)
354 os.MkdirAll(txPath, os.FileMode(0700))
355 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
356 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
359 ctx.Neigh[*nodeOur.Id].Freq = &spool
360 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
361 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
364 for fileName, fileData := range files {
365 if err := ioutil.WriteFile(
366 filepath.Join(spool, fileName),
373 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
374 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
377 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
379 _, _, err := PktEncRead(ctx.Self, ctx.Neigh, job.Fd, &buf)
385 if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
389 if pkt.Nice != replyNice {
392 dst := string(pkt.Path[:int(pkt.PathLen)])
393 if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
399 if err := quick.Check(f, nil); err != nil {
404 func TestTossTrns(t *testing.T) {
405 f := func(datumLens []uint8) bool {
406 if len(datumLens) == 0 {
409 datum := make(map[int][]byte)
410 for i, datumLen := range datumLens {
412 data := make([]byte, datumLen)
413 if _, err := io.ReadFull(rand.Reader, data); err != nil {
418 spool, err := ioutil.TempDir("", "testtoss")
422 defer os.RemoveAll(spool)
423 nodeOur, err := NewNodeGenerate()
432 Neigh: make(map[NodeId]*Node),
433 Alias: make(map[string]*NodeId),
434 LogPath: filepath.Join(spool, "log.log"),
437 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
438 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
439 os.MkdirAll(rxPath, os.FileMode(0700))
440 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
441 os.MkdirAll(txPath, os.FileMode(0700))
442 for _, data := range datum {
446 PathLen: blake2b.Size256,
447 Path: new([MaxPathSize]byte),
449 copy(pktTrans.Path[:], nodeOur.Id[:])
451 if err := PktEncWrite(
453 ctx.Neigh[*nodeOur.Id],
458 bytes.NewReader(data),
464 checksum := blake2b.Sum256(dst.Bytes())
465 if err := ioutil.WriteFile(
466 filepath.Join(rxPath, ToBase32(checksum[:])),
473 ctx.Toss(ctx.Self.Id, 123, false, false, false, false, false, false)
474 if len(dirFiles(rxPath)) != 0 {
477 for _, filename := range dirFiles(txPath) {
478 dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
482 for k, data := range datum {
483 if bytes.Compare(dataRead, data) == 0 {
493 if err := quick.Check(f, nil); err != nil {