diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | chrome/manifest.json | 3 | ||||
-rw-r--r-- | index.js | 38 | ||||
-rw-r--r-- | lib/string.js | 3 | ||||
-rw-r--r-- | socket.js | 119 | ||||
-rw-r--r-- | test/echo/echo.c | 94 |
6 files changed, 162 insertions, 96 deletions
@@ -1,5 +1,6 @@ bundle.js tmp +*.out lib-cov *.seed diff --git a/chrome/manifest.json b/chrome/manifest.json index 40f6e4e..ef5e481 100644 --- a/chrome/manifest.json +++ b/chrome/manifest.json @@ -16,7 +16,8 @@ "socket": [ "tcp-connect:*:*", "tcp-listen::*", - "udp-send-to::*" + "udp-send-to::*", + "udp-bind::*" ] }, "storage", @@ -1,27 +1,31 @@ -var isChromeApp = !!(window.chrome && chrome.app && chrome.app.runtime) +// var isChromeApp = !!(window.chrome && chrome.app && chrome.app.runtime) -if (isChromeApp) { - console.log('This is a Chrome App') -} +// if (isChromeApp) { +// console.log('This is a Chrome App') +// } -var DHT = require('./lib/bittorrent-dht') -var leaves = 'D2474E86C95B19B8BCFDB92BC12C9D44667CFA36' +// var DHT = require('./lib/bittorrent-dht') +// var leaves = 'D2474E86C95B19B8BCFDB92BC12C9D44667CFA36' -var dht = new DHT(leaves) -dht.on('peer', function (peer) { - console.log(peer) -}) -dht.findPeers(300) +// var dht = new DHT(leaves) +// dht.on('peer', function (peer) { +// console.log(peer) +// }) +// dht.findPeers(300) // Send UDP packet to echo server -// var socket = require('./socket') +var string = require('./lib/string') +var socket = require('./socket') -// var sock = new socket.UDPSocket('localhost', 54244) -// sock.connect(function (err) { -// if (err) throw err +var sock = new socket.UDPSocket() +sock.on('bound', function(port) { + console.log('Bound to port: ' + port) +}) -// sock.write('hello') -// }) +sock.on('data', function(data, host, port) { + console.log('Got data from host ' + host + ' port ' + port + ': ' + string.fromUTF8Arr(data)) +}) +sock.sendTo('lol', 'localhost', 50963)
\ No newline at end of file diff --git a/lib/string.js b/lib/string.js index 80b1362..9df92a2 100644 --- a/lib/string.js +++ b/lib/string.js @@ -6,6 +6,9 @@ exports.toUTF8Arr = strToUTF8Arr /* UTF-8 array to DOMString and vice versa */ function UTF8ArrToStr (aBytes) { + if (!aBytes.buffer) { + aBytes = new Uint8Array(aBytes) + } var sView = ""; @@ -5,96 +5,59 @@ var EventEmitter = require('events').EventEmitter var string = require('./lib/string') var util = require('util') -util.inherits(BaseSocket, EventEmitter) +util.inherits(UDPSocket, EventEmitter) -function BaseSocket (host, port) { +function UDPSocket () { var self = this - self.host = host - self.port = port - - self.paused = true - self.readPending = false + if (!(self instanceof UDPSocket)) return new UDPSocket() EventEmitter.call(self) -} - -BaseSocket.prototype.connect = function (cb) { - var self = this - self._create(function (err, id) { - if (err) return cb(err) - self.id = id - chrome.socket.connect(self.id, self.host, self.port, function (res) { - if (res === 0) cb(null) - else cb(new Error('Unexpected connect result:' + res)) - }) - }) -} -BaseSocket.prototype.end = function () { - var self = this - if (!self.id) return - chrome.socket.destroy(self.id) - self.id = null // mark socket as destroyed -} - -BaseSocket.prototype.getInfo = function (cb) { - var self = this - chrome.socket.getInfo(self.id, cb) -} - -BaseSocket.prototype.pause = function () { - var self = this - self.paused = true -} + self.sendBuffer = [] + self.localPort = 0 + self.bound = false -BaseSocket.prototype.resume = function () { - var self = this - self.paused = false - self.read() -} + chrome.socket.create('udp', {}, function (createInfo) { + self.id = createInfo.socketId -BaseSocket.prototype.read = function (readLength) { - var self = self - if (self.paused || self.readPending) return - self.readPending = true - - chrome.socket.read(self.id, readLength, function (readInfo) { - self.readPending = false - if (readInfo.resultCode < 0) return self.end() - - if (readInfo.data) { - self.emit('data', readInfo.data) - try { - // only read if not closed - if (self.id) self.read() - } catch (e) { - self.emit('error', e.stack || e.message || e) - self.end() + chrome.socket.bind(self.id, '0.0.0.0', 0, function (result) { + if (result < 0) { + console.warn('UDPSocket ' + self.id + ' failed to bind') + return } - } + chrome.socket.getInfo(self.id, function (result) { + if (!result.localPort) { + console.warn('Cannot get local port for UDPSocket ' + self.id) + return + } + self.localPort = result.localPort + self._onBound() + }) + }) }) } - -util.inherits(UDPSocket, BaseSocket) - -function UDPSocket (host, port) { +UDPSocket.prototype._onBound = function () { var self = this - if (!(self instanceof UDPSocket)) return new UDPSocket(host, port) - BaseSocket.call(self, host, port) -} + self.bound = true + self.emit('bound', self.localPort) + while (self.sendBuffer.length) { + var message = self.sendBuffer.shift() + self.sendTo(message.data, message.host, message.port, message.cb) + } -UDPSocket.prototype._create = function (cb) { - var self = this - chrome.socket.create('udp', {}, function (createInfo) { - cb(null, createInfo.socketId) - }) + self._recvLoop() } -UDPSocket.prototype.write = function (data) { +UDPSocket.prototype.sendTo = function (data, host, port, cb) { var self = this - if (!self.id) return + + cb = cb || function() {} + if (!self.bound) { + self.sendBuffer.push({'data': data, 'host': host, 'port': port, 'cb': cb}); + return + } if (typeof data === 'string') { data = string.toUTF8Arr(data).buffer @@ -102,24 +65,24 @@ UDPSocket.prototype.write = function (data) { data = data.buffer } - chrome.socket.write(self.id, data, function (writeInfo) { + chrome.socket.sendTo(self.id, data, host, port, function (writeInfo) { if (writeInfo.bytesWritten < 0) { console.warn('UDPSocket ' + self.id + ' write: ' + writeInfo.bytesWritten) - return self.end() } + cb() }) } -UDPSocket.prototype.recvLoop = function() { +UDPSocket.prototype._recvLoop = function() { var self = this chrome.socket.recvFrom(self.id, function (recvFromInfo) { if (recvFromInfo.resultCode > 0) { self.emit('data', recvFromInfo.data, recvFromInfo.address, recvFromInfo.port) - self.recvLoop() + self._recvLoop() } else { console.warn('UDPSocket ' + self.id + ' recvFrom: ', recvFromInfo) } }) -} +}
\ No newline at end of file diff --git a/test/echo/echo.c b/test/echo/echo.c new file mode 100644 index 0000000..693a07d --- /dev/null +++ b/test/echo/echo.c @@ -0,0 +1,94 @@ +/* UDP echo server program -- echo-server-udp.c */ + +#include <stdio.h> /* standard C i/o facilities */ +#include <stdlib.h> /* needed for atoi() */ +#include <unistd.h> /* defines STDIN_FILENO, system calls,etc */ +#include <sys/types.h> /* system data type definitions */ +#include <sys/socket.h> /* socket specific definitions */ +#include <netinet/in.h> /* INET constants and stuff */ +#include <arpa/inet.h> /* IP address conversion stuff */ +#include <netdb.h> /* gethostbyname */ + + + +/* this routine echos any messages (UDP datagrams) received */ + +#define MAXBUF 1024*1024 + +void echo( int sd ) { + int len,n; + char bufin[MAXBUF]; + struct sockaddr_in remote; + + /* need to know how big address struct is, len must be set before the + call to recvfrom!!! */ + + len = sizeof(remote); + + while (1) { + /* read a datagram from the socket (put result in bufin) */ + n=recvfrom(sd,bufin,MAXBUF,0,(struct sockaddr *)&remote,&len); + + /* print out the address of the sender */ + printf("Got a datagram from %s port %d\n", + inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); + + if (n<0) { + perror("Error receiving data"); + } else { + printf("GOT %d BYTES\n",n); + /* Got something, just send it back */ + sendto(sd,bufin,n,0,(struct sockaddr *)&remote,len); + } + } +} + +/* server main routine */ + +int main() { + int ld; + struct sockaddr_in skaddr; + int length; + + /* create a socket + IP protocol family (PF_INET) + UDP protocol (SOCK_DGRAM) + */ + + if ((ld = socket( PF_INET, SOCK_DGRAM, 0 )) < 0) { + printf("Problem creating socket\n"); + exit(1); + } + + /* establish our address + address family is AF_INET + our IP address is INADDR_ANY (any of our IP addresses) + the port number is assigned by the kernel + */ + + skaddr.sin_family = AF_INET; + skaddr.sin_addr.s_addr = htonl(INADDR_ANY); + skaddr.sin_port = htons(0); + + if (bind(ld, (struct sockaddr *) &skaddr, sizeof(skaddr))<0) { + printf("Problem binding\n"); + exit(0); + } + + /* find out what port we were assigned and print it out */ + + length = sizeof( skaddr ); + if (getsockname(ld, (struct sockaddr *) &skaddr, &length)<0) { + printf("Error getsockname\n"); + exit(1); + } + + /* port number's are network byte order, we have to convert to + host byte order before printing ! + */ + printf("The server UDP port number is %d\n",ntohs(skaddr.sin_port)); + + /* Go echo every datagram we get */ + echo(ld); + return(0); +} |