From 0b73e8b0f3c1df431ce242046a443bfca20e14cf Mon Sep 17 00:00:00 2001 From: qiurui Date: Mon, 13 May 2024 01:27:53 +0800 Subject: [PATCH] add tcp establish check --- test/C/hid_gadget_test_select-keeplive.c | 446 +++++++++++++++++++++++ test/C/hid_gadget_test_select.c | 17 +- usr/bin/hid_gadget_test_select-keeplive | Bin 0 -> 18040 bytes usr/bin/hid_gadget_test_select-tcpinfo | Bin 0 -> 17992 bytes 4 files changed, 462 insertions(+), 1 deletion(-) create mode 100755 test/C/hid_gadget_test_select-keeplive.c create mode 100755 usr/bin/hid_gadget_test_select-keeplive create mode 100755 usr/bin/hid_gadget_test_select-tcpinfo diff --git a/test/C/hid_gadget_test_select-keeplive.c b/test/C/hid_gadget_test_select-keeplive.c new file mode 100755 index 0000000..30608e7 --- /dev/null +++ b/test/C/hid_gadget_test_select-keeplive.c @@ -0,0 +1,446 @@ + /* hid_gadget_test */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIZE 1024 + +struct options { + const char *opt; + unsigned char val; +}; + +static struct options kmod[] = { + {.opt = "--left-ctrl", .val = 0x01}, + {.opt = "--right-ctrl", .val = 0x10}, + {.opt = "--left-shift", .val = 0x02}, + {.opt = "--right-shift", .val = 0x20}, + {.opt = "--left-alt", .val = 0x04}, + {.opt = "--right-alt", .val = 0x40}, + {.opt = "--left-meta", .val = 0x08}, + {.opt = "--right-meta", .val = 0x80}, + {.opt = NULL} +}; + +static struct options kval[] = { + {.opt = "--return", .val = 0x28}, + {.opt = "--esc", .val = 0x29}, + {.opt = "--bckspc", .val = 0x2a}, + {.opt = "--tab", .val = 0x2b}, + {.opt = "--spacebar", .val = 0x2c}, + {.opt = "---", .val = 0x2d}, + {.opt = "--=", .val = 0x2e}, + {.opt = "--[", .val = 0x2f}, + {.opt = "--]", .val = 0x30}, + {.opt = "--fx", .val = 0x31}, + {.opt = "--;", .val = 0x33}, + {.opt = "--'", .val = 0x34}, + {.opt = "--`", .val = 0x35}, + {.opt = "--,", .val = 0x36}, + {.opt = "--.", .val = 0x37}, + {.opt = "--/", .val = 0x38}, + {.opt = "--caps-lock", .val = 0x39}, + {.opt = "--f1", .val = 0x3a}, + {.opt = "--f2", .val = 0x3b}, + {.opt = "--f3", .val = 0x3c}, + {.opt = "--f4", .val = 0x3d}, + {.opt = "--f5", .val = 0x3e}, + {.opt = "--f6", .val = 0x3f}, + {.opt = "--f7", .val = 0x40}, + {.opt = "--f8", .val = 0x41}, + {.opt = "--f9", .val = 0x42}, + {.opt = "--f10", .val = 0x43}, + {.opt = "--f11", .val = 0x44}, + {.opt = "--f12", .val = 0x45}, + {.opt = "--insert", .val = 0x49}, + {.opt = "--home", .val = 0x4a}, + {.opt = "--pageup", .val = 0x4b}, + {.opt = "--del", .val = 0x4c}, + {.opt = "--end", .val = 0x4d}, + {.opt = "--pagedown", .val = 0x4e}, + {.opt = "--right", .val = 0x4f}, + {.opt = "--left", .val = 0x50}, + {.opt = "--down", .val = 0x51}, + {.opt = "--kp-enter", .val = 0x58}, + {.opt = "--up", .val = 0x52}, + {.opt = "--num-lock", .val = 0x53}, + {.opt = "--1", .val = 0x1e}, + {.opt = "--2", .val = 0x1f}, + {.opt = "--3", .val = 0x20}, + {.opt = "--4", .val = 0x21}, + {.opt = "--5", .val = 0x22}, + {.opt = "--6", .val = 0x23}, + {.opt = "--7", .val = 0x24}, + {.opt = "--8", .val = 0x25}, + {.opt = "--9", .val = 0x26}, + {.opt = "--0", .val = 0x27}, + {.opt = NULL} +}; + +int keyboard_fill_report(char report[8], char buf[SIZE], int *hold) +{ + char *tok = strtok(buf, " "); + int key = 0; + int i = 0; + + for (; tok != NULL; tok = strtok(NULL, " ")) { + + if (strcmp(tok, "--quit") == 0) + return -1; + + if (strcmp(tok, "--hold") == 0) { + *hold = 1; + continue; + } + + if (key < 6) { + for (i = 0; kval[i].opt != NULL; i++) + if (strcmp(tok, kval[i].opt) == 0) { + report[2 + key++] = kval[i].val; + break; + } + if (kval[i].opt != NULL) + continue; + } + + if (key < 6) + if (islower(tok[0])) { + report[2 + key++] = (tok[0] - ('a' - 0x04)); + continue; + } + + for (i = 0; kmod[i].opt != NULL; i++) + if (strcmp(tok, kmod[i].opt) == 0) { + report[0] = report[0] | kmod[i].val; + break; + } + if (kmod[i].opt != NULL) + continue; + + if (key < 6) + fprintf(stderr, "unknown option: %s\n", tok); + } + return 8; +} + +static struct options mmod[] = { + {.opt = "--b1", .val = 0x01}, + {.opt = "--b2", .val = 0x02}, + {.opt = "--b3", .val = 0x04}, + {.opt = NULL} +}; + +int mouse_fill_report(char report[8], char buf[SIZE], int *hold) +{ + char *tok = strtok(buf, " "); + int mvt = 0; + int i = 0; + for (; tok != NULL; tok = strtok(NULL, " ")) { + + if (strcmp(tok, "--quit") == 0) + return -1; + + if (strcmp(tok, "--hold") == 0) { + *hold = 1; + continue; + } + + for (i = 0; mmod[i].opt != NULL; i++) + if (strcmp(tok, mmod[i].opt) == 0) { + report[0] = report[0] | mmod[i].val; + break; + } + if (mmod[i].opt != NULL) + continue; + + if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) { + errno = 0; + report[1 + mvt++] = (char)strtol(tok, NULL, 0); + if (errno != 0) { + fprintf(stderr, "Bad value:'%s'\n", tok); + report[1 + mvt--] = 0; + } + continue; + } + + fprintf(stderr, "unknown option: %s\n", tok); + } + return 3; +} + +static struct options jmod[] = { + {.opt = "--b1", .val = 0x10}, + {.opt = "--b2", .val = 0x20}, + {.opt = "--b3", .val = 0x40}, + {.opt = "--b4", .val = 0x80}, + {.opt = "--hat1", .val = 0x00}, + {.opt = "--hat2", .val = 0x01}, + {.opt = "--hat3", .val = 0x02}, + {.opt = "--hat4", .val = 0x03}, + {.opt = "--hatneutral", .val = 0x04}, + {.opt = NULL} +}; + +int joystick_fill_report(char report[8], char buf[SIZE], int *hold) +{ + char *tok = strtok(buf, " "); + int mvt = 0; + int i = 0; + + *hold = 1; + + /* set default hat position: neutral */ + report[3] = 0x04; + + for (; tok != NULL; tok = strtok(NULL, " ")) { + + if (strcmp(tok, "--quit") == 0) + return -1; + + for (i = 0; jmod[i].opt != NULL; i++) + if (strcmp(tok, jmod[i].opt) == 0) { + report[3] = (report[3] & 0xF0) | jmod[i].val; + break; + } + if (jmod[i].opt != NULL) + continue; + + if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) { + errno = 0; + report[mvt++] = (char)strtol(tok, NULL, 0); + if (errno != 0) { + fprintf(stderr, "Bad value:'%s'\n", tok); + report[mvt--] = 0; + } + continue; + } + + fprintf(stderr, "unknown option: %s\n", tok); + } + return 4; +} + +void print_options(char c) +{ + int i = 0; + + if (c == 'k') { + printf(" keyboard options:\n" + " --hold\n"); + for (i = 0; kmod[i].opt != NULL; i++) + printf("\t\t%s\n", kmod[i].opt); + printf("\n keyboard values:\n" + " [a-z] or\n"); + for (i = 0; kval[i].opt != NULL; i++) + printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : ""); + printf("\n"); + } else if (c == 'm') { + printf(" mouse options:\n" + " --hold\n"); + for (i = 0; mmod[i].opt != NULL; i++) + printf("\t\t%s\n", mmod[i].opt); + printf("\n mouse values:\n" + " Two signed numbers\n" + "--quit to close\n"); + } else { + printf(" joystick options:\n"); + for (i = 0; jmod[i].opt != NULL; i++) + printf("\t\t%s\n", jmod[i].opt); + printf("\n joystick values:\n" + " three signed numbers\n" + "--quit to close\n"); + } +} + +int main(int argc, const char *argv[]) +{ + char *ip = "0.0.0.0"; + int port = 50009; + int e; + + int server_fd, client_fd; + struct sockaddr_in server_addr, client_addr; + char buffer[SIZE]; + + const char *filename = NULL; + int fd = 0; + char buf[SIZE]; + int cmd_len; + char report[8]; + int to_send = 8; + int hold = 0; + fd_set rfds; + int retval, i; + + if (argc < 3) { + fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n", + argv[0]); + return 1; + } + + if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j') + return 2; + + filename = argv[1]; + + + server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(server_fd<0) + { + perror("[-]Error in socket"); + exit(1); + } + printf("[+]Server socket created. \n"); + + /* Set the option active */ + int optval = 1; + socklen_t optlen = sizeof(optval); + + if(setsockopt(server_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { + perror("[-]Error in TCP_KEEPCNT"); + exit(1); + } + printf("SO_KEEPALIVE set on socket\n"); + + /* Check the status again */ + if(getsockopt(server_fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, &optlen) < 0) { + perror("[-]Error in TCP_KEEPCNT"); + exit(1); + } + printf("TCP_KEEPIDLE is %d\n", optval ); + /* Check the status again */ + if(getsockopt(server_fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, &optlen) < 0) { + perror("[-]Error in TCP_KEEPCNT"); + exit(1); + } + printf("TCP_KEEPCNT is %d\n", optval); + + /* Check the status again */ + if(getsockopt(server_fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, &optlen) < 0) { + perror("getsockopt()"); + close(server_fd); + exit(EXIT_FAILURE); + } + printf("TCP_KEEPINTVL is %d\n", optval ); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = inet_addr(ip); + + e = bind(server_fd,(struct sockaddr*)&server_addr, sizeof(server_addr)); + if(e<0) + { + perror("[-]Error in Binding"); + exit(1); + } + printf("[+]Binding Successfull.\n"); + + e = listen(server_fd, 10); + if(e==0) + { + printf("[+]Listening...\n"); + } + else + { + perror("[-]Error in Binding"); + exit(1); + } + socklen_t addr_size = sizeof(client_addr); + client_fd = accept(server_fd,(struct sockaddr*)&client_addr, &addr_size); + if(client_fd < 0){ + perror("[-]Error in Accepting"); + exit(1); + }else{ + printf("[+]Connection accepted\n"); + system("ls /sys/class/udc > /sys/kernel/config/usb_gadget/g1/UDC"); + } + + + if ((fd = open(filename, O_RDWR, 0666)) == -1) { + perror(filename); + return 3; + } + + print_options(argv[2][0]); + + while (42) { + + FD_ZERO(&rfds); + FD_SET(client_fd, &rfds); + FD_SET(fd, &rfds); + + retval = select(fd + 1, &rfds, NULL, NULL, NULL); + if (retval == -1 && errno == EINTR) + continue; + if (retval < 0) { + perror("select()"); + return 4; + } + + if (FD_ISSET(fd, &rfds)) { + cmd_len = read(fd, buf, SIZE - 1); + printf("recv report:"); + for (i = 0; i < cmd_len; i++) + printf(" %02x", buf[i]); + printf("\n"); + } + + if (FD_ISSET(client_fd, &rfds)) { + memset(report, 0x0, sizeof(report)); + bzero(buf,SIZE); + cmd_len = read(client_fd, buf, SIZE - 1); + + if (cmd_len == 0) + break; + + if(buf[cmd_len - 1] == '\n') + { + buf[cmd_len - 1] = '\0'; + } + fprintf(stdout, "buffer set: %s\n", buf); + fprintf(stdout, "cmd_len set: %d\n", cmd_len); + hold = 0; + + memset(report, 0x0, sizeof(report)); + const char *message = "receive"; + send(client_fd, message, strlen(message), 0); + if (argv[2][0] == 'k') + to_send = keyboard_fill_report(report, buf, &hold); + else if (argv[2][0] == 'm') + to_send = mouse_fill_report(report, buf, &hold); + else + to_send = joystick_fill_report(report, buf, &hold); + + if (to_send == -1) + break; + + if (write(fd, report, to_send) != to_send) { + perror(filename); + return 5; + } + if (!hold) { + memset(report, 0x0, sizeof(report)); + if (write(fd, report, to_send) != to_send) { + perror(filename); + return 6; + } + } + } + } + system("echo > /sys/kernel/config/usb_gadget/g1/UDC"); + close(fd); + return 0; +} \ No newline at end of file diff --git a/test/C/hid_gadget_test_select.c b/test/C/hid_gadget_test_select.c index 5b4215a..909fa28 100755 --- a/test/C/hid_gadget_test_select.c +++ b/test/C/hid_gadget_test_select.c @@ -1,8 +1,9 @@ /* hid_gadget_test */ - +//arm-linux-gnueabihf-gcc -o usr/bin/hid_gadget_test_select-tcpinfo test/C/hid_gadget_test_select.c #include #include #include +#include #include #include #include @@ -272,6 +273,8 @@ int main(int argc, const char *argv[]) int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; + struct tcp_info tcp_info; + char buffer[SIZE]; const char *filename = NULL; @@ -372,6 +375,18 @@ int main(int argc, const char *argv[]) bzero(buf,SIZE); cmd_len = read(client_fd, buf, SIZE - 1); + int error = sizeof(tcp_info); + getsockopt(client_fd, IPPROTO_TCP, TCP_INFO, &tcp_info, (socklen_t *)&error); + + if(tcp_info.tcpi_state == TCP_ESTABLISHED) + { + printf("connect ok \r\n"); + } + else + { + printf("connect error\r\n"); + return 7; + } if (cmd_len == 0) break; diff --git a/usr/bin/hid_gadget_test_select-keeplive b/usr/bin/hid_gadget_test_select-keeplive new file mode 100755 index 0000000000000000000000000000000000000000..67b3d6a0fda4ddf1bb0d8d24924c43c9f6ca0ec8 GIT binary patch literal 18040 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 literal 0 HcmV?d00001