125 lines
4.5 KiB
JavaScript
125 lines
4.5 KiB
JavaScript
/* CBDL_netwine - netwine (bi-directional proxy) network library
|
|
|
|
This library is designed to interface with the netwine server - a proxy server that seemlessly connects the networking methods of browser-based JavaScript to a standard TCP bidirectional stream. To understand more of this technology, see http://kettek.exoss.net/netwine/
|
|
|
|
Provided is a single Socket "class" that does its best to emulate a normal bi-direction TCP stream. This is accomplished through one dedicated inbound stream from the server (non-closing socket) and multiple dynamically created outbound push requests to the server.
|
|
|
|
In future versions, netwine may also provide a WebSockets interface for more efficient bandwidth usage and less latency.
|
|
|
|
*/
|
|
|
|
CBDL.netwine = CBDL.netwine || {
|
|
version: 0.1,
|
|
FLAG: {
|
|
SYNC: 0x01 // syncronous socket behavior
|
|
},
|
|
UNOPENED: 0x00,
|
|
PROXY_CONNECTING: 0x01,
|
|
PROXY_CONNECTED: 0x02,
|
|
PROXY_FAILED: 0x03,
|
|
SERVER_CONNECTING: 0x04,
|
|
SERVER_CONNECTED: 0x05,
|
|
SERVER_FAILED: 0x06
|
|
};
|
|
|
|
// TODO: Socket should produce Event(s) in the standard browser method - I hope custom events are possible.
|
|
CBDL.netwine.Socket = function(proxy_address, proxy_port, target_address, target_port, flags) {
|
|
this.proxy_address = proxy_address;
|
|
this.proxy_port = proxy_port;
|
|
this.target_address = target_address;
|
|
this.target_port = target_port;
|
|
|
|
this.key = null;
|
|
|
|
this.flags = flags;
|
|
|
|
this.in_socket = null; // our in socket - outbound is dynamically created
|
|
this.inbound = []; // inbound sockets, uses an array due to socket refresh
|
|
this.outbound = []; // outbound sockets
|
|
|
|
this.is_connected = false;
|
|
this.status = 0;
|
|
this.poll_interval = 50; // poll input every 50 ms
|
|
|
|
this.buffer = ""; // our buffer of bytes received
|
|
this.bytes = 0; // the amount of bytes read thus far
|
|
|
|
//
|
|
};
|
|
|
|
CBDL.netwine.Socket.prototype.Connect = function() {
|
|
// first we open up our INIT request socket and wait for the ack and our new key
|
|
// if successful, we establish INIT socket as our input and poll it for new data according to poll_interval. Due to the input being cached, it may be wise to open a new input connection (live), switch to it, then close the original seemlessly, so as to free memory
|
|
//
|
|
this.status = CBDL.netwine.PROXY_CONNECTING;
|
|
var init_socket = new XMLHttpRequest();
|
|
init_socket.open("INIT", "/"+this.target_address+":"+this.target_port, (this.flags & CBDL.netwine.FLAG.SYNC ? false : true));
|
|
init_socket.onreadystatechange = (function(socket) {return function() {
|
|
switch(this.readyState) {
|
|
case 1: // open
|
|
break;
|
|
case 2: // headers received
|
|
if (this.status == 200) { // we're good!
|
|
console.log(this.status+': '+this.statusText);
|
|
// report connection ok
|
|
socket.key = this.statusText;
|
|
socket.in_socket = this;
|
|
socket.status = CBDL.netwine.PROXY_CONNECTED;
|
|
socket.bytes = this.responseText.length;
|
|
}
|
|
CBDL.fireEvent(socket, "open", {status: this.status});
|
|
break;
|
|
case 3: // loading
|
|
// FIXME: loading triggers even when responseText is not populated with new bytes! :S
|
|
// "read in" the new bytes
|
|
var read = this.responseText.substr(socket.bytes);
|
|
// increment our bytes read
|
|
socket.bytes += read.length;
|
|
// append to the socket's buffer (remove?)
|
|
socket.buffer += read;
|
|
// send off the event to all our listeners out there!
|
|
CBDL.fireEvent(socket, "recv", {data: read, length: read.length});
|
|
break;
|
|
case 4: // done
|
|
CBDL.fireEvent(socket, "close", {});
|
|
break;
|
|
}
|
|
}})(this);
|
|
init_socket.send("");
|
|
return 0;
|
|
};
|
|
|
|
//this function sends the provided data to the netwine server we are connected to.
|
|
CBDL.netwine.Socket.prototype.Send = function(bytes, size) {
|
|
if (this.status != CBDL.netwine.PROXY_CONNECTED) {
|
|
return 1;
|
|
}
|
|
if (!this.key) {
|
|
return 2;
|
|
}
|
|
var socket = new XMLHttpRequest();
|
|
socket.open("PUSH", this.key, (this.flags & CBDL.netwine.FLAG.SYNC ? false : true));
|
|
socket.onreadystatechange = (function(socket) {return function() {
|
|
switch(this.readyState) {
|
|
case 1: // open
|
|
break;
|
|
case 2: // headers received
|
|
if (this.response == 200) { // we're good!
|
|
}
|
|
break;
|
|
case 3: // loading
|
|
break;
|
|
case 4: // done
|
|
break;
|
|
}
|
|
}})(this);
|
|
socket.send(bytes);
|
|
|
|
return 0; // success
|
|
};
|
|
|
|
// this function is called by the parent program to see if any new data has come on.
|
|
CBDL.netwine.Socket.Poll = function() {
|
|
|
|
};
|