Upstream version 6.34.113.0
[platform/framework/web/crosswalk.git] / src / xwalk / sysapps / raw_socket / raw_socket_api.js
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.
4
5 // Implementation of the W3C's Raw Socket API.
6 // http://www.w3.org/2012/sysapps/raw-sockets/
7
8 var v8tools = requireNative('v8tools');
9
10 var internal = requireNative('internal');
11 internal.setupInternalExtension(extension);
12
13 var common = requireNative('sysapps_common');
14 common.setupSysAppsCommon(internal, v8tools);
15
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).
20 //
21 var ReadyStateObserver = function(object_id, initial_state) {
22   common.BindingObject.call(this, object_id);
23   common.EventTarget.call(this);
24
25   this._addEvent("readystate");
26   this.readyState = initial_state;
27
28   var that = this;
29   this.onreadystate = function(event) {
30     that.readyState = event.data;
31   };
32
33   this.destructor = function() {
34     this.onreadystate = null;
35   };
36 };
37
38 ReadyStateObserver.prototype = new common.EventTargetPrototype();
39
40 // TCPSocket interface.
41 //
42 // TODO(tmpsantos): We are currently not throwing any exceptions
43 // neither validating the input parameters.
44 //
45 // TODO(tmpsantos): TCPOptions argument is being ignored by now.
46 //
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);
50
51   if (object_id == undefined)
52     internal.postMessage("TCPSocketConstructor", [this._id]);
53
54   options = options || {};
55
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;
62   if (!options.noDelay)
63     options.noDelay = true;
64   if (!options.useSecureTransport)
65     options.useSecureTransport = false;
66
67   this._addMethod("_close");
68   this._addMethod("_halfclose");
69   this._addMethod("suspend");
70   this._addMethod("resume");
71   this._addMethod("_sendString");
72
73   this._addEvent("drain");
74   this._addEvent("open");
75   this._addEvent("close");
76   this._addEvent("error");
77   this._addEvent("data");
78
79   function sendWrapper(data) {
80     this._sendString(data);
81
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.
87     return true;
88   };
89
90   function closeWrapper(data) {
91     if (this._readyStateObserver.readyState == "closed")
92       return;
93
94     this._readyStateObserver.readyState = "closing";
95     this._close();
96   };
97
98   function halfcloseWrapper(data) {
99     if (this._readyStateObserver.readyState == "closed")
100       return;
101
102     this._readyStateObserver.readyState = "halfclosed";
103     this._halfclose();
104   };
105
106   Object.defineProperties(this, {
107     "_readyStateObserver": {
108       value: new ReadyStateObserver(
109           this._id, object_id ? "open" : "opening"),
110     },
111     "_readyStateObserverDeleter": {
112       value: v8tools.lifecycleTracker(),
113     },
114     "send": {
115       value: sendWrapper,
116       enumerable: true,
117     },
118     "close": {
119       value: closeWrapper,
120       enumerable: true,
121     },
122     "halfclose": {
123       value: halfcloseWrapper,
124       enumerable: true,
125     },
126     "remoteAddress": {
127       value: remoteAddress,
128       enumerable: true,
129     },
130     "remotePort": {
131       value: remotePort,
132       enumerable: true,
133     },
134     "localAddress": {
135       value: options.localAddress,
136       enumerable: true,
137     },
138     "localPort": {
139       value: options.localPort,
140       enumerable: true,
141     },
142     "noDelay": {
143       value: options.noDelay,
144       enumerable: true,
145     },
146     "addressReuse": {
147       value: options.addressReuse,
148       enumerable: true,
149     },
150     "bufferedAmount": {
151       value: 0,
152       enumerable: true,
153     },
154     "readyState": {
155       get: function() { return this._readyStateObserver.readyState; },
156       enumerable: true,
157     },
158   });
159
160   var watcher = this._readyStateObserver;
161   this._readyStateObserverDeleter.destructor = function() {
162     watcher.destructor();
163   };
164
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]);
169   };
170
171   this._registerLifecycleTracker();
172   setTimeout(delayedInitialization, 0, this);
173 };
174
175 TCPSocket.prototype = new common.EventTargetPrototype();
176 TCPSocket.prototype.constructor = TCPSocket;
177
178 // TCPServerSocket interface.
179 //
180 // TODO(tmpsantos): We are currently not throwing any exceptions
181 // neither validating the input parameters.
182 //
183 var TCPServerSocket = function(options) {
184   common.BindingObject.call(this, common.getUniqueId());
185   common.EventTarget.call(this);
186
187   internal.postMessage("TCPServerSocketConstructor", [this._id]);
188
189   options = options || {};
190
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;
199
200   this._addMethod("_close");
201   this._addMethod("suspend");
202   this._addMethod("resume");
203
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];
209
210     this.type = type;
211     this.connectedSocket = new TCPSocket(
212         options.localAddress, options.localPort, {}, object_id);
213   }
214
215   this._addEvent("open");
216   this._addEvent("connect", ConnectEvent);
217   this._addEvent("error");
218   this._addEvent("connecterror");
219
220   function closeWrapper(data) {
221     if (this._readyStateObserver.readyState = "closed")
222       return;
223
224     this._readyStateObserver.readyState = "closing";
225     this._close();
226   };
227
228   Object.defineProperties(this, {
229     "_readyStateObserver": {
230       value: new ReadyStateObserver(this._id, "opening"),
231     },
232     "_readyStateObserverDeleter": {
233       value: v8tools.lifecycleTracker(),
234     },
235     "close": {
236       value: closeWrapper,
237       enumerable: true,
238     },
239     "localAddress": {
240       value: options.localAddress,
241       enumerable: true,
242     },
243     "localPort": {
244       value: options.localPort,
245       enumerable: true,
246     },
247     "addressReuse": {
248       value: options.addressReuse,
249       enumerable: true,
250     },
251     "readyState": {
252       get: function() { return this._readyStateObserver.readyState; },
253       enumerable: true,
254     },
255   });
256
257   var watcher = this._readyStateObserver;
258   this._readyStateObserverDeleter.destructor = function() {
259     watcher.destructor();
260   };
261
262   function delayedInitialization(obj) {
263     obj._postMessage("init", [options]);
264   };
265
266   this._registerLifecycleTracker();
267   setTimeout(delayedInitialization, 0, this);
268 };
269
270 TCPServerSocket.prototype = new common.EventTargetPrototype();
271 TCPServerSocket.prototype.constructor = TCPServerSocket;
272
273 // UDPSocket interface.
274 //
275 // TODO(tmpsantos): We are currently not throwing any exceptions
276 // neither validating the input parameters.
277 //
278 var UDPSocket = function(options) {
279   common.BindingObject.call(this, common.getUniqueId());
280   common.EventTarget.call(this);
281
282   internal.postMessage("UDPSocketConstructor", [this._id]);
283
284   var options = options || {};
285
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;
298
299   this._addMethod("_close");
300   this._addMethod("suspend");
301   this._addMethod("resume");
302   this._addMethod("joinMulticast");
303   this._addMethod("leaveMulticast");
304   this._addMethod("_sendString");
305
306   function MessageEvent(type, data) {
307     this.type = type;
308     this.data = data.data;
309     this.remotePort = data.remotePort;
310     this.remoteAddress = data.remoteAddress;
311   }
312
313   this._addEvent("open");
314   this._addEvent("drain");
315   this._addEvent("error");
316   this._addEvent("message", MessageEvent);
317
318   function sendWrapper(data, remoteAddress, remotePort) {
319     this._sendString(data, remoteAddress, remotePort);
320
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.
326     return true;
327   };
328
329   function closeWrapper(data) {
330     if (this._readyStateObserver.readyState == "closed")
331       return;
332
333     this._readyStateObserver.readyState = "closing";
334     this._close();
335   };
336
337   Object.defineProperties(this, {
338     "_readyStateObserver": {
339       value: new ReadyStateObserver(this._id, "opening"),
340     },
341     "_readyStateObserverDeleter": {
342       value: v8tools.lifecycleTracker(),
343     },
344     "send": {
345       value: sendWrapper,
346       enumerable: true,
347     },
348     "close": {
349       value: closeWrapper,
350       enumerable: true,
351     },
352     "remoteAddress": {
353       value: options.remoteAddress,
354       enumerable: true,
355     },
356     "remotePort": {
357       value: options.remotePort,
358       enumerable: true,
359     },
360     "localAddress": {
361       value: options.localAddress,
362       enumerable: true,
363     },
364     "localPort": {
365       value: options.localPort,
366       enumerable: true,
367     },
368     "addressReuse": {
369       value: options.addressReuse,
370       enumerable: true,
371     },
372     "loopback": {
373       value: options.loopback,
374       enumerable: true,
375     },
376     "bufferedAmount": {
377       value: 0,
378       enumerable: true,
379     },
380     "readyState": {
381       get: function() { return this._readyStateObserver.readyState; },
382       enumerable: true,
383     },
384   });
385
386   var watcher = this._readyStateObserver;
387   this._readyStateObserverDeleter.destructor = function() {
388     watcher.destructor();
389   };
390
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]);
395   };
396
397   this._registerLifecycleTracker();
398   setTimeout(delayedInitialization, 0, this);
399 };
400
401 UDPSocket.prototype = new common.EventTargetPrototype();
402 UDPSocket.prototype.constructor = UDPSocket;
403
404 // Exported API.
405 exports.TCPSocket = TCPSocket;
406 exports.TCPServerSocket = TCPServerSocket;
407 exports.UDPSocket = UDPSocket;