2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2018 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, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 "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"},
107 for _, recipient := range recipients {
108 ctx.Self = privates[recipient]
109 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
110 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
111 if len(dirFiles(rxPath)) == 0 {
114 ctx.Toss(ctx.Self.Id, DefaultNiceExec-1, false, false, false, false, false, false)
115 if len(dirFiles(rxPath)) == 0 {
118 ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
119 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
120 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
121 if len(dirFiles(rxPath)) == 0 {
124 ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{
127 "echo $NNCP_NICE $0 $1 >> %s ; cat >> %s",
128 filepath.Join(spool, "mbox"),
129 filepath.Join(spool, "mbox"),
132 ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
133 if len(dirFiles(rxPath)) != 0 {
137 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
141 expected := make([]byte, 0, 16)
142 for i := 0; i < 16; i++ {
145 []byte(fmt.Sprintf("%d arg0 arg1\n", replyNice))...,
147 expected = append(expected, []byte("BODY\n")...)
149 return bytes.Compare(mbox, expected) == 0
151 if err := quick.Check(f, nil); err != nil {
156 func TestTossFile(t *testing.T) {
157 f := func(fileSizes []uint8) bool {
158 if len(fileSizes) == 0 {
161 files := make(map[string][]byte)
162 for i, fileSize := range fileSizes {
163 data := make([]byte, fileSize)
164 if _, err := io.ReadFull(rand.Reader, data); err != nil {
167 files[strconv.Itoa(i)] = data
169 spool, err := ioutil.TempDir("", "testtoss")
173 defer os.RemoveAll(spool)
174 nodeOur, err := NewNodeGenerate()
183 Neigh: make(map[NodeId]*Node),
184 Alias: make(map[string]*NodeId),
185 LogPath: filepath.Join(spool, "log.log"),
188 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
189 incomingPath := filepath.Join(spool, "incoming")
190 for _, fileData := range files {
191 checksum := blake2b.Sum256(fileData)
192 fileName := ToBase32(checksum[:])
193 src := filepath.Join(spool, fileName)
194 if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
197 if err := ctx.TxFile(
198 ctx.Neigh[*nodeOur.Id],
208 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
209 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
210 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
211 if len(dirFiles(rxPath)) == 0 {
214 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
215 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
216 if len(dirFiles(rxPath)) != 0 {
219 for _, fileData := range files {
220 checksum := blake2b.Sum256(fileData)
221 fileName := ToBase32(checksum[:])
222 data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
226 if bytes.Compare(data, fileData) != 0 {
232 if err := quick.Check(f, nil); err != nil {
237 func TestTossFileSameName(t *testing.T) {
238 f := func(filesRaw uint8) bool {
239 files := int(filesRaw)%8 + 1
240 spool, err := ioutil.TempDir("", "testtoss")
244 defer os.RemoveAll(spool)
245 nodeOur, err := NewNodeGenerate()
254 Neigh: make(map[NodeId]*Node),
255 Alias: make(map[string]*NodeId),
256 LogPath: filepath.Join(spool, "log.log"),
259 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
260 srcPath := filepath.Join(spool, "junk")
261 if err = ioutil.WriteFile(
263 []byte("doesnotmatter"),
269 incomingPath := filepath.Join(spool, "incoming")
270 for i := 0; i < files; i++ {
271 if err := ctx.TxFile(
272 ctx.Neigh[*nodeOur.Id],
282 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
283 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
284 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
285 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
286 expected := make(map[string]struct{})
287 expected["samefile"] = struct{}{}
288 for i := 0; i < files-1; i++ {
289 expected["samefile"+strconv.Itoa(i)] = struct{}{}
291 for _, filename := range dirFiles(incomingPath) {
292 if _, exists := expected[filename]; !exists {
295 delete(expected, filename)
297 if len(expected) != 0 {
302 if err := quick.Check(f, nil); err != nil {
307 func TestTossFreq(t *testing.T) {
308 f := func(fileSizes []uint8, replyNice uint8) bool {
309 if len(fileSizes) == 0 {
312 spool, err := ioutil.TempDir("", "testtoss")
316 defer os.RemoveAll(spool)
317 nodeOur, err := NewNodeGenerate()
326 Neigh: make(map[NodeId]*Node),
327 Alias: make(map[string]*NodeId),
328 LogPath: filepath.Join(spool, "log.log"),
331 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
332 files := make(map[string][]byte)
333 for i, fileSize := range fileSizes {
334 fileData := make([]byte, fileSize)
335 if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
338 fileName := strconv.Itoa(i)
339 files[fileName] = fileData
340 if err := ctx.TxFreq(
341 ctx.Neigh[*nodeOur.Id],
352 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
353 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
354 os.Rename(txPath, rxPath)
355 os.MkdirAll(txPath, os.FileMode(0700))
356 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
357 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
360 ctx.Neigh[*nodeOur.Id].Freq = &spool
361 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
362 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
365 for fileName, fileData := range files {
366 if err := ioutil.WriteFile(
367 filepath.Join(spool, fileName),
374 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
375 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
378 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
380 _, _, err := PktEncRead(ctx.Self, ctx.Neigh, job.Fd, &buf)
386 if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
390 if pkt.Nice != replyNice {
393 dst := string(pkt.Path[:int(pkt.PathLen)])
394 if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
400 if err := quick.Check(f, nil); err != nil {
405 func TestTossTrns(t *testing.T) {
406 f := func(datumLens []uint8) bool {
407 if len(datumLens) == 0 {
410 datum := make(map[int][]byte)
411 for i, datumLen := range datumLens {
413 data := make([]byte, datumLen)
414 if _, err := io.ReadFull(rand.Reader, data); err != nil {
419 spool, err := ioutil.TempDir("", "testtoss")
423 defer os.RemoveAll(spool)
424 nodeOur, err := NewNodeGenerate()
433 Neigh: make(map[NodeId]*Node),
434 Alias: make(map[string]*NodeId),
435 LogPath: filepath.Join(spool, "log.log"),
438 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
439 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
440 os.MkdirAll(rxPath, os.FileMode(0700))
441 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
442 os.MkdirAll(txPath, os.FileMode(0700))
443 for _, data := range datum {
447 PathLen: blake2b.Size256,
448 Path: new([MaxPathSize]byte),
450 copy(pktTrans.Path[:], nodeOur.Id[:])
452 if err := PktEncWrite(
454 ctx.Neigh[*nodeOur.Id],
459 bytes.NewReader(data),
465 checksum := blake2b.Sum256(dst.Bytes())
466 if err := ioutil.WriteFile(
467 filepath.Join(rxPath, ToBase32(checksum[:])),
474 ctx.Toss(ctx.Self.Id, 123, false, false, false, false, false, false)
475 if len(dirFiles(rxPath)) != 0 {
478 for _, filename := range dirFiles(txPath) {
479 dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
483 for k, data := range datum {
484 if bytes.Compare(dataRead, data) == 0 {
494 if err := quick.Check(f, nil); err != nil {