Home | History | Annotate | Download | only in lib
      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 (function() {
      6   var internal = mojo.internal;
      7 
      8   function Connector(handle) {
      9     if (!(handle instanceof MojoHandle))
     10       throw new Error("Connector: not a handle " + handle);
     11     this.handle_ = handle;
     12     this.dropWrites_ = false;
     13     this.error_ = false;
     14     this.incomingReceiver_ = null;
     15     this.readWatcher_ = null;
     16     this.errorHandler_ = null;
     17     this.paused_ = false;
     18 
     19     this.waitToReadMore();
     20   }
     21 
     22   Connector.prototype.close = function() {
     23     this.cancelWait();
     24     if (this.handle_ != null) {
     25       this.handle_.close();
     26       this.handle_ = null;
     27     }
     28   };
     29 
     30   Connector.prototype.pauseIncomingMethodCallProcessing = function() {
     31     if (this.paused_) {
     32       return;
     33     }
     34     this.paused_= true;
     35     this.cancelWait();
     36   };
     37 
     38   Connector.prototype.resumeIncomingMethodCallProcessing = function() {
     39     if (!this.paused_) {
     40       return;
     41     }
     42     this.paused_= false;
     43     this.waitToReadMore();
     44   };
     45 
     46   Connector.prototype.accept = function(message) {
     47     if (this.error_)
     48       return false;
     49 
     50     if (this.dropWrites_)
     51       return true;
     52 
     53     var result = this.handle_.writeMessage(
     54         new Uint8Array(message.buffer.arrayBuffer), message.handles);
     55     switch (result) {
     56       case Mojo.RESULT_OK:
     57         // The handles were successfully transferred, so we don't own them
     58         // anymore.
     59         message.handles = [];
     60         break;
     61       case Mojo.RESULT_FAILED_PRECONDITION:
     62         // There's no point in continuing to write to this pipe since the other
     63         // end is gone. Avoid writing any future messages. Hide write failures
     64         // from the caller since we'd like them to continue consuming any
     65         // backlog of incoming messages before regarding the message pipe as
     66         // closed.
     67         this.dropWrites_ = true;
     68         break;
     69       default:
     70         // This particular write was rejected, presumably because of bad input.
     71         // The pipe is not necessarily in a bad state.
     72         return false;
     73     }
     74     return true;
     75   };
     76 
     77   Connector.prototype.setIncomingReceiver = function(receiver) {
     78     this.incomingReceiver_ = receiver;
     79   };
     80 
     81   Connector.prototype.setErrorHandler = function(handler) {
     82     this.errorHandler_ = handler;
     83   };
     84 
     85   Connector.prototype.readMore_ = function(result) {
     86     for (;;) {
     87       if (this.paused_) {
     88         return;
     89       }
     90 
     91       var read = this.handle_.readMessage();
     92       if (this.handle_ == null) // The connector has been closed.
     93         return;
     94       if (read.result == Mojo.RESULT_SHOULD_WAIT)
     95         return;
     96       if (read.result != Mojo.RESULT_OK) {
     97         this.handleError(read.result !== Mojo.RESULT_FAILED_PRECONDITION,
     98             false);
     99         return;
    100       }
    101       var messageBuffer = new internal.Buffer(read.buffer);
    102       var message = new internal.Message(messageBuffer, read.handles);
    103       var receiverResult = this.incomingReceiver_ &&
    104           this.incomingReceiver_.accept(message);
    105 
    106       // Dispatching the message may have closed the connector.
    107       if (this.handle_ == null)
    108         return;
    109 
    110       // Handle invalid incoming message.
    111       if (!internal.isTestingMode() && !receiverResult) {
    112         // TODO(yzshen): Consider notifying the embedder.
    113         this.handleError(true, false);
    114       }
    115     }
    116   };
    117 
    118   Connector.prototype.cancelWait = function() {
    119     if (this.readWatcher_) {
    120       this.readWatcher_.cancel();
    121       this.readWatcher_ = null;
    122     }
    123   };
    124 
    125   Connector.prototype.waitToReadMore = function() {
    126     if (this.handle_) {
    127       this.readWatcher_ = this.handle_.watch({readable: true},
    128                                              this.readMore_.bind(this));
    129     }
    130   };
    131 
    132   Connector.prototype.handleError = function(forcePipeReset,
    133                                              forceAsyncHandler) {
    134     if (this.error_ || this.handle_ === null) {
    135       return;
    136     }
    137 
    138     if (this.paused_) {
    139       // Enforce calling the error handler asynchronously if the user has
    140       // paused receiving messages. We need to wait until the user starts
    141       // receiving messages again.
    142       forceAsyncHandler = true;
    143     }
    144 
    145     if (!forcePipeReset && forceAsyncHandler) {
    146       forcePipeReset = true;
    147     }
    148 
    149     this.cancelWait();
    150     if (forcePipeReset) {
    151       this.handle_.close();
    152       var dummyPipe = Mojo.createMessagePipe();
    153       this.handle_ = dummyPipe.handle0;
    154     }
    155 
    156     if (forceAsyncHandler) {
    157       if (!this.paused_) {
    158         this.waitToReadMore();
    159       }
    160     } else {
    161       this.error_ = true;
    162       if (this.errorHandler_) {
    163         this.errorHandler_.onError();
    164       }
    165     }
    166   };
    167 
    168   internal.Connector = Connector;
    169 })();
    170