1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "nacl_io/devfs/jspipe_event_emitter.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <assert.h>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <errno.h>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <string.h>
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <algorithm>
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#define TRACE(format, ...) \
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  LOG_TRACE("jspipe[%s]: " format, name_.c_str(), ##__VA_ARGS__)
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#define ERROR(format, ...) \
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  LOG_ERROR("jspipe[%s]: " format, name_.c_str(), ##__VA_ARGS__)
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "nacl_io/log.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "nacl_io/osinttypes.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "nacl_io/pepper_interface.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const size_t kMaxPostMessageSize = 64 * 1024;
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* kDictKeyPipe = "pipe";
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* kDictKeyOperation = "operation";
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* kDictKeyPayload = "payload";
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* kOperationNameAck = "ack";
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* kOperationNameWrite = "write";
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace nacl_io {
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)JSPipeEventEmitter::JSPipeEventEmitter(PepperInterface* ppapi, size_t size)
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : input_fifo_(size),
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      post_message_buffer_size_(size),
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      bytes_sent_(0),
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      bytes_acked_(0),
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      bytes_read_(0),
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ppapi_(ppapi),
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      messaging_iface_(NULL),
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      var_iface_(NULL),
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      array_iface_(NULL),
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      buffer_iface_(NULL),
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      dict_iface_(NULL),
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      pipe_name_var_(PP_MakeUndefined()),
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      pipe_key_(PP_MakeUndefined()),
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      operation_key_(PP_MakeUndefined()),
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      payload_key_(PP_MakeUndefined()),
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      write_var_(PP_MakeUndefined()),
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ack_var_(PP_MakeUndefined()) {
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateStatus_Locked();
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (ppapi == NULL) {
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    TRACE("missing PPAPI provider");
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  messaging_iface_ = ppapi->GetMessagingInterface();
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_ = ppapi->GetVarInterface();
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  array_iface_ = ppapi->GetVarArrayInterface();
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  buffer_iface_ = ppapi->GetVarArrayBufferInterface();
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict_iface_ = ppapi->GetVarDictionaryInterface();
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (var_iface_ == NULL)
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pipe_key_ = VarFromCStr(kDictKeyPipe);
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  operation_key_ = VarFromCStr(kDictKeyOperation);
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  payload_key_ = VarFromCStr(kDictKeyPayload);
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  write_var_ = VarFromCStr(kOperationNameWrite);
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ack_var_ = VarFromCStr(kOperationNameAck);
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void JSPipeEventEmitter::Destroy() {
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (var_iface_ == NULL)
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(pipe_name_var_);
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(pipe_key_);
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(operation_key_);
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(payload_key_);
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(write_var_);
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(ack_var_);
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PP_Var JSPipeEventEmitter::VarFromCStr(const char* string) {
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  assert(var_iface_);
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return var_iface_->VarFromUtf8(string, strlen(string));
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void JSPipeEventEmitter::UpdateStatus_Locked() {
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t status = 0;
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!input_fifo_.IsEmpty())
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    status |= POLLIN;
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetOSpace() > 0)
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    status |= POLLOUT;
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ClearEvents_Locked(~status);
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RaiseEvents_Locked(status);
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::Read_Locked(char* data, size_t len, int* out_bytes) {
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *out_bytes = input_fifo_.Read(data, len);
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (*out_bytes > 0) {
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bytes_read_ += *out_bytes;
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Error err = SendAckMessage(bytes_read_);
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (err != 0)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ERROR("Sending ACK failed: %d\n", err.error);
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateStatus_Locked();
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::SendWriteMessage(const void* buf, size_t count) {
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  TRACE("SendWriteMessage [%" PRIuS "] total=%" PRIuS, count, bytes_sent_);
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!var_iface_ || !buffer_iface_) {
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Got NULL interface(s): %s%s",
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          var_iface_ ? "" : "Var ",
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          buffer_iface_ ? "" : "ArrayBuffer");
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EIO;
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Copy payload data in a new ArrayBuffer
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PP_Var buffer = buffer_iface_->Create(count);
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  memcpy(buffer_iface_->Map(buffer), buf, count);
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  buffer_iface_->Unmap(buffer);
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Error rtn = SendMessageToJS(write_var_, buffer);
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(buffer);
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return rtn;
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::SetName(const char* name) {
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (var_iface_ == NULL) {
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // No error here: many of the tests trigger this message.
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_TRACE("Got NULL interface: Var");
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EIO;
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // name can only be set once
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!name_.empty()) {
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Attempting to set name more than once.");
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EIO;
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // new name must not be empty
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!name || strlen(name) == 0) {
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Empty name is invalid.");
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EIO;
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TRACE("set name: %s", name);
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  name_ = name;
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pipe_name_var_ = VarFromCStr(name);
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Error JSPipeEventEmitter::SendMessageToJS(PP_Var operation, PP_Var payload) {
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ppapi_) {
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("ppapi_ is NULL.");
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EIO;
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!messaging_iface_ || !var_iface_ || !dict_iface_) {
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Got NULL interface(s): %s%s%s",
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              messaging_iface_ ? "" : "Messaging ",
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              dict_iface_ ? "" : "Dictionary ",
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              var_iface_ ? "" : "Var");
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return EIO;
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Create dict object which will be sent to JavaScript.
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PP_Var dict = dict_iface_->Create();
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Set three keys in the dictionary: 'pipe', 'operation', and 'payload'
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict_iface_->Set(dict, pipe_key_, pipe_name_var_);
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict_iface_->Set(dict, operation_key_, operation);
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict_iface_->Set(dict, payload_key_, payload);
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Send the dict via PostMessage
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  messaging_iface_->PostMessage(ppapi_->GetInstance(), dict);
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Release the dict
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(dict);
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::SendAckMessage(size_t byte_count) {
18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  TRACE("SendAckMessage %" PRIuS, byte_count);
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PP_Var payload;
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  payload.type = PP_VARTYPE_INT32;
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  payload.value.as_int = (int32_t)byte_count;
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return SendMessageToJS(ack_var_, payload);
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)size_t JSPipeEventEmitter::HandleJSWrite(const char* data, size_t len) {
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t out_len = input_fifo_.Write(data, len);
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateStatus_Locked();
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return out_len;
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void JSPipeEventEmitter::HandleJSAck(size_t byte_count) {
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (byte_count > bytes_sent_) {
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Unexpected byte count: %" PRIuS, byte_count);
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bytes_acked_ = byte_count;
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TRACE("HandleAck: %" SCNuS "/%" PRIuS, bytes_acked_, bytes_sent_);
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateStatus_Locked();
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::HandleJSWrite(struct PP_Var message) {
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TRACE("HandleJSWrite");
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (message.type != PP_VARTYPE_ARRAY_BUFFER) {
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Expected ArrayBuffer but got %d.", message.type);
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EINVAL;
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t length;
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (buffer_iface_->ByteLength(message, &length) != PP_TRUE) {
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("ArrayBuffer.ByteLength returned PP_FALSE");
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EINVAL;
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  char* buffer = (char*)buffer_iface_->Map(message);
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Write data to the input fifo
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t wrote = HandleJSWrite(buffer, length);
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  buffer_iface_->Unmap(message);
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (wrote != length) {
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Only wrote %d of %d bytes to pipe", (int)wrote, (int)length);
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EIO;
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TRACE("done HandleWrite: %d", length);
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::HandleJSAck(PP_Var message) {
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (message.type != PP_VARTYPE_INT32) {
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Integer object expected but got %d.", message.type);
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EINVAL;
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  HandleJSAck(message.value.as_int);
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int JSPipeEventEmitter::VarStrcmp(PP_Var a, PP_Var b) {
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t length_a = 0;
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t length_b = 0;
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const char* cstring_a = var_iface_->VarToUtf8(a, &length_a);
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const char* cstring_b = var_iface_->VarToUtf8(a, &length_b);
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string string_a(cstring_a, length_a);
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string string_b(cstring_b, length_a);
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return strcmp(string_a.c_str(), string_b.c_str());
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Error JSPipeEventEmitter::HandleJSMessage(struct PP_Var message) {
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Error err = 0;
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!messaging_iface_ || !var_iface_ || !dict_iface_ || !buffer_iface_) {
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Got NULL interface(s): %s%s%s%s",
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          messaging_iface_ ? "" : "Messaging ",
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          var_iface_ ? "" : "Var ",
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          dict_iface_ ? "" : "Dictionary ",
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          buffer_iface_ ? "" : "ArrayBuffer");
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return ENOSYS;
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Verify that we have an array with size two.
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (message.type != PP_VARTYPE_DICTIONARY) {
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Expected Dictionary but got %d.", message.type);
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EINVAL;
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#ifndef NDEBUG
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PP_Var pipe_name_var = dict_iface_->Get(message, pipe_key_);
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (VarStrcmp(pipe_name_var, pipe_name_var_)) {
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Wrong pipe name.");
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return EINVAL;
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(pipe_name_var);
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PP_Var operation_var = dict_iface_->Get(message, operation_key_);
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (operation_var.type != PP_VARTYPE_STRING) {
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ERROR("Expected String but got %d.", operation_var.type);
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    err = EINVAL;
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    uint32_t length;
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const char* operation_string;
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    operation_string = var_iface_->VarToUtf8(operation_var, &length);
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::string message_type(operation_string, length);
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    TRACE("HandleJSMessage %s", message_type.c_str());
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PP_Var payload = dict_iface_->Get(message, payload_key_);
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (message_type == kOperationNameWrite) {
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      err = HandleJSWrite(payload);
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else if (message_type == kOperationNameAck) {
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      err = HandleJSAck(payload);
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ERROR("Unknown message type: %s", message_type.c_str());
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      err = EINVAL;
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var_iface_->Release(payload);
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var_iface_->Release(operation_var);
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return err;
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
31046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Error JSPipeEventEmitter::Write_Locked(const char* data,
31146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       size_t len,
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       int* out_bytes) {
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetOSpace() == 0) {
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    *out_bytes = 0;
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return 0;
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (len > GetOSpace())
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    len = GetOSpace();
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Limit the size of the data we send with PostMessage to kMaxPostMessageSize
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (len > kMaxPostMessageSize)
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    len = kMaxPostMessageSize;
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Error err = SendWriteMessage(data, len);
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (err != 0)
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return err;
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *out_bytes = len;
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bytes_sent_ += len;
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateStatus_Locked();
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace nacl_io
336