jspipe_test.cc revision 010d83a9304c5a91596085d917d248abff47903a
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 <errno.h> 6#include <fcntl.h> 7#include <string.h> 8#include <sys/ioctl.h> 9#include <sys/select.h> 10#include <sys/stat.h> 11#include <sys/time.h> 12#include <string> 13 14#include "dev_fs_for_testing.h" 15#include "fake_ppapi/fake_messaging_interface.h" 16#include "gtest/gtest.h" 17#include "nacl_io/devfs/dev_fs.h" 18#include "nacl_io/filesystem.h" 19#include "nacl_io/ioctl.h" 20#include "nacl_io/kernel_intercept.h" 21#include "nacl_io/kernel_proxy.h" 22#include "nacl_io/osdirent.h" 23 24using namespace nacl_io; 25 26namespace { 27 28class JSPipeTest : public ::testing::Test { 29 public: 30 JSPipeTest() : fs_(&pepper_) {} 31 32 void SetUp() { 33 ASSERT_EQ(0, ki_push_state_for_testing()); 34 ASSERT_EQ(0, ki_init(&kp_)); 35 ASSERT_EQ(0, fs_.Access(Path("/jspipe1"), R_OK | W_OK)); 36 ASSERT_EQ(EACCES, fs_.Access(Path("/jspipe1"), X_OK)); 37 ASSERT_EQ(0, fs_.Open(Path("/jspipe1"), O_RDWR, &pipe_dev_)); 38 ASSERT_NE(NULL_NODE, pipe_dev_.get()); 39 } 40 41 void TearDown() { ki_uninit(); } 42 43 protected: 44 KernelProxy kp_; 45 FakePepperInterface pepper_; 46 DevFsForTesting fs_; 47 ScopedNode pipe_dev_; 48}; 49 50TEST_F(JSPipeTest, InvalidIoctl) { 51 // 123 is not a valid ioctl request. 52 EXPECT_EQ(EINVAL, pipe_dev_->Ioctl(123)); 53} 54 55TEST_F(JSPipeTest, JSPipeInput) { 56 // First we send some data into the pipe. This is how messages 57 // from javascript are injected into the pipe nodes. 58 std::string message("hello, how are you?\n"); 59 struct tioc_nacl_input_string packaged_message; 60 packaged_message.length = message.size(); 61 packaged_message.buffer = message.data(); 62 ASSERT_EQ(0, pipe_dev_->Ioctl(TIOCNACLINPUT, &packaged_message)); 63 64 // Now we make buffer we'll read into. 65 // We fill the buffer and a backup buffer with arbitrary data 66 // and compare them after reading to make sure read doesn't 67 // clobber parts of the buffer it shouldn't. 68 int bytes_read; 69 char buffer[100]; 70 char backup_buffer[100]; 71 memset(buffer, 'a', sizeof(buffer)); 72 memset(backup_buffer, 'a', sizeof(backup_buffer)); 73 74 // We read a small chunk first to ensure it doesn't give us 75 // more than we ask for. 76 HandleAttr attrs; 77 ASSERT_EQ(0, pipe_dev_->Read(attrs, buffer, 5, &bytes_read)); 78 EXPECT_EQ(5, bytes_read); 79 EXPECT_EQ(0, memcmp(message.data(), buffer, 5)); 80 EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, sizeof(buffer)-5)); 81 82 // Now we ask for more data than is left in the pipe, to ensure 83 // it doesn't give us more than there is. 84 ASSERT_EQ(0, pipe_dev_->Read(attrs, buffer + 5, sizeof(buffer)-5, 85 &bytes_read)); 86 EXPECT_EQ(bytes_read, message.size() - 5); 87 EXPECT_EQ(0, memcmp(message.data(), buffer, message.size())); 88 EXPECT_EQ(0, memcmp(buffer + message.size(), 89 backup_buffer + message.size(), 90 100 - message.size())); 91} 92 93TEST_F(JSPipeTest, JSPipeOutput) { 94 const char* message = "hello"; 95 const int message_len = strlen(message); 96 97 int bytes_written = 999; 98 HandleAttr attrs; 99 ASSERT_EQ(0, pipe_dev_->Write(attrs, message, message_len, &bytes_written)); 100 ASSERT_EQ(message_len, bytes_written); 101 102 // Verify that the correct messages was sent via PostMessage. 103 FakeMessagingInterface* iface = 104 (FakeMessagingInterface*)fs_.ppapi()->GetMessagingInterface(); 105 VarArrayInterface* array_iface = fs_.ppapi()->GetVarArrayInterface(); 106 VarInterface* var_iface = fs_.ppapi()->GetVarInterface(); 107 VarArrayBufferInterface* buffer_iface = 108 fs_.ppapi()->GetVarArrayBufferInterface(); 109 110 // Verify that exaclty one message was sent of type PP_VARTYPE_ARRAY 111 ASSERT_EQ(1, iface->messages.size()); 112 PP_Var array = iface->messages[0]; 113 ASSERT_EQ(PP_VARTYPE_ARRAY, array.type); 114 115 // Verify that the array contains two element, the prefix, 116 // and an ArrayBuffer containing the message. 117 ASSERT_EQ(2, array_iface->GetLength(array)); 118 PP_Var item0 = array_iface->Get(array, 0); 119 PP_Var item1 = array_iface->Get(array, 1); 120 ASSERT_EQ(PP_VARTYPE_STRING, item0.type); 121 ASSERT_EQ(PP_VARTYPE_ARRAY_BUFFER, item1.type); 122 uint32_t len = 0; 123 const char* item0_string = var_iface->VarToUtf8(item0, &len); 124 ASSERT_STREQ("jspipe1", std::string(item0_string, len).c_str()); 125 ASSERT_EQ(0, memcmp(message, buffer_iface->Map(item1), strlen(message))); 126 var_iface->Release(item0); 127 var_iface->Release(item1); 128} 129 130TEST_F(JSPipeTest, JSPipeOutputWithNulls) { 131 char message[20]; 132 int message_len = sizeof(message); 133 134 // Construct a 20-byte message containing the string 'hello' but with 135 // null chars on either end. 136 memset(message, 0 , message_len); 137 memcpy(message+10, "hello", 5); 138 139 int bytes_written = 999; 140 HandleAttr attrs; 141 EXPECT_EQ(0, pipe_dev_->Write(attrs, message, message_len, &bytes_written)); 142 EXPECT_EQ(message_len, bytes_written); 143 144 // Verify that the correct messages was sent via PostMessage. 145 FakeMessagingInterface* iface = 146 (FakeMessagingInterface*)fs_.ppapi()->GetMessagingInterface(); 147 VarArrayInterface* array_iface = fs_.ppapi()->GetVarArrayInterface(); 148 VarInterface* var_iface = fs_.ppapi()->GetVarInterface(); 149 VarArrayBufferInterface* buffer_iface = 150 fs_.ppapi()->GetVarArrayBufferInterface(); 151 152 // Verify that exactly one message was sent of type PP_VARTYPE_ARRAY 153 EXPECT_EQ(1, iface->messages.size()); 154 PP_Var array = iface->messages[0]; 155 ASSERT_EQ(PP_VARTYPE_ARRAY, array.type); 156 157 // Verify that the array contains two element, the prefix, 158 // and an ArrayBuffer containing the message. 159 ASSERT_EQ(2, array_iface->GetLength(array)); 160 PP_Var item0 = array_iface->Get(array, 0); 161 PP_Var item1 = array_iface->Get(array, 1); 162 ASSERT_EQ(PP_VARTYPE_STRING, item0.type); 163 ASSERT_EQ(PP_VARTYPE_ARRAY_BUFFER, item1.type); 164 uint32_t len = 0; 165 ASSERT_STREQ("jspipe1", var_iface->VarToUtf8(item0, &len)); 166 ASSERT_EQ(0, memcmp(message, buffer_iface->Map(item1), strlen(message))); 167 var_iface->Release(item0); 168 var_iface->Release(item1); 169} 170 171static int ki_ioctl_wrapper(int fd, int request, ...) { 172 va_list ap; 173 va_start(ap, request); 174 int rtn = ki_ioctl(fd, request, ap); 175 va_end(ap); 176 return rtn; 177} 178 179static int JSPipeWrite(int fd, const char* string) { 180 struct tioc_nacl_input_string input; 181 input.buffer = string; 182 input.length = strlen(input.buffer); 183 return ki_ioctl_wrapper(fd, TIOCNACLINPUT, &input); 184} 185 186// Returns: 187// 0 -> Not readable 188// 1 -> Readable 189// -1 -> Error occured 190static int IsReadable(int fd) { 191 struct timeval timeout = {0, 0}; 192 fd_set readfds; 193 fd_set errorfds; 194 FD_ZERO(&readfds); 195 FD_ZERO(&errorfds); 196 FD_SET(fd, &readfds); 197 FD_SET(fd, &errorfds); 198 int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout); 199 if (rtn == 0) 200 return 0; // not readable 201 if (rtn != 1) 202 return -1; // error 203 if (FD_ISSET(fd, &errorfds)) 204 return -2; // error 205 if (!FD_ISSET(fd, &readfds)) 206 return -3; // error 207 return 1; // readable 208} 209 210TEST_F(JSPipeTest, JSPipeSelect) { 211 struct timeval timeout; 212 fd_set readfds; 213 fd_set writefds; 214 fd_set errorfds; 215 216 int pipe_fd = ki_open("/dev/jspipe1", O_RDONLY); 217 ASSERT_GT(pipe_fd, 0) << "jspipe1 open failed: " << errno; 218 219 FD_ZERO(&readfds); 220 FD_ZERO(&errorfds); 221 FD_SET(pipe_fd, &readfds); 222 FD_SET(pipe_fd, &errorfds); 223 // 10 millisecond timeout 224 timeout.tv_sec = 0; 225 timeout.tv_usec = 10 * 1000; 226 // Should timeout when no input is available. 227 int rtn = ki_select(pipe_fd + 1, &readfds, NULL, &errorfds, &timeout); 228 ASSERT_EQ(0, rtn) << "select failed: " << rtn << " err=" << strerror(errno); 229 ASSERT_FALSE(FD_ISSET(pipe_fd, &readfds)); 230 ASSERT_FALSE(FD_ISSET(pipe_fd, &errorfds)); 231 232 FD_ZERO(&readfds); 233 FD_ZERO(&writefds); 234 FD_ZERO(&errorfds); 235 FD_SET(pipe_fd, &readfds); 236 FD_SET(pipe_fd, &writefds); 237 FD_SET(pipe_fd, &errorfds); 238 // Pipe should be writable on startup. 239 rtn = ki_select(pipe_fd + 1, &readfds, &writefds, &errorfds, NULL); 240 ASSERT_EQ(1, rtn); 241 ASSERT_TRUE(FD_ISSET(pipe_fd, &writefds)); 242 ASSERT_FALSE(FD_ISSET(pipe_fd, &readfds)); 243 ASSERT_FALSE(FD_ISSET(pipe_fd, &errorfds)); 244 245 // Send 4 bytes to the pipe 246 ASSERT_EQ(0, JSPipeWrite(pipe_fd, "test")); 247 248 // Pipe should now be readable 249 ASSERT_EQ(1, IsReadable(pipe_fd)); 250 251 ki_close(pipe_fd); 252} 253 254} 255