///
///
///
///
///
///
///
///
///
///
///
module Pipe {
var log :Freedom_UproxyLogging.Log = freedom['core.log']('pipe');
/**
* Listens on a port for UDP datagrams -- emitting a Freedom message for each
* datagram received -- and sends UDP datagrams to a destination, in response
* to Freedom messages.
*
* Each incoming and outgoing message is first passed through an obfuscator.
* The obfuscator is used via direct function calls rather than Freedom
* message passing owing to the inelegance of receiving a response *back*
* from a Freedom module.
*/
export class Server {
// Socket on which the server is listening.
private socket_ :freedom_UdpSocket.Socket;
// Obfuscates and deobfuscates messages.
private transformer_ :UTransformers.Transformer;
// Endpoint to which all messages are sent.
private remoteAddress_ :string;
private remotePort_ :number;
// TODO: define a type for event dispatcher in freedom-typescript-api
constructor (private dispatchEvent_ ?:(name:string, args:any) => void) {
this.socket_ = freedom['core.udpsocket']();
}
/**
* Returns a promise to create a socket, bind to the specified address, and
* start listening for datagrams.
*/
public bind = (
localAddress :string,
localPort :number,
remoteAddress :string,
remotePort :number,
transformerName :string,
key ?:ArrayBuffer,
config ?:string)
:Promise => {
// First, try to make our transformer.
try {
this.transformer_ = this.makeTransformer_(transformerName, key, config);
} catch (e) {
return Promise.reject(e);
}
// Next, bind to a socket.
this.remoteAddress_ = remoteAddress;
this.remotePort_ = remotePort;
return this.socket_.bind(localAddress, localPort)
.then((resultCode:number) => {
if (resultCode != 0) {
return Promise.reject(new Error(
'listen failed with result code ' + resultCode));
}
this.socket_.on('onData', this.onData_);
});
}
private makeTransformer_ = (
// Name of transformer to use, e.g. 'rabbit' or 'none'.
name :string,
// Key for transformer, if any.
key ?:ArrayBuffer,
// JSON-encoded configuration, if any.
config ?:string)
:UTransformers.Transformer => {
var transformer :UTransformers.Transformer;
if (name == 'rabbit') {
transformer = new rabbit.Transformer();
} else if (name == 'fte') {
transformer = new fte.Transformer();
} else if (name == 'caesar') {
transformer = new Transformers.CaesarCipher();
} else if (name == 'none') {
transformer = new Transformers.PassThrough();
} else {
throw new Error('unknown transformer: ' + name);
}
if (key) {
transformer.setKey(key);
}
if (config) {
transformer.configure(config);
}
return transformer;
}
/**
* Sends a message over the network to the remote side.
* The message is obfuscated before it hits the wire.
*/
public send = (buffer:ArrayBuffer) => {
var transformedBuffer = this.transformer_.transform(buffer);
return this.socket_.sendTo(
transformedBuffer,
this.remoteAddress_,
this.remotePort_).then(() => {
return Promise.resolve();
});
}
public getLocalEndpoint = () : Promise => {
return this.socket_.getInfo().then((socketInfo:freedom_UdpSocket.SocketInfo) => {
return {
address: socketInfo.localAddress,
port: socketInfo.localPort
}
});
}
/**
* Called when a message is received over the network from the remote side.
* The message is de-obfuscated before the Freedom message is emitted.
*/
private onData_ = (recvFromInfo:freedom_UdpSocket.RecvFromInfo) => {
var transformedBuffer = recvFromInfo.data;
var buffer = this.transformer_.restore(transformedBuffer);
this.dispatchEvent_('message', {
data: buffer
});
}
}
if (typeof freedom !== 'undefined') {
freedom.pipe().providePromises(Pipe.Server);
}
}