Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "nacl_io/devfs/jspipe_node.h" | 5 #include "nacl_io/devfs/jspipe_node.h" |
| 6 | 6 |
| 7 //#include <cstdio> | |
| 8 #include <cstring> | 7 #include <cstring> |
| 9 | 8 |
| 10 #include "nacl_io/devfs/dev_fs.h" | 9 #include "nacl_io/devfs/dev_fs.h" |
| 11 #include "nacl_io/error.h" | 10 #include "nacl_io/error.h" |
| 12 #include "nacl_io/ioctl.h" | 11 #include "nacl_io/ioctl.h" |
| 13 #include "nacl_io/kernel_handle.h" | 12 #include "nacl_io/kernel_handle.h" |
| 13 #include "nacl_io/log.h" | |
| 14 #include "nacl_io/pepper_interface.h" | 14 #include "nacl_io/pepper_interface.h" |
| 15 | 15 |
| 16 #define TRACE(format, ...) LOG_TRACE("jspipe: " format, ##__VA_ARGS__) | |
| 17 #define ERROR(format, ...) LOG_TRACE("jspipe: " format, ##__VA_ARGS__) | |
| 18 | |
| 19 namespace { | |
| 20 const size_t kPostMessageBufferSize = 512*1024; | |
| 21 } | |
| 22 | |
| 16 namespace nacl_io { | 23 namespace nacl_io { |
| 17 | 24 |
| 18 #define MAX_MESSAGE_SIZE (64*1024) | 25 JSPipeNode::JSPipeNode(Filesystem* filesystem) |
| 26 : Node(filesystem), | |
| 27 pipe_(new JSPipeEventEmitter(filesystem_->ppapi(), kPostMessageBufferSize)), | |
| 28 messaging_iface_(NULL), | |
| 29 var_iface_(NULL), | |
| 30 array_iface_(NULL), | |
| 31 buffer_iface_(NULL), | |
| 32 dict_iface_(NULL) { | |
| 33 PepperInterface* ppapi = filesystem_->ppapi(); | |
| 34 if (ppapi) { | |
| 35 messaging_iface_ = ppapi->GetMessagingInterface(); | |
| 36 var_iface_ = ppapi->GetVarInterface(); | |
| 37 array_iface_ = ppapi->GetVarArrayInterface(); | |
| 38 buffer_iface_ = ppapi->GetVarArrayBufferInterface(); | |
| 39 dict_iface_ = ppapi->GetVarDictionaryInterface(); | |
| 40 } else { | |
| 41 TRACE("missing PPAPI provider"); | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 JSPipeEventEmitter* JSPipeNode::GetEventEmitter() { | |
| 46 return pipe_.get(); | |
| 47 } | |
| 48 | |
| 49 Error JSPipeNode::HandleJSWrite(struct PP_Var message) { | |
| 50 TRACE("HandleJSWrite"); | |
| 51 if (message.type != PP_VARTYPE_ARRAY_BUFFER) { | |
| 52 TRACE("HandleJSWrite expected ArrayBuffer but got %d.", message.type); | |
| 53 return EINVAL; | |
| 54 } | |
| 55 uint32_t length; | |
| 56 if (buffer_iface_->ByteLength(message, &length) != PP_TRUE) | |
| 57 return EINVAL; | |
| 58 | |
| 59 char* buffer = (char*)buffer_iface_->Map(message); | |
| 60 | |
| 61 // Write data to the input fifo | |
| 62 int wrote = GetEventEmitter()->HandleJSWrite(buffer, length); | |
|
binji
2014/05/01 20:22:31
returns size_t
| |
| 63 buffer_iface_->Unmap(message); | |
| 64 if (wrote != (int) length) { | |
| 65 LOG_ERROR("Only wrote %d of %d bytes to pipe", wrote, length); | |
|
binji
2014/05/01 20:22:31
ERROR instead of LOG_ERROR?
Sam Clegg
2014/05/01 22:16:55
File local macro that also print the name of the p
| |
| 66 return EIO; | |
| 67 } | |
| 68 TRACE("done HandleWrite: %d", length); | |
| 69 return 0; | |
| 70 } | |
| 71 | |
| 72 Error JSPipeNode::HandleJSAck(PP_Var message) { | |
| 73 if (message.type != PP_VARTYPE_INT32) { | |
| 74 TRACE("HandleAck integer object expected but got %d.", message.type); | |
| 75 return EINVAL; | |
| 76 } | |
| 77 GetEventEmitter()->HandleJSAck(message.value.as_int); | |
|
binji
2014/05/01 20:22:31
This will never be able to ack above 2**31
Sam Clegg
2014/05/01 22:16:55
True, this is a current know issue that also effec
| |
| 78 return 0; | |
| 79 } | |
| 80 | |
| 81 Error JSPipeNode::HandleJSMessage(struct PP_Var message) { | |
| 82 Error err = 0; | |
| 83 if (!messaging_iface_ || !var_iface_ || !array_iface_ || !buffer_iface_) { | |
| 84 TRACE("HandleJSMessage: missing PPAPI interfaces"); | |
| 85 return ENOSYS; | |
| 86 } | |
| 87 | |
| 88 // Verify that we have an array with size two. | |
| 89 if (message.type != PP_VARTYPE_ARRAY) { | |
| 90 TRACE("HandleJSMessage passed non-array var"); | |
| 91 return EINVAL; | |
| 92 } | |
| 93 | |
| 94 if (array_iface_->GetLength(message) != 2) { | |
| 95 TRACE("HandleJSMessage passed array of size %d", | |
| 96 array_iface_->GetLength(message)); | |
| 97 return EINVAL; | |
| 98 } | |
| 99 | |
| 100 PP_Var message_type_var = array_iface_->Get(message, 0); | |
| 101 PP_Var payload = array_iface_->Get(message, 1); | |
| 102 if (message_type_var.type != PP_VARTYPE_STRING) { | |
| 103 err = EINVAL; | |
| 104 } else { | |
| 105 uint32_t length; | |
| 106 const char* message_type_string; | |
| 107 message_type_string = var_iface_->VarToUtf8(message_type_var, &length); | |
| 108 std::string message_type(message_type_string, length); | |
| 109 | |
| 110 TRACE("HandleJSMessage %s", message_type.c_str()); | |
| 111 if (message_type == "write") { | |
| 112 err = HandleJSWrite(payload); | |
| 113 } else if (message_type == "ack") { | |
| 114 err = HandleJSAck(payload); | |
| 115 } else { | |
| 116 TRACE("Unknown message type: %s", message_type.c_str()); | |
| 117 err = EINVAL; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 var_iface_->Release(message_type_var); | |
| 122 var_iface_->Release(payload); | |
| 123 return err; | |
| 124 } | |
| 125 | |
| 126 Error JSPipeNode::Read(const HandleAttr& attr, | |
| 127 void* buf, | |
| 128 size_t count, | |
| 129 int* out_bytes) { | |
| 130 int ms = attr.IsBlocking() ? -1 : 0; | |
| 131 | |
| 132 EventListenerLock wait(GetEventEmitter()); | |
| 133 Error err = wait.WaitOnEvent(POLLIN, ms); | |
| 134 if (err == ETIMEDOUT) | |
| 135 err = EWOULDBLOCK; | |
| 136 if (err) | |
| 137 return err; | |
| 138 | |
| 139 *out_bytes = GetEventEmitter()->Read_Locked(static_cast<char*>(buf), count); | |
| 140 return 0; | |
| 141 } | |
| 142 | |
| 19 Error JSPipeNode::Write(const HandleAttr& attr, | 143 Error JSPipeNode::Write(const HandleAttr& attr, |
| 20 const void* buf, | 144 const void* buf, |
| 21 size_t count, | 145 size_t count, |
| 22 int* out_bytes) { | 146 int* out_bytes) { |
| 23 PepperInterface* ppapi = filesystem_->ppapi(); | 147 int ms = attr.IsBlocking() ? -1 : 0; |
| 24 MessagingInterface* iface = ppapi->GetMessagingInterface(); | 148 TRACE("write %d", ms); |
| 25 VarInterface* var_iface = ppapi->GetVarInterface(); | |
| 26 VarArrayInterface* array_iface = ppapi->GetVarArrayInterface(); | |
| 27 VarArrayBufferInterface* buffer_iface = ppapi->GetVarArrayBufferInterface(); | |
| 28 if (!iface || !var_iface || !array_iface || !buffer_iface) | |
| 29 return ENOSYS; | |
| 30 | 149 |
| 31 if (name_.empty()) | 150 EventListenerLock wait(GetEventEmitter()); |
| 32 return EIO; | 151 Error err = wait.WaitOnEvent(POLLOUT, ms); |
| 152 if (err == ETIMEDOUT) | |
| 153 err = EWOULDBLOCK; | |
| 154 if (err) | |
| 155 return err; | |
| 33 | 156 |
| 34 // Limit the size of the data we send with PostMessage to MAX_MESSAGE_SIZE | 157 *out_bytes = GetEventEmitter()->Write_Locked(static_cast<const char*>(buf), |
| 35 if (count > MAX_MESSAGE_SIZE) | 158 count); |
| 36 count = MAX_MESSAGE_SIZE; | |
| 37 | |
| 38 // Copy data in a new ArrayBuffer | |
| 39 PP_Var buffer = buffer_iface->Create(count); | |
| 40 memcpy(buffer_iface->Map(buffer), buf, count); | |
| 41 buffer_iface->Unmap(buffer); | |
| 42 | |
| 43 // Construct string var containing the name of the pipe | |
| 44 PP_Var string = var_iface->VarFromUtf8(name_.c_str(), name_.size()); | |
| 45 | |
| 46 // Construct two element array containing string and array buffer | |
| 47 PP_Var array = array_iface->Create(); | |
| 48 array_iface->Set(array, 0, string); | |
| 49 array_iface->Set(array, 1, buffer); | |
| 50 | |
| 51 // Release our handles to the items that are now in the array | |
| 52 var_iface->Release(string); | |
| 53 var_iface->Release(buffer); | |
| 54 | |
| 55 // Send array via PostMessage | |
| 56 iface->PostMessage(ppapi->GetInstance(), array); | |
| 57 | |
| 58 // Release the array | |
| 59 var_iface->Release(array); | |
| 60 | |
| 61 *out_bytes = count; | |
| 62 return 0; | 159 return 0; |
| 63 } | 160 } |
| 64 | 161 |
| 65 Error JSPipeNode::VIoctl(int request, va_list args) { | 162 Error JSPipeNode::VIoctl(int request, va_list args) { |
| 163 AUTO_LOCK(node_lock_); | |
| 164 | |
| 66 switch (request) { | 165 switch (request) { |
| 67 case TIOCNACLPIPENAME: { | 166 case NACL_IOC_PIPE_SETNAME: { |
| 68 // name can only be set once | |
| 69 if (!name_.empty()) | |
| 70 return EIO; | |
| 71 | |
| 72 const char* new_name = va_arg(args, char*); | 167 const char* new_name = va_arg(args, char*); |
| 73 // new name must not be empty | 168 return GetEventEmitter()->SetName(new_name); |
| 74 if (!new_name || strlen(new_name) == 0) | 169 } |
| 75 return EIO; | 170 case NACL_IOC_PIPE_GETISPACE: { |
| 76 | 171 int* space = va_arg(args, int*); |
| 77 name_ = new_name; | 172 *space = GetEventEmitter()->GetISpace(); |
| 78 return 0; | 173 return 0; |
| 79 } | 174 } |
| 80 case TIOCNACLINPUT: { | 175 case NACL_IOC_PIPE_GETOSPACE: { |
| 81 // This ioctl is used to deliver data from javascipt into the pipe. | 176 int* space = va_arg(args, int*); |
| 82 struct tioc_nacl_input_string* message = | 177 *space = GetEventEmitter()->GetOSpace(); |
| 83 va_arg(args, struct tioc_nacl_input_string*); | |
| 84 const char* buffer = message->buffer; | |
| 85 int num_bytes = message->length; | |
| 86 int wrote = 0; | |
| 87 HandleAttr data; | |
| 88 // Write to the underlying pipe. Calling JSPipeNode::Write | |
| 89 // would write using PostMessage. | |
| 90 int error = PipeNode::Write(data, buffer, num_bytes, &wrote); | |
| 91 if (error || wrote != num_bytes) | |
| 92 return EIO; | |
| 93 return 0; | 178 return 0; |
| 94 } | 179 } |
| 180 case NACL_IOC_HANDLEMESSAGE: { | |
| 181 struct PP_Var* message = va_arg(args, struct PP_Var*); | |
| 182 return HandleJSMessage(*message); | |
| 183 } | |
| 184 default: | |
| 185 TRACE("unknown ioctl: %#x", request); | |
| 186 break; | |
| 95 } | 187 } |
| 96 | 188 |
| 97 return EINVAL; | 189 return EINVAL; |
| 98 } | 190 } |
| 99 | 191 |
| 100 } // namespace nacl_io | 192 } // namespace nacl_io |
| OLD | NEW |