Commit b6c86417 authored by binji@chromium.org's avatar binji@chromium.org

[NaCl SDK] Remove use of TIOCNACLINPUT from nacl_io/ppapi_simple.

This is replaced by NACL_IOC_HANDLEMESSAGE.

BUG=none
R=sbc@chromium.org

Review URL: https://codereview.chromium.org/334983007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278099 0039d316-1c4b-4281-b951-d872f2087c98
parent 2fc155f2
...@@ -150,7 +150,7 @@ Error JSPipeEventEmitter::SendMessageToJS(PP_Var operation, PP_Var payload) { ...@@ -150,7 +150,7 @@ Error JSPipeEventEmitter::SendMessageToJS(PP_Var operation, PP_Var payload) {
// Create dict object which will be sent to JavaScript. // Create dict object which will be sent to JavaScript.
PP_Var dict = dict_iface_->Create(); PP_Var dict = dict_iface_->Create();
// Set try keys in the dictionaty: 'pipe', 'operation', and 'payload' // Set three keys in the dictionary: 'pipe', 'operation', and 'payload'
dict_iface_->Set(dict, pipe_key_, pipe_name_var_); dict_iface_->Set(dict, pipe_key_, pipe_name_var_);
dict_iface_->Set(dict, operation_key_, operation); dict_iface_->Set(dict, operation_key_, operation);
dict_iface_->Set(dict, payload_key_, payload); dict_iface_->Set(dict, payload_key_, payload);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "nacl_io/ioctl.h" #include "nacl_io/ioctl.h"
#include "nacl_io/kernel_handle.h" #include "nacl_io/kernel_handle.h"
#include "nacl_io/kernel_intercept.h" #include "nacl_io/kernel_intercept.h"
#include "nacl_io/log.h"
#include "nacl_io/pepper_interface.h" #include "nacl_io/pepper_interface.h"
#include "sdk_util/auto_lock.h" #include "sdk_util/auto_lock.h"
...@@ -167,11 +168,32 @@ Error TtyNode::Echo(const char* string, int count) { ...@@ -167,11 +168,32 @@ Error TtyNode::Echo(const char* string, int count) {
return 0; return 0;
} }
Error TtyNode::ProcessInput(struct tioc_nacl_input_string* message) { Error TtyNode::ProcessInput(PP_Var message) {
AUTO_LOCK(emitter_->GetLock()) if (message.type != PP_VARTYPE_STRING) {
LOG_ERROR("ProcessInput: expected VarString but got %d.", message.type);
return EINVAL;
}
PepperInterface* ppapi = filesystem_->ppapi();
if (!ppapi) {
LOG_ERROR("ProcessInput: ppapi is NULL.");
return EINVAL;
}
VarInterface* var_iface = ppapi->GetVarInterface();
if (!var_iface) {
LOG_ERROR("ProcessInput: Var interface pointer is NULL.");
return EINVAL;
}
const char* buffer = message->buffer; uint32_t num_bytes;
size_t num_bytes = message->length; const char* buffer = var_iface->VarToUtf8(message, &num_bytes);
Error error = ProcessInput(buffer, num_bytes);
return error;
}
Error TtyNode::ProcessInput(const char* buffer, size_t num_bytes) {
AUTO_LOCK(emitter_->GetLock())
for (size_t i = 0; i < num_bytes; i++) { for (size_t i = 0; i < num_bytes; i++) {
char c = buffer[i]; char c = buffer[i];
...@@ -248,12 +270,9 @@ Error TtyNode::VIoctl(int request, va_list args) { ...@@ -248,12 +270,9 @@ Error TtyNode::VIoctl(int request, va_list args) {
output_handler_ = *arg; output_handler_ = *arg;
return 0; return 0;
} }
case TIOCNACLINPUT: { case NACL_IOC_HANDLEMESSAGE: {
// This ioctl is used to deliver data from the user to this tty node's struct PP_Var* message = va_arg(args, struct PP_Var*);
// input buffer. return ProcessInput(*message);
struct tioc_nacl_input_string* message =
va_arg(args, struct tioc_nacl_input_string*);
return ProcessInput(message);
} }
case TIOCSWINSZ: { case TIOCSWINSZ: {
struct winsize* size = va_arg(args, struct winsize*); struct winsize* size = va_arg(args, struct winsize*);
...@@ -280,6 +299,9 @@ Error TtyNode::VIoctl(int request, va_list args) { ...@@ -280,6 +299,9 @@ Error TtyNode::VIoctl(int request, va_list args) {
size->ws_col = cols_; size->ws_col = cols_;
return 0; return 0;
} }
default: {
LOG_ERROR("TtyNode:VIoctl: Unknown request: %#x", request);
}
} }
return EINVAL; return EINVAL;
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <deque> #include <deque>
#include <ppapi/c/pp_var.h>
#include "nacl_io/char_node.h" #include "nacl_io/char_node.h"
#include "nacl_io/ioctl.h" #include "nacl_io/ioctl.h"
#include "nacl_io/ostermios.h" #include "nacl_io/ostermios.h"
...@@ -43,7 +45,8 @@ class TtyNode : public CharNode { ...@@ -43,7 +45,8 @@ class TtyNode : public CharNode {
private: private:
ScopedEventEmitter emitter_; ScopedEventEmitter emitter_;
Error ProcessInput(struct tioc_nacl_input_string* message); Error ProcessInput(PP_Var var);
Error ProcessInput(const char* buffer, size_t num_bytes);
Error Echo(const char* string, int count); Error Echo(const char* string, int count);
void InitTermios(); void InitTermios();
......
...@@ -8,20 +8,13 @@ ...@@ -8,20 +8,13 @@
#include <sys/types.h> #include <sys/types.h>
/* /*
* ioctl to feed input to a tty node. Accepts a pointer to the following * ioctl to register an output handler with the tty node. Will fail with
* struct (tioc_nacl_input_string), which contains a pointer to an array * EALREADY if a handler is already registered. Expects an argument of type
* of characters. * tioc_nacl_output. The handler will be called during calls to write() on the
*/ * thread that calls write(), or, for echoed input during the
#define TIOCNACLINPUT 0xadcd02 * NACL_IOC_HANDLEMESSAGE ioctl() on the thread calling ioctl(). The handler
* should return the number of bytes written/handled, or -errno if an error
/* * occured.
* ioctl to register an output handler with the tty node. Will fail
* with EALREADY if a handler is already registered. Expects an
* argument of type tioc_nacl_output. The handler will be called during
* calls to write() on the thread that calls write(), or, for echoed input
* during the TIOCNACLINPUT ioctl() on the thread calling ioctl(). The
* handler should return the number of bytes written/handled, or -errno
* if an error occured.
*/ */
#define TIOCNACLOUTPUT 0xadcd03 #define TIOCNACLOUTPUT 0xadcd03
...@@ -51,11 +44,6 @@ ...@@ -51,11 +44,6 @@
typedef char* naclioc_jspipe_name; typedef char* naclioc_jspipe_name;
struct tioc_nacl_input_string {
size_t length;
const char* buffer;
};
typedef ssize_t (*tioc_nacl_output_handler_t)(const char* buf, typedef ssize_t (*tioc_nacl_output_handler_t)(const char* buf,
size_t count, size_t count,
void* user_data); void* user_data);
......
...@@ -290,7 +290,7 @@ bool PSInstance::ProcessProperties() { ...@@ -290,7 +290,7 @@ bool PSInstance::ProcessProperties() {
exit_message_ = getenv("PS_EXIT_MESSAGE"); exit_message_ = getenv("PS_EXIT_MESSAGE");
// If PS_EXIT_MESSAGE is set in the envionment then we perform a handshake // If PS_EXIT_MESSAGE is set in the environment then we perform a handshake
// with JavaScript when program exits. // with JavaScript when program exits.
if (exit_message_ != NULL) if (exit_message_ != NULL)
nacl_io_register_exit_handler(HandleExitStatic, this); nacl_io_register_exit_handler(HandleExitStatic, this);
...@@ -409,27 +409,6 @@ void PSInstance::MessageHandlerInput(const pp::Var& key, ...@@ -409,27 +409,6 @@ void PSInstance::MessageHandlerInput(const pp::Var& key,
const pp::Var& message) { const pp::Var& message) {
std::string key_string = key.AsString(); std::string key_string = key.AsString();
if (message.is_string() && key_string == tty_prefix_) {
std::string buffer = message.AsString();
// Since our message may contain null characters, we can't send it as a
// naked C string, so we package it up in this struct before sending it
// to the ioctl.
struct tioc_nacl_input_string ioctl_message;
ioctl_message.length = buffer.size();
ioctl_message.buffer = buffer.c_str();
int ret = ioctl(tty_fd_, TIOCNACLINPUT, &ioctl_message);
if (ret != 0 && errno != ENOTTY) {
Error("ioctl returned unexpected error: %d.\n", ret);
}
return;
}
if (!message.is_array_buffer()) {
Error("Expected ArrayBuffer object but got: %d", message.pp_var().type);
return;
}
const char* filename = NULL; const char* filename = NULL;
if (key_string == tty_prefix_) { if (key_string == tty_prefix_) {
filename = "/dev/tty"; filename = "/dev/tty";
...@@ -453,12 +432,15 @@ void PSInstance::MessageHandlerInput(const pp::Var& key, ...@@ -453,12 +432,15 @@ void PSInstance::MessageHandlerInput(const pp::Var& key,
int ret = ioctl(fd, NACL_IOC_HANDLEMESSAGE, &message.pp_var()); int ret = ioctl(fd, NACL_IOC_HANDLEMESSAGE, &message.pp_var());
if (ret != 0) { if (ret != 0) {
Error("ioctl on %s failed: %d.\n", filename, ret); Error("ioctl on %s failed: %d.\n", filename, ret);
close(fd);
return; return;
} }
close(fd);
} }
void PSInstance::HandleExitStatic(int status, void* user_data) { void PSInstance::HandleExitStatic(int status, void* user_data) {
PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); PSInstance* instance = static_cast<PSInstance*>(user_data);
instance->ExitHandshake(status); instance->ExitHandshake(status);
} }
...@@ -483,28 +465,28 @@ void PSInstance::MessageHandlerResize(const pp::Var& message) { ...@@ -483,28 +465,28 @@ void PSInstance::MessageHandlerResize(const pp::Var& message) {
ssize_t PSInstance::TtyOutputHandlerStatic(const char* buf, ssize_t PSInstance::TtyOutputHandlerStatic(const char* buf,
size_t count, size_t count,
void* user_data) { void* user_data) {
PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); PSInstance* instance = static_cast<PSInstance*>(user_data);
return instance->TtyOutputHandler(buf, count); return instance->TtyOutputHandler(buf, count);
} }
void PSInstance::MessageHandlerExitStatic(const pp::Var& key, void PSInstance::MessageHandlerExitStatic(const pp::Var& key,
const pp::Var& value, const pp::Var& value,
void* user_data) { void* user_data) {
PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); PSInstance* instance = static_cast<PSInstance*>(user_data);
instance->MessageHandlerExit(value); instance->MessageHandlerExit(value);
} }
void PSInstance::MessageHandlerInputStatic(const pp::Var& key, void PSInstance::MessageHandlerInputStatic(const pp::Var& key,
const pp::Var& value, const pp::Var& value,
void* user_data) { void* user_data) {
PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); PSInstance* instance = static_cast<PSInstance*>(user_data);
instance->MessageHandlerInput(key, value); instance->MessageHandlerInput(key, value);
} }
void PSInstance::MessageHandlerResizeStatic(const pp::Var& key, void PSInstance::MessageHandlerResizeStatic(const pp::Var& key,
const pp::Var& value, const pp::Var& value,
void* user_data) { void* user_data) {
PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); PSInstance* instance = static_cast<PSInstance*>(user_data);
instance->MessageHandlerResize(value); instance->MessageHandlerResize(value);
} }
...@@ -525,21 +507,6 @@ void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { ...@@ -525,21 +507,6 @@ void PSInstance::PostEvent(PSEventType type, const PP_Var& var) {
assert(PSE_INSTANCE_HANDLEMESSAGE == type); assert(PSE_INSTANCE_HANDLEMESSAGE == type);
pp::Var event(var); pp::Var event(var);
// Legacy support for passing TTY input as a string <prefix>:<payload>
// TODO(sbc): remove this in a future release.
if (tty_fd_ >= 0 && event.is_string()) {
std::string message = event.AsString();
size_t prefix_len = strlen(tty_prefix_);
if (message.size() > prefix_len) {
if (!strncmp(message.c_str(), tty_prefix_, prefix_len)) {
LOG_WARN("Passing TTY data using a string prefix is deprecated. "
"Use a JavaScript dictionary instead.");
MessageHandlerInput(pp::Var(message.substr(0, prefix_len)),
pp::Var(message.substr(prefix_len)));
return;
}
}
}
// If the message is a dictionary then see if it matches one // If the message is a dictionary then see if it matches one
// of the specific handlers, then call that handler rather than // of the specific handlers, then call that handler rather than
...@@ -550,8 +517,7 @@ void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { ...@@ -550,8 +517,7 @@ void PSInstance::PostEvent(PSEventType type, const PP_Var& var) {
if (keys.GetLength() == 1) { if (keys.GetLength() == 1) {
pp::Var key = keys.Get(0); pp::Var key = keys.Get(0);
Trace("calling handler for: %s", key.AsString().c_str()); Trace("calling handler for: %s", key.AsString().c_str());
MessageHandlerMap::iterator iter = MessageHandlerMap::iterator iter = message_handlers_.find(key.AsString());
message_handlers_.find(key.AsString());
if (iter != message_handlers_.end()) { if (iter != message_handlers_.end()) {
MessageHandler_t handler = iter->second.handler; MessageHandler_t handler = iter->second.handler;
void* user_data = iter->second.user_data; void* user_data = iter->second.user_data;
......
...@@ -109,7 +109,6 @@ class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient { ...@@ -109,7 +109,6 @@ class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient {
MessageHandler_t handler, MessageHandler_t handler,
void* user_data); void* user_data);
// Perform exit handshake with JavaScript. // Perform exit handshake with JavaScript.
// This is called by _exit before the process is terminated to ensure // This is called by _exit before the process is terminated to ensure
// that all messages sent prior to _exit arrive at the JavaScript side. // that all messages sent prior to _exit arrive at the JavaScript side.
......
...@@ -155,7 +155,11 @@ class JSPipeNodeTest : public ::testing::Test { ...@@ -155,7 +155,11 @@ class JSPipeNodeTest : public ::testing::Test {
} }
// Verify the contents of the jspipe mesage, which should be // Verify the contents of the jspipe mesage, which should be
// {'<pipe_name>' : ['<command_name>', payload] } // {
// "pipe": '<pipe_name>',
// "operation": '<command_name>',
// "payload": payload
// }
void VerifyPipeMessage(PP_Var message, void VerifyPipeMessage(PP_Var message,
const char* pipe_name, const char* pipe_name,
const char* operation, const char* operation,
......
...@@ -24,9 +24,17 @@ using namespace nacl_io; ...@@ -24,9 +24,17 @@ using namespace nacl_io;
namespace { namespace {
static int ki_ioctl_wrapper(int fd, int request, ...) {
va_list ap;
va_start(ap, request);
int rtn = ki_ioctl(fd, request, ap);
va_end(ap);
return rtn;
}
class TtyNodeTest : public ::testing::Test { class TtyNodeTest : public ::testing::Test {
public: public:
TtyNodeTest() : fs_(&pepper_) {} TtyNodeTest() : fs_(&ppapi_) {}
void SetUp() { void SetUp() {
ASSERT_EQ(0, fs_.Access(Path("/tty"), R_OK | W_OK)); ASSERT_EQ(0, fs_.Access(Path("/tty"), R_OK | W_OK));
...@@ -36,7 +44,7 @@ class TtyNodeTest : public ::testing::Test { ...@@ -36,7 +44,7 @@ class TtyNodeTest : public ::testing::Test {
} }
protected: protected:
FakePepperInterface pepper_; FakePepperInterface ppapi_;
DevFsForTesting fs_; DevFsForTesting fs_;
ScopedNode dev_tty_; ScopedNode dev_tty_;
}; };
...@@ -45,15 +53,26 @@ class TtyTest : public ::testing::Test { ...@@ -45,15 +53,26 @@ class TtyTest : public ::testing::Test {
public: public:
void SetUp() { void SetUp() {
ASSERT_EQ(0, ki_push_state_for_testing()); ASSERT_EQ(0, ki_push_state_for_testing());
ASSERT_EQ(0, ki_init(&kp_)); ASSERT_EQ(0, ki_init_interface(&kp_, &ppapi_));
var_iface_ = ppapi_.GetVarInterface();
} }
void TearDown() { void TearDown() {
ki_uninit(); ki_uninit();
} }
int TtyWrite(int fd, const char* string) {
PP_Var message_var = var_iface_->VarFromUtf8(string, strlen(string));
int result = ki_ioctl_wrapper(fd, NACL_IOC_HANDLEMESSAGE, &message_var);
var_iface_->Release(message_var);
return result;
}
protected: protected:
FakePepperInterface ppapi_;
KernelProxy kp_; KernelProxy kp_;
VarInterface* var_iface_;
}; };
TEST_F(TtyNodeTest, InvalidIoctl) { TEST_F(TtyNodeTest, InvalidIoctl) {
...@@ -65,9 +84,8 @@ TEST_F(TtyNodeTest, TtyInput) { ...@@ -65,9 +84,8 @@ TEST_F(TtyNodeTest, TtyInput) {
// Now let's try sending some data over. // Now let's try sending some data over.
// First we create the message. // First we create the message.
std::string message("hello, how are you?\n"); std::string message("hello, how are you?\n");
struct tioc_nacl_input_string packaged_message; VarInterface* var_iface = ppapi_.GetVarInterface();
packaged_message.length = message.size(); PP_Var message_var = var_iface->VarFromUtf8(message.data(), message.size());
packaged_message.buffer = message.data();
// Now we make buffer we'll read into. // Now we make buffer we'll read into.
// We fill the buffer and a backup buffer with arbitrary data // We fill the buffer and a backup buffer with arbitrary data
...@@ -80,7 +98,9 @@ TEST_F(TtyNodeTest, TtyInput) { ...@@ -80,7 +98,9 @@ TEST_F(TtyNodeTest, TtyInput) {
memset(backup_buffer, 'a', 100); memset(backup_buffer, 'a', 100);
// Now we actually send the data // Now we actually send the data
EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLINPUT, &packaged_message)); EXPECT_EQ(0, dev_tty_->Ioctl(NACL_IOC_HANDLEMESSAGE, &message_var));
var_iface->Release(message_var);
// We read a small chunk first to ensure it doesn't give us // We read a small chunk first to ensure it doesn't give us
// more than we ask for. // more than we ask for.
...@@ -137,21 +157,6 @@ TEST_F(TtyNodeTest, TtyOutput) { ...@@ -137,21 +157,6 @@ TEST_F(TtyNodeTest, TtyOutput) {
EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len)); EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len));
} }
static int ki_ioctl_wrapper(int fd, int request, ...) {
va_list ap;
va_start(ap, request);
int rtn = ki_ioctl(fd, request, ap);
va_end(ap);
return rtn;
}
static int TtyWrite(int fd, const char* string) {
struct tioc_nacl_input_string input;
input.buffer = string;
input.length = strlen(input.buffer);
return ki_ioctl_wrapper(fd, TIOCNACLINPUT, &input);
}
// Returns: // Returns:
// 0 -> Not readable // 0 -> Not readable
// 1 -> Readable // 1 -> Readable
...@@ -337,10 +342,12 @@ TEST_F(TtyTest, ResizeDuringSelect) { ...@@ -337,10 +342,12 @@ TEST_F(TtyTest, ResizeDuringSelect) {
* Sleep for 50ms then send some input to the /dev/tty. * Sleep for 50ms then send some input to the /dev/tty.
*/ */
static void* input_thread_main(void* arg) { static void* input_thread_main(void* arg) {
TtyTest* thiz = static_cast<TtyTest*>(arg);
usleep(50 * 1000); usleep(50 * 1000);
int fd = ki_open("/dev/tty", O_RDONLY); int fd = ki_open("/dev/tty", O_RDONLY);
TtyWrite(fd, "test\n"); thiz->TtyWrite(fd, "test\n");
return NULL; return NULL;
} }
...@@ -357,7 +364,7 @@ TEST_F(TtyTest, InputDuringSelect) { ...@@ -357,7 +364,7 @@ TEST_F(TtyTest, InputDuringSelect) {
FD_SET(tty_fd, &errorfds); FD_SET(tty_fd, &errorfds);
pthread_t resize_thread; pthread_t resize_thread;
pthread_create(&resize_thread, NULL, input_thread_main, NULL); pthread_create(&resize_thread, NULL, input_thread_main, this);
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = 20; timeout.tv_sec = 20;
...@@ -368,4 +375,5 @@ TEST_F(TtyTest, InputDuringSelect) { ...@@ -368,4 +375,5 @@ TEST_F(TtyTest, InputDuringSelect) {
ASSERT_EQ(1, rtn); ASSERT_EQ(1, rtn);
} }
}
} // namespace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment