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*71e7a249SAndrew Jeffery #include "config.c"
235e7c0786SAndrew Jeffery #include "console-socket.c"
245e7c0786SAndrew Jeffery #define main __main
25c5ce2cbdSJeremy Kerr #include "console-client.c"
26c5ce2cbdSJeremy Kerr #undef read
275e7c0786SAndrew Jeffery #undef main
28c5ce2cbdSJeremy Kerr 
29c5ce2cbdSJeremy Kerr struct test {
30c5ce2cbdSJeremy Kerr 	enum esc_type	esc_type;
31c5ce2cbdSJeremy Kerr 	union {
32c5ce2cbdSJeremy Kerr 		struct ssh_esc_state ssh;
33c5ce2cbdSJeremy Kerr 		struct str_esc_state str;
34c5ce2cbdSJeremy Kerr 	} esc_state;
35c5ce2cbdSJeremy Kerr 	const char	*in[4];
36c5ce2cbdSJeremy Kerr 	int		n_in;
37c5ce2cbdSJeremy Kerr 	const char	*exp_out;
38c5ce2cbdSJeremy Kerr 	int		exp_rc;
39c5ce2cbdSJeremy Kerr };
40c5ce2cbdSJeremy Kerr 
41c5ce2cbdSJeremy Kerr struct test_ctx {
42c5ce2cbdSJeremy Kerr 	struct console_client	client;
43c5ce2cbdSJeremy Kerr 	struct test		*test;
44c5ce2cbdSJeremy Kerr 	uint8_t			out[4096];
45c5ce2cbdSJeremy Kerr 	int			cur_in;
46c5ce2cbdSJeremy Kerr 	int			cur_out;
47c5ce2cbdSJeremy Kerr };
48c5ce2cbdSJeremy Kerr 
49c5ce2cbdSJeremy Kerr 
50c5ce2cbdSJeremy Kerr struct test tests[] = {
51c5ce2cbdSJeremy Kerr 	{
52c5ce2cbdSJeremy Kerr 		/* no escape code */
53c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
54c5ce2cbdSJeremy Kerr 		.in		= {"a"},
55c5ce2cbdSJeremy Kerr 		.n_in		= 1,
56c5ce2cbdSJeremy Kerr 		.exp_out	= "a",
57c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
58c5ce2cbdSJeremy Kerr 	},
59c5ce2cbdSJeremy Kerr 	{
60c5ce2cbdSJeremy Kerr 		/* no escape code, multiple reads */
61c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
62c5ce2cbdSJeremy Kerr 		.in		= {"a", "b"},
63c5ce2cbdSJeremy Kerr 		.n_in		= 2,
64c5ce2cbdSJeremy Kerr 		.exp_out	= "ab",
65c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
66c5ce2cbdSJeremy Kerr 	},
67c5ce2cbdSJeremy Kerr 	{
68c5ce2cbdSJeremy Kerr 		/* ssh escape in one read */
69c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
70c5ce2cbdSJeremy Kerr 		.in		= {"a\r~."},
71c5ce2cbdSJeremy Kerr 		.n_in		= 1,
72c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r",
73c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
74c5ce2cbdSJeremy Kerr 	},
75c5ce2cbdSJeremy Kerr 	{
76c5ce2cbdSJeremy Kerr 		/* ssh escape, partial ~ is not output. */
77c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
78c5ce2cbdSJeremy Kerr 		.in		= {"a\r~"},
79c5ce2cbdSJeremy Kerr 		.n_in		= 1,
80c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r",
81c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
82c5ce2cbdSJeremy Kerr 	},
83c5ce2cbdSJeremy Kerr 	{
84c5ce2cbdSJeremy Kerr 		/* ssh escape split into individual reads */
85c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
86c5ce2cbdSJeremy Kerr 		.in		= {"a", "\r", "~", "."},
87c5ce2cbdSJeremy Kerr 		.n_in		= 4,
88c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r",
89c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
90c5ce2cbdSJeremy Kerr 	},
91c5ce2cbdSJeremy Kerr 	{
92c5ce2cbdSJeremy Kerr 		/* ssh escape, escaped. */
93c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
94c5ce2cbdSJeremy Kerr 		.in		= {"a\r~~."},
95c5ce2cbdSJeremy Kerr 		.n_in		= 1,
96c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r~.",
97c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
98c5ce2cbdSJeremy Kerr 	},
99c5ce2cbdSJeremy Kerr 	{
100c5ce2cbdSJeremy Kerr 		/* ssh escape, escaped ~, and not completed. */
101c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_SSH,
102c5ce2cbdSJeremy Kerr 		.in		= {"a\r~~"},
103c5ce2cbdSJeremy Kerr 		.n_in		= 1,
104c5ce2cbdSJeremy Kerr 		.exp_out	= "a\r~",
105c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
106c5ce2cbdSJeremy Kerr 	},
107c5ce2cbdSJeremy Kerr 	{
108c5ce2cbdSJeremy Kerr 		/* str escape, no match */
109c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
110c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"c" } },
111c5ce2cbdSJeremy Kerr 		.in		= {"ab"},
112c5ce2cbdSJeremy Kerr 		.n_in		= 1,
113c5ce2cbdSJeremy Kerr 		.exp_out	= "ab",
114c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
115c5ce2cbdSJeremy Kerr 	},
116c5ce2cbdSJeremy Kerr 	{
117c5ce2cbdSJeremy Kerr 		/* str escape, one byte, as one read */
118c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
119c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"b" } },
120c5ce2cbdSJeremy Kerr 		.in		= {"abc"},
121c5ce2cbdSJeremy Kerr 		.n_in		= 1,
122c5ce2cbdSJeremy Kerr 		.exp_out	= "ab",
123c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
124c5ce2cbdSJeremy Kerr 	},
125c5ce2cbdSJeremy Kerr 	{
126c5ce2cbdSJeremy Kerr 		/* str escape, multiple bytes, as one read */
127c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
128c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"bc" } },
129c5ce2cbdSJeremy Kerr 		.in		= {"abcd"},
130c5ce2cbdSJeremy Kerr 		.n_in		= 1,
131c5ce2cbdSJeremy Kerr 		.exp_out	= "abc",
132c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
133c5ce2cbdSJeremy Kerr 	},
134c5ce2cbdSJeremy Kerr 	{
135c5ce2cbdSJeremy Kerr 		/* str escape, multiple bytes, split over reads */
136c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
137c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"bc" } },
138c5ce2cbdSJeremy Kerr 		.in		= {"ab", "cd"},
139c5ce2cbdSJeremy Kerr 		.n_in		= 2,
140c5ce2cbdSJeremy Kerr 		.exp_out	= "abc",
141c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_ESC,
142c5ce2cbdSJeremy Kerr 	},
143c5ce2cbdSJeremy Kerr 	{
144c5ce2cbdSJeremy Kerr 		/* str escape, not matched due to intermediate data */
145c5ce2cbdSJeremy Kerr 		.esc_type	= ESC_TYPE_STR,
146c5ce2cbdSJeremy Kerr 		.esc_state	= { .str = { .str = (const uint8_t *)"ab" } },
147c5ce2cbdSJeremy Kerr 		.in		= {"acb"},
148c5ce2cbdSJeremy Kerr 		.n_in		= 1,
149c5ce2cbdSJeremy Kerr 		.exp_out	= "acb",
150c5ce2cbdSJeremy Kerr 		.exp_rc		= PROCESS_EXIT,
151c5ce2cbdSJeremy Kerr 	},
152c5ce2cbdSJeremy Kerr };
153c5ce2cbdSJeremy Kerr 
154c5ce2cbdSJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
155c5ce2cbdSJeremy Kerr 
156c5ce2cbdSJeremy Kerr struct test_ctx ctxs[ARRAY_SIZE(tests)];
157c5ce2cbdSJeremy Kerr 
158c5ce2cbdSJeremy Kerr int write_buf_to_fd(int fd, const uint8_t *buf, size_t len)
159c5ce2cbdSJeremy Kerr {
160c5ce2cbdSJeremy Kerr 	struct test_ctx *ctx = &ctxs[fd];
161c5ce2cbdSJeremy Kerr 
162c5ce2cbdSJeremy Kerr 	assert(ctx->cur_out + len <= sizeof(ctx->out));
163c5ce2cbdSJeremy Kerr 	memcpy(ctx->out + ctx->cur_out, buf, len);
164c5ce2cbdSJeremy Kerr 	ctx->cur_out += len;
165c5ce2cbdSJeremy Kerr 
166c5ce2cbdSJeremy Kerr 	return 0;
167c5ce2cbdSJeremy Kerr }
168c5ce2cbdSJeremy Kerr 
169c5ce2cbdSJeremy Kerr ssize_t __read(int fd, void *buf, size_t len)
170c5ce2cbdSJeremy Kerr {
171c5ce2cbdSJeremy Kerr 	struct test_ctx *ctx = &ctxs[fd];
172c5ce2cbdSJeremy Kerr 	const char *inbuf;
173c5ce2cbdSJeremy Kerr 	size_t inlen;
174c5ce2cbdSJeremy Kerr 
175c5ce2cbdSJeremy Kerr 	if (ctx->cur_in >= ctx->test->n_in)
176c5ce2cbdSJeremy Kerr 		return 0;
177c5ce2cbdSJeremy Kerr 
178c5ce2cbdSJeremy Kerr 	inbuf = ctx->test->in[ctx->cur_in];
179c5ce2cbdSJeremy Kerr 	inlen = strlen(inbuf);
180c5ce2cbdSJeremy Kerr 	assert(inlen <= len);
181c5ce2cbdSJeremy Kerr 	memcpy(buf, inbuf, inlen);
182c5ce2cbdSJeremy Kerr 	ctx->cur_in++;
183c5ce2cbdSJeremy Kerr 	return inlen;
184c5ce2cbdSJeremy Kerr }
185c5ce2cbdSJeremy Kerr 
186c5ce2cbdSJeremy Kerr void run_one_test(int idx, struct test *test, struct test_ctx *ctx)
187c5ce2cbdSJeremy Kerr {
188c5ce2cbdSJeremy Kerr 	size_t exp_out_len;
189c5ce2cbdSJeremy Kerr 	int rc;
190c5ce2cbdSJeremy Kerr 
191c5ce2cbdSJeremy Kerr 	/* we store the index into the context array as a FD, so we
192c5ce2cbdSJeremy Kerr 	 * can refer to it through the read & write callbacks.
193c5ce2cbdSJeremy Kerr 	 */
194c5ce2cbdSJeremy Kerr 	ctx->client.console_sd = idx;
195c5ce2cbdSJeremy Kerr 	ctx->client.fd_in = idx;
196c5ce2cbdSJeremy Kerr 	ctx->client.esc_type = test->esc_type;
197c5ce2cbdSJeremy Kerr 	memcpy(&ctx->client.esc_state, &test->esc_state,
198c5ce2cbdSJeremy Kerr 			sizeof(test->esc_state));
199c5ce2cbdSJeremy Kerr 	ctx->test = test;
200c5ce2cbdSJeremy Kerr 
201c5ce2cbdSJeremy Kerr 	for (;;) {
202c5ce2cbdSJeremy Kerr 		rc = process_tty(&ctx->client);
203c5ce2cbdSJeremy Kerr 		if (rc != PROCESS_OK)
204c5ce2cbdSJeremy Kerr 			break;
205c5ce2cbdSJeremy Kerr 	}
206c5ce2cbdSJeremy Kerr 
207c5ce2cbdSJeremy Kerr 	exp_out_len = strlen(test->exp_out);
208c5ce2cbdSJeremy Kerr 
209c5ce2cbdSJeremy Kerr #ifdef DEBUG
210c5ce2cbdSJeremy Kerr 	printf("got: rc %d %s(%d), exp: rc %d %s(%ld)\n",
211c5ce2cbdSJeremy Kerr 			rc, ctx->out, ctx->cur_out,
212c5ce2cbdSJeremy Kerr 			test->exp_rc, test->exp_out, exp_out_len);
213c5ce2cbdSJeremy Kerr 	fflush(stdout);
214c5ce2cbdSJeremy Kerr #endif
215c5ce2cbdSJeremy Kerr 	assert(rc == test->exp_rc);
216c5ce2cbdSJeremy Kerr 	assert(exp_out_len == ctx->cur_out);
217c5ce2cbdSJeremy Kerr 	assert(!memcmp(ctx->out, test->exp_out, exp_out_len));
218c5ce2cbdSJeremy Kerr }
219c5ce2cbdSJeremy Kerr 
220c5ce2cbdSJeremy Kerr int main(void)
221c5ce2cbdSJeremy Kerr {
222c5ce2cbdSJeremy Kerr 	int i;
223c5ce2cbdSJeremy Kerr 
224c5ce2cbdSJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(tests); i++)
225c5ce2cbdSJeremy Kerr 		run_one_test(i, &tests[i], &ctxs[i]);
226c5ce2cbdSJeremy Kerr 
227c5ce2cbdSJeremy Kerr 	return EXIT_SUCCESS;
228c5ce2cbdSJeremy Kerr }
229