diff options
author | pommicket <pommicket@gmail.com> | 2023-09-10 13:40:05 -0400 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2023-09-10 13:40:05 -0400 |
commit | 6586f9e66d87017984f57b3b4579c78897ba66f2 (patch) | |
tree | f84ab9a9b4a6449e123cfed0a3e9245750a19fd6 | |
parent | 5e22cc67e92a87a0448dea70c89a4472b961fa14 (diff) |
LSP over TCP on windows
-rw-r--r-- | base.h | 3 | ||||
-rw-r--r-- | build.c | 2 | ||||
-rw-r--r-- | lsp-write.c | 6 | ||||
-rw-r--r-- | lsp.c | 10 | ||||
-rw-r--r-- | main.c | 5 | ||||
-rw-r--r-- | os-posix.c | 3 | ||||
-rw-r--r-- | os-win.c | 104 | ||||
-rw-r--r-- | tags.c | 2 |
8 files changed, 126 insertions, 9 deletions
@@ -22,6 +22,9 @@ #endif #if _WIN32 +// windows is stupid — we have to include winsock2.h first +#include <winsock2.h> +#include <ws2tcpip.h> #include <windows.h> #include <shlobj.h> #include <dbghelp.h> @@ -121,7 +121,7 @@ void build_start(Ted *ted) { Assoc associations[] = { #if _WIN32 - {"make.bat", "make.bat"}, + {"make.bat", "cmd /c make.bat"}, #endif {"Cargo.toml", "cargo build"}, {"Makefile", "make -j16"}, diff --git a/lsp-write.c b/lsp-write.c index 0eed987..974a845 100644 --- a/lsp-write.c +++ b/lsp-write.c @@ -332,8 +332,12 @@ static void message_writer_write_and_free(LSP *lsp, JSONWriter *o) { memcpy(content, header_str, header_size); #if LSP_SHOW_C2S - printf("%s%s%s\n",term_bold(stdout),content,term_clear(stdout)); + const int limit = 1000; + debug_println("%s%.*s%s%s",term_italics(stdout),limit,content, + strlen(content) > (size_t)limit ? "..." : "", + term_clear(stdout)); #endif + if (lsp->log) { fprintf(lsp->log, "LSP MESSAGE FROM CLIENT TO SERVER\n%s\n\n", content + header_size); } @@ -395,7 +395,7 @@ static bool lsp_receive(LSP *lsp, size_t max_size) { if (status != 0) { bool not_found = #if _WIN32 - false // @TODO + false #else info.exit_code == 127 #endif @@ -444,7 +444,7 @@ static bool lsp_receive(LSP *lsp, size_t max_size) { lsp->received_data[received_so_far] = '\0';// null terminate #if LSP_SHOW_S2C const int limit = 1000; - printf("%s%.*s%s%s\n",term_italics(stdout),limit,lsp->received_data, + debug_println("%s%.*s%s%s",term_italics(stdout),limit,lsp->received_data, strlen(lsp->received_data) > (size_t)limit ? "..." : "", term_clear(stdout)); #endif @@ -594,7 +594,6 @@ static int lsp_communication_thread(void *data) { } lsp->exited = true; - if (!lsp->process) { // process already exited return 0; @@ -681,10 +680,8 @@ LSP *lsp_create(const LSPSetup *setup) { lsp->port = port; lsp->send_delay = setup->send_delay; - #if DEBUG - printf("Starting up LSP %p (ID %u) `%s` (port %u) in %s\n", + debug_println("Starting up LSP %p (ID %u) `%s` (port %u) in %s", (void *)lsp, (unsigned)lsp->id, command ? command : "(no command)", port, root_dir); - #endif str_hash_table_create(&lsp->document_ids, sizeof(u32)); lsp->command = str_dup(command); @@ -714,6 +711,7 @@ LSP *lsp_create(const LSPSetup *setup) { #if _WIN32 if (strstr(error, " 2)")) { if (lsp->log) fprintf(lsp->log, "Couldn't start LSP server %s: file not found.", command); + debug_println("error: %s", error); } else #endif lsp_set_error(lsp, "Couldn't start LSP server: %s", error); @@ -31,6 +31,7 @@ FUTURE FEATURES: #pragma comment(lib, "ole32.lib") #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "shell32.lib") +#pragma comment(lib, "ws2_32.lib") #endif @@ -262,6 +263,10 @@ INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WideCharToMultiByte(CP_UTF8, 0, wide_arg, len, argv[i], bufsz - 1, NULL, NULL); } LocalFree(wide_argv); + { + WSADATA wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); + } SetProcessDPIAware(); #else @@ -458,6 +458,8 @@ Socket *socket_connect_tcp(const char *address, u16 port) { if (connect(fd, &addr, sizeof addr) < 0) { strbuf_printf(s->error, "couldn't connect to %s:%u (%s)", address, port, strerror(errno)); + close(fd); + return s; } set_nonblocking(fd); @@ -492,5 +494,6 @@ void socket_close(Socket **psocket) { if (!s) return; if (s->fd > 0) close(s->fd); + free(s); *psocket = NULL; } @@ -431,3 +431,107 @@ bool open_with_default_application(const char *path) { bool change_directory(const char *path) { return _chdir(path) == 0; } + +struct Socket { + SOCKET sock; + char error[256]; +}; + +Socket *socket_connect_tcp(const char *address, u16 port) { + Socket *s = calloc(1, sizeof *s); + if (!s) return NULL; + s->sock = INVALID_SOCKET; + if (!address) address = "127.0.0.1"; + + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(port), + }; + if (inet_pton(AF_INET, address, &addr.sin_addr) != 1) { + strbuf_printf(s->error, "Invalid address"); + return s; + } + + SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + strbuf_printf(s->error, "Couldn't create socket (error code %d)", + WSAGetLastError()); + return s; + } + if (connect(sock, (SOCKADDR *)&addr, sizeof addr) != 0) { + strbuf_printf(s->error, "Couldn't connect to %s:%u (error code %d)", + address, port, WSAGetLastError()); + closesocket(sock); + return s; + } + + u_long mode = 1; // non-blocking + ioctlsocket(sock, FIONBIO, &mode); + s->sock = sock; + return s; +} +const char *socket_get_error(Socket *s) { + return s->error; +} + +long long socket_read(Socket *s, char *data, size_t size) { + if (size > INT_MAX) { + strbuf_printf(s->error, "Too much data to read."); + return -2; + } + size_t so_far = 0; + while (so_far < size) { + int bytes_read = recv(s->sock, data + so_far, (int)(size - so_far), 0); + if (bytes_read > 0) { + so_far += (size_t)bytes_read; + } else if (bytes_read == 0) { + return (long long)so_far; + } else { + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + return so_far == 0 ? -1 : (long long)so_far; + } else if (err == WSAECONNRESET) { + return 0; + } else { + strbuf_printf(s->error, "recv failed (error code %d)", err); + return -2; + } + } + } + return (long long)size; +} + +long long socket_write(Socket *s, const char *data, size_t size) { + if (size > INT_MAX) { + strbuf_printf(s->error, "too much data to write"); + return -2; + } + size_t so_far = 0; + while (so_far < size) { + int bytes_written = send(s->sock, data + so_far, (int)(size - so_far), 0); + if (bytes_written > 0) { + so_far += (size_t)bytes_written; + } else { + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + return (long long)so_far; + } else if (err == WSAEHOSTUNREACH || err == WSAECONNRESET) { + return -1; + } else { + strbuf_printf(s->error, "write failed (error code %d)", err); + return -2; + } + } + } + return (long long)size; +} + +void socket_close(Socket **psocket) { + Socket *s = *psocket; + if (!s) return; + if (s->sock != INVALID_SOCKET) + closesocket(s->sock); + free(s); + *psocket = NULL; +} @@ -18,7 +18,7 @@ static bool get_tags_dir(Ted *ted, bool error_if_does_not_exist) { strbuf_cpy(ted->tags_dir, path); } if (error_if_does_not_exist) - ted_error(ted, "No tags file. Try running ctags."); + ted_flash_error_cursor(ted); return false; } |