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