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 "mojo/edk/js/core.h" 6 7 #include <stddef.h> 8 #include <stdint.h> 9 10 #include "base/bind.h" 11 #include "base/logging.h" 12 #include "gin/arguments.h" 13 #include "gin/array_buffer.h" 14 #include "gin/converter.h" 15 #include "gin/dictionary.h" 16 #include "gin/function_template.h" 17 #include "gin/handle.h" 18 #include "gin/object_template_builder.h" 19 #include "gin/per_isolate_data.h" 20 #include "gin/public/wrapper_info.h" 21 #include "gin/wrappable.h" 22 #include "mojo/edk/js/drain_data.h" 23 #include "mojo/edk/js/handle.h" 24 25 namespace mojo { 26 namespace edk { 27 namespace js { 28 29 namespace { 30 31 MojoResult CloseHandle(gin::Handle<HandleWrapper> handle) { 32 if (!handle->get().is_valid()) 33 return MOJO_RESULT_INVALID_ARGUMENT; 34 handle->Close(); 35 return MOJO_RESULT_OK; 36 } 37 38 gin::Dictionary WaitHandle(const gin::Arguments& args, 39 mojo::Handle handle, 40 MojoHandleSignals signals, 41 MojoDeadline deadline) { 42 v8::Isolate* isolate = args.isolate(); 43 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate); 44 45 MojoHandleSignalsState signals_state; 46 MojoResult result = mojo::Wait(handle, signals, deadline, &signals_state); 47 dictionary.Set("result", result); 48 49 mojo::WaitManyResult wmv(result, 0); 50 if (!wmv.AreSignalsStatesValid()) { 51 dictionary.Set("signalsState", v8::Null(isolate).As<v8::Value>()); 52 } else { 53 gin::Dictionary signalsStateDict = gin::Dictionary::CreateEmpty(isolate); 54 signalsStateDict.Set("satisfiedSignals", signals_state.satisfied_signals); 55 signalsStateDict.Set("satisfiableSignals", 56 signals_state.satisfiable_signals); 57 dictionary.Set("signalsState", signalsStateDict); 58 } 59 60 return dictionary; 61 } 62 63 gin::Dictionary WaitMany(const gin::Arguments& args, 64 const std::vector<mojo::Handle>& handles, 65 const std::vector<MojoHandleSignals>& signals, 66 MojoDeadline deadline) { 67 v8::Isolate* isolate = args.isolate(); 68 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate); 69 70 std::vector<MojoHandleSignalsState> signals_states(signals.size()); 71 mojo::WaitManyResult wmv = 72 mojo::WaitMany(handles, signals, deadline, &signals_states); 73 dictionary.Set("result", wmv.result); 74 if (wmv.IsIndexValid()) { 75 dictionary.Set("index", wmv.index); 76 } else { 77 dictionary.Set("index", v8::Null(isolate).As<v8::Value>()); 78 } 79 if (wmv.AreSignalsStatesValid()) { 80 std::vector<gin::Dictionary> vec; 81 for (size_t i = 0; i < handles.size(); ++i) { 82 gin::Dictionary signalsStateDict = gin::Dictionary::CreateEmpty(isolate); 83 signalsStateDict.Set("satisfiedSignals", 84 signals_states[i].satisfied_signals); 85 signalsStateDict.Set("satisfiableSignals", 86 signals_states[i].satisfiable_signals); 87 vec.push_back(signalsStateDict); 88 } 89 dictionary.Set("signalsState", vec); 90 } else { 91 dictionary.Set("signalsState", v8::Null(isolate).As<v8::Value>()); 92 } 93 94 return dictionary; 95 } 96 97 gin::Dictionary CreateMessagePipe(const gin::Arguments& args) { 98 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 99 dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT); 100 101 MojoHandle handle0 = MOJO_HANDLE_INVALID; 102 MojoHandle handle1 = MOJO_HANDLE_INVALID; 103 MojoResult result = MOJO_RESULT_OK; 104 105 v8::Handle<v8::Value> options_value = args.PeekNext(); 106 if (options_value.IsEmpty() || options_value->IsNull() || 107 options_value->IsUndefined()) { 108 result = MojoCreateMessagePipe(NULL, &handle0, &handle1); 109 } else if (options_value->IsObject()) { 110 gin::Dictionary options_dict(args.isolate(), options_value->ToObject()); 111 MojoCreateMessagePipeOptions options; 112 // For future struct_size, we can probably infer that from the presence of 113 // properties in options_dict. For now, it's always 8. 114 options.struct_size = 8; 115 // Ideally these would be optional. But the interface makes it hard to 116 // typecheck them then. 117 if (!options_dict.Get("flags", &options.flags)) { 118 return dictionary; 119 } 120 121 result = MojoCreateMessagePipe(&options, &handle0, &handle1); 122 } else { 123 return dictionary; 124 } 125 126 CHECK_EQ(MOJO_RESULT_OK, result); 127 128 dictionary.Set("result", result); 129 dictionary.Set("handle0", mojo::Handle(handle0)); 130 dictionary.Set("handle1", mojo::Handle(handle1)); 131 return dictionary; 132 } 133 134 MojoResult WriteMessage( 135 mojo::Handle handle, 136 const gin::ArrayBufferView& buffer, 137 const std::vector<gin::Handle<HandleWrapper> >& handles, 138 MojoWriteMessageFlags flags) { 139 std::vector<MojoHandle> raw_handles(handles.size()); 140 for (size_t i = 0; i < handles.size(); ++i) 141 raw_handles[i] = handles[i]->get().value(); 142 MojoResult rv = MojoWriteMessage(handle.value(), 143 buffer.bytes(), 144 static_cast<uint32_t>(buffer.num_bytes()), 145 raw_handles.empty() ? NULL : &raw_handles[0], 146 static_cast<uint32_t>(raw_handles.size()), 147 flags); 148 // MojoWriteMessage takes ownership of the handles, so release them here. 149 for (size_t i = 0; i < handles.size(); ++i) 150 ignore_result(handles[i]->release()); 151 152 return rv; 153 } 154 155 gin::Dictionary ReadMessage(const gin::Arguments& args, 156 mojo::Handle handle, 157 MojoReadMessageFlags flags) { 158 uint32_t num_bytes = 0; 159 uint32_t num_handles = 0; 160 MojoResult result = MojoReadMessage( 161 handle.value(), NULL, &num_bytes, NULL, &num_handles, flags); 162 if (result != MOJO_RESULT_RESOURCE_EXHAUSTED) { 163 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 164 dictionary.Set("result", result); 165 return dictionary; 166 } 167 168 v8::Handle<v8::ArrayBuffer> array_buffer = 169 v8::ArrayBuffer::New(args.isolate(), num_bytes); 170 std::vector<mojo::Handle> handles(num_handles); 171 172 gin::ArrayBuffer buffer; 173 ConvertFromV8(args.isolate(), array_buffer, &buffer); 174 CHECK(buffer.num_bytes() == num_bytes); 175 176 result = MojoReadMessage(handle.value(), 177 buffer.bytes(), 178 &num_bytes, 179 handles.empty() ? NULL : 180 reinterpret_cast<MojoHandle*>(&handles[0]), 181 &num_handles, 182 flags); 183 184 CHECK(buffer.num_bytes() == num_bytes); 185 CHECK(handles.size() == num_handles); 186 187 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 188 dictionary.Set("result", result); 189 dictionary.Set("buffer", array_buffer); 190 dictionary.Set("handles", handles); 191 return dictionary; 192 } 193 194 gin::Dictionary CreateDataPipe(const gin::Arguments& args) { 195 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 196 dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT); 197 198 MojoHandle producer_handle = MOJO_HANDLE_INVALID; 199 MojoHandle consumer_handle = MOJO_HANDLE_INVALID; 200 MojoResult result = MOJO_RESULT_OK; 201 202 v8::Handle<v8::Value> options_value = args.PeekNext(); 203 if (options_value.IsEmpty() || options_value->IsNull() || 204 options_value->IsUndefined()) { 205 result = MojoCreateDataPipe(NULL, &producer_handle, &consumer_handle); 206 } else if (options_value->IsObject()) { 207 gin::Dictionary options_dict(args.isolate(), options_value->ToObject()); 208 MojoCreateDataPipeOptions options; 209 // For future struct_size, we can probably infer that from the presence of 210 // properties in options_dict. For now, it's always 16. 211 options.struct_size = 16; 212 // Ideally these would be optional. But the interface makes it hard to 213 // typecheck them then. 214 if (!options_dict.Get("flags", &options.flags) || 215 !options_dict.Get("elementNumBytes", &options.element_num_bytes) || 216 !options_dict.Get("capacityNumBytes", &options.capacity_num_bytes)) { 217 return dictionary; 218 } 219 220 result = MojoCreateDataPipe(&options, &producer_handle, &consumer_handle); 221 } else { 222 return dictionary; 223 } 224 225 CHECK_EQ(MOJO_RESULT_OK, result); 226 227 dictionary.Set("result", result); 228 dictionary.Set("producerHandle", mojo::Handle(producer_handle)); 229 dictionary.Set("consumerHandle", mojo::Handle(consumer_handle)); 230 return dictionary; 231 } 232 233 gin::Dictionary WriteData(const gin::Arguments& args, 234 mojo::Handle handle, 235 const gin::ArrayBufferView& buffer, 236 MojoWriteDataFlags flags) { 237 uint32_t num_bytes = static_cast<uint32_t>(buffer.num_bytes()); 238 MojoResult result = 239 MojoWriteData(handle.value(), buffer.bytes(), &num_bytes, flags); 240 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 241 dictionary.Set("result", result); 242 dictionary.Set("numBytes", num_bytes); 243 return dictionary; 244 } 245 246 gin::Dictionary ReadData(const gin::Arguments& args, 247 mojo::Handle handle, 248 MojoReadDataFlags flags) { 249 uint32_t num_bytes = 0; 250 MojoResult result = MojoReadData( 251 handle.value(), NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY); 252 if (result != MOJO_RESULT_OK) { 253 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 254 dictionary.Set("result", result); 255 return dictionary; 256 } 257 258 v8::Handle<v8::ArrayBuffer> array_buffer = 259 v8::ArrayBuffer::New(args.isolate(), num_bytes); 260 gin::ArrayBuffer buffer; 261 ConvertFromV8(args.isolate(), array_buffer, &buffer); 262 CHECK_EQ(num_bytes, buffer.num_bytes()); 263 264 result = MojoReadData(handle.value(), buffer.bytes(), &num_bytes, flags); 265 CHECK_EQ(num_bytes, buffer.num_bytes()); 266 267 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate()); 268 dictionary.Set("result", result); 269 dictionary.Set("buffer", array_buffer); 270 return dictionary; 271 } 272 273 // Asynchronously read all of the data available for the specified data pipe 274 // consumer handle until the remote handle is closed or an error occurs. A 275 // Promise is returned whose settled value is an object like this: 276 // {result: core.RESULT_OK, buffer: dataArrayBuffer}. If the read failed, 277 // then the Promise is rejected, the result will be the actual error code, 278 // and the buffer will contain whatever was read before the error occurred. 279 // The drainData data pipe handle argument is closed automatically. 280 281 v8::Handle<v8::Value> DoDrainData(gin::Arguments* args, 282 gin::Handle<HandleWrapper> handle) { 283 return (new DrainData(args->isolate(), handle->release()))->GetPromise(); 284 } 285 286 bool IsHandle(gin::Arguments* args, v8::Handle<v8::Value> val) { 287 gin::Handle<mojo::edk::js::HandleWrapper> ignore_handle; 288 return gin::Converter<gin::Handle<mojo::edk::js::HandleWrapper>>::FromV8( 289 args->isolate(), val, &ignore_handle); 290 } 291 292 293 gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin }; 294 295 } // namespace 296 297 const char Core::kModuleName[] = "mojo/public/js/core"; 298 299 v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) { 300 gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); 301 v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate( 302 &g_wrapper_info); 303 304 if (templ.IsEmpty()) { 305 templ = 306 gin::ObjectTemplateBuilder(isolate) 307 // TODO(mpcomplete): Should these just be methods on the JS Handle 308 // object? 309 .SetMethod("close", CloseHandle) 310 .SetMethod("wait", WaitHandle) 311 .SetMethod("waitMany", WaitMany) 312 .SetMethod("createMessagePipe", CreateMessagePipe) 313 .SetMethod("writeMessage", WriteMessage) 314 .SetMethod("readMessage", ReadMessage) 315 .SetMethod("createDataPipe", CreateDataPipe) 316 .SetMethod("writeData", WriteData) 317 .SetMethod("readData", ReadData) 318 .SetMethod("drainData", DoDrainData) 319 .SetMethod("isHandle", IsHandle) 320 321 .SetValue("RESULT_OK", MOJO_RESULT_OK) 322 .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED) 323 .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN) 324 .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT) 325 .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED) 326 .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND) 327 .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS) 328 .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED) 329 .SetValue("RESULT_RESOURCE_EXHAUSTED", 330 MOJO_RESULT_RESOURCE_EXHAUSTED) 331 .SetValue("RESULT_FAILED_PRECONDITION", 332 MOJO_RESULT_FAILED_PRECONDITION) 333 .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED) 334 .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE) 335 .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED) 336 .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL) 337 .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE) 338 .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS) 339 .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY) 340 .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT) 341 342 .SetValue("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE) 343 344 .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE) 345 .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE) 346 .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE) 347 .SetValue("HANDLE_SIGNAL_PEER_CLOSED", 348 MOJO_HANDLE_SIGNAL_PEER_CLOSED) 349 350 .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE", 351 MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE) 352 353 .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE) 354 355 .SetValue("READ_MESSAGE_FLAG_NONE", MOJO_READ_MESSAGE_FLAG_NONE) 356 .SetValue("READ_MESSAGE_FLAG_MAY_DISCARD", 357 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD) 358 359 .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE", 360 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE) 361 362 .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE) 363 .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE", 364 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) 365 366 .SetValue("READ_DATA_FLAG_NONE", MOJO_READ_DATA_FLAG_NONE) 367 .SetValue("READ_DATA_FLAG_ALL_OR_NONE", 368 MOJO_READ_DATA_FLAG_ALL_OR_NONE) 369 .SetValue("READ_DATA_FLAG_DISCARD", MOJO_READ_DATA_FLAG_DISCARD) 370 .SetValue("READ_DATA_FLAG_QUERY", MOJO_READ_DATA_FLAG_QUERY) 371 .SetValue("READ_DATA_FLAG_PEEK", MOJO_READ_DATA_FLAG_PEEK) 372 .Build(); 373 374 data->SetObjectTemplate(&g_wrapper_info, templ); 375 } 376 377 return templ->NewInstance(); 378 } 379 380 } // namespace js 381 } // namespace edk 382 } // namespace mojo 383