8bf4d037f517d9093607f3b6c688541cc03a0d3f
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / devfs / jspipe_event_emitter.cc
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 #include "nacl_io/devfs/jspipe_event_emitter.h"
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include <algorithm>
12
13 #define TRACE(format, ...) \
14   LOG_TRACE("jspipe[%s]: " format, name_.c_str(), ##__VA_ARGS__)
15 #define ERROR(format, ...) \
16   LOG_ERROR("jspipe[%s]: " format, name_.c_str(), ##__VA_ARGS__)
17
18 #include "nacl_io/log.h"
19 #include "nacl_io/osinttypes.h"
20 #include "nacl_io/pepper_interface.h"
21
22 namespace {
23 const size_t kMaxPostMessageSize = 64 * 1024;
24 const char* kDictKeyPipe = "pipe";
25 const char* kDictKeyOperation = "operation";
26 const char* kDictKeyPayload = "payload";
27 const char* kOperationNameAck = "ack";
28 const char* kOperationNameWrite = "write";
29 }
30
31 namespace nacl_io {
32
33 JSPipeEventEmitter::JSPipeEventEmitter(PepperInterface* ppapi, size_t size)
34     : input_fifo_(size),
35       post_message_buffer_size_(size),
36       bytes_sent_(0),
37       bytes_acked_(0),
38       bytes_read_(0),
39       ppapi_(ppapi),
40       messaging_iface_(NULL),
41       var_iface_(NULL),
42       array_iface_(NULL),
43       buffer_iface_(NULL),
44       dict_iface_(NULL),
45       pipe_name_var_(PP_MakeUndefined()),
46       pipe_key_(PP_MakeUndefined()),
47       operation_key_(PP_MakeUndefined()),
48       payload_key_(PP_MakeUndefined()),
49       write_var_(PP_MakeUndefined()),
50       ack_var_(PP_MakeUndefined()) {
51   UpdateStatus_Locked();
52   if (ppapi == NULL) {
53     TRACE("missing PPAPI provider");
54     return;
55   }
56   messaging_iface_ = ppapi->GetMessagingInterface();
57   var_iface_ = ppapi->GetVarInterface();
58   array_iface_ = ppapi->GetVarArrayInterface();
59   buffer_iface_ = ppapi->GetVarArrayBufferInterface();
60   dict_iface_ = ppapi->GetVarDictionaryInterface();
61
62   if (var_iface_ == NULL)
63     return;
64
65   pipe_key_ = VarFromCStr(kDictKeyPipe);
66   operation_key_ = VarFromCStr(kDictKeyOperation);
67   payload_key_ = VarFromCStr(kDictKeyPayload);
68   write_var_ = VarFromCStr(kOperationNameWrite);
69   ack_var_ = VarFromCStr(kOperationNameAck);
70 }
71
72 void JSPipeEventEmitter::Destroy() {
73   if (var_iface_ == NULL)
74     return;
75   var_iface_->Release(pipe_name_var_);
76   var_iface_->Release(pipe_key_);
77   var_iface_->Release(operation_key_);
78   var_iface_->Release(payload_key_);
79   var_iface_->Release(write_var_);
80   var_iface_->Release(ack_var_);
81 }
82
83 PP_Var JSPipeEventEmitter::VarFromCStr(const char* string) {
84   assert(var_iface_);
85   return var_iface_->VarFromUtf8(string, strlen(string));
86 }
87
88 void JSPipeEventEmitter::UpdateStatus_Locked() {
89   uint32_t status = 0;
90   if (!input_fifo_.IsEmpty())
91     status |= POLLIN;
92
93   if (GetOSpace() > 0)
94     status |= POLLOUT;
95
96   ClearEvents_Locked(~status);
97   RaiseEvents_Locked(status);
98 }
99
100 Error JSPipeEventEmitter::Read_Locked(char* data, size_t len, int* out_bytes) {
101   *out_bytes = input_fifo_.Read(data, len);
102   if (*out_bytes > 0) {
103     bytes_read_ += *out_bytes;
104     Error err = SendAckMessage(bytes_read_);
105     if (err != 0)
106       ERROR("Sending ACK failed: %d\n", err.error);
107   }
108
109   UpdateStatus_Locked();
110   return 0;
111 }
112
113 Error JSPipeEventEmitter::SendWriteMessage(const void* buf, size_t count) {
114   TRACE("SendWriteMessage [%" PRIuS "] total=%" PRIuS, count, bytes_sent_);
115   if (!var_iface_ || !buffer_iface_) {
116     ERROR("Got NULL interface(s): %s%s",
117           var_iface_ ? "" : "Var ",
118           buffer_iface_ ? "" : "ArrayBuffer");
119     return EIO;
120   }
121
122   // Copy payload data in a new ArrayBuffer
123   PP_Var buffer = buffer_iface_->Create(count);
124   memcpy(buffer_iface_->Map(buffer), buf, count);
125   buffer_iface_->Unmap(buffer);
126
127   Error rtn = SendMessageToJS(write_var_, buffer);
128   var_iface_->Release(buffer);
129   return rtn;
130 }
131
132 Error JSPipeEventEmitter::SetName(const char* name) {
133   if (var_iface_ == NULL) {
134     // No error here: many of the tests trigger this message.
135     LOG_TRACE("Got NULL interface: Var");
136     return EIO;
137   }
138
139   // name can only be set once
140   if (!name_.empty()) {
141     LOG_ERROR("Attempting to set name more than once.");
142     return EIO;
143   }
144
145   // new name must not be empty
146   if (!name || strlen(name) == 0) {
147     LOG_ERROR("Empty name is invalid.");
148     return EIO;
149   }
150
151   TRACE("set name: %s", name);
152   name_ = name;
153   pipe_name_var_ = VarFromCStr(name);
154   return 0;
155 }
156
157 Error JSPipeEventEmitter::SendMessageToJS(PP_Var operation, PP_Var payload) {
158   if (!ppapi_) {
159     LOG_ERROR("ppapi_ is NULL.");
160     return EIO;
161   }
162
163   if (!messaging_iface_ || !var_iface_ || !dict_iface_) {
164     LOG_ERROR("Got NULL interface(s): %s%s%s",
165               messaging_iface_ ? "" : "Messaging ",
166               dict_iface_ ? "" : "Dictionary ",
167               var_iface_ ? "" : "Var");
168     return EIO;
169   }
170
171   // Create dict object which will be sent to JavaScript.
172   PP_Var dict = dict_iface_->Create();
173
174   // Set three keys in the dictionary: 'pipe', 'operation', and 'payload'
175   dict_iface_->Set(dict, pipe_key_, pipe_name_var_);
176   dict_iface_->Set(dict, operation_key_, operation);
177   dict_iface_->Set(dict, payload_key_, payload);
178
179   // Send the dict via PostMessage
180   messaging_iface_->PostMessage(ppapi_->GetInstance(), dict);
181
182   // Release the dict
183   var_iface_->Release(dict);
184   return 0;
185 }
186
187 Error JSPipeEventEmitter::SendAckMessage(size_t byte_count) {
188   TRACE("SendAckMessage %" PRIuS, byte_count);
189   PP_Var payload;
190   payload.type = PP_VARTYPE_INT32;
191   payload.value.as_int = (int32_t)byte_count;
192
193   return SendMessageToJS(ack_var_, payload);
194 }
195
196 size_t JSPipeEventEmitter::HandleJSWrite(const char* data, size_t len) {
197   size_t out_len = input_fifo_.Write(data, len);
198   UpdateStatus_Locked();
199   return out_len;
200 }
201
202 void JSPipeEventEmitter::HandleJSAck(size_t byte_count) {
203   if (byte_count > bytes_sent_) {
204     ERROR("Unexpected byte count: %" PRIuS, byte_count);
205     return;
206   }
207
208   bytes_acked_ = byte_count;
209   TRACE("HandleAck: %" SCNuS "/%" PRIuS, bytes_acked_, bytes_sent_);
210   UpdateStatus_Locked();
211 }
212
213 Error JSPipeEventEmitter::HandleJSWrite(struct PP_Var message) {
214   TRACE("HandleJSWrite");
215   if (message.type != PP_VARTYPE_ARRAY_BUFFER) {
216     ERROR("Expected ArrayBuffer but got %d.", message.type);
217     return EINVAL;
218   }
219   uint32_t length;
220   if (buffer_iface_->ByteLength(message, &length) != PP_TRUE) {
221     ERROR("ArrayBuffer.ByteLength returned PP_FALSE");
222     return EINVAL;
223   }
224
225   char* buffer = (char*)buffer_iface_->Map(message);
226
227   // Write data to the input fifo
228   size_t wrote = HandleJSWrite(buffer, length);
229   buffer_iface_->Unmap(message);
230   if (wrote != length) {
231     ERROR("Only wrote %d of %d bytes to pipe", (int)wrote, (int)length);
232     return EIO;
233   }
234   TRACE("done HandleWrite: %d", length);
235   return 0;
236 }
237
238 Error JSPipeEventEmitter::HandleJSAck(PP_Var message) {
239   if (message.type != PP_VARTYPE_INT32) {
240     ERROR("Integer object expected but got %d.", message.type);
241     return EINVAL;
242   }
243   HandleJSAck(message.value.as_int);
244   return 0;
245 }
246
247 int JSPipeEventEmitter::VarStrcmp(PP_Var a, PP_Var b) {
248   uint32_t length_a = 0;
249   uint32_t length_b = 0;
250   const char* cstring_a = var_iface_->VarToUtf8(a, &length_a);
251   const char* cstring_b = var_iface_->VarToUtf8(a, &length_b);
252   std::string string_a(cstring_a, length_a);
253   std::string string_b(cstring_b, length_a);
254   return strcmp(string_a.c_str(), string_b.c_str());
255 }
256
257 Error JSPipeEventEmitter::HandleJSMessage(struct PP_Var message) {
258   Error err = 0;
259   if (!messaging_iface_ || !var_iface_ || !dict_iface_ || !buffer_iface_) {
260     ERROR("Got NULL interface(s): %s%s%s%s",
261           messaging_iface_ ? "" : "Messaging ",
262           var_iface_ ? "" : "Var ",
263           dict_iface_ ? "" : "Dictionary ",
264           buffer_iface_ ? "" : "ArrayBuffer");
265     return ENOSYS;
266   }
267
268   // Verify that we have an array with size two.
269   if (message.type != PP_VARTYPE_DICTIONARY) {
270     ERROR("Expected Dictionary but got %d.", message.type);
271     return EINVAL;
272   }
273
274 #ifndef NDEBUG
275   PP_Var pipe_name_var = dict_iface_->Get(message, pipe_key_);
276   if (VarStrcmp(pipe_name_var, pipe_name_var_)) {
277     ERROR("Wrong pipe name.");
278     return EINVAL;
279   }
280   var_iface_->Release(pipe_name_var);
281 #endif
282
283   PP_Var operation_var = dict_iface_->Get(message, operation_key_);
284   if (operation_var.type != PP_VARTYPE_STRING) {
285     ERROR("Expected String but got %d.", operation_var.type);
286     err = EINVAL;
287   } else {
288     uint32_t length;
289     const char* operation_string;
290     operation_string = var_iface_->VarToUtf8(operation_var, &length);
291     std::string message_type(operation_string, length);
292
293     TRACE("HandleJSMessage %s", message_type.c_str());
294     PP_Var payload = dict_iface_->Get(message, payload_key_);
295     if (message_type == kOperationNameWrite) {
296       err = HandleJSWrite(payload);
297     } else if (message_type == kOperationNameAck) {
298       err = HandleJSAck(payload);
299     } else {
300       ERROR("Unknown message type: %s", message_type.c_str());
301       err = EINVAL;
302     }
303     var_iface_->Release(payload);
304   }
305
306   var_iface_->Release(operation_var);
307   return err;
308 }
309
310 Error JSPipeEventEmitter::Write_Locked(const char* data,
311                                        size_t len,
312                                        int* out_bytes) {
313   if (GetOSpace() == 0) {
314     *out_bytes = 0;
315     return 0;
316   }
317
318   if (len > GetOSpace())
319     len = GetOSpace();
320
321   // Limit the size of the data we send with PostMessage to kMaxPostMessageSize
322   if (len > kMaxPostMessageSize)
323     len = kMaxPostMessageSize;
324
325   Error err = SendWriteMessage(data, len);
326   if (err != 0)
327     return err;
328   *out_bytes = len;
329   bytes_sent_ += len;
330
331   UpdateStatus_Locked();
332   return 0;
333 }
334
335 }  // namespace nacl_io