1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Implementation of the W3C's Raw Socket API.
6 // http://www.w3.org/2012/sysapps/raw-sockets/
8 var v8tools = requireNative('v8tools');
10 var internal = requireNative('internal');
11 internal.setupInternalExtension(extension);
13 var common = requireNative('sysapps_common');
14 common.setupSysAppsCommon(internal, v8tools);
16 // The ReadyStateObserver is a proxy object that will
17 // subscribe to the parent's |readystate| event. An object
18 // cannot subscribe to its own events otherwise it will
19 // leak (because it creates a circular reference).
21 var ReadyStateObserver = function(object_id, initial_state) {
22 common.BindingObject.call(this, object_id);
23 common.EventTarget.call(this);
25 this._addEvent("readystate");
26 this.readyState = initial_state;
29 this.onreadystate = function(event) {
30 that.readyState = event.data;
33 this.destructor = function() {
34 this.onreadystate = null;
38 ReadyStateObserver.prototype = new common.EventTargetPrototype();
40 // TCPSocket interface.
42 // TODO(tmpsantos): We are currently not throwing any exceptions
43 // neither validating the input parameters.
45 // TODO(tmpsantos): TCPOptions argument is being ignored by now.
47 var TCPSocket = function(remoteAddress, remotePort, options, object_id) {
48 common.BindingObject.call(this, object_id ? object_id : common.getUniqueId());
49 common.EventTarget.call(this);
51 if (object_id == undefined)
52 internal.postMessage("TCPSocketConstructor", [this._id]);
54 options = options || {};
56 if (!options.localAddress)
57 options.localAddress = "0.0.0.0";
58 if (!options.localPort)
59 options.localPort = 0;
60 if (!options.addressReuse)
61 options.addressReuse = true;
63 options.noDelay = true;
64 if (!options.useSecureTransport)
65 options.useSecureTransport = false;
67 this._addMethod("_close");
68 this._addMethod("_halfclose");
69 this._addMethod("suspend");
70 this._addMethod("resume");
71 this._addMethod("_sendString");
73 this._addEvent("drain");
74 this._addEvent("open");
75 this._addEvent("close");
76 this._addEvent("error");
77 this._addEvent("data");
79 function sendWrapper(data) {
80 this._sendString(data);
82 // FIXME(tmpsantos): The spec says that send() should always
83 // return if you can keep sending data. This can only be
84 // verified in the native implementation, which makes this
85 // call sync. We are returning always true here to keep the
86 // implementation async.
90 function closeWrapper(data) {
91 if (this._readyStateObserver.readyState == "closed")
94 this._readyStateObserver.readyState = "closing";
98 function halfcloseWrapper(data) {
99 if (this._readyStateObserver.readyState == "closed")
102 this._readyStateObserver.readyState = "halfclosed";
106 Object.defineProperties(this, {
107 "_readyStateObserver": {
108 value: new ReadyStateObserver(
109 this._id, object_id ? "open" : "opening"),
111 "_readyStateObserverDeleter": {
112 value: v8tools.lifecycleTracker(),
123 value: halfcloseWrapper,
127 value: remoteAddress,
135 value: options.localAddress,
139 value: options.localPort,
143 value: options.noDelay,
147 value: options.addressReuse,
155 get: function() { return this._readyStateObserver.readyState; },
160 var watcher = this._readyStateObserver;
161 this._readyStateObserverDeleter.destructor = function() {
162 watcher.destructor();
165 // This is needed, otherwise events like "error" can get fired before
166 // we give the user a chance to register a listener.
167 function delayedInitialization(obj) {
168 obj._postMessage("init", [remoteAddress, remotePort, options]);
171 this._registerLifecycleTracker();
172 setTimeout(delayedInitialization, 0, this);
175 TCPSocket.prototype = new common.EventTargetPrototype();
176 TCPSocket.prototype.constructor = TCPSocket;
178 // TCPServerSocket interface.
180 // TODO(tmpsantos): We are currently not throwing any exceptions
181 // neither validating the input parameters.
183 var TCPServerSocket = function(options) {
184 common.BindingObject.call(this, common.getUniqueId());
185 common.EventTarget.call(this);
187 internal.postMessage("TCPServerSocketConstructor", [this._id]);
189 options = options || {};
191 if (!options.localAddress)
192 options.localAddress = "0.0.0.0";
193 if (!options.localPort)
194 options.localPort = 1234;
195 if (!options.addressReuse)
196 options.addressReuse = true;
197 if (!options.useSecureTransport)
198 options.useSecureTransport = false;
200 this._addMethod("_close");
201 this._addMethod("suspend");
202 this._addMethod("resume");
204 // FIXME(tmpsantos): Get the real remote IP and port
205 // from the native backend.
206 function ConnectEvent(type, data) {
207 var object_id = data[0];
208 var options = data[1];
211 this.connectedSocket = new TCPSocket(
212 options.localAddress, options.localPort, {}, object_id);
215 this._addEvent("open");
216 this._addEvent("connect", ConnectEvent);
217 this._addEvent("error");
218 this._addEvent("connecterror");
220 function closeWrapper(data) {
221 if (this._readyStateObserver.readyState = "closed")
224 this._readyStateObserver.readyState = "closing";
228 Object.defineProperties(this, {
229 "_readyStateObserver": {
230 value: new ReadyStateObserver(this._id, "opening"),
232 "_readyStateObserverDeleter": {
233 value: v8tools.lifecycleTracker(),
240 value: options.localAddress,
244 value: options.localPort,
248 value: options.addressReuse,
252 get: function() { return this._readyStateObserver.readyState; },
257 var watcher = this._readyStateObserver;
258 this._readyStateObserverDeleter.destructor = function() {
259 watcher.destructor();
262 function delayedInitialization(obj) {
263 obj._postMessage("init", [options]);
266 this._registerLifecycleTracker();
267 setTimeout(delayedInitialization, 0, this);
270 TCPServerSocket.prototype = new common.EventTargetPrototype();
271 TCPServerSocket.prototype.constructor = TCPServerSocket;
273 // UDPSocket interface.
275 // TODO(tmpsantos): We are currently not throwing any exceptions
276 // neither validating the input parameters.
278 var UDPSocket = function(options) {
279 common.BindingObject.call(this, common.getUniqueId());
280 common.EventTarget.call(this);
282 internal.postMessage("UDPSocketConstructor", [this._id]);
284 var options = options || {};
286 if (!options.localAddress)
287 options.localAddress = "";
288 if (!options.localPort)
289 options.localPort = 0;
290 if (!options.remoteAddress)
291 options.remoteAddress = "";
292 if (!options.remotePort)
293 options.remotePort = 0;
294 if (!options.addressReuse)
295 options.addressReuse = true;
296 if (!options.loopback)
297 options.loopback = false;
299 this._addMethod("_close");
300 this._addMethod("suspend");
301 this._addMethod("resume");
302 this._addMethod("joinMulticast");
303 this._addMethod("leaveMulticast");
304 this._addMethod("_sendString");
306 function MessageEvent(type, data) {
308 this.data = data.data;
309 this.remotePort = data.remotePort;
310 this.remoteAddress = data.remoteAddress;
313 this._addEvent("open");
314 this._addEvent("drain");
315 this._addEvent("error");
316 this._addEvent("message", MessageEvent);
318 function sendWrapper(data, remoteAddress, remotePort) {
319 this._sendString(data, remoteAddress, remotePort);
321 // FIXME(tmpsantos): The spec says that send() should always
322 // return if you can keep sending data. This can only be
323 // verified in the native implementation, which makes this
324 // call sync. We are returning always true here to keep the
325 // implementation async.
329 function closeWrapper(data) {
330 if (this._readyStateObserver.readyState == "closed")
333 this._readyStateObserver.readyState = "closing";
337 Object.defineProperties(this, {
338 "_readyStateObserver": {
339 value: new ReadyStateObserver(this._id, "opening"),
341 "_readyStateObserverDeleter": {
342 value: v8tools.lifecycleTracker(),
353 value: options.remoteAddress,
357 value: options.remotePort,
361 value: options.localAddress,
365 value: options.localPort,
369 value: options.addressReuse,
373 value: options.loopback,
381 get: function() { return this._readyStateObserver.readyState; },
386 var watcher = this._readyStateObserver;
387 this._readyStateObserverDeleter.destructor = function() {
388 watcher.destructor();
391 // This is needed, otherwise events like "error" can get fired before
392 // we give the user a chance to register a listener.
393 function delayedInitialization(obj) {
394 obj._postMessage("init", [options]);
397 this._registerLifecycleTracker();
398 setTimeout(delayedInitialization, 0, this);
401 UDPSocket.prototype = new common.EventTargetPrototype();
402 UDPSocket.prototype.constructor = UDPSocket;
405 exports.TCPSocket = TCPSocket;
406 exports.TCPServerSocket = TCPServerSocket;
407 exports.UDPSocket = UDPSocket;