Chromium Code Reviews| Index: remoting/webapp/crd/js/xmpp_connection.js |
| diff --git a/remoting/webapp/crd/js/xmpp_connection.js b/remoting/webapp/crd/js/xmpp_connection.js |
| index 6f56f58da8474a8a22dff9ec89d69a5831c3d3c3..e81b53c2f7025bd85596c5b1c722ea01c03e3d26 100644 |
| --- a/remoting/webapp/crd/js/xmpp_connection.js |
| +++ b/remoting/webapp/crd/js/xmpp_connection.js |
| @@ -10,6 +10,11 @@ var remoting = remoting || {}; |
| /** |
| * A connection to an XMPP server. |
| * |
| + * TODO(sergeyu): Chrome provides two APIs for TCP sockets: chrome.socket and |
| + * chrome.sockets.tcp . chrome.socket is deprecated but it's still used here |
| + * because TLS support in chrome.sockets.tcp is currently broken, see |
| + * crbug.com/403076 . |
| + * |
| * @constructor |
| * @implements {remoting.SignalStrategy} |
| */ |
| @@ -22,11 +27,13 @@ remoting.XmppConnection = function() { |
| this.onStateChangedCallback_ = null; |
| /** @private {?function(Element):void} */ |
| this.onIncomingStanzaCallback_ = null; |
| - /** @type {?remoting.TcpSocket} @private */ |
| - this.socket_ = null; |
| + /** @private */ |
| + this.socketId_ = -1; |
| /** @private */ |
| this.state_ = remoting.SignalStrategy.State.NOT_CONNECTED; |
| /** @private */ |
| + this.readPending_ = false; |
| + /** @private */ |
| this.sendPending_ = false; |
| /** @private */ |
| this.startTlsPending_ = false; |
| @@ -39,7 +46,7 @@ remoting.XmppConnection = function() { |
| /** @private */ |
| this.jid_ = ''; |
| /** @private */ |
| - this.error_ = remoting.Error.NONE; |
| + this.error_ = remoting.Error.none(); |
| }; |
| /** |
| @@ -50,11 +57,6 @@ remoting.XmppConnection.prototype.setStateChangedCallback = function( |
| this.onStateChangedCallback_ = onStateChangedCallback; |
| }; |
| -remoting.XmppConnection.prototype.setSocketForTests = function( |
| - /** remoting.TcpSocket */ socket) { |
| - this.socket_ = socket; |
| -}; |
| - |
| /** |
| * @param {?function(Element):void} onIncomingStanzaCallback Callback to call on |
| * incoming messages. |
| @@ -74,7 +76,7 @@ remoting.XmppConnection.prototype.connect = |
| base.debug.assert(this.state_ == remoting.SignalStrategy.State.NOT_CONNECTED); |
| base.debug.assert(this.onStateChangedCallback_ != null); |
| - this.error_ = remoting.Error.NONE; |
| + this.error_ = remoting.Error.none(); |
| var hostnameAndPort = server.split(':', 2); |
| this.server_ = hostnameAndPort[0]; |
| this.port_ = |
| @@ -102,18 +104,8 @@ remoting.XmppConnection.prototype.connect = |
| xmppServer, username, authToken, needHandshakeBeforeTls, |
| this.sendString_.bind(this), this.startTls_.bind(this), |
| this.onHandshakeDone_.bind(this), this.onError_.bind(this)); |
| + chrome.socket.create("tcp", {}, this.onSocketCreated_.bind(this)); |
| this.setState_(remoting.SignalStrategy.State.CONNECTING); |
| - |
| - if (!this.socket_) { |
| - this.socket_ = new remoting.TcpSocket(); |
| - } |
| - var that = this; |
| - this.socket_.connect(this.server_, this.port_) |
| - .then(this.onSocketConnected_.bind(this)) |
| - .catch(function(error) { |
| - that.onError_(remoting.Error.NETWORK_FAILURE, |
| - 'Failed to connect to ' + that.server_ + ': ' + error); |
| - }); |
| }; |
| /** @param {string} message */ |
| @@ -151,13 +143,15 @@ remoting.XmppConnection.prototype.getType = function() { |
| }; |
| remoting.XmppConnection.prototype.dispose = function() { |
| - base.dispose(this.socket_); |
| - this.socket_ = null; |
| + this.closeSocket_(); |
| this.setState_(remoting.SignalStrategy.State.CLOSED); |
| }; |
| -/** @private */ |
| -remoting.XmppConnection.prototype.onSocketConnected_ = function() { |
| +/** |
| + * @param {chrome.socket.CreateInfo} createInfo |
| + * @private |
| + */ |
| +remoting.XmppConnection.prototype.onSocketCreated_ = function(createInfo) { |
| // Check if connection was destroyed. |
| if (this.state_ != remoting.SignalStrategy.State.CONNECTING) { |
| return; |
| @@ -167,33 +161,31 @@ remoting.XmppConnection.prototype.onSocketConnected_ = function() { |
| this.loginHandler_.start(); |
| if (!this.startTlsPending_) { |
| - this.socket_.startReceiving(this.onReceive_.bind(this), |
| - this.onReceiveError_.bind(this)); |
| + this.tryRead_(); |
| } |
| }; |
| /** |
| - * @param {ArrayBuffer} data |
| * @private |
| */ |
| -remoting.XmppConnection.prototype.onReceive_ = function(data) { |
| +remoting.XmppConnection.prototype.tryRead_ = function() { |
| + base.debug.assert(!this.readPending_); |
| base.debug.assert(this.state_ == remoting.SignalStrategy.State.HANDSHAKE || |
| this.state_ == remoting.SignalStrategy.State.CONNECTED); |
| + base.debug.assert(!this.startTlsPending_); |
| - if (this.state_ == remoting.SignalStrategy.State.HANDSHAKE) { |
| - this.loginHandler_.onDataReceived(data); |
| - } else if (this.state_ == remoting.SignalStrategy.State.CONNECTED) { |
| - this.streamParser_.appendData(data); |
| - } |
| + this.readPending_ = true; |
| + chrome.socket.read(this.socketId_, this.onRead_.bind(this)); |
| }; |
| /** |
| - * @param {number} errorCode |
| + * @param {chrome.socket.ReadInfo} readInfo |
| * @private |
| */ |
| remoting.XmppConnection.prototype.onReceiveError_ = function(errorCode) { |
| - this.onError_(remoting.Error.NETWORK_FAILURE, |
| - 'Failed to receive from XMPP socket: ' + errorCode); |
| + this.onError_( |
| + new remoting.Error(remoting.Error.Tag.NETWORK_FAILURE), |
| + 'Failed to receive from XMPP socket: ' + errorCode); |
| }; |
| /** |
| @@ -221,40 +213,39 @@ remoting.XmppConnection.prototype.flushSendQueue_ = function() { |
| return; |
| } |
| - var that = this; |
| - |
| + var data = this.sendQueue_[0] |
| this.sendPending_ = true; |
| - this.socket_.send(this.sendQueue_[0]) |
| - .then(function(/** number */ bytesSent) { |
| - that.sendPending_ = false; |
| - that.onSent_(bytesSent); |
| - }) |
| - .catch(function(/** number */ error) { |
| - that.sendPending_ = false; |
| - that.onError_(remoting.Error.NETWORK_FAILURE, |
| - 'TCP write failed with error ' + error); |
| - }); |
| + chrome.socket.write(this.socketId_, data, this.onWrite_.bind(this)); |
| }; |
| /** |
| - * @param {number} bytesSent |
| + * @param {chrome.socket.WriteInfo} writeInfo |
| * @private |
| */ |
| -remoting.XmppConnection.prototype.onSent_ = function(bytesSent) { |
| - // Ignore send() result if the socket was closed. |
| +remoting.XmppConnection.prototype.onWrite_ = function(writeInfo) { |
| + base.debug.assert(this.sendPending_); |
| + this.sendPending_ = false; |
| + |
| + // Ignore write() result if the socket was closed. |
| if (this.state_ != remoting.SignalStrategy.State.HANDSHAKE && |
| this.state_ != remoting.SignalStrategy.State.CONNECTED) { |
| return; |
| } |
| + if (writeInfo.bytesWritten < 0) { |
| + this.onError_(remoting.Error.NETWORK_FAILURE, |
|
Jamie
2015/03/12 21:40:11
The change (and the next) looks like it's going in
John Williams
2015/03/13 00:26:35
Ugh. Long story. But you are correct.
|
| + 'TCP write failed with error ' + writeInfo.bytesWritten); |
| + return; |
| + } |
| + |
| base.debug.assert(this.sendQueue_.length > 0); |
| - var data = this.sendQueue_[0]; |
| - base.debug.assert(bytesSent <= data.byteLength); |
| - if (bytesSent == data.byteLength) { |
| + var data = this.sendQueue_[0] |
| + base.debug.assert(writeInfo.bytesWritten <= data.byteLength); |
| + if (writeInfo.bytesWritten == data.byteLength) { |
| this.sendQueue_.shift(); |
| } else { |
| - this.sendQueue_[0] = data.slice(data.byteLength - bytesSent); |
| + this.sendQueue_[0] = data.slice(data.byteLength - writeInfo.bytesWritten); |
| } |
| this.flushSendQueue_(); |
| @@ -264,27 +255,33 @@ remoting.XmppConnection.prototype.onSent_ = function(bytesSent) { |
| * @private |
| */ |
| remoting.XmppConnection.prototype.startTls_ = function() { |
| + base.debug.assert(!this.readPending_); |
| base.debug.assert(!this.startTlsPending_); |
| - var that = this; |
| - |
| this.startTlsPending_ = true; |
| - this.socket_.startTls() |
| - .then(function() { |
| - that.startTlsPending_ = false; |
| - that.socket_.startReceiving(that.onReceive_.bind(that), |
| - that.onReceiveError_.bind(that)); |
| - |
| - that.loginHandler_.onTlsStarted(); |
| - }) |
| - .catch(function(/** number */ error) { |
| - that.startTlsPending_ = false; |
| - that.onError_(remoting.Error.NETWORK_FAILURE, |
| - 'Failed to start TLS: ' + error); |
| - }); |
| + chrome.socket.secure( |
| + this.socketId_, {}, this.onTlsStarted_.bind(this)); |
| } |
| /** |
| + * @param {number} resultCode |
| + * @private |
| + */ |
| +remoting.XmppConnection.prototype.onTlsStarted_ = function(resultCode) { |
| + base.debug.assert(this.startTlsPending_); |
| + this.startTlsPending_ = false; |
| + |
| + if (resultCode < 0) { |
| + this.onError_(remoting.Error.NETWORK_FAILURE, |
| + 'Failed to start TLS: ' + resultCode); |
| + return; |
| + } |
| + |
| + this.tryRead_(); |
| + this.loginHandler_.onTlsStarted(); |
| +}; |
| + |
| +/** |
| * @param {string} jid |
| * @param {remoting.XmppStreamParser} streamParser |
| * @private |
| @@ -313,7 +310,7 @@ remoting.XmppConnection.prototype.onIncomingStanza_ = function(stanza) { |
| * @private |
| */ |
| remoting.XmppConnection.prototype.onParserError_ = function(text) { |
| - this.onError_(remoting.Error.UNEXPECTED, text); |
| + this.onError_(remoting.Error.unexpected(), text); |
| } |
| /** |
| @@ -324,12 +321,21 @@ remoting.XmppConnection.prototype.onParserError_ = function(text) { |
| remoting.XmppConnection.prototype.onError_ = function(error, text) { |
| console.error(text); |
| this.error_ = error; |
| - base.dispose(this.socket_); |
| - this.socket_ = null; |
| + this.closeSocket_(); |
| this.setState_(remoting.SignalStrategy.State.FAILED); |
| }; |
| /** |
| + * @private |
| + */ |
| +remoting.XmppConnection.prototype.closeSocket_ = function() { |
| + if (this.socketId_ != -1) { |
| + chrome.socket.destroy(this.socketId_); |
| + this.socketId_ = -1; |
| + } |
| +}; |
| + |
| +/** |
| * @param {remoting.SignalStrategy.State} newState |
| * @private |
| */ |