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