Skip to content

Commit 51743dc

Browse files
committed
first commit
0 parents  commit 51743dc

16 files changed

+651
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
*.log
3+
yarn.lock
4+
5+
node_modules/

.npmignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
*.log
3+
4+
node_modules/

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
node_js:
3+
- "stable"

LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2016 Lsong <[email protected]>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

README.md

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
## tftp2
2+
3+
> simple tftp server and client in node.js
4+
5+
![[email protected]](https://img.shields.io/npm/v/tftp2.svg)
6+
[![Build Status](https://travis-ci.org/song940/node-tftp.svg?branch=master)](https://travis-ci.org/song940/node-tftp)
7+
8+
### Installation
9+
10+
```bash
11+
$ npm i tftp2
12+
```
13+
14+
### Example
15+
16+
```js
17+
const tftp = require('tftp2');
18+
19+
const { read, write } = tftp('127.0.0.1', 6969);
20+
21+
read('remote.txt').pipe(fs.createWriteStream('/tmp/demo.txt'));
22+
23+
```
24+
25+
```js
26+
const fs = require('fs');
27+
const tftp = require('tftp2');
28+
29+
const server = tftp.createServer();
30+
31+
server.on('get', async (req, send) => {
32+
const { filename, mode, address, port } = req;
33+
console.log('get', filename, mode, address, port);
34+
await send(fs.readFileSync(filename));
35+
});
36+
37+
server.on('put', async (req, read) => {
38+
const { filename, mode, address, port } = req;
39+
console.log('put', filename, mode, address, port);
40+
const buffer = [];
41+
read(chunk => buffer.push(chunk), () => {
42+
fs.writeFileSync(filename, Buffer.concat(buffer));
43+
});
44+
});
45+
46+
```
47+
48+
### Contributing
49+
- Fork this Repo first
50+
- Clone your Repo
51+
- Install dependencies by `$ npm install`
52+
- Checkout a feature branch
53+
- Feel free to add your features
54+
- Make sure your features are fully tested
55+
- Publish your local branch, Open a pull request
56+
- Enjoy hacking <3
57+
58+
### MIT
59+
60+
Copyright (c) 2016 Lsong &lt;[email protected]&gt;
61+
62+
Permission is hereby granted, free of charge, to any person obtaining a copy
63+
of this software and associated documentation files (the "Software"), to deal
64+
in the Software without restriction, including without limitation the rights
65+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66+
copies of the Software, and to permit persons to whom the Software is
67+
furnished to do so, subject to the following conditions:
68+
69+
The above copyright notice and this permission notice shall be included in
70+
all copies or substantial portions of the Software.
71+
72+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
75+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
76+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
77+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
78+
THE SOFTWARE.
79+
80+
81+
---

connection.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const udp = require('dgram');
2+
const { debuglog } = require('util');
3+
const EventEmitter = require('events');
4+
const Packet = require('./packet');
5+
6+
const debug = debuglog('tftp2:server');
7+
8+
class Connection extends EventEmitter {
9+
constructor(rinfo) {
10+
super('udp4');
11+
this.setRemoteDescription(rinfo);
12+
}
13+
setRemoteDescription(rinfo) {
14+
return Object.assign(this, this.rinfo = rinfo);
15+
}
16+
send(data) {
17+
const { rinfo } = this;
18+
if (data instanceof Packet)
19+
data = data.toBuffer();
20+
return new Promise((resolve, reject) => {
21+
this.socket.send(data, rinfo.port, rinfo.address, (err, length) => {
22+
if (err) return reject(err);
23+
resolve(length);
24+
});
25+
});
26+
}
27+
sendRequest(opcode, filename) {
28+
const packet = Packet.createRequest(opcode, filename);
29+
return this.send(packet);
30+
};
31+
sendAck(block) {
32+
const { rinfo } = this;
33+
const packet = Packet.createAck(block);
34+
debug('send ack block %s to %s:%s', block, rinfo.address, rinfo.port);
35+
return this.send(packet);
36+
}
37+
sendBlock(block, data) {
38+
const { rinfo } = this;
39+
const packet = Packet.createData(block, data);
40+
debug('send block %s size %s, to %s:%s', block, data.length, rinfo.address, rinfo.port);
41+
return this.send(packet);
42+
}
43+
wait(fn) {
44+
return new Promise((resolve, reject) => {
45+
const onMessage = (message, rinfo) => {
46+
const packet = Packet.parse(message);
47+
packet.rinfo = rinfo;
48+
fn(packet) && (resolve(packet), removeListener());
49+
};
50+
const removeListener = () =>
51+
this.socket.removeListener('message', onMessage);
52+
this.socket.on('message', onMessage);
53+
});
54+
}
55+
waitAck(block) {
56+
return this.wait(message =>
57+
message.opcode === Packet.OPCODE.ACK && message.block === block);
58+
}
59+
waitBlock(block) {
60+
return this.wait(message =>
61+
message.opcode === Packet.OPCODE.DATA && message.block === block);
62+
}
63+
}
64+
65+
module.exports = Connection;

example/index.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const tftp = require('..');
2+
const assert = require('assert');
3+
4+
const { read, write } = tftp('127.0.0.1', '6969');
5+
6+
const readChunk = filename =>
7+
new Promise(async (resolve, reject) => {
8+
const buffer = [];
9+
await read(filename, chunk => buffer.push(chunk), () =>
10+
resolve(Buffer.concat(buffer)));
11+
});
12+
13+
(async () => {
14+
15+
const filename = `node-tftp-test-data`;
16+
await write(filename, Buffer.allocUnsafe(0xffffff));
17+
18+
console.log('write done');
19+
const b = await readChunk(filename);
20+
21+
assert.equal(a.length, 0xffffff);
22+
assert.equal(b.length, 0xffffff);
23+
assert.deepEqual(a, b);
24+
25+
console.log('All Tests PASS');
26+
27+
})();

example/server.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const fs = require('fs');
2+
const tftp = require('..');
3+
4+
const server = tftp.createServer()
5+
6+
server.on('get', async (req, send) => {
7+
const { filename, mode, address, port } = req;
8+
console.log('get', filename, mode, address, port);
9+
await send(fs.readFileSync(filename));
10+
});
11+
12+
server.on('put', async (req, read) => {
13+
const { filename, mode, address, port } = req;
14+
console.log('put', filename, mode, address, port);
15+
const buffer = [];
16+
read(chunk => buffer.push(chunk), () => {
17+
fs.writeFileSync(filename, Buffer.concat(buffer));
18+
});
19+
});
20+
21+
server.listen(6969);

index.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const { debuglog } = require('util');
2+
const Packet = require('./packet');
3+
const Connection = require('./connection');
4+
5+
const debug = debuglog('tftp2');
6+
7+
/**
8+
* [TFTP description]
9+
* @param {[type]} options [description]
10+
*/
11+
const TFTP = (host, port, { BLOCK_SIZE = 512 } = {}) => {
12+
const rinfo = { address: host, port };
13+
const client = new Connection(rinfo);
14+
const init = () => client.setRemoteDescription(rinfo);
15+
return {
16+
async read(filename, push, done) {
17+
let block = 0, rinfo, data;
18+
await init();
19+
await client.sendRequest(Packet.OPCODE.RRQ, filename);
20+
while (true) {
21+
({ rinfo, block, data } = await client.waitBlock(block + 1));
22+
debug('received block(%s) size(%s), from %s:%s', block, data.length, rinfo.address, rinfo.port);
23+
push(data);
24+
await client.setRemoteDescription(rinfo);
25+
await client.sendAck(block);
26+
if (data.length < BLOCK_SIZE) {
27+
done();
28+
break;
29+
}
30+
}
31+
},
32+
async write(filename, data) {
33+
let block, rinfo;
34+
await init();
35+
await client.sendRequest(Packet.OPCODE.WRQ, filename);
36+
const blocks = Math.floor(data.length / BLOCK_SIZE | 0) + 1;
37+
for (var i = 0; i < blocks; i++) {
38+
({ rinfo, block } = await client.waitAck(i));
39+
await client.setRemoteDescription(rinfo);
40+
debug('request block %s, from %s:%s', block, rinfo.address, rinfo.port);
41+
const start = block * BLOCK_SIZE;
42+
const end = Math.min(start + BLOCK_SIZE, data.length);
43+
await client.sendBlock(block + 1, data.slice(start, end));
44+
}
45+
debug('done');
46+
}
47+
};
48+
};
49+
50+
TFTP.Client = TFTP;
51+
TFTP.Packet = Packet;
52+
TFTP.Server = require('./server');
53+
TFTP.createServer = () => new TFTP.Server();
54+
55+
module.exports = TFTP;

package.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "tftp2",
3+
"version": "0.0.0",
4+
"description": "simple tftp server and client in node.js",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "node test",
8+
"start": "node server.js"
9+
},
10+
"repository": {
11+
"url": "git+https://github.com/song940/node-tftp.git",
12+
"type": "git"
13+
},
14+
"author": "Lsong <[email protected]>",
15+
"license": "MIT",
16+
"bugs": {
17+
"url": "https://github.com/song940/node-tftp/issues"
18+
},
19+
"homepage": "https://github.com/song940/node-tftp#readme",
20+
"directories": {
21+
"example": "example",
22+
"test": "test"
23+
},
24+
"keywords": [
25+
"tftp",
26+
"tftpd",
27+
"ftp"
28+
]
29+
}

0 commit comments

Comments
 (0)