Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tests / nacl_io_test / tty_test.cc
1 // Copyright 2013 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 "gtest/gtest.h"
16 #include "nacl_io/devfs/dev_fs.h"
17 #include "nacl_io/filesystem.h"
18 #include "nacl_io/ioctl.h"
19 #include "nacl_io/kernel_intercept.h"
20 #include "nacl_io/kernel_proxy.h"
21 #include "nacl_io/osdirent.h"
22
23 using namespace nacl_io;
24
25 namespace {
26
27 class TtyNodeTest : public ::testing::Test {
28  public:
29   TtyNodeTest() : fs_(&pepper_) {}
30
31   void SetUp() {
32     ASSERT_EQ(0, fs_.Access(Path("/tty"), R_OK | W_OK));
33     ASSERT_EQ(EACCES, fs_.Access(Path("/tty"), X_OK));
34     ASSERT_EQ(0, fs_.Open(Path("/tty"), O_RDWR, &dev_tty_));
35     ASSERT_NE(NULL_NODE, dev_tty_.get());
36   }
37
38  protected:
39   FakePepperInterface pepper_;
40   DevFsForTesting fs_;
41   ScopedNode dev_tty_;
42 };
43
44 class TtyTest : public ::testing::Test {
45  public:
46   void SetUp() {
47     ASSERT_EQ(0, ki_push_state_for_testing());
48     ASSERT_EQ(0, ki_init(&kp_));
49   }
50
51   void TearDown() {
52     ki_uninit();
53   }
54
55  protected:
56   KernelProxy kp_;
57 };
58
59 TEST_F(TtyNodeTest, InvalidIoctl) {
60   // 123 is not a valid ioctl request.
61   EXPECT_EQ(EINVAL, dev_tty_->Ioctl(123));
62 }
63
64 TEST_F(TtyNodeTest, TtyInput) {
65   // Now let's try sending some data over.
66   // First we create the message.
67   std::string message("hello, how are you?\n");
68   struct tioc_nacl_input_string packaged_message;
69   packaged_message.length = message.size();
70   packaged_message.buffer = message.data();
71
72   // Now we make buffer we'll read into.
73   // We fill the buffer and a backup buffer with arbitrary data
74   // and compare them after reading to make sure read doesn't
75   // clobber parts of the buffer it shouldn't.
76   int bytes_read;
77   char buffer[100];
78   char backup_buffer[100];
79   memset(buffer, 'a', 100);
80   memset(backup_buffer, 'a', 100);
81
82   // Now we actually send the data
83   EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLINPUT, &packaged_message));
84
85   // We read a small chunk first to ensure it doesn't give us
86   // more than we ask for.
87   HandleAttr attrs;
88   EXPECT_EQ(0, dev_tty_->Read(attrs, buffer, 5, &bytes_read));
89   EXPECT_EQ(5, bytes_read);
90   EXPECT_EQ(0, memcmp(message.data(), buffer, 5));
91   EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
92
93   // Now we ask for more data than is left in the tty, to ensure
94   // it doesn't give us more than is there.
95   EXPECT_EQ(0, dev_tty_->Read(attrs, buffer + 5, 95, &bytes_read));
96   EXPECT_EQ(bytes_read, message.size() - 5);
97   EXPECT_EQ(0, memcmp(message.data(), buffer, message.size()));
98   EXPECT_EQ(0, memcmp(buffer + message.size(),
99                       backup_buffer + message.size(),
100                       100 - message.size()));
101 }
102
103 struct user_data_t {
104   const char* output_buf;
105   size_t output_count;
106 };
107
108 static ssize_t output_handler(const char* buf, size_t count, void* data) {
109   user_data_t* user_data = static_cast<user_data_t*>(data);
110   user_data->output_buf = buf;
111   user_data->output_count = count;
112   return count;
113 }
114
115 TEST_F(TtyNodeTest, TtyOutput) {
116   // When no handler is registered then all writes should return EIO
117   int bytes_written = 10;
118   const char* message = "hello\n";
119   int message_len = strlen(message);
120   HandleAttr attrs;
121   EXPECT_EQ(EIO, dev_tty_->Write(attrs, message, message_len, &bytes_written));
122
123   // Setup output handler with user_data to record calls.
124   user_data_t user_data;
125   user_data.output_buf = NULL;
126   user_data.output_count = 0;
127
128   tioc_nacl_output handler;
129   handler.handler = output_handler;
130   handler.user_data = &user_data;
131
132   EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLOUTPUT, &handler));
133
134   EXPECT_EQ(0, dev_tty_->Write(attrs, message, message_len, &bytes_written));
135   EXPECT_EQ(message_len, bytes_written);
136   EXPECT_EQ(message_len, user_data.output_count);
137   EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len));
138 }
139
140 static int ki_ioctl_wrapper(int fd, int request, ...) {
141   va_list ap;
142   va_start(ap, request);
143   int rtn = ki_ioctl(fd, request, ap);
144   va_end(ap);
145   return rtn;
146 }
147
148 static int TtyWrite(int fd, const char* string) {
149   struct tioc_nacl_input_string input;
150   input.buffer = string;
151   input.length = strlen(input.buffer);
152   return ki_ioctl_wrapper(fd, TIOCNACLINPUT, &input);
153 }
154
155 // Returns:
156 //   0 -> Not readable
157 //   1 -> Readable
158 //  -1 -> Error occured
159 static int IsReadable(int fd) {
160   struct timeval timeout = {0, 0};
161   fd_set readfds;
162   fd_set errorfds;
163   FD_ZERO(&readfds);
164   FD_ZERO(&errorfds);
165   FD_SET(fd, &readfds);
166   FD_SET(fd, &errorfds);
167   int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout);
168   if (rtn == 0)
169     return 0;  // not readable
170   if (rtn != 1)
171     return -1;  // error
172   if (FD_ISSET(fd, &errorfds))
173     return -2;  // error
174   if (!FD_ISSET(fd, &readfds))
175     return -3;  // error
176   return 1;     // readable
177 }
178
179 TEST_F(TtyTest, TtySelect) {
180   struct timeval timeout;
181   fd_set readfds;
182   fd_set writefds;
183   fd_set errorfds;
184
185   int tty_fd = ki_open("/dev/tty", O_RDONLY);
186   ASSERT_GT(tty_fd, 0) << "tty open failed: " << errno;
187
188   FD_ZERO(&readfds);
189   FD_ZERO(&errorfds);
190   FD_SET(tty_fd, &readfds);
191   FD_SET(tty_fd, &errorfds);
192   // 10 millisecond timeout
193   timeout.tv_sec = 0;
194   timeout.tv_usec = 10 * 1000;
195   // Should timeout when no input is available.
196   int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
197   ASSERT_EQ(0, rtn) << "select failed: " << rtn << " err=" << strerror(errno);
198   ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
199   ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
200
201   FD_ZERO(&readfds);
202   FD_ZERO(&writefds);
203   FD_ZERO(&errorfds);
204   FD_SET(tty_fd, &readfds);
205   FD_SET(tty_fd, &writefds);
206   FD_SET(tty_fd, &errorfds);
207   // TTY should be writable on startup.
208   rtn = ki_select(tty_fd + 1, &readfds, &writefds, &errorfds, NULL);
209   ASSERT_EQ(1, rtn);
210   ASSERT_TRUE(FD_ISSET(tty_fd, &writefds));
211   ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
212   ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
213
214   // Send 4 bytes to TTY input
215   ASSERT_EQ(0, TtyWrite(tty_fd, "input:test"));
216
217   // TTY should not be readable until newline in written
218   ASSERT_EQ(IsReadable(tty_fd), 0);
219   ASSERT_EQ(0, TtyWrite(tty_fd, "input:\n"));
220
221   // TTY should now be readable
222   ASSERT_EQ(1, IsReadable(tty_fd));
223
224   ki_close(tty_fd);
225 }
226
227 TEST_F(TtyTest, TtyICANON) {
228   int tty_fd = ki_open("/dev/tty", O_RDONLY);
229
230   ASSERT_EQ(0, IsReadable(tty_fd));
231
232   struct termios tattr;
233   ki_tcgetattr(tty_fd, &tattr);
234   tattr.c_lflag &= ~(ICANON | ECHO); /* Clear ICANON and ECHO. */
235   ki_tcsetattr(tty_fd, TCSAFLUSH, &tattr);
236
237   ASSERT_EQ(0, IsReadable(tty_fd));
238
239   // Set some bytes to the TTY, not including newline
240   ASSERT_EQ(0, TtyWrite(tty_fd, "a"));
241
242   // Since we are not in canonical mode the bytes should be
243   // immediately readable.
244   ASSERT_EQ(1, IsReadable(tty_fd));
245
246   // Read byte from tty.
247   char c;
248   ASSERT_EQ(1, ki_read(tty_fd, &c, 1));
249   ASSERT_EQ('a', c);
250
251   ASSERT_EQ(0, IsReadable(tty_fd));
252 }
253
254 static int g_received_signal;
255
256 static void sighandler(int sig) { g_received_signal = sig; }
257
258 TEST_F(TtyTest, WindowSize) {
259   // Get current window size
260   struct winsize old_winsize = {0};
261   int tty_fd = ki_open("/dev/tty", O_RDONLY);
262   ASSERT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCGWINSZ, &old_winsize));
263
264   // Install signal handler
265   sighandler_t new_handler = sighandler;
266   sighandler_t old_handler = ki_signal(SIGWINCH, new_handler);
267   ASSERT_NE(SIG_ERR, old_handler) << "signal return error: " << errno;
268
269   g_received_signal = 0;
270
271   // Set a new windows size
272   struct winsize winsize;
273   winsize.ws_col = 100;
274   winsize.ws_row = 200;
275   EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCSWINSZ, &winsize));
276   EXPECT_EQ(SIGWINCH, g_received_signal);
277
278   // Restore old signal handler
279   EXPECT_EQ(new_handler, ki_signal(SIGWINCH, old_handler));
280
281   // Verify new window size can be queried correctly.
282   winsize.ws_col = 0;
283   winsize.ws_row = 0;
284   EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCGWINSZ, &winsize));
285   EXPECT_EQ(100, winsize.ws_col);
286   EXPECT_EQ(200, winsize.ws_row);
287
288   // Restore original windows size.
289   EXPECT_EQ(0, ki_ioctl_wrapper(tty_fd, TIOCSWINSZ, &old_winsize));
290 }
291
292 /*
293  * Sleep for 50ms then send a resize event to /dev/tty.
294  */
295 static void* resize_thread_main(void* arg) {
296   usleep(50 * 1000);
297
298   int* tty_fd = static_cast<int*>(arg);
299   struct winsize winsize;
300   winsize.ws_col = 100;
301   winsize.ws_row = 200;
302   ki_ioctl_wrapper(*tty_fd, TIOCSWINSZ, &winsize);
303   return NULL;
304 }
305
306 TEST_F(TtyTest, ResizeDuringSelect) {
307   // Test that a window resize during a call
308   // to select(3) will cause it to fail with EINTR.
309   int tty_fd = ki_open("/dev/tty", O_RDONLY);
310
311   fd_set readfds;
312   fd_set errorfds;
313   FD_ZERO(&readfds);
314   FD_ZERO(&errorfds);
315   FD_SET(tty_fd, &readfds);
316   FD_SET(tty_fd, &errorfds);
317
318   pthread_t resize_thread;
319   pthread_create(&resize_thread, NULL, resize_thread_main, &tty_fd);
320
321   struct timeval timeout;
322   timeout.tv_sec = 20;
323   timeout.tv_usec = 0;
324
325   // TTY should not be readable either before or after the
326   // call to select(3).
327   ASSERT_EQ(0, IsReadable(tty_fd));
328
329   int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
330   pthread_join(resize_thread, NULL);
331   ASSERT_EQ(-1, rtn);
332   ASSERT_EQ(EINTR, errno);
333   ASSERT_EQ(0, IsReadable(tty_fd));
334 }
335
336 /*
337  * Sleep for 50ms then send some input to the /dev/tty.
338  */
339 static void* input_thread_main(void* arg) {
340   usleep(50 * 1000);
341
342   int fd = ki_open("/dev/tty", O_RDONLY);
343   TtyWrite(fd, "test\n");
344   return NULL;
345 }
346
347 TEST_F(TtyTest, InputDuringSelect) {
348   // Test that input which occurs while in select causes
349   // select to return.
350   int tty_fd = ki_open("/dev/tty", O_RDONLY);
351
352   fd_set readfds;
353   fd_set errorfds;
354   FD_ZERO(&readfds);
355   FD_ZERO(&errorfds);
356   FD_SET(tty_fd, &readfds);
357   FD_SET(tty_fd, &errorfds);
358
359   pthread_t resize_thread;
360   pthread_create(&resize_thread, NULL, input_thread_main, NULL);
361
362   struct timeval timeout;
363   timeout.tv_sec = 20;
364   timeout.tv_usec = 0;
365
366   int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
367   pthread_join(resize_thread, NULL);
368
369   ASSERT_EQ(1, rtn);
370 }
371 }