diff --git a/exec/ax25tunnel.js b/exec/ax25tunnel.js index 7c2b015dbb7085b7413294a300fc8302a5a70897..a634c113d13997d1d54c714687d7983619920538 100644 --- a/exec/ax25tunnel.js +++ b/exec/ax25tunnel.js @@ -1,90 +1,165 @@ -/* ax25tunnel.js - echicken -at- bbs.electronicchicken.com (VE3XEC) +// ax25tunnel.js +// VE3XEC (echicken -at- bbs.electronicchicken.com) +// Work-in-progress AX.25 unproto <-> Synchronet RLogin server tunnel - This script is responsible for handling connections from AX.25 clients - and then tunneling traffic between them and the packet-bbs.js service - that you'll also need to run. It should be replaced by something that - creates an rlogin session for each connecting client and translates - output from the Synchronet terminal server for transmission to AX.25 - clients. I don't feel like writing an rlogin client in JS right now, - so this is what you get. +load("sbbsdefs.js"); +load("sockdefs.js"); +load("kissAX25lib.js"); + +/* This could be made into more of a proper RLogin client, but for now it's + just the bare minimum required for the purposes of this script. */ +var RLogin = function(host, port, username, password, terminal) { + + var settings = { + 'timeout' : 30, + 'receiveBuffer' : 255 + }; - Prior to running this script, you'll need to edit ctrl/kiss.ini in order - to configure your TNC(s). You'll also need to add packet-bbs.js to your - ctrl/services.ini file (see the comments at the top of packet-bbs.js for - details.) Once this is done, run this script via jsexec like so: + var socket = new Socket(); - jsexec -l ax25tunnel.js tnc1 tnc2 tnc3 etc... + this.__defineGetter__( + "connected", + function() { + return socket.is_connected; + } + ); - Where tnc1, tnc2, tnc3 are the names of sections from your ctrl/kiss.ini - file. */ + this.__defineGetter__( + "dataWaiting", + function() { + return socket.data_waiting; + } + ); -load("sbbsdefs.js"); -load("kissAX25lib.js"); -load("event-timer.js"); + this.connect = function() { + socket.connect(host, port); + socket.sendBin(0, 1); + socket.send(username); + socket.sendBin(0, 1); + socket.send(password); + socket.sendBin(0, 1); + socket.send(terminal); + socket.sendBin(0, 1); + var sTime = time(); + while(time() - sTime < settings.timeout) { + if(socket.poll(.1)) + break; + } + if(socket.recvBin(1) != 0) + return false; + return true; + } + + this.disconnect = function() { + socket.close(); + } + + this.receive = function() { + if(!socket.is_connected || !socket.data_waiting) + return false; + var r = socket.recv(settings.receiveBuffer); + r = r.split(""); + switch(r[0]) { + case 80: + r.shift(); + break; + case 10: + r.shift(); + break; + case 20: + r.shift(); + break; + case 02: + r.shift(); + break; + default: + break; + } + return (r.length > 0) ? r.join("") : ""; + } + + this.send = function(str) { + if(!socket.is_connected || !socket.is_writeable) + return false; + socket.write(str); + } -var timer = new Timer(); -var kissTNCs = []; -for(var k = 0; k < argc; k++) { - kissTNCs.push(loadKISSInterface(argv[k])); } -var kissFrame; -var sockRet = ""; -var ax25Clients = new Object(); -var f = new File(system.ctrl_dir + "services.ini"); -f.open("r"); -var i = f.iniGetObject("Packet-BBS"); -f.close(); - -function beaconAllTNCs() { - for(var k = 0; k < kissTNCs.length; k++) { - kissTNCs[k].beacon(); - } -} -timer.addEvent(600000, true, beaconAllTNCs); -beaconAllTNCs(); +AX25.logging = true; +var tnc = AX25.loadAllTNCs(); +var tunnels = {}; while(!js.terminated) { - // Check for frames waiting on any KISS interface - for(var k = 0; k < kissTNCs.length; k++) { - kissFrame = kissTNCs[k].getKISSFrame(); - if(!kissFrame) + + for(var tnc in AX25.tncs) { + AX25.tncs[tnc].cycle(); + while(AX25.tncs[tnc].dataWaiting) { + var packet = AX25.tncs[tnc].receive(); + if( + packet.destinationCallsign != AX25.tncs[tnc].callsign + || + packet.destinationSSID != AX25.tncs[tnc].ssid + ) { + continue; + } + if(!AX25.clients.hasOwnProperty(packet.clientID)) { + var a = new AX25.Client(AX25.tncs[tnc], packet); + var usernumber = system.matchuserdata(U_HANDLE, packet.sourceCallsign); + if(usernumber < 1) { + // Get Deuce's WD1CKS newuser creation thing to better + // populate user data here. + var u = system.new_user(packet.sourceCallsign); + u.alias = packet.sourceCallsign; + u.name = packet.sourceCallsign; + u.handle = packet.sourceCallsign; + u.security.password = time(); // Do something better here + } else { + var u = new User(usernumber); + } + var username = u.alias; + var password = u.security.password; + tunnels[packet.clientID] = new RLogin( + system.inet_addr, + 513, + username, + password, + "dumb/9600" + ); + tunnels[packet.clientID].connect(); + } else { + AX25.clients[packet.clientID].receivePacket(packet); + } + } + } + + for(var c in AX25.clients) { + AX25.clients[c].cycle(); + if(!AX25.clients[c].connected) { + if(tunnels.hasOwnProperty(AX25.clients[c].id)) { + tunnels[AX25.clients[c].id].disconnect(); + delete tunnels[AX25.clients[c].id]; + } + delete AX25.clients[c]; continue; - var p = new ax25packet(); - p.disassemble(kissFrame); - if(p.destination != kissTNCs[k].callsign || p.destinationSSID != kissTNCs[k].ssid) + } + if( + !tunnels.hasOwnProperty(AX25.clients[c].id) + || + !tunnels[AX25.clients[c].id].connected + ) { + AX25.clients[c].disconnect(); continue; - if(!ax25Clients.hasOwnProperty(p.clientID)) { - ax25Clients[p.clientID] = new ax25Client(p.destination, p.destinationSSID, p.source, p.sourceSSID, kissTNCs[k]); - ax25Clients[p.clientID].sock = new Socket(); - ax25Clients[p.clientID].sock.connect("localhost", i.Port); - ax25Clients[p.clientID].sock.send(ax25Clients[p.clientID].callsign + "\r\n"); - ax25Clients[p.clientID].sock.send(ax25Clients[p.clientID].ssid + "\r\n"); - ax25Clients[p.clientID].sock.send(ax25Clients[p.clientID].kissTNC.callsign + "\r\n"); - ax25Clients[p.clientID].sock.send(ax25Clients[p.clientID].kissTNC.ssid + "\r\n"); } - sockRet = byteArrayToString(ax25Clients[p.clientID].receive(p)); - if(sockRet) - ax25Clients[p.clientID].sock.send(sockRet + "\r\n"); - if(!ax25Clients[p.clientID].connected) { - ax25Clients[p.clientID].sock.close(); - delete(ax25Clients[p.clientID]); + if(tunnels[AX25.clients[c].id].dataWaiting) { + var fromTunnel = tunnels[AX25.clients[c].id].receive(); + AX25.clients[c].sendString(fromTunnel); } - } - // Check for data waiting on any sockets - for(var c in ax25Clients) { - if(ax25Clients[c].wait) - continue; - if(ax25Clients[c].sock.data_waiting && ax25Clients[c].nr == ax25Clients[c].ssv && !ax25Clients[c].reject) { - var sendMe = ax25Clients[c].sock.recvfrom(false, 256).data; - sendMe = stringToByteArray(sendMe); - ax25Clients[c].send(sendMe); - } else if(!ax25Clients[c].sock.is_connected) { - ax25Clients[c].disconnect(); - log(LOG_INFO, ax25Clients[c].callsign + "-" + ax25Clients[c].ssid + " has disconnected from " + ax25Clients[c].kissTNC.name + ", " + ax25Clients[c].kissTNC.callsign + "-" + ax25Clients[c].kissTNC.ssid); - delete(ax25Clients[p.clientID]); + if(AX25.clients[c].dataWaiting) { + var fromClient = AX25.clients[c].receiveString(); + tunnels[AX25.clients[c].id].send(fromClient); } } - timer.cycle(); -} + + mswait(5); +} \ No newline at end of file