--- lbbs/src/io.c 2025/05/19 13:03:14 1.32 +++ lbbs/src/io.c 2025/06/27 13:01:24 1.48 @@ -14,19 +14,22 @@ * * ***************************************************************************/ +#include "common.h" #include "io.h" #include "log.h" -#include "common.h" #include -#include +#include #include +#include #include #include -#include #include -#include -#include #include +#include +#include +#include +#include +#include static char stdout_buf[BUFSIZ]; static int stdout_buf_len = 0; @@ -58,6 +61,7 @@ int prints(const char *format, ...) { errno = EAGAIN; ret = (BUFSIZ - stdout_buf_len - ret); + log_error("Output buffer is full, additional %d is required\n", ret); } } @@ -87,7 +91,7 @@ int outc(char c) return ret; } -int iflush() +int iflush(void) { int flags; struct epoll_event ev, events[MAX_EVENTS]; @@ -146,7 +150,20 @@ int iflush() { while (stdout_buf_offset < stdout_buf_len && !SYS_server_exit) // write until complete or error { - ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset)); + if (SSH_v2) + { + ret = ssh_channel_write(SSH_channel, stdout_buf + stdout_buf_offset, (uint32_t)(stdout_buf_len - stdout_buf_offset)); + if (ret == SSH_ERROR) + { + log_error("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session)); + retry = 0; + break; + } + } + else + { + ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset)); + } if (ret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) @@ -159,7 +176,9 @@ int iflush() } else { +#ifdef _DEBUG log_error("write(STDOUT) error (%d)\n", errno); +#endif retry = 0; break; } @@ -218,99 +237,141 @@ int igetch(int timeout) int i = 0; int flags; - epollfd = epoll_create1(0); - if (epollfd < 0) + if (pos >= len) { - log_error("epoll_create1() error (%d)\n", errno); - return -1; - } - - ev.events = EPOLLIN; - ev.data.fd = STDIN_FILENO; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1) - { - log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno); + len = 0; + pos = 0; - if (close(epollfd) < 0) + epollfd = epoll_create1(0); + if (epollfd < 0) { - log_error("close(epoll) error (%d)\n"); + log_error("epoll_create1() error (%d)\n", errno); + return -1; } - return -1; - } - - flags = fcntl(STDIN_FILENO, F_GETFL, 0); - fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); - loop = 1; + ev.events = EPOLLIN; + ev.data.fd = STDIN_FILENO; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1) + { + log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno); - while (loop && pos >= len && !SYS_server_exit) - { - len = 0; - pos = 0; + if (close(epollfd) < 0) + { + log_error("close(epoll) error (%d)\n"); + } + return -1; + } - nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout); + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); - if (nfds < 0) + for (loop = 1; loop && !SYS_server_exit;) { - if (errno != EINTR) + if (SSH_v2 && ssh_channel_is_closed(SSH_channel)) { - log_error("epoll_wait() error (%d)\n", errno); + log_error("SSH channel is closed\n"); + loop = 0; break; } - continue; - } - else if (nfds == 0) // timeout - { - out = KEY_TIMEOUT; - break; - } - for (int i = 0; i < nfds; i++) - { - if (events[i].data.fd == STDIN_FILENO) + nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout); + + if (nfds < 0) { - while (len < sizeof(buf) && !SYS_server_exit) // read until complete or error + if (errno != EINTR) { - ret = (int)read(STDIN_FILENO, buf + len, sizeof(buf) - (size_t)len); - if (ret < 0) + log_error("epoll_wait() error (%d)\n", errno); + break; + } + continue; + } + else if (nfds == 0) // timeout + { + out = KEY_TIMEOUT; + break; + } + + for (int i = 0; i < nfds; i++) + { + if (events[i].data.fd == STDIN_FILENO) + { + while (len < sizeof(buf) && !SYS_server_exit) // read until complete or error { - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (SSH_v2) { - out = 0; - loop = 0; - break; + ret = ssh_channel_read_nonblocking(SSH_channel, buf + len, sizeof(buf) - (uint32_t)len, 0); + if (ret == SSH_ERROR) + { + log_error("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session)); + loop = 0; + break; + } + else if (ret == SSH_EOF) + { + loop = 0; + break; + } + else if (ret == 0) + { + out = 0; + break; // Check whether channel is still open + } } - else if (errno == EINTR) + else { - continue; + ret = (int)read(STDIN_FILENO, buf + len, sizeof(buf) - (size_t)len); } - else + if (ret < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + out = 0; + loop = 0; + break; + } + else if (errno == EINTR) + { + continue; + } + else + { +#ifdef _DEBUG + log_error("read(STDIN) error (%d)\n", errno); +#endif + loop = 0; + break; + } + } + else if (ret == 0) // broken pipe { - log_error("read(STDIN) error (%d)\n", errno); loop = 0; break; } - } - else if (ret == 0) // broken pipe - { - loop = 0; - break; - } - else - { - len += ret; - continue; + else + { + len += ret; + continue; + } } } } + + // For debug +#ifdef _DEBUG + for (int j = pos; j < len; j++) + { + log_common("Debug: <--[%u]\n", (buf[j] + 256) % 256); + } +#endif } - // For debug - // for (j = 0; j < len; j++) - // log_std ("<--[%u]\n", (buf[j] + 256) % 256); - } + fcntl(STDIN_FILENO, F_SETFL, flags); - fcntl(STDIN_FILENO, F_SETFL, flags); + if (close(epollfd) < 0) + { + log_error("close(epoll) error (%d)\n"); + } + } while (pos < len) { @@ -338,7 +399,7 @@ int igetch(int timeout) continue; } - if (c == ESC_KEY) + if (c == KEY_ESC) { if (in_esc == 0) { @@ -349,7 +410,7 @@ int igetch(int timeout) } else { - out = ESC_KEY; + out = KEY_CSI; in_esc = 0; break; } @@ -360,30 +421,122 @@ int igetch(int timeout) if (in_ascii) { tmp[i++] = c; - if (c == 'm') - { - in_ascii = 0; - continue; - } - if (i == 2 && c >= 'A' && c <= 'D') + if (i == 2 && (tmp[0] == 79 || tmp[0] == 91)) { in_ascii = 0; - switch (c) + switch (tmp[1]) { - case 'A': + case 65: out = KEY_UP; break; - case 'B': + case 66: out = KEY_DOWN; break; - case 'C': + case 67: out = KEY_RIGHT; break; - case 'D': + case 68: out = KEY_LEFT; break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 2 && tmp[0] == 91) // Fterm + { + in_ascii = 0; + switch (tmp[1]) + { + case 86: + out = KEY_SHIFT_F1; + break; + case 90: + out = KEY_SHIFT_F2; + break; + case 97: + out = KEY_SHIFT_F3; + break; + case 98: + out = KEY_SHIFT_F4; + break; + case 99: + out = KEY_SHIFT_F5; + break; + case 100: + out = KEY_SHIFT_F6; + break; + case 101: + out = KEY_SHIFT_F7; + break; + case 102: + out = KEY_SHIFT_F8; + break; + case 103: + out = KEY_SHIFT_F9; + break; + case 104: + out = KEY_SHIFT_F10; + break; + case 107: + out = KEY_CTRL_F1; + break; + case 108: + out = KEY_CTRL_F2; + break; + case 109: + out = KEY_CTRL_F3; + break; + case 112: + out = KEY_CTRL_F6; + break; + case 113: + out = KEY_CTRL_F7; + break; + case 114: + out = KEY_CTRL_F8; + break; + case 115: + out = KEY_CTRL_F9; + break; + case 116: + out = KEY_CTRL_F10; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 2 && tmp[0] == 79) // Xterm + { + in_ascii = 0; + switch (tmp[1]) + { + case 80: + out = KEY_F1; + break; + case 81: + out = KEY_F2; + break; + case 82: + out = KEY_F3; + break; + case 83: + out = KEY_F4; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; } - break; } if (i == 3 && tmp[0] == 91 && tmp[2] == 126) { @@ -393,6 +546,9 @@ int igetch(int timeout) case 49: out = KEY_HOME; break; + case 50: + out = KEY_INS; + break; case 51: out = KEY_DEL; break; @@ -405,8 +561,248 @@ int igetch(int timeout) case 54: out = KEY_PGDN; break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 4 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 126) // Fterm + { + in_ascii = 0; + switch (tmp[2]) + { + case 49: + out = KEY_F1; + break; + case 50: + out = KEY_F2; + break; + case 51: + out = KEY_F3; + break; + case 52: + out = KEY_F4; + break; + case 53: + out = KEY_F5; + break; + case 55: + out = KEY_F6; + break; + case 56: + out = KEY_F7; + break; + case 57: + out = KEY_F8; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 4 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 126) // Fterm + { + in_ascii = 0; + switch (tmp[2]) + { + case 48: + out = KEY_F9; + break; + case 49: + out = KEY_F10; + break; + case 50: + out = KEY_F11; // Fterm + break; + case 51: + out = KEY_F11; // Xterm + break; + case 52: + out = KEY_F12; // Xterm + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; } - break; + } + if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 53) // Xterm + { + in_ascii = 0; + switch (tmp[4]) + { + case 65: + out = KEY_CTRL_UP; + break; + case 66: + out = KEY_CTRL_DOWN; + break; + case 67: + out = KEY_CTRL_RIGHT; + break; + case 68: + out = KEY_CTRL_LEFT; + break; + case 70: + out = KEY_CTRL_END; + break; + case 72: + out = KEY_CTRL_HOME; + break; + case 80: + out = KEY_CTRL_F1; + break; + case 81: + out = KEY_CTRL_F2; + break; + case 82: + out = KEY_CTRL_F3; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm + { + in_ascii = 0; + switch (tmp[2]) + { + case 53: + out = KEY_CTRL_F5; + break; + case 55: + out = KEY_CTRL_F6; + break; + case 56: + out = KEY_CTRL_F7; + break; + case 57: + out = KEY_CTRL_F8; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm + { + in_ascii = 0; + switch (tmp[2]) + { + case 48: + out = KEY_CTRL_F9; + break; + case 49: + out = KEY_CTRL_F10; + break; + case 51: + out = KEY_CTRL_F11; + break; + case 52: + out = KEY_CTRL_F12; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 50) // Xterm + { + in_ascii = 0; + switch (tmp[4]) + { + case 80: + out = KEY_SHIFT_F1; + break; + case 81: + out = KEY_SHIFT_F2; + break; + case 82: + out = KEY_SHIFT_F3; + break; + case 83: + out = KEY_SHIFT_F4; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm + { + in_ascii = 0; + switch (tmp[2]) + { + case 53: + out = KEY_SHIFT_F5; + break; + case 55: + out = KEY_SHIFT_F6; + break; + case 56: + out = KEY_SHIFT_F7; + break; + case 57: + out = KEY_SHIFT_F8; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm + { + in_ascii = 0; + switch (tmp[2]) + { + case 48: + out = KEY_SHIFT_F9; + break; + case 49: + out = KEY_SHIFT_F10; + break; + case 51: + out = KEY_SHIFT_F11; + break; + case 52: + out = KEY_SHIFT_F12; + break; + default: + in_ascii = 1; + } + if (!in_ascii) + { + break; + } + } + + if (c == 'm') + { + in_ascii = 0; } continue; } @@ -415,13 +811,19 @@ int igetch(int timeout) break; } - // for debug - // log_std ("-->[%u]\n", out); + // For ESC key + if (out == 0 && in_esc) + { + out = KEY_ESC; + } - if (close(epollfd) < 0) + // for debug +#ifdef _DEBUG + if (out != KEY_TIMEOUT && out != KEY_NULL) { - log_error("close(epoll) error (%d)\n"); + log_common("Debug: -->[0x %x]\n", out); } +#endif return out; } @@ -429,12 +831,12 @@ int igetch(int timeout) int igetch_t(int sec) { int ch; - time_t t_begin = time(0); + time_t t_begin = time(NULL); do { ch = igetch(100); - } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec)); + } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(NULL) - t_begin < sec)); return ch; }