1// Copyright 2014 The Chromium Authors. 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 5define("mojo/public/js/bindings/connector", [ 6 "mojo/public/js/bindings/buffer", 7 "mojo/public/js/bindings/codec", 8 "mojo/public/js/bindings/core", 9 "mojo/public/js/bindings/support", 10], function(buffer, codec, core, support) { 11 12 function Connector(handle) { 13 this.handle_ = handle; 14 this.dropWrites_ = false; 15 this.error_ = false; 16 this.incomingReceiver_ = null; 17 this.readWaitCookie_ = null; 18 this.errorHandler_ = null; 19 20 this.waitToReadMore_(); 21 } 22 23 Connector.prototype.close = function() { 24 if (this.readWaitCookie_) { 25 support.cancelWait(this.readWaitCookie_); 26 this.readWaitCookie_ = null; 27 } 28 if (this.handle_ != null) { 29 core.close(this.handle_); 30 this.handle_ = null; 31 } 32 }; 33 34 Connector.prototype.accept = function(message) { 35 if (this.error_) 36 return false; 37 38 if (this.dropWrites_) 39 return true; 40 41 var result = core.writeMessage(this.handle_, 42 new Uint8Array(message.buffer.arrayBuffer), 43 message.handles, 44 core.WRITE_MESSAGE_FLAG_NONE); 45 switch (result) { 46 case core.RESULT_OK: 47 // The handles were successfully transferred, so we don't own them 48 // anymore. 49 message.handles = []; 50 break; 51 case core.RESULT_FAILED_PRECONDITION: 52 // There's no point in continuing to write to this pipe since the other 53 // end is gone. Avoid writing any future messages. Hide write failures 54 // from the caller since we'd like them to continue consuming any 55 // backlog of incoming messages before regarding the message pipe as 56 // closed. 57 this.dropWrites_ = true; 58 break; 59 default: 60 // This particular write was rejected, presumably because of bad input. 61 // The pipe is not necessarily in a bad state. 62 return false; 63 } 64 return true; 65 }; 66 67 Connector.prototype.setIncomingReceiver = function(receiver) { 68 this.incomingReceiver_ = receiver; 69 }; 70 71 Connector.prototype.setErrorHandler = function(handler) { 72 this.errorHandler_ = handler; 73 }; 74 75 Connector.prototype.encounteredError = function() { 76 return this.error_; 77 }; 78 79 Connector.prototype.waitToReadMore_ = function() { 80 this.readWaitCookie_ = support.asyncWait(this.handle_, 81 core.HANDLE_SIGNAL_READABLE, 82 this.readMore_.bind(this)); 83 }; 84 85 Connector.prototype.readMore_ = function(result) { 86 for (;;) { 87 var read = core.readMessage(this.handle_, 88 core.READ_MESSAGE_FLAG_NONE); 89 if (read.result == core.RESULT_SHOULD_WAIT) { 90 this.waitToReadMore_(); 91 return; 92 } 93 if (read.result != core.RESULT_OK) { 94 this.error_ = true; 95 if (this.errorHandler_) 96 this.errorHandler_.onError(read.result); 97 return; 98 } 99 var messageBuffer = new buffer.Buffer(read.buffer); 100 var message = new codec.Message(messageBuffer, read.handles); 101 if (this.incomingReceiver_) { 102 this.incomingReceiver_.accept(message); 103 } 104 } 105 }; 106 107 // The TestConnector subclass is only intended to be used in unit tests. It 108 // enables delivering a message to the pipe's handle without an async wait. 109 110 function TestConnector(handle) { 111 Connector.call(this, handle); 112 } 113 114 TestConnector.prototype = Object.create(Connector.prototype); 115 116 TestConnector.prototype.waitToReadMore_ = function() { 117 }; 118 119 TestConnector.prototype.deliverMessage = function() { 120 this.readMore_(core.RESULT_OK); 121 } 122 123 var exports = {}; 124 exports.Connector = Connector; 125 exports.TestConnector = TestConnector; 126 return exports; 127}); 128