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