From 0e2796b6c4b362d223e3f078710bfb4ec5e702de Mon Sep 17 00:00:00 2001 From: Paul J R Date: Wed, 16 Jan 2013 02:18:19 +1100 Subject: [PATCH] initial commits --- lxc/appconfig | 12 + lxc/config | 12 + lxc/init.js | 275 ++++++++++ lxc/lxc-nodejs | 274 ++++++++++ tftp/node_modules/.bin/tftp-client | 110 ++++ tftp/node_modules/tftp-client/.npmignore | 2 + tftp/node_modules/tftp-client/README.md | 64 +++ .../tftp-client/TFTP-Client.sublime-project | 8 + .../tftp-client/TFTP-Client.sublime-workspace | 575 ++++++++++++++++++++ tftp/node_modules/tftp-client/bin/tftp.js | 110 ++++ tftp/node_modules/tftp-client/lib/tftp.js | 457 ++++++++++++++++ tftp/node_modules/tftp-client/package.json | 26 + tftp/tftpd.js | 19 + tftp/tftpd_1.js | 55 ++ 14 files changed, 1999 insertions(+), 0 deletions(-) create mode 100644 lxc/appconfig create mode 100644 lxc/config create mode 100644 lxc/init.js create mode 100755 lxc/lxc-nodejs create mode 100755 tftp/node_modules/.bin/tftp-client create mode 100644 tftp/node_modules/tftp-client/.npmignore create mode 100644 tftp/node_modules/tftp-client/README.md create mode 100644 tftp/node_modules/tftp-client/TFTP-Client.sublime-project create mode 100644 tftp/node_modules/tftp-client/TFTP-Client.sublime-workspace create mode 100755 tftp/node_modules/tftp-client/bin/tftp.js create mode 100644 tftp/node_modules/tftp-client/lib/tftp.js create mode 100644 tftp/node_modules/tftp-client/package.json create mode 100644 tftp/tftpd.js create mode 100644 tftp/tftpd_1.js diff --git a/lxc/appconfig b/lxc/appconfig new file mode 100644 index 0000000..f87b232 --- /dev/null +++ b/lxc/appconfig @@ -0,0 +1,12 @@ +# this is an appconfig file +# it has the format of: +# appname:directory:appfilepath[:options] +# where +# appname is an internally used name to identify the app +# directory is the directory to start the app from +# appfilepath is the path to the js file to start +# options is a set of options such as norestart to not restart application on a failure +appname1:.:/node/app.js +appname2:.:/node/app.js +appname3:.:/node/app.js +appname4:.:/node/app.js diff --git a/lxc/config b/lxc/config new file mode 100644 index 0000000..aaec2c5 --- /dev/null +++ b/lxc/config @@ -0,0 +1,12 @@ +# there arent many config variables here +# just ip address, hostname and gateway +#debug=true +ip4address=eth0:10.0.3.100/24 +ip4address=lo:127.0.0.1/8 +ip6address=eth0:auto +hostname=nd +ip4gateway=10.0.3.1 +ip6gateway=auto +dnsserver=10.0.3.1 +random=whatever +checktimer=1000 diff --git a/lxc/init.js b/lxc/init.js new file mode 100644 index 0000000..7dc3a5b --- /dev/null +++ b/lxc/init.js @@ -0,0 +1,275 @@ +#!/node/bin/node + +//var uid=$user +var fs = require("fs"); +var asroot = false; +var debug_output = false; +var default_loop_time = 2000; + +// set the global context +global.lxcnodejs = new Object(); + +// and begin... +if(process.getuid() == 0) { + asroot = true; +} else { + console.log("Not running as root, assuming debug mode, config file should be ./config"); +} + +if(asroot) var mnt = require("/node_modules/mount"); + +// perform mount +console.log("Mounting proc"); +if(asroot) { + mnt.mount("proc", "/proc", "proc"); +} else { + //console.log("fake mount"); + console.log("(debug) pass /proc mount"); +} + +// get the global space setup + + +// read main and node config file and parse +if(asroot) { + console.log("Reading config file /config"); + loadConfig("/config"); + loadNodeConfig("/node_base/appconfig", "/node_base"); +} else { + console.log("Reading config file ./config (debug mode)"); + loadConfig("./config"); + loadNodeConfig("./appconfig", "."); +} + +// begin the main loop +if(asroot) { + startMainLoop(); +} else { + if(debug_output) console.log("(debug) main loop now begins with process monitor"); + startMainLoop(); +} + +/* + * + * END OF MAIN ROUTINE + * + */ + +function loadNodeConfig(file, basedir) { + var configFile = fs.readFileSync(file).toString(); + var lines = configFile.split("\n"); + var nodes = new Object(); + + for(var i=0; i < lines.length; i++) { + //console.log("line: ", lines[i].trim()); + var sks = lines[i].match(/^[^#][a-zA-Z0-9:]+/); + var lks = null; + if(sks != null) lks = lines[i].split(":"); + if(lks!=null) { + stl = lines[i].split(":"); + //console.log("lks is: '%s', '%s'", stl[0], stl[1]); + if(stl.length < 3) { + console.log("Invalid config line '%s', should be 'appname:directory:appfilepath[:options]'", lines[i].trim()); + } else { + var args = null; + if(stl[3] != null) args = stl[3]; + nodes[stl[0]] = new Object(); + nodes[stl[0]].directory = stl[1]; + nodes[stl[0]].file = stl[2]; + nodes[stl[0]].args = args; + console.log("Adding node config for '%s'", stl[0]); + } + } + } + + // check our config against the current global + for(key in global.lxcnodejs) { + if(typeof nodes[key] == "undefined") { + global.lxcnodejs[key].stop_and_kill = true; + } else { + if(global.lxcnodejs[key].directory != nodes[key].directory) { + if(debug_output) console.log("(debug) marking '%s' for restart on config change (directory)", key); + global.lxcnodejs[key].directory = nodes[key].directory; + global.lxcnodejs[key].restart = true; + } + if(global.lxcnodejs[key].file != nodes[key].file) { + if(debug_output) console.log("(debug) marking '%s' for restart on config change (file)", key); + global.lxcnodejs[key].file = nodes[key].file; + global.lxcnodejs[key].restart = true; + } + if(global.lxcnodejs[key].args != nodes[key].args) { + if(debug_output) console.log("(debug) marking '%s' for restart on config change (options)", key); + global.lxcnodejs[key].args = nodes[key].args; + global.lxcnodejs[key].restart = true; + } + } + } + + // check for new configs and load them + for(key in nodes) { + if(typeof global.lxcnodejs[key] == "undefined") { + if(debug_output) console.log("(debug) application '%s' is a new config, creating", key); + global.lxcnodejs[key] = new Object(); + global.lxcnodejs[key].directory = nodes[key].directory; + global.lxcnodejs[key].file = nodes[key].file; + global.lxcnodejs[key].args = nodes[key].args; + global.lxcnodejs[key].pid = -1; + } + } +} + +function loadConfig(file) { + var configFile = fs.readFileSync(file).toString(); + + var lines = configFile.split("\n"); + + for(var i=0; i < lines.length; i++) { + //console.log("line: ", lines[i].trim()); + var lks = lines[i].match(/^[^#][a-zA-Z0-9]+\=.*/); + if(lks!=null) { + stl = lines[i].split("="); + //console.log("lks is: '%s', '%s'", stl[0], stl[1]); + if(stl.length !=2) { + console.log("Invalid config line '%s', should be name=value format", lines[i].trim()); + } else { + parseConfigLine(stl[0].trim(), stl[1].trim()); + } + } + } +} + +function parseConfigLine(key, value) { + //console.log("parsing config '%s' = '%s'", key, value); + switch(key) { + case "ip4address": + var lxon = value.split(":"); + var iface = ""; + var addrs = ""; + if(lxon.length!=2) { + console.log("Address config isnt correct, expect 'interface:address/mask'"); + } else { + iface = lxon[0]; + addrs = lxon[1]; + console.log("IPv4 address for '%s' is '%s'", iface, addrs); + if(asroot) { + var nodespawn = require("child_process").spawn, + nodeproc = nodespawn("/sbin/ip", ["link", "set", iface, "address", addrs, "up"], opts); + } else { + if(debug_output) console.log("(debug) would run /sbin/ip link set %s address %s up", iface, addrs); + } + } + break; + case "ip6address": + var lxon = value.split(":"); + var iface = ""; + var addrs = ""; + if(lxon.length!=2) { + console.log("Address config isnt correct, expect 'interface:address/mask'"); + } else { + iface = lxon[0]; + addrs = lxon[1]; + console.log("IPv4 address for '%s' is '%s'", iface, addrs); + } + break; + case "ip4gateway": + console.log("Default IPv4 gateway is: '%s'", value); + if(asroot) { + var nodespawn = require("child_process").spawn, + nodeproc = nodespawn("/sbin/ip", ["route", "add", "default", "via", value], opts); + } else { + if(debug_output) console.log("(debug) would run /sbin/ip route add default via %s", value); + } + break; + case "checktimer": + console.log("Setting health check timer to %s ms", value); + default_loop_time = parseInt(value); + if(default_loop_time < 100) { + console.log("(warning) health check timer must be larger then 100, setting to 100, was %s", value); + default_loop_time = 100; + } + break; + case "ip6gateway": + console.log("Default IPv6 gateway is: '%s'", value); + break; + case "dnsserver": + console.log("DNS address set to: '%s'", value); + break; + case "hostname": + console.log("Hostname set to: '%s'", value); + break; + case "debug": + if(value == "true") { + debug_output = true; + console.log("(debug) Turning debugging on"); + } + default: + console.log("Unknown config line: '%s' = '%s'", key, value); + } +} + +function startApp(appname, directory, file, uid) { + + var opts = { uid: uid, env: process.env, cwd: directory }; + var sleeplen = Math.floor(Math.random()*60); + var nodespawn = require("child_process").spawn; + var nodeproc = null; + + if(asroot) { + nodeproc = nodespawn("/node/bin/node", ["/node_code/nc.js"], opts); + } else { + if(debug_output) console.log("(debug) using sleep to emulator process '%s'", appname); + nodeproc = nodespawn("sleep", [sleeplen], opts); + } + + nodeproc.procname = appname; + global.lxcnodejs[appname].pid = nodeproc.pid; + + if(debug_output) console.log("(debug) application started with pid of %d", nodeproc.pid); + + nodeproc.stdout.on("data", function(data) { + console.log("data from nodespawn: '%s', '%s'", data, nodeproc.procname); + }); + nodeproc.stderr.on("data", function(data) { + console.log("stderrdata from nodespawn: '%s', '%s'", data, nodeproc.procname); + }); + nodeproc.on("exit", function(data) { + console.log("nodespawn died for '%s'", nodeproc.procname); + global.lxcnodejs[nodeproc.procname].pid = 0; + }); +} + +// main loop does all starting/restarting of applications +function startMainLoop() { + // this loop kicks around every 5 seconds and just checks on the health of the processes or whatever + for(key in global.lxcnodejs) { + if(debug_output) console.log("(debug) checking state of '%s'", key); + if(typeof global.lxcnodejs[key].pid == "undefined") { + // start it. + console.log("Starting application '%s' (no pid was defined)", key); + startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null); + } else if(global.lxcnodejs[key].pid == -1) { + // start it. + console.log("Starting application '%s' (initial start)", key); + startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null); + } else if(global.lxcnodejs[key].pid == 0) { + // start it. + console.log("Starting application '%s' (pid 0, possible application crash?)", key); + startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null); + } else if(typeof global.lxcnodejs[key].restart != "undefined") { + // restart it + console.log("Restarting application '%s' (restart defined)", key); + startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null); + } else if(typeof global.lxcnodejs[key].stop_and_kill != "undefined") { + // kill it + console.log("Restarting application '%s'", key); + } else { + if(debug_output) console.log("(debug) state of '%s' is healthy", key); + } + + // we also need to check the control directory and see + // if theres any control files + } + + // and restart the loop + setTimeout(startMainLoop, default_loop_time); +} \ No newline at end of file diff --git a/lxc/lxc-nodejs b/lxc/lxc-nodejs new file mode 100755 index 0000000..df653ca --- /dev/null +++ b/lxc/lxc-nodejs @@ -0,0 +1,274 @@ +#!/bin/bash + +# +# lxc: linux Container library + +# Authors: +# Paul Robinson + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +setup_node() +{ + user=$3 + rootfs=$1 + name=$2 + + echo "Creating default configuration, $rootfs/config - EDIT THIS CONFIG" + + pushd $rootfs + cat > config < node_base/config < /dev/null || return 1 + + # minimal devices needed for busybox + mknod tty c 5 0 || res=1 + mknod console c 5 1 || res=1 + chmod 666 tty console || res=1 + mknod tty0 c 4 0 || res=1 + mknod tty1 c 4 0 || res=1 + mknod tty5 c 4 0 || res=1 + chmod 666 tty0 || res=1 + mknod ram0 b 1 0 || res=1 + chmod 600 ram0 || res=1 + mknod null c 1 3 || res=1 + chmod 666 null || res=1 + + + echo "Downloading latest nodejs binaries for linux x64" + #fname=/tmp/nodejs.$RANDOM.`date +%s`tar.gz + # TODO: DONT FORGET TO REMOVE THIS + fname=/tmp/nodejs.11298.tar.gz + #wget -O $fname http://nodejs.org/dist/v0.8.17/node-v0.8.17-linux-x64.tar.gz + + pushd $rootfs + tar xfz $fname + ln -s node*linux*64* node + popd + + pushd $rootfs + echo "Installing ip cmd from upper OS" + cp /sbin/ip ./sbin/ + popd + + pushd $rootfs + echo "PWD is $PWD" + cat >> sbin/init <> $path/config +lxc.utsname = $name +lxc.tty = 1 +lxc.pts = 1 +lxc.rootfs = $rootfs +# uncomment the next line to run the container unconfined: +#lxc.aa_profile = unconfined +EOF + +if [ -d "$rootfs/lib" ]; then +cat <> $path/config +lxc.mount.entry=/lib $rootfs/lib none ro,bind 0 0 +lxc.mount.entry=/usr/lib $rootfs/usr/lib none ro,bind 0 0 +EOF +fi + +if [ -d "/lib64" ] && [ -d "$rootfs/lib64" ]; then +cat <> $path/config +lxc.mount.entry=/lib64 $rootfs/lib64 none ro,bind 0 0 +EOF +fi + +if [ -d "/usr/lib64" ] && [ -d "$rootfs/usr/lib64" ]; then +cat <> $path/config +lxc.mount.entry=/usr/lib64 $rootfs/usr/lib64 none ro,bind 0 0 +EOF +fi +} + +usage() +{ + cat < -u|--user= -i|--ip= +EOF + return 0 +} + +user=0 +ip_last=$(($RANDOM%100+100)) +ip=10.0.3.$ip_last/24 + +options=$(getopt -o hp:u:n:i:g: -l help,path:,user:,name:,ip:,gateway: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +while true +do + case "$1" in + -h|--help) usage $0 && exit 0;; + -u|--user) user=$2; shift 2;; + -i|--ip) ip=$2; shift 2;; + -g|--gateway) gw=$2; shift 2;; + -p|--path) path=$2; shift 2;; + -n|--name) name=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +rootfs=$path/rootfs + +install_node $rootfs $name $user +if [ $? -ne 0 ]; then + echo "failed to install the nodejs rootfs" + exit 1 +fi + +setup_node $rootfs $name $user +if [ $? -ne 0 ]; then + echo "Failed to setup node" + exit 1 +fi + +echo "sleeping for check - 20s" +#sleep 20 + +echo Params are, $user, $path, $name +#exit 1 + +copy_configuration $path $rootfs $name +if [ $? -ne 0 ]; then + echo "failed to write configuration file" + exit 1 +fi diff --git a/tftp/node_modules/.bin/tftp-client b/tftp/node_modules/.bin/tftp-client new file mode 100755 index 0000000..e48a173 --- /dev/null +++ b/tftp/node_modules/.bin/tftp-client @@ -0,0 +1,110 @@ +#!/usr/bin/env node + +// Require needed modules +var TFTP = require('..'), // The tftp-client module + fs = require('fs'), // Simple wrappers around standard POSIX functions + path = require('path'); // Contains utilities for handling and transforming file paths + +/**********************\ +|* Validate arguments *| +\**********************/ + +// Too few arguments (node + path_to_this_file + host + cmd + file = 5) +if (process.argv.length < 5) { + // Print usage, and exit + console.log('Needs atleast 3 arguments (you had %d)', process.argv.length-2); + console.log(''); + printUsage(true); +} + +// Grab arguments +var host = process.argv[2]; +var cmd = process.argv[3]; +var file = process.argv[4]; +var port = process.argv[5] || 69; // Port defaults to 69 if omitted + +// If cmd is neither read nor write, print usage & exit +if (['read', 'write'].indexOf(cmd)===-1) { + console.log('Command must be read or write (you had %s)', cmd); + printUsage(true); +} + +/*******************\ +|* Validation done *| +\*******************/ + +// Create the client +var client = new TFTP(port, host); + +var basename = path.basename(file); + +/********\ +|* READ *| +\********/ +if (cmd == 'read') { + // Read from server + client.read(basename, function(err, data) { + // If error, output some error message + if (err) { + console.error('Oh noes! Error while reading file from tftp server:'); + console.error(err); + } else { + + // No error, we got the file, lets write it + + fs.writeFile(file, data, function (err) { + + // If error, output some error message + if (err) { + console.error('Dang it! Error while writing file!'); + console.error(err); + } else { + + // No error, the file has been written! + + console.log('File saved (%d bytes)', data.length); + } + }); + } + }); +} +/*********\ +|* WRITE *| +\*********/ +else if (cmd == 'write') { + // If file does not exist, print error and usage & exit + if (!fs.existsSync(file)) { + console.log('File (%s) does not exist!', file); + printUsage(true); + } + + // Read file first, then send to server + var data = fs.readFileSync(file); + + client.write(basename, data, function (err, bytes) { + if (err) { + console.error('ERROR:'); + console.error(err); + return; + } + + console.log('File sent (%d bytes)', bytes); + }); +} else { + console.log('???HOW DID YOU GET HERE???'); +} + +/** + * Prints usage - how to use tftp-client + * @param {boolean} exit Wether it sould exit the process + */ +function printUsage(exit) { + console.log('Usage:'); + console.log(' tftp-client (read|write) []'); + console.log(''); + console.log('Example:'); + console.log(' tftp-client localhost read 1.txt'); + + if (exit===true) + process.exit(0); +} \ No newline at end of file diff --git a/tftp/node_modules/tftp-client/.npmignore b/tftp/node_modules/tftp-client/.npmignore new file mode 100644 index 0000000..84a3249 --- /dev/null +++ b/tftp/node_modules/tftp-client/.npmignore @@ -0,0 +1,2 @@ +.git* +example/ \ No newline at end of file diff --git a/tftp/node_modules/tftp-client/README.md b/tftp/node_modules/tftp-client/README.md new file mode 100644 index 0000000..ca09b89 --- /dev/null +++ b/tftp/node_modules/tftp-client/README.md @@ -0,0 +1,64 @@ +# TFTP-Client + +A simple TFTP client for Node.Js. +*Should not be used in production - first of all: this module is at an early stage (written in less than 12 hours), second: tftp is terrible* + +## Install + +### As a module +`npm install tftp-client` + +### As CLI +`npm install -g tftp-client` + +## Usage + +### Module + +`var client = new TFTP(port, client)` to create a new client. + +`client.read(filename, callback)` to **read** from the server. + ~ The Callback is passed 2 arguments `(err, data)`, where `data` is the contents of the file. + +`client.write(filename, data, callback)` to **write** to the server, where `data` is the contents of the file. + ~ The callback is passed 2 arguments `(err, bytes)`, where `bytes` is the number of bytes sent. + +**Simple read example:** + +```javascript +var TFTP = require('tftp-client'); + +// Initialize the tftp client +var client = new TFTP(69, 'localhost'); + +// Read 1.txt from the server +client.read('1.txt', function (err, data) { + if (err) { + console.error('ERROR:'); + console.error(err); + return; + } + + console.log('Got data (%d bytes). First 100 bytes:', data.length); + console.log(data.toString('utf8', 0, 100)); +}); +``` + +### Command line + +To install the tftp-client as CLI, run `npm install -g tftp-client`. + +`tftp-client (read|write) []` +* hostname - Hostname of tftp server +* read|write - Wether you want to read or write +* filename - Path to the file you want to read or write +* port - Optional. Defaults to 69 + +**Example**: +`tftp-client localhost read 1.txt` + +## TODO + +- Error packets - [RFC](http://tools.ietf.org/html/rfc1350#page-8). (implemented, but not tested) +- Do the initial connection as defined in section 4 (TID's: port numbers from request ack) - [RFC](http://tools.ietf.org/html/rfc1350#section-4). +- Currently, any DATA or ACK packet is responded to. Eg. An ACK packet will get a `DATA` response. There is not check for the block numbers to be in order. diff --git a/tftp/node_modules/tftp-client/TFTP-Client.sublime-project b/tftp/node_modules/tftp-client/TFTP-Client.sublime-project new file mode 100644 index 0000000..02d0d4b --- /dev/null +++ b/tftp/node_modules/tftp-client/TFTP-Client.sublime-project @@ -0,0 +1,8 @@ +{ + "folders": + [ + { + "path": "/D/Dokumenter/GitHub/TFTP-Client" + } + ] +} diff --git a/tftp/node_modules/tftp-client/TFTP-Client.sublime-workspace b/tftp/node_modules/tftp-client/TFTP-Client.sublime-workspace new file mode 100644 index 0000000..35cc7eb --- /dev/null +++ b/tftp/node_modules/tftp-client/TFTP-Client.sublime-workspace @@ -0,0 +1,575 @@ +{ + "auto_complete": + { + "selected_items": + [ + [ + "exists", + "path.existsSync(path);" + ], + [ + "cons", + "console.error();" + ], + [ + "D", + "Dokumenter" + ], + [ + "process", + "process.exit(code);" + ], + [ + "proces", + "process.exit(code);" + ], + [ + "createse", + "http.createServer(requestListener);" + ], + [ + "createSe", + "http.createServer(requestListener);" + ], + [ + "child", + "child_process.exec(command /*, options, callback */);" + ], + [ + "timeout", + "timers.setTimeout(callback, after);" + ], + [ + "node", + "node.events.EventEmitter.on Snippet: NodeJS EventEmitter" + ] + ] + }, + "buffers": + [ + { + "file": "package.json", + "settings": + { + "buffer_size": 242, + "line_ending": "Windows", + "name": "package.json" + } + }, + { + "file": "lib/tftp.js", + "settings": + { + "buffer_size": 7942, + "line_ending": "Windows", + "name": "tftp.js" + } + }, + { + "file": "bin/tftp.js", + "settings": + { + "buffer_size": 2683, + "line_ending": "Windows" + } + }, + { + "file": "README.md", + "settings": + { + "buffer_size": 1790, + "line_ending": "Windows", + "name": "README.md" + } + } + ], + "build_system": "", + "command_palette": + { + "height": 380.0, + "selected_items": + [ + [ + "mark", + "Markdown Preview: preview in Browser" + ], + [ + "git diff", + "Git: Diff Current File" + ], + [ + "markd", + "Markdown Preview: preview in Browser" + ], + [ + "markdown", + "Markdown Preview: preview in Browser" + ], + [ + "npm", + "Nodejs::NPM::Command" + ], + [ + "npl", + "Nodejs::NPM::List" + ], + [ + "install", + "Package Control: Install Package" + ], + [ + "MARK", + "Markdown Preview: preview in Browser" + ], + [ + "markdo", + "Markdown Preview: preview in Browser" + ], + [ + "git", + "Git: Gui" + ], + [ + "gitadd", + "Git: Add..." + ], + [ + "remo", + "Package Control: Remove Package" + ], + [ + "gut", + "GitHub: Open Gist in Browser" + ], + [ + "intall", + "Package Control: Install Package" + ], + [ + "snippet", + "Snippet: setTimeout function" + ], + [ + "kar", + "Package Control: Add Repository" + ], + [ + "ma", + "Markdown Preview: preview in Sublime Text" + ], + [ + "list", + "Package Control: List Packages" + ], + [ + "package", + "Package Control: List Packages" + ], + [ + "mar", + "Markdown Preview: preview in Browser" + ], + [ + "Package Control: list", + "Package Control: List Packages" + ], + [ + "insta", + "Package Control: Install Package" + ], + [ + "node", + "Nodejs::Run::Current File" + ], + [ + "package up", + "Package Control: Upgrade Package" + ], + [ + "list packa", + "Package Control: Install Package" + ], + [ + "package install", + "Package Control: Install Package" + ], + [ + "package discover", + "Package Control: Discover Packages" + ] + ], + "width": 512.0 + }, + "console": + { + "height": 227.0 + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "file_history": + [ + "/D/Dokumenter/GitHub/TFTP-Client/TFTP-Client.sublime-project", + "/D/Dokumenter/GitHub/TFTP-Client/.npmignore", + "/D/Dokumenter/GitHub/TFTP-Client/example/read.js", + "/D/Dokumenter/GitHub/TFTP-Client/example/write.js", + "/D/Dokumenter/GitHub/TFTP-Client/bin/tftp.js", + "/C/Users/Kristjan/AppData/Roaming/Sublime Text 2/Packages/Default/Default (Windows).sublime-keymap", + "/D/Dokumenter/GitHub/TFTP-Client/lib/write.js", + "/D/Dokumenter/GitHub/TFTP-Client/lib/read.js", + "/D/Dokumenter/GitHub/TFTP-Client/example/transaction.js", + "/D/Dokumenter/GitHub/JsControl/JsControl.sublime-project", + "/D/Dokumenter/GitHub/JsControl/test.js", + "/D/Dokumenter/GitHub/JsControl/.gitignore", + "/D/Dokumenter/GitHub/JsControl/JsControl.js", + "/D/Dokumenter/GitHub/JsControl/controller/test.js", + "/D/Dokumenter/GitHub/JsControl/package.json", + "/D/Dokumenter/GitHub/JsControl/plugins/playerlist/player.js", + "/D/Dokumenter/GitHub/JsControl/controller/modules/maps.js", + "/D/Dokumenter/GitHub/JsControl/controller/modules/game.js", + "/D/Dokumenter/GitHub/JsControl/config/config.json", + "/D/Dokumenter/GitHub/JsControl/Run.cmd", + "/D/Dokumenter/GitHub/JsControl/plugins/playerlist/index.js", + "/D/Dokumenter/GitHub/JsControl/config/players.sample.json", + "/D/Dokumenter/GitHub/JsControl/README.md", + "/D/Dokumenter/GitHub/JsControl/controller/modules/players/players.js", + "/D/Dokumenter/GitHub/JsControl/config/config.sample.json", + "/D/Dokumenter/GitHub/JsControl/todo.md", + "/D/Dokumenter/GitHub/JsControl/Plugins/second/index.js", + "/D/Dokumenter/GitHub/JsControl/controller/player.js", + "/D/Dokumenter/GitHub/JsControl/config/plugins/admin.sample.json", + "/D/Dokumenter/GitHub/JsControl/controller/players.js", + "/D/Dokumenter/GitHub/JsControl/Plugins/admin.js", + "/D/Dokumenter/GitHub/JsControl/plugins/commands.js", + "/D/Dokumenter/GitHub/JsControl/plugins/database.js", + "/C/Users/Kristjan/AppData/Roaming/Sublime Text 2/Packages/User/Distraction Free.sublime-settings", + "/C/Users/Kristjan/AppData/Roaming/Sublime Text 2/Packages/User/Default (Windows).sublime-keymap", + "/D/Dokumenter/GitHub/JsControl/Plugins/webcontroller/index.js", + "/D/Dokumenter/GitHub/JsControl/config/plugins/webcontroller.json", + "/D/Dokumenter/GitHub/JsControl/config/config.js", + "/D/Dokumenter/GitHub/JsControl/config/plugins/webcontroller.js", + "/D/Dokumenter/GitHub/node-gbxremote/package.json", + "/D/Dokumenter/GitHub/node-gbxremote/lib/gbxremote.js", + "/D/Dokumenter/GitHub/node-gbxremote/lib/client.js", + "/D/Dokumenter/GitHub/node-gbxremote/.gitignore", + "/D/Dokumenter/GitHub/node-gbxremote/example/client.js", + "/D/Dokumenter/GitHub/node-gbxremote/lib/deserializer.js", + "/D/Dokumenter/GitHub/node-gbxremote/example/authenticate.js", + "/C/Users/Kristjan/AppData/Roaming/Sublime Text 2/Packages/Default/Preferences.sublime-settings", + "/C/Users/Kristjan/AppData/Roaming/Sublime Text 2/Packages/User/Preferences.sublime-settings" + ], + "find": + { + "height": 34.0 + }, + "find_in_files": + { + "height": 0.0, + "where_history": + [ + "todo.md", + "controller.js", + "" + ] + }, + "find_state": + { + "case_sensitive": false, + "find_history": + [ + "Timeout", + "- ", + "tftp is terrible", + "argc", + "length", + "args", + "line", + "bytes", + "createAck", + "this.current", + "netascii", + "/", + " 2 Access violation.\n 3 Disk full or allocation exceeded.\n 4 Illegal TFTP operation.\n 5 Unknown transfer ID.\n 6 File already exists.\n 7 No such user.\n", + "tftp", + "________________________________________________________", + "client", + "players", + "PlayerList", + "Maps", + "this.query", + "playerlist", + "name", + "this", + "plugins", + ".emit", + ".on", + "plugin", + "requirePlugin", + "require", + "!!(", + "(fl.pop())", + "fl.pop()", + "spec.pop()", + "spec", + "Is", + "spectator", + "self", + "this", + "console", + "ingame", + "shift", + "plugin", + "ready", + "file", + "Connection", + "\\\\", + "/", + " /##################\\\\');", + "function", + "s", + "loadPlugins", + " self.loadPlugins();\n", + "loadPlugins", + " self.loadPlugins();\n self.loadPlugins();\n self.loadPlugins();\n self.loadPlugins();\n self.loadPlugins();\n", + " self.loadPlugins();\n self.loadPlugins();\n self.loadPlugins();\n self.loadPlugins();\n", + " self.loadPlugins();\n", + "loadPlugins", + "function", + "commands", + "without", + ".", + "*", + "ctrl+b", + "Plugin", + "password", + "config.U", + "config.I", + "config.P", + "\n\n //return;\n setTimeout(function () {\n console.log(\"Exiting!\");\n client.terminate();\n }, 1000);", + " [\"SuperAdmin\", \"SuperAdmin\"], function(err, result) {\n if (err) {\n console.log(err);\n } else {\n if (result === true)\n console.log(\"Authenticated!\");\n }\n });\n \n client.methodCall(\"EnableCallbacks\", [true], function(err, res) {\n console.log(err, res);\n });\n\n //return;\n setTimeout(function () {\n console.log(\"Exiting!\");\n client.terminate();\n }, 1000);\n}", + " });" + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + "-", + "config.u", + "config.i", + "config.p" + ], + "reverse": false, + "show_context": true, + "use_buffer2": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "selected": 3, + "sheets": + [ + { + "buffer": 0, + "file": "package.json", + "settings": + { + "buffer_size": 242, + "regions": + { + }, + "selection": + [ + [ + 242, + 242 + ] + ], + "settings": + { + "auto_name": "package.json", + "syntax": "Packages/JavaScript/JSON.tmLanguage" + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "type": "text" + }, + { + "buffer": 1, + "file": "lib/tftp.js", + "settings": + { + "buffer_size": 7942, + "regions": + { + }, + "selection": + [ + [ + 1556, + 1556 + ] + ], + "settings": + { + "auto_name": "tftp.js", + "syntax": "Packages/JavaScript/JavaScript.tmLanguage", + "translate_tabs_to_spaces": false + }, + "translation.x": 0.0, + "translation.y": 2077.0, + "zoom_level": 1.0 + }, + "type": "text" + }, + { + "buffer": 2, + "file": "bin/tftp.js", + "settings": + { + "buffer_size": 2683, + "regions": + { + }, + "selection": + [ + [ + 2608, + 2640 + ] + ], + "settings": + { + "syntax": "Packages/JavaScript/JavaScript.tmLanguage", + "translate_tabs_to_spaces": false + }, + "translation.x": 0.0, + "translation.y": 924.0, + "zoom_level": 1.0 + }, + "type": "text" + }, + { + "buffer": 3, + "file": "README.md", + "settings": + { + "buffer_size": 1790, + "regions": + { + }, + "selection": + [ + [ + 1643, + 1643 + ] + ], + "settings": + { + "auto_name": "README.md", + "syntax": "Packages/Markdown/Markdown.tmLanguage" + }, + "translation.x": 0.0, + "translation.y": 168.0, + "zoom_level": 1.0 + }, + "type": "text" + } + ] + } + ], + "incremental_find": + { + "height": 0.0 + }, + "input": + { + "height": 30.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ] + ], + "cols": + [ + 0.0, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "output.exec": + { + "height": 248.0 + }, + "output.git": + { + "height": 545.0 + }, + "replace": + { + "height": 0.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "selected_items": + [ + [ + "c", + "JsControl.js" + ], + [ + "clien", + "lib/client.js" + ], + [ + ".git", + ".gitignore" + ], + [ + "packa", + "package.json" + ] + ], + "width": 0.0 + }, + "select_project": + { + "height": 500.0, + "selected_items": + [ + ], + "width": 380.0 + }, + "show_minimap": true, + "show_open_files": false, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 212.0, + "status_bar_visible": true +} diff --git a/tftp/node_modules/tftp-client/bin/tftp.js b/tftp/node_modules/tftp-client/bin/tftp.js new file mode 100755 index 0000000..e48a173 --- /dev/null +++ b/tftp/node_modules/tftp-client/bin/tftp.js @@ -0,0 +1,110 @@ +#!/usr/bin/env node + +// Require needed modules +var TFTP = require('..'), // The tftp-client module + fs = require('fs'), // Simple wrappers around standard POSIX functions + path = require('path'); // Contains utilities for handling and transforming file paths + +/**********************\ +|* Validate arguments *| +\**********************/ + +// Too few arguments (node + path_to_this_file + host + cmd + file = 5) +if (process.argv.length < 5) { + // Print usage, and exit + console.log('Needs atleast 3 arguments (you had %d)', process.argv.length-2); + console.log(''); + printUsage(true); +} + +// Grab arguments +var host = process.argv[2]; +var cmd = process.argv[3]; +var file = process.argv[4]; +var port = process.argv[5] || 69; // Port defaults to 69 if omitted + +// If cmd is neither read nor write, print usage & exit +if (['read', 'write'].indexOf(cmd)===-1) { + console.log('Command must be read or write (you had %s)', cmd); + printUsage(true); +} + +/*******************\ +|* Validation done *| +\*******************/ + +// Create the client +var client = new TFTP(port, host); + +var basename = path.basename(file); + +/********\ +|* READ *| +\********/ +if (cmd == 'read') { + // Read from server + client.read(basename, function(err, data) { + // If error, output some error message + if (err) { + console.error('Oh noes! Error while reading file from tftp server:'); + console.error(err); + } else { + + // No error, we got the file, lets write it + + fs.writeFile(file, data, function (err) { + + // If error, output some error message + if (err) { + console.error('Dang it! Error while writing file!'); + console.error(err); + } else { + + // No error, the file has been written! + + console.log('File saved (%d bytes)', data.length); + } + }); + } + }); +} +/*********\ +|* WRITE *| +\*********/ +else if (cmd == 'write') { + // If file does not exist, print error and usage & exit + if (!fs.existsSync(file)) { + console.log('File (%s) does not exist!', file); + printUsage(true); + } + + // Read file first, then send to server + var data = fs.readFileSync(file); + + client.write(basename, data, function (err, bytes) { + if (err) { + console.error('ERROR:'); + console.error(err); + return; + } + + console.log('File sent (%d bytes)', bytes); + }); +} else { + console.log('???HOW DID YOU GET HERE???'); +} + +/** + * Prints usage - how to use tftp-client + * @param {boolean} exit Wether it sould exit the process + */ +function printUsage(exit) { + console.log('Usage:'); + console.log(' tftp-client (read|write) []'); + console.log(''); + console.log('Example:'); + console.log(' tftp-client localhost read 1.txt'); + + if (exit===true) + process.exit(0); +} \ No newline at end of file diff --git a/tftp/node_modules/tftp-client/lib/tftp.js b/tftp/node_modules/tftp-client/lib/tftp.js new file mode 100644 index 0000000..4029627 --- /dev/null +++ b/tftp/node_modules/tftp-client/lib/tftp.js @@ -0,0 +1,457 @@ +var dgram = require('dgram'); // UDP (datagram) + +// Timeout for ack/data packet +var TIMEOUT = 5000; // 5 seconds +// Max retransmits if timeout +var MAX_RETRANSMITS = 3; + +// type: Opcode +var types = { + 'rrq': 1, // Read ReQuest + 'wrq': 2, // Write ReQuest + 'data':3, + 'ack': 4, + 'err': 5, + + // aliases: + 'read':1, + 'write':2 +} + +// Error strings ([errorCode] = errorString) +var errors = [ + 'Not defined, see error message (if any).', + 'File not found.', + 'Access violation.', + 'Disk full or allocation exceeded.', + 'Illegal TFTP operation.', + 'Unknown transfer ID.', + 'File already exists.', + 'No such user.' +]; + +/** + * Constructor + * @param {Number} port Port the tftp server is listening to + * @param {String} ip Ip or hostname of the tftp server + */ +var TFTP = module.exports = function(port, ip) { + this.ip = ip || '127.0.0.1'; + this.port = port || 69; + + // Hold the current operation + this.current = false; + // Holds the queue of the next operations + this.queue = []; + + // Client will be created when needed + this.client = null; + + // Display debug messages? + this.debug = false; +} + +TFTP.prototype.createClient = function() { + if (this.client !== null) + return; + + // We need this inside onMessage... + var self = this; + + // Called when getting an message from the server + var onMessage = function(msg, rinfo) { + + // Type of message (see `types` above) + var type = msg.readUInt16BE(0); + + switch (type) { + // Data - Respond with Ack + case types.data: + var block = msg.readUInt16BE(2); + var data = msg.slice(4); // From byte 4 is data + + if (self.debug) { + console.log('> Received data. Block#: %d Bytes: %d', block, data.length); + console.log('< Sending ACK. Block#: %d', block); + } + + // Concat the two buffers + self.current.data = Buffer.concat([self.current.data, data]); + + // Create and send ACK packet + var ack = createAck(block); + self.send(ack); + + // If less than 512 bytes were received, it's the end... + if (data.length < 512) { + // Send the data to the callback + self.current.callback(null, self.current.data); + + // Go to next operation in queue + self.next(); + } + break; + // Ack - Respond with Data + case types.ack: + var block = msg.readUInt16BE(2); + + if (self.debug) + console.log('> Received ACK. Block#: %d', block); + + // If this is the ack for the last block + if (block == self.current.blocks) { + // Send callback + self.current.callback(null, self.current.data.length); + + // Go to next operation in queue + self.next(); + + // Break out of switch + break; + } + + if (self.debug) + console.log('< Sending data. Block#: %d', block + 1); + + // Create the data packet for the next block of data + var start = 512 * block; + // End is `start + 512`, or end of data, whichever comes first + var end = Math.min(start + 512, self.current.data.length); + var data = self.current.data.slice(start, end); + + var packet = createData(block+1, data); + + // Send data block + self.send(packet); + break; + // Error + case types.err: + // Create new Error(), and send callback + var errorCode = msg.readUInt16BE(2); + var errMsg = msg.toString('ascii', 4, msg.length - 1); + // @TODO: Take errMsg from `errors`, unless code == 0? + var err = new Error(errMsg); + err.code = errorCode; + + if (self.debug) + console.log('> Received Error. code: %d - msg: %s', errorCode, ErrMsg); + + // Callback + self.current.callback(err); + + // Go to next operation in queue + self.next(); + break; + } + } + + // Create socket, and listen to messages + this.client = dgram.createSocket("udp4", onMessage); +}; + +/** + * Shortcut for sending packet to server + * @param {Buffer} buff The buffer to send + * @param {Function} cb Callback - (err, bytes) + */ +TFTP.prototype.send = function(buff, cb) { + if (typeof cb !== 'function') cb = function() {}; + + // We need this later + var self = this; + + // Create function of sending this packet so that we can call it again on timeout + var send = function() { + self.client.send(buff, 0, buff.length, self.port, self.ip, cb); + }; + // Send the packet already + send(); + + var onTimeout = function() { + // If we have retransmitted less than MAX_RETRANSMITS + if (MAX_RETRANSMITS > ++self.current.timeout.retransmits) { + + if (self.debug) + console.log('! Timeout - Retransmitting (%d bytes)', buff.length); + + // Send the packet again + send(); + + // Set a new timeout for the packet we just sent + self.current.timeout.id = setTimeout(onTimeout, TIMEOUT); + } + + // If we sent too many retransmitts, the remote server did not respond... + else { + if (self.debug) + console.log('! Timeout - End'); + + // Create error + var err = new Error("Timeout"); + err.code = 0; + + self.current.callback(err); + // Reset current, and check queue - (no answer from server) + self.next(); + } + } + + // If there is a timeout, clear the timeout + if (this.current.timeout) + clearTimeout(this.current.timeout.id); + + // Create a timeout object where we store information about this timeout + this.current.timeout = { + id: setTimeout(onTimeout, TIMEOUT), + retransmits: 0 + } +}; + +/** + * Goes to next item in queue (if any). Same as `check()`, but clears current first + */ +TFTP.prototype.next = function() { + // Has to clear any timeout + if (this.current && this.current.timeout) + clearTimeout(this.current.timeout.id); + + // Reset current, and check queue + this.current = false; + this.check(); +}; + +/** + * Checks the Queue. + * If no operation is currently active, go to the next item in the queue (if any). + */ +TFTP.prototype.check = function() { + // If there currently is an active operation + // Or if the queue is empty, just return + if (this.current !== false) + return; + + // If there is nothing running, and the queue is empty + if (this.queue.length == 0) { + // Close client + this.client.close(); + return; + } else { + // Create client + this.createClient(); + } + + // Take the first item in queue + this.current = this.queue.shift(); + + // We need this later + var self = this; + + + if (self.debug) + console.log('< Sending request'); + + // Create the request... + var buff = createRequest(this.current.type, this.current.filename); + // Send the request + this.send(buff, function(err, bytes) { + // If there was an error sending the packet + if (err) { + // Create Error message + var err = new Error(['Error when sending ', + self.current.type, + ' request for ', + self.current.filename].join()); + + // Send error to the callback of the current operation + self.current.callback(err); + + // Reset current + self.current = false; + + // Then check queue + self.check(); + } + }); +}; + +/** + * Sends a file to the server + * @param {String} filename File to send + * @param {Buffer} data The data to write/send to the server + * @param {Function} cb Callback - (err) + */ +TFTP.prototype.write = function(filename, data, cb) { + if (typeof cb !== 'function') cb = function() {}; // Default cb to an empty function + if (!Buffer.isBuffer(data)) data = new Buffer(data); // If data is not a Buffer, make it a buffer + + // Item to put into the queue + var queueItem = { + type: 'write', + filename: filename, + callback: cb, + data: data, + blocks: Math.ceil(data.length / 512) // Number of blocks to transfer data. + // When we receive an ACK with this number, the transfer is finished + }; + + // Push the queueItem to the end of the queue. + this.queue.push(queueItem); + + // Check the queue... + this.check(); +}; + +/** + * Reads a file off the server + * @param {String} filename File to read from server + * @param {Function} cb Callback - (err, data) + */ +TFTP.prototype.read = function(filename, cb) { + if (typeof cb !== 'function') cb = function() {}; // Default cb to an empty function + + // Item to put into the queue + var queueItem = { + type: 'read', + filename: filename, + callback: cb, + data: new Buffer(0) // Buffer of size 0 which will be filled up by onMessage + }; + + // Push the queueItem to the end of the queue. + this.queue.push(queueItem); + + // Check the queue... + this.check(); +}; + +/** + * Creates a buffer for a request. + + 2 bytes string 1 byte string 1 byte + ------------------------------------------------ + | Opcode | Filename | 0 | Mode | 0 | + ------------------------------------------------ + + * @param {String|Number} type Int Opcode, or String (read|write|rrq|wrq) + * @param {String} filename Filename to add in the request + * @param {String} mode optional Mode (netascii|octet|email) - Defaults to octet + * @return {Buffer} The Buffer + */ +function createRequest(type, filename, mode) { + // Figure out the opcode for the type + if (typeof type === 'string') { + type = type.toLowerCase(); + + // If it exists in the types object, we found it + if (types.hasOwnProperty(type)) + type = types[type]; + // If not, we dno what type + else + throw 'Unknown type (' + type + ')'; + } + // Not a string, nor a number, then we dno what type of request it is... + else if (typeof type !== 'number') + throw 'Unknown type (' + type + ')'; + + // Default mode to 'octet' + mode = mode || 'octet'; + + // Calculate the length of the buffer + // mode (2 byte opcode) + length of filename + 1 null byte + length of mode + 1 null byte. + var buffLen = 4 + filename.length + mode.length; + + // Create the buffer + var buff = new Buffer(buffLen); + // Write mode (as unsigned 16 bit integer) on offset 0 + buff.writeUInt16BE(type, 0); + // Write filename as ascii on offset 2 + buff.write(filename, 2, 'ascii'); + // Write mode as ascii on offset filename.length + 3 (type + filename null termination) + buff.write(mode, 2 + filename.length + 1, 'ascii'); + + // Make sure the ends of the strings are null + buff[2 + filename.length] = buff[buffLen - 1] = 0; + + // Return the new buffer + return buff; +} + +/** + * Creates a buffer for a data packet + + 2 bytes 2 bytes n bytes + ---------------------------------- + | Opcode | Block # | Data | + ---------------------------------- + + * @param {Number} blockNumber Which block of the transaction it is + * @param {String} data The data to send + * @return {Buffer} The Buffer + */ +function createData(blockNumber, data) { + var type = types['data']; + + // Type + blocknumber + length of data(max 512) + var dataLen = Math.min(data.length, 512); + var buffLen = 4 + dataLen; + + var buff = new Buffer(buffLen); + + buff.writeUInt16BE(type, 0); // Type as UInt16BE on offset: 0 + buff.writeUInt16BE(blockNumber, 2); // BlockNumber as UInt16BE on offset: 2 + // Copy `data` into buff on offset 4. bytes 0 to 512 from `data`. + data.copy(buff, 4, 0, dataLen); // targetBuffer, targetStart, sourceStart, sourceEnd + + return buff; +} + +/** + * Creates a buffer for a ACK packet + + 2 bytes 2 bytes + --------------------- + | Opcode | Block # | + --------------------- + + * @param {Number} blockNumber Which block to ack + * @return {Buffer} The Buffer + */ +function createAck(blockNumber) { + var type = types['ack']; + + var buff = new Buffer(4); + buff.writeUInt16BE(type, 0); // Type as UInt16BE on offset: 0 + buff.writeUInt16BE(blockNumber, 2); // BlockNumber as UInt16BE on offset: 2 + + return buff; +} + +/** + * Creates a buffer for an ERROR packet + + 2 bytes 2 bytes string 1 byte + ----------------------------------------- + | Opcode | ErrorCode | ErrMsg | 0 | + ----------------------------------------- + + * @param {Number} code ErrorCode + * @param {String} msg Optional message - defaults to the message of the error code + * @return {Buffer} The Buffer + */ +function createError(code, msg) { + // Default error message to the error message for the code (defined on top) + msg = msg || errors[code]; + if (typeof msg !== 'string') msg = ''; + + var type = types['error']; + + var buffLen = 4 + msg.length + 1; + + var buff = new Buffer(buffLen); + buff.writeUInt16BE(type, 0); // Type as UInt16BE on offset: 0 + buff.writeUInt16BE(code, 2); // ErrorCode as UInt16BE on offset: 2 + buff.write(msg, 4, 'ascii'); // ErrMsg as ascii string on offset: 4 + buff[buffLen - 1] = 0; // Last byte is 0 + + return buff; +} diff --git a/tftp/node_modules/tftp-client/package.json b/tftp/node_modules/tftp-client/package.json new file mode 100644 index 0000000..f3a63be --- /dev/null +++ b/tftp/node_modules/tftp-client/package.json @@ -0,0 +1,26 @@ +{ + "name": "tftp-client", + "version": "0.2.1", + "description": "Very simple TFTP client", + "keywords": [ + "tftp" + ], + "author": { + "name": "MiniGod" + }, + "repository": { + "type": "git", + "url": "http://github.com/MiniGod/TFTP-Client" + }, + "main": "./lib/tftp.js", + "bin": { + "tftp-client": "./bin/tftp.js" + }, + "readme": "# TFTP-Client\r\n\r\nA simple TFTP client for Node.Js. \r\n*Should not be used in production - first of all: this module is at an early stage (written in less than 12 hours), second: tftp is terrible*\r\n\r\n## Install\r\n\r\n### As a module\r\n`npm install tftp-client`\r\n\r\n### As CLI\r\n`npm install -g tftp-client`\r\n\r\n## Usage\r\n\r\n### Module\r\n\r\n`var client = new TFTP(port, client)` to create a new client.\r\n\r\n`client.read(filename, callback)` to **read** from the server. \r\n ~ The Callback is passed 2 arguments `(err, data)`, where `data` is the contents of the file. \r\n\r\n`client.write(filename, data, callback)` to **write** to the server, where `data` is the contents of the file. \r\n ~ The callback is passed 2 arguments `(err, bytes)`, where `bytes` is the number of bytes sent. \r\n\r\n**Simple read example:**\r\n\r\n```javascript\r\nvar TFTP = require('tftp-client');\r\n\r\n// Initialize the tftp client\r\nvar client = new TFTP(69, 'localhost');\r\n\r\n// Read 1.txt from the server\r\nclient.read('1.txt', function (err, data) {\r\n\tif (err) {\r\n\t\tconsole.error('ERROR:');\r\n\t\tconsole.error(err);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconsole.log('Got data (%d bytes). First 100 bytes:', data.length);\r\n\tconsole.log(data.toString('utf8', 0, 100));\r\n});\r\n```\r\n\r\n### Command line\r\n\r\nTo install the tftp-client as CLI, run `npm install -g tftp-client`.\r\n\r\n`tftp-client (read|write) []`\r\n* hostname - Hostname of tftp server\r\n* read|write - Wether you want to read or write\r\n* filename - Path to the file you want to read or write\r\n* port - Optional. Defaults to 69\r\n\r\n**Example**:\r\n`tftp-client localhost read 1.txt`\r\n\r\n## TODO\r\n\r\n- Error packets - [RFC](http://tools.ietf.org/html/rfc1350#page-8). (implemented, but not tested)\r\n- Do the initial connection as defined in section 4 (TID's: port numbers from request ack) - [RFC](http://tools.ietf.org/html/rfc1350#section-4).\r\n- Currently, any DATA or ACK packet is responded to. Eg. An ACK packet will get a `DATA` response. There is not check for the block numbers to be in order.\r\n", + "readmeFilename": "README.md", + "_id": "tftp-client@0.2.1", + "dist": { + "shasum": "b66ceee832562b8a03ad616b40e3470f5dbd68c0" + }, + "_from": "tftp-client" +} diff --git a/tftp/tftpd.js b/tftp/tftpd.js new file mode 100644 index 0000000..c023096 --- /dev/null +++ b/tftp/tftpd.js @@ -0,0 +1,19 @@ +var dgram = require("dgram"); +var server = dgram.createSocket("udp4"); + + +exports.start = function(port) { + server.on("message", function (msg, rinfo) { + console.log("msg: ", msg); + console.log("server got: " + msg + " from " + + rinfo.address + ":" + rinfo.port); + parseMsg(msg); + }); + + server.on("listening", function () { + var address = server.address(); + console.log("server listening " + address.address + ":" + address.port); + }); + + server.bind(port); +} \ No newline at end of file diff --git a/tftp/tftpd_1.js b/tftp/tftpd_1.js new file mode 100644 index 0000000..7d6c745 --- /dev/null +++ b/tftp/tftpd_1.js @@ -0,0 +1,55 @@ +var dgram = require("dgram"); + +var server = dgram.createSocket("udp4"); + +server.on("message", function (msg, rinfo) { + console.log("msg: ", msg); + console.log("server got: " + msg + " from " + + rinfo.address + ":" + rinfo.port); + parseMsg(msg); +}); + +server.on("listening", function () { + var address = server.address(); + console.log("server listening " + + address.address + ":" + address.port); +}); + +function parseMsg(msg) { + var lkb = msg.readUInt16BE(0); + var fnamend = 0; + + for(i=2; i<(msg.length-1); i++) { + if(msg[i] == 0) { + fnamend = i; + console.log("setname end to ", fnamend); + } + } + + switch(lkb) { + case 1: + console.log("read request"); + break; + case 2: + console.log("write request"); + break; + } + + var fname = msg.toString("utf8", 2, fnamend); + var ftype = msg.toString("utf8", fnamend+1, msg.length-1); + + console.log("fun is, '%s', '%s'", fname, ftype); + + switch(ftype) { + case "netascii": + console.log("was netascii"); + break; + case "octet": + console.log("was octet"); + break; + default: + console.log("errr: '", ftype, "'"); + } +} + +server.bind(41234); \ No newline at end of file -- 1.7.0.4