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