1c5ce2cbdSJeremy Kerr /**
2c5ce2cbdSJeremy Kerr  * Copyright © 2019 IBM Corporation
3c5ce2cbdSJeremy Kerr  *
4c5ce2cbdSJeremy Kerr  * Licensed under the Apache License, Version 2.0 (the "License");
5c5ce2cbdSJeremy Kerr  * you may not use this file except in compliance with the License.
6c5ce2cbdSJeremy Kerr  * You may obtain a copy of the License at
7c5ce2cbdSJeremy Kerr  *
8c5ce2cbdSJeremy Kerr  *     http://www.apache.org/licenses/LICENSE-2.0
9c5ce2cbdSJeremy Kerr  *
10c5ce2cbdSJeremy Kerr  * Unless required by applicable law or agreed to in writing, software
11c5ce2cbdSJeremy Kerr  * distributed under the License is distributed on an "AS IS" BASIS,
12c5ce2cbdSJeremy Kerr  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c5ce2cbdSJeremy Kerr  * See the License for the specific language governing permissions and
14c5ce2cbdSJeremy Kerr  * limitations under the License.
15c5ce2cbdSJeremy Kerr  */
16c5ce2cbdSJeremy Kerr 
17c5ce2cbdSJeremy Kerr #include <assert.h>
18c5ce2cbdSJeremy Kerr #include <stdint.h>
19c5ce2cbdSJeremy Kerr #include <stdio.h>
20c5ce2cbdSJeremy Kerr 
21c5ce2cbdSJeremy Kerr #define read __read
22*5e7c0786SAndrew Jeffery #include "console-socket.c"
23*5e7c0786SAndrew Jeffery #define main __main
24c5ce2cbdSJeremy Kerr #include "console-client.c"
25c5ce2cbdSJeremy Kerr #undef read
26*5e7c0786SAndrew Jeffery #undef main
27c5ce2cbdSJeremy Kerr 
28c5ce2cbdSJeremy Kerr struct test {
29c5ce2cbdSJeremy Kerr 	enum esc_type	esc_type;
30c5ce2cbdSJeremy Kerr 	union {
31c5ce2cbdSJeremy Kerr 		struct ssh_esc_state ssh;
32c5ce2cbdSJeremy Kerr 		struct str_esc_state str;
33c5ce2cbdSJeremy Kerr 	} esc_state;
34c5ce2cbdSJeremy Kerr 	const char	*in[4];
35c5ce2cbdSJeremy Kerr 	int		n_in;
36c5ce2cbdSJeremy Kerr 	const char	*exp_out;
37c5ce2cbdSJeremy Kerr 	int		exp_rc;
38c5ce2cbdSJeremy Kerr };
39c5ce2cbdSJeremy Kerr 
40c5ce2cbdSJeremy Kerr struct test_ctx {
41c5ce2cbdSJeremy Kerr 	struct console_client	client;
42c5ce2cbdSJeremy Kerr 	struct test		*test;
43c5ce2cbdSJeremy Kerr 	uint8_t			out[4096];
44c5ce2cbdSJeremy Kerr 	int			cur_in;
45c5ce2cbdSJeremy Kerr 	int			cur_out;
46c5ce2cbdSJeremy Kerr };
47c5ce2cbdSJeremy Kerr 
48c5ce2cbdSJeremy Kerr 
49c5ce2cbdSJeremy Kerr struct test tests[] = {
50c5ce2cbdSJeremy Kerr 	{
51c5ce2cbdSJeremy Kerr 		/* no escape code */
52c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
53c5ce2cbdSJeremy Kerr 		.in		= {"a"},
54c5ce2cbdSJeremy Kerr 		.n_in		= 1,
55c5ce2cbdSJeremy Kerr 		.exp_out	= "a",
56c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
57c5ce2cbdSJeremy Kerr 	},
58c5ce2cbdSJeremy Kerr 	{
59c5ce2cbdSJeremy Kerr 		/* no escape code, multiple reads */
60c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
61c5ce2cbdSJeremy Kerr 		.in		= {"a", "b"},
62c5ce2cbdSJeremy Kerr 		.n_in		= 2,
63c5ce2cbdSJeremy Kerr 		.exp_out	= "ab",
64c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
65c5ce2cbdSJeremy Kerr 	},
66c5ce2cbdSJeremy Kerr 	{
67c5ce2cbdSJeremy Kerr 		/* ssh escape in one read */
68c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
69c5ce2cbdSJeremy Kerr 		.in		= {"a\r~."},
70c5ce2cbdSJeremy Kerr 		.n_in		= 1,
71c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r",
72c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
73c5ce2cbdSJeremy Kerr 	},
74c5ce2cbdSJeremy Kerr 	{
75c5ce2cbdSJeremy Kerr 		/* ssh escape, partial ~ is not output. */
76c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
77c5ce2cbdSJeremy Kerr 		.in		= {"a\r~"},
78c5ce2cbdSJeremy Kerr 		.n_in		= 1,
79c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r",
80c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
81c5ce2cbdSJeremy Kerr 	},
82c5ce2cbdSJeremy Kerr 	{
83c5ce2cbdSJeremy Kerr 		/* ssh escape split into individual reads */
84c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
85c5ce2cbdSJeremy Kerr 		.in		= {"a", "\r", "~", "."},
86c5ce2cbdSJeremy Kerr 		.n_in		= 4,
87c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r",
88c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
89c5ce2cbdSJeremy Kerr 	},
90c5ce2cbdSJeremy Kerr 	{
91c5ce2cbdSJeremy Kerr 		/* ssh escape, escaped. */
92c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
93c5ce2cbdSJeremy Kerr 		.in		= {"a\r~~."},
94c5ce2cbdSJeremy Kerr 		.n_in		= 1,
95c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r~.",
96c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
97c5ce2cbdSJeremy Kerr 	},
98c5ce2cbdSJeremy Kerr 	{
99c5ce2cbdSJeremy Kerr 		/* ssh escape, escaped ~, and not completed. */
100c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
101c5ce2cbdSJeremy Kerr 		.in		= {"a\r~~"},
102c5ce2cbdSJeremy Kerr 		.n_in		= 1,
103c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r~",
104c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
105c5ce2cbdSJeremy Kerr 	},
106c5ce2cbdSJeremy Kerr 	{
107c5ce2cbdSJeremy Kerr 		/* str escape, no match */
108c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
109c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"c" } },
110c5ce2cbdSJeremy Kerr 		.in		= {"ab"},
111c5ce2cbdSJeremy Kerr 		.n_in		= 1,
112c5ce2cbdSJeremy Kerr 		.exp_out	= "ab",
113c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
114c5ce2cbdSJeremy Kerr 	},
115c5ce2cbdSJeremy Kerr 	{
116c5ce2cbdSJeremy Kerr 		/* str escape, one byte, as one read */
117c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
118c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"b" } },
119c5ce2cbdSJeremy Kerr 		.in		= {"abc"},
120c5ce2cbdSJeremy Kerr 		.n_in		= 1,
121c5ce2cbdSJeremy Kerr 		.exp_out	= "ab",
122c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
123c5ce2cbdSJeremy Kerr 	},
124c5ce2cbdSJeremy Kerr 	{
125c5ce2cbdSJeremy Kerr 		/* str escape, multiple bytes, as one read */
126c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
127c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"bc" } },
128c5ce2cbdSJeremy Kerr 		.in		= {"abcd"},
129c5ce2cbdSJeremy Kerr 		.n_in		= 1,
130c5ce2cbdSJeremy Kerr 		.exp_out	= "abc",
131c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
132c5ce2cbdSJeremy Kerr 	},
133c5ce2cbdSJeremy Kerr 	{
134c5ce2cbdSJeremy Kerr 		/* str escape, multiple bytes, split over reads */
135c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
136c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"bc" } },
137c5ce2cbdSJeremy Kerr 		.in		= {"ab", "cd"},
138c5ce2cbdSJeremy Kerr 		.n_in		= 2,
139c5ce2cbdSJeremy Kerr 		.exp_out	= "abc",
140c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
141c5ce2cbdSJeremy Kerr 	},
142c5ce2cbdSJeremy Kerr 	{
143c5ce2cbdSJeremy Kerr 		/* str escape, not matched due to intermediate data */
144c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
145c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"ab" } },
146c5ce2cbdSJeremy Kerr 		.in		= {"acb"},
147c5ce2cbdSJeremy Kerr 		.n_in		= 1,
148c5ce2cbdSJeremy Kerr 		.exp_out	= "acb",
149c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
150c5ce2cbdSJeremy Kerr 	},
151c5ce2cbdSJeremy Kerr };
152c5ce2cbdSJeremy Kerr 
153c5ce2cbdSJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
154c5ce2cbdSJeremy Kerr 
155c5ce2cbdSJeremy Kerr struct test_ctx ctxs[ARRAY_SIZE(tests)];
156c5ce2cbdSJeremy Kerr 
157c5ce2cbdSJeremy Kerr int write_buf_to_fd(int fd, const uint8_t *buf, size_t len)
158c5ce2cbdSJeremy Kerr {
159c5ce2cbdSJeremy Kerr 	struct test_ctx *ctx = &ctxs[fd];
160c5ce2cbdSJeremy Kerr 
161c5ce2cbdSJeremy Kerr 	assert(ctx->cur_out + len <= sizeof(ctx->out));
162c5ce2cbdSJeremy Kerr 	memcpy(ctx->out + ctx->cur_out, buf, len);
163c5ce2cbdSJeremy Kerr 	ctx->cur_out += len;
164c5ce2cbdSJeremy Kerr 
165c5ce2cbdSJeremy Kerr 	return 0;
166c5ce2cbdSJeremy Kerr }
167c5ce2cbdSJeremy Kerr 
168c5ce2cbdSJeremy Kerr ssize_t __read(int fd, void *buf, size_t len)
169c5ce2cbdSJeremy Kerr {
170c5ce2cbdSJeremy Kerr 	struct test_ctx *ctx = &ctxs[fd];
171c5ce2cbdSJeremy Kerr 	const char *inbuf;
172c5ce2cbdSJeremy Kerr 	size_t inlen;
173c5ce2cbdSJeremy Kerr 
174c5ce2cbdSJeremy Kerr 	if (ctx->cur_in >= ctx->test->n_in)
175c5ce2cbdSJeremy Kerr 		return 0;
176c5ce2cbdSJeremy Kerr 
177c5ce2cbdSJeremy Kerr 	inbuf = ctx->test->in[ctx->cur_in];
178c5ce2cbdSJeremy Kerr 	inlen = strlen(inbuf);
179c5ce2cbdSJeremy Kerr 	assert(inlen <= len);
180c5ce2cbdSJeremy Kerr 	memcpy(buf, inbuf, inlen);
181c5ce2cbdSJeremy Kerr 	ctx->cur_in++;
182c5ce2cbdSJeremy Kerr 	return inlen;
183c5ce2cbdSJeremy Kerr }
184c5ce2cbdSJeremy Kerr 
185c5ce2cbdSJeremy Kerr void run_one_test(int idx, struct test *test, struct test_ctx *ctx)
186c5ce2cbdSJeremy Kerr {
187c5ce2cbdSJeremy Kerr 	size_t exp_out_len;
188c5ce2cbdSJeremy Kerr 	int rc;
189c5ce2cbdSJeremy Kerr 
190c5ce2cbdSJeremy Kerr 	/* we store the index into the context array as a FD, so we
191c5ce2cbdSJeremy Kerr 	 * can refer to it through the read & write callbacks.
192c5ce2cbdSJeremy Kerr 	 */
193c5ce2cbdSJeremy Kerr 	ctx->client.console_sd = idx;
194c5ce2cbdSJeremy Kerr 	ctx->client.fd_in = idx;
195c5ce2cbdSJeremy Kerr 	ctx->client.esc_type = test->esc_type;
196c5ce2cbdSJeremy Kerr 	memcpy(&ctx->client.esc_state, &test->esc_state,
197c5ce2cbdSJeremy Kerr 			sizeof(test->esc_state));
198c5ce2cbdSJeremy Kerr 	ctx->test = test;
199c5ce2cbdSJeremy Kerr 
200c5ce2cbdSJeremy Kerr 	for (;;) {
201c5ce2cbdSJeremy Kerr 		rc = process_tty(&ctx->client);
202c5ce2cbdSJeremy Kerr 		if (rc != PROCESS_OK)
203c5ce2cbdSJeremy Kerr 			break;
204c5ce2cbdSJeremy Kerr 	}
205c5ce2cbdSJeremy Kerr 
206c5ce2cbdSJeremy Kerr 	exp_out_len = strlen(test->exp_out);
207c5ce2cbdSJeremy Kerr 
208c5ce2cbdSJeremy Kerr #ifdef DEBUG
209c5ce2cbdSJeremy Kerr 	printf("got: rc %d %s(%d), exp: rc %d %s(%ld)\n",
210c5ce2cbdSJeremy Kerr 			rc, ctx->out, ctx->cur_out,
211c5ce2cbdSJeremy Kerr 			test->exp_rc, test->exp_out, exp_out_len);
212c5ce2cbdSJeremy Kerr 	fflush(stdout);
213c5ce2cbdSJeremy Kerr #endif
214c5ce2cbdSJeremy Kerr 	assert(rc == test->exp_rc);
215c5ce2cbdSJeremy Kerr 	assert(exp_out_len == ctx->cur_out);
216c5ce2cbdSJeremy Kerr 	assert(!memcmp(ctx->out, test->exp_out, exp_out_len));
217c5ce2cbdSJeremy Kerr }
218c5ce2cbdSJeremy Kerr 
219c5ce2cbdSJeremy Kerr int main(void)
220c5ce2cbdSJeremy Kerr {
221c5ce2cbdSJeremy Kerr 	int i;
222c5ce2cbdSJeremy Kerr 
223c5ce2cbdSJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(tests); i++)
224c5ce2cbdSJeremy Kerr 		run_one_test(i, &tests[i], &ctxs[i]);
225c5ce2cbdSJeremy Kerr 
226c5ce2cbdSJeremy Kerr 	return EXIT_SUCCESS;
227c5ce2cbdSJeremy Kerr }
228