diff --git a/src/wslbridge2-backend.cpp b/src/wslbridge2-backend.cpp index 8b86cc6..63a19e5 100644 --- a/src/wslbridge2-backend.cpp +++ b/src/wslbridge2-backend.cpp @@ -17,6 +17,7 @@ #include #include #include +#include // PIPE_BUF #include #include @@ -196,6 +197,7 @@ int main(int argc, char *argv[]) ssize_t readRet = 0, writeRet = 0; char data[1024]; /* Buffer to hold raw data from pty */ + assert(sizeof data <= PIPE_BUF); do { @@ -206,8 +208,85 @@ int main(int argc, char *argv[]) if (fds[0].revents & POLLIN) { readRet = recv(ioSockets.inputSock, data, sizeof data, 0); - if (readRet > 0) - writeRet = write(mfd_dp, data, readRet); + char * s = data; + int len = readRet; + writeRet = 1; + while (writeRet > 0 && len > 0) + { + if (!*s) + { + // dispatch NUL escaped inband information + s++; + len--; + + if (len < 9 && s + 9 >= data + sizeof data) + { + // make room for additional loading + memcpy(data, s, len); + s = data; + } + + // ensure 1 more byte is loaded to dispatch on + if (!len) + { + readRet = recv(ioSockets.inputSock, s, 1, 0); + if (readRet > 0) + { + len += readRet; + } + else + { + writeRet = -1; + break; + } + } + if (*s == 2) + { + // STX: escaped NUL + s++; + len--; + writeRet = write(mfd_dp, "", 1); + } + else if (*s == 16) + { + // DLE: terminal window size change + s++; + len--; + // ensure 8 more bytes are loaded for winsize + while (readRet > 0 && len < 8) + { + readRet = recv(ioSockets.inputSock, s + len, 8 - len, 0); + if (readRet > 0) + { + len += readRet; + } + } + if (readRet <= 0) + { + writeRet = -1; + break; + } + struct winsize * winsp = (struct winsize *)s; + s += 8; + len -= 8; + winsp->ws_xpixel = 0; + winsp->ws_ypixel = 0; + ret = ioctl(mfd, TIOCSWINSZ, winsp); + if (ret != 0) + perror("ioctl(TIOCSWINSZ)"); + } + } + else + { + int n = strnlen(s, len); + writeRet = write(mfd_dp, s, n); + if (writeRet > 0) + { + s += writeRet; + len -= writeRet; + } + } + } } /* Resize window when buffer received in control socket */ diff --git a/src/wslbridge2.cpp b/src/wslbridge2.cpp index 300ad57..3ba9096 100644 --- a/src/wslbridge2.cpp +++ b/src/wslbridge2.cpp @@ -43,19 +43,41 @@ union IoSockets /* global variable */ static volatile union IoSockets g_ioSockets = { 0 }; +#define dont_debug_inband +#define dont_use_controlsocket + static void resize_window(int signum) { +#ifdef use_controlsocket +#warning this may crash for unknown reason, maybe terminate the backend struct winsize winp; + ioctl(STDIN_FILENO, TIOCGWINSZ, &winp); /* Send terminal window size to control socket */ - ioctl(STDIN_FILENO, TIOCGWINSZ, &winp); send(g_ioSockets.controlSock, (char *)&winp, sizeof winp, 0); +#else + static char wins[2 + sizeof(struct winsize)] = {0, 16}; + static struct winsize * winsp = (struct winsize *)&wins[2]; + ioctl(STDIN_FILENO, TIOCGWINSZ, winsp); + +#ifdef debug_inband + /* Send terminal window size inband, visualized as ESC sequence */ + char resizesc[55]; + //sprintf(resizesc, "\e_8;%u;%u\a", winsp->ws_row, winsp->ws_col); + sprintf(resizesc, "^[_8;%u;%u^G", winsp->ws_row, winsp->ws_col); + send(g_ioSockets.inputSock, resizesc, strlen(resizesc), 0); +#else + /* Send terminal window size inband, with NUL escape */ + send(g_ioSockets.inputSock, wins, sizeof wins, 0); +#endif +#endif } static void* send_buffer(void *param) { int ret; char data[1024]; + assert(sizeof data <= PIPE_BUF); while (1) { @@ -65,8 +87,33 @@ static void* send_buffer(void *param) closesocket(g_ioSockets.inputSock); break; } - if (!send(g_ioSockets.inputSock, data, ret, 0)) - break; + char * s = data; + int len = ret; + while (ret > 0 && len > 0) + { + if (!*s) + { + // send NUL STX +#ifdef debug_inband + ret = send(g_ioSockets.inputSock, (void*)"nul", 3, 0); +#else + static char NUL_STX[] = {0, 2}; + ret = send(g_ioSockets.inputSock, NUL_STX, 2, 0); +#endif + s++; + len--; + } + else + { + int n = strnlen(s, len); + ret = send(g_ioSockets.inputSock, s, n, 0); + if (ret > 0) + { + s += ret; + len -= ret; + } + } + } } pthread_exit(&ret); @@ -480,16 +527,6 @@ int main(int argc, char *argv[]) g_ioSockets.controlSock = win_local_accept(controlSock); } - /* Capture window resize signal and send buffer to control socket */ - { - struct sigaction act; - memset(&act, 0, sizeof act); - act.sa_handler = resize_window; - act.sa_flags = SA_RESTART; - ret = sigaction(SIGWINCH, &act, NULL); - assert(ret == 0); - } - /* Create thread to send input buffer to input socket */ pthread_t tidInput; ret = pthread_create(&tidInput, nullptr, send_buffer, nullptr); @@ -502,6 +539,17 @@ int main(int argc, char *argv[]) termState.enterRawMode(); + /* Create thread to send window size through control socket */ + struct sigaction act = {}; + act.sa_handler = resize_window; + act.sa_flags = SA_RESTART; + ret = sigaction(SIGWINCH, &act, NULL); + assert(ret == 0); + + /* Notify initial size in case it's changed since starting */ + //resize_window(0); + kill(getpid(), SIGWINCH); + /* * wsltty#254: WORKAROUND: Terminates input thread forcefully * when output thread exits. Need some inter-thread syncing.