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.
5 #include "nacl_io/devfs/jspipe_event_emitter.h"
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__)
18 #include "nacl_io/log.h"
19 #include "nacl_io/osinttypes.h"
20 #include "nacl_io/pepper_interface.h"
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";
33 JSPipeEventEmitter::JSPipeEventEmitter(PepperInterface
* ppapi
, size_t size
)
35 post_message_buffer_size_(size
),
40 messaging_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();
53 TRACE("missing PPAPI provider");
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();
62 if (var_iface_
== NULL
)
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
);
72 void JSPipeEventEmitter::Destroy() {
73 if (var_iface_
== NULL
)
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_
);
83 PP_Var
JSPipeEventEmitter::VarFromCStr(const char* string
) {
85 return var_iface_
->VarFromUtf8(string
, strlen(string
));
88 void JSPipeEventEmitter::UpdateStatus_Locked() {
90 if (!input_fifo_
.IsEmpty())
96 ClearEvents_Locked(~status
);
97 RaiseEvents_Locked(status
);
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_
);
106 ERROR("Sending ACK failed: %d\n", err
.error
);
109 UpdateStatus_Locked();
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");
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
);
127 Error rtn
= SendMessageToJS(write_var_
, buffer
);
128 var_iface_
->Release(buffer
);
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");
139 // name can only be set once
140 if (!name_
.empty()) {
141 LOG_ERROR("Attempting to set name more than once.");
145 // new name must not be empty
146 if (!name
|| strlen(name
) == 0) {
147 LOG_ERROR("Empty name is invalid.");
151 TRACE("set name: %s", name
);
153 pipe_name_var_
= VarFromCStr(name
);
157 Error
JSPipeEventEmitter::SendMessageToJS(PP_Var operation
, PP_Var payload
) {
159 LOG_ERROR("ppapi_ is NULL.");
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");
171 // Create dict object which will be sent to JavaScript.
172 PP_Var dict
= dict_iface_
->Create();
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
);
179 // Send the dict via PostMessage
180 messaging_iface_
->PostMessage(ppapi_
->GetInstance(), dict
);
183 var_iface_
->Release(dict
);
187 Error
JSPipeEventEmitter::SendAckMessage(size_t byte_count
) {
188 TRACE("SendAckMessage %" PRIuS
, byte_count
);
190 payload
.type
= PP_VARTYPE_INT32
;
191 payload
.value
.as_int
= (int32_t)byte_count
;
193 return SendMessageToJS(ack_var_
, payload
);
196 size_t JSPipeEventEmitter::HandleJSWrite(const char* data
, size_t len
) {
197 size_t out_len
= input_fifo_
.Write(data
, len
);
198 UpdateStatus_Locked();
202 void JSPipeEventEmitter::HandleJSAck(size_t byte_count
) {
203 if (byte_count
> bytes_sent_
) {
204 ERROR("Unexpected byte count: %" PRIuS
, byte_count
);
208 bytes_acked_
= byte_count
;
209 TRACE("HandleAck: %" SCNuS
"/%" PRIuS
, bytes_acked_
, bytes_sent_
);
210 UpdateStatus_Locked();
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
);
220 if (buffer_iface_
->ByteLength(message
, &length
) != PP_TRUE
) {
221 ERROR("ArrayBuffer.ByteLength returned PP_FALSE");
225 char* buffer
= (char*)buffer_iface_
->Map(message
);
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
);
234 TRACE("done HandleWrite: %d", length
);
238 Error
JSPipeEventEmitter::HandleJSAck(PP_Var message
) {
239 if (message
.type
!= PP_VARTYPE_INT32
) {
240 ERROR("Integer object expected but got %d.", message
.type
);
243 HandleJSAck(message
.value
.as_int
);
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());
257 Error
JSPipeEventEmitter::HandleJSMessage(struct PP_Var message
) {
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");
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
);
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.");
280 var_iface_
->Release(pipe_name_var
);
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
);
289 const char* operation_string
;
290 operation_string
= var_iface_
->VarToUtf8(operation_var
, &length
);
291 std::string
message_type(operation_string
, length
);
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
);
300 ERROR("Unknown message type: %s", message_type
.c_str());
303 var_iface_
->Release(payload
);
306 var_iface_
->Release(operation_var
);
310 Error
JSPipeEventEmitter::Write_Locked(const char* data
,
313 if (GetOSpace() == 0) {
318 if (len
> GetOSpace())
321 // Limit the size of the data we send with PostMessage to kMaxPostMessageSize
322 if (len
> kMaxPostMessageSize
)
323 len
= kMaxPostMessageSize
;
325 Error err
= SendWriteMessage(data
, len
);
331 UpdateStatus_Locked();
335 } // namespace nacl_io