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 |