From a187409c6747e3bd525bd20610d17064bc97c82a Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Tue, 10 Jan 2023 19:37:14 +0600 Subject: [PATCH 01/12] Organize source files Signed-off-by: Mubashshir --- Makefile | 29 +++++++++++++++++++++++++++-- src/Makefile | 4 ++++ main.c => src/main.c | 0 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/Makefile rename main.c => src/main.c (100%) diff --git a/Makefile b/Makefile index a518f3d..035eed6 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,27 @@ -winediscordipcbridge.exe: main.c - i686-w64-mingw32-gcc -masm=intel main.c -o winediscordipcbridge +OUTPUT ?= winediscordipcbridge.exe + + +CC := i686-w64-mingw32-gcc + +<> := $(wildcard src/*.c) +<> := $(<>:src/%.c=obj/%.o) + +<< := @echo +ifneq ($(shell eval 'echo -e'),-e) + << += -e +endif + +obj/%.o: src/%.c + $(<<) "CC\t$(<)" + @mkdir -p obj && $(CC) -masm=intel -c $(<) -o $(@) + +all: $(OUTPUT) + +$(OUTPUT): $(<>) + $(<<) "LINK\t$(@)" + @$(CC) $(^) -o $(@) -lshlwapi + +clean: + @rm -fv $(<>) $(OUTPUT) + +.PHONY: clean all diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..49ae948 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,4 @@ +all: + make -C .. all +clean: + make -C .. clean diff --git a/main.c b/src/main.c similarity index 100% rename from main.c rename to src/main.c From ec6d224340bffc1efa33292c1999474586e8c74d Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Tue, 10 Jan 2023 20:02:49 +0600 Subject: [PATCH 02/12] Separate syscall wrappers and code Signed-off-by: Mubashshir --- src/main.c | 171 +------------------------------------------------ src/syscalls.c | 146 +++++++++++++++++++++++++++++++++++++++++ src/syscalls.h | 34 ++++++++++ 3 files changed, 181 insertions(+), 170 deletions(-) create mode 100644 src/syscalls.c create mode 100644 src/syscalls.h diff --git a/src/main.c b/src/main.c index e381de2..f0c1eb7 100644 --- a/src/main.c +++ b/src/main.c @@ -3,176 +3,7 @@ #include #include #include - -#pragma region -struct sockaddr_un { - unsigned short sun_family; /* AF_UNIX */ - char sun_path[108]; /* pathname */ -}; -/* struct sockaddr { */ -/* unsigned short sa_family; // address family, AF_xxx */ -/* char sa_data[14]; // 14 bytes of protocol address */ -/* }; */ -#define AF_UNIX 1 -#define SOCK_STREAM 1 -#define F_SETFL 4 -#define O_RDONLY 00000000 -#define O_WRONLY 00000001 -#define O_CREAT 00000100 -#define O_APPEND 00002000 -#define O_NONBLOCK 00004000 -#define BUFSIZE 2048 // size of read/write buffers - -#pragma endregion wine-specific header thingy -#pragma region -__declspec(naked) int l_close(int fd) { - __asm__ ( - "push ebx\n\t" - - "mov eax, 0x06\n\t" - "mov ebx, [esp + 4 + 4]\n\t" - "int 0x80\n\t" - - "pop ebx\n\t" - "ret" - ); -} -__declspec(naked) int l_socketcall(int call, void* args) { - __asm__ ( - "push ebx\n\t" - - "mov eax, 0x66\n\t" - "mov ebx, [esp + 4 + 4]\n\t" - "mov ecx, [esp + 4 + 8]\n\t" - "int 0x80\n\t" - - "pop ebx\n\t" - "ret" - ); -} -__declspec(naked) int l_open(const char* filename, int flags, int mode) { - __asm__ ( - "push ebx\n\t" - - "mov eax, 0x05\n\t" - "mov ebx, [esp + 4 + 4]\n\t" - "mov ecx, [esp + 4 + 8]\n\t" - "mov edx, [esp + 4 + 12]\n\t" - "int 0x80\n\t" - - "pop ebx\n\t" - "ret" - ); -} -__declspec(naked) int l_write(unsigned int fd, const char* buf, unsigned int count) { - __asm__ ( - "push ebx\n\t" - - "mov eax, 0x04\n\t" - "mov ebx, [esp + 4 + 4]\n\t" - "mov ecx, [esp + 4 + 8]\n\t" - "mov edx, [esp + 4 + 12]\n\t" - "int 0x80\n\t" - - "pop ebx\n\t" - "ret" - ); -} -__declspec(naked) int l_read(unsigned int fd, char* buf, unsigned int count) { - __asm__ ( - "push ebx\n\t" - - "mov eax, 0x03\n\t" - "mov ebx, [esp + 4 + 4]\n\t" - "mov ecx, [esp + 4 + 8]\n\t" - "mov edx, [esp + 4 + 12]\n\t" - "int 0x80\n\t" - - "pop ebx\n\t" - "ret" - ); -} -#pragma endregion syscall wrappers -#pragma region -int l_socket(int domain, int type, int protocol) { - void* args[3]; - args[0] = (void*)(int*)domain; - args[1] = (void*)(int*)type; - args[2] = (void*)(int*)protocol; - return l_socketcall(1, args); -} -int l_connect(int sockfd, const struct sockaddr *addr, unsigned int addrlen) { - void* args[3]; - args[0] = (void*)(int*)sockfd; - args[1] = (void*)addr; - args[2] = (void*)(int*)addrlen; - return l_socketcall(3, args); -} -/* int send(int sockfd, const void* buf, unsigned int len, int flags) { */ -/* void* args[4]; */ -/* args[0] = (void*)(int*)sockfd; */ -/* args[1] = (void*)buf; */ -/* args[2] = (void*)(unsigned int*)len; */ -/* args[3] = (void*)(int*)flags; */ -/* return l_socketcall(9, args); */ -/* } */ -/* int recv(int fd, void* buf, unsigned int len, int flags) { */ -/* void* args[4]; */ -/* args[0] = (void*)(int*)fd; */ -/* args[1] = (void*)buf; */ -/* args[2] = (void*)(unsigned int*)len; */ -/* args[3] = (void*)(int*)flags; */ -/* return l_socketcall(10, args); */ -/* } */ -#pragma endregion socketcall wrappers - -char* getenv_(char* name) // written by https://github.com/Francesco149 -{ - static char buf[1024 * 1024]; - static char* end = 0; - unsigned int namelen; - char* p; - - if (!end) { - int fd, n; - - fd = l_open("/proc/self/environ", 0, 0); - if (fd < 0) { - return 0; - } - - n = l_read((unsigned int)fd, buf, (unsigned int)sizeof(buf)); - if (n < 0) { - return 0; - } - - l_close(fd); - end = buf + n; - } - - namelen = strlen(name); - - for (p = buf; p < end;) { - if (!strncmp(p, name, namelen)) { - return p + namelen + 1; /* skip name and the = */ - } - - for (; *p && p < end; ++p); /* skip to next entry */ - ++p; - } - - return 0; -} - -static const char* get_temp_path() -{ - const char* temp = getenv_("XDG_RUNTIME_DIR"); - temp = temp ? temp : getenv_("TMPDIR"); - temp = temp ? temp : getenv_("TMP"); - temp = temp ? temp : getenv_("TEMP"); - temp = temp ? temp : "/tmp"; - return temp; -} +#include "syscalls.h" static HANDLE hPipe = INVALID_HANDLE_VALUE; static int sock_fd; diff --git a/src/syscalls.c b/src/syscalls.c new file mode 100644 index 0000000..0f07ad8 --- /dev/null +++ b/src/syscalls.c @@ -0,0 +1,146 @@ +#include +#include "syscalls.h" + +// syscall wrappers +SFUNC int l_close(int fd) +{ + __asm__ ( + "push ebx\n\t" + "mov eax, 0x06\n\t" + "mov ebx, [esp + 4 + 4]\n\t" + "int 0x80\n\t" + "pop ebx\n\t" + "ret" + ); +} + +SFUNC int l_socketcall(int call, void* args) +{ + __asm__ ( + "push ebx\n\t" + "mov eax, 0x66\n\t" + "mov ebx, [esp + 4 + 4]\n\t" + "mov ecx, [esp + 4 + 8]\n\t" + "int 0x80\n\t" + "pop ebx\n\t" + "ret" + ); +} + +SFUNC int l_open(const char* filename, int flags, int mode) +{ + __asm__ ( + "push ebx\n\t" + "mov eax, 0x05\n\t" + "mov ebx, [esp + 4 + 4]\n\t" + "mov ecx, [esp + 4 + 8]\n\t" + "mov edx, [esp + 4 + 12]\n\t" + "int 0x80\n\t" + "pop ebx\n\t" + "ret" + ); +} + +SFUNC int l_write(unsigned int fd, const char* buf, unsigned int count) +{ + __asm__ ( + "push ebx\n\t" + "mov eax, 0x04\n\t" + "mov ebx, [esp + 4 + 4]\n\t" + "mov ecx, [esp + 4 + 8]\n\t" + "mov edx, [esp + 4 + 12]\n\t" + "int 0x80\n\t" + "pop ebx\n\t" + "ret" + ); +} + +SFUNC int l_read(unsigned int fd, char* buf, unsigned int count) +{ + __asm__ ( + "push ebx\n\t" + "mov eax, 0x03\n\t" + "mov ebx, [esp + 4 + 4]\n\t" + "mov ecx, [esp + 4 + 8]\n\t" + "mov edx, [esp + 4 + 12]\n\t" + "int 0x80\n\t" + "pop ebx\n\t" + "ret" + ); +} + +// socket wrappers +CFUNC int l_socket(int domain, int type, int protocol) +{ + void* args[3]; + args[0] = (void*)(int*)domain; + args[1] = (void*)(int*)type; + args[2] = (void*)(int*)protocol; + return l_socketcall(1, args); +} + +CFUNC int l_connect(int sockfd, const struct sockaddr *addr, unsigned int addrlen) +{ + void* args[3]; + args[0] = (void*)(int*)sockfd; + args[1] = (void*)addr; + args[2] = (void*)(int*)addrlen; + return l_socketcall(3, args); +} +/* int send(int sockfd, const void* buf, unsigned int len, int flags) { */ +/* void* args[4]; */ +/* args[0] = (void*)(int*)sockfd; */ +/* args[1] = (void*)buf; */ +/* args[2] = (void*)(unsigned int*)len; */ +/* args[3] = (void*)(int*)flags; */ +/* return l_socketcall(9, args); */ +/* } */ +/* int recv(int fd, void* buf, unsigned int len, int flags) { */ +/* void* args[4]; */ +/* args[0] = (void*)(int*)fd; */ +/* args[1] = (void*)buf; */ +/* args[2] = (void*)(unsigned int*)len; */ +/* args[3] = (void*)(int*)flags; */ +/* return l_socketcall(10, args); */ +/* } */ + +// env wrappers +CFUNC char* getenv_(char* name) // written by https://github.com/Francesco149 +{ + static char buf[1024 * 1024]; + static char* end = 0; + unsigned int namelen; + char* p; + if (!end) { + int fd, n; + fd = l_open("/proc/self/environ", 0, 0); + if (fd < 0) { + return 0; + } + n = l_read((unsigned int)fd, buf, (unsigned int)sizeof(buf)); + if (n < 0) { + return 0; + } + l_close(fd); + end = buf + n; + } + namelen = strlen(name); + for (p = buf; p < end;) { + if (!strncmp(p, name, namelen)) { + return p + namelen + 1; /* skip name and the = */ + } + for (; *p && p < end; ++p); /* skip to next entry */ + ++p; + } + return 0; +} + +CFUNC const char* get_temp_path() +{ + const char* temp = getenv_("XDG_RUNTIME_DIR"); + temp = temp ? temp : getenv_("TMPDIR"); + temp = temp ? temp : getenv_("TMP"); + temp = temp ? temp : getenv_("TEMP"); + temp = temp ? temp : "/tmp"; + return temp; +} diff --git a/src/syscalls.h b/src/syscalls.h new file mode 100644 index 0000000..53aacd8 --- /dev/null +++ b/src/syscalls.h @@ -0,0 +1,34 @@ +#ifndef __SYSCALLS_H__ +#define __SYSCALLS_H__ + +#include + +typedef struct sockaddr_un { + unsigned short sun_family; /* AF_UNIX */ + char sun_path[108]; /* pathname */ +} sockaddr_un; + +#define AF_UNIX 1 +#define SOCK_STREAM 1 +#define F_SETFL 4 +#define O_RDONLY 00000000 +#define O_WRONLY 00000001 +#define O_CREAT 00000100 +#define O_APPEND 00002000 +#define O_NONBLOCK 00004000 +#define BUFSIZE 2048 // size of read/write buffers +#define SFUNC __declspec(naked) // inline asm function +#define CFUNC // C function + +// linux syscall wrappers +SFUNC int l_close(int); +SFUNC int l_socketcall(int, void*); +SFUNC int l_open(const char*, int, int); +SFUNC int l_write(unsigned int, const char*, unsigned int); +SFUNC int l_read(unsigned int, char*, unsigned int); +CFUNC int l_socket(int, int, int); +CFUNC int l_connect(int, const struct sockaddr*, unsigned int); +CFUNC char* getenv_(char*); +CFUNC const char* get_temp_path(); + +#endif From fb097a13233e56b16f9e0365d21af4404b696d4a Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Tue, 10 Jan 2023 20:11:33 +0600 Subject: [PATCH 03/12] Prepare for implementing service Signed-off-by: Mubashshir --- src/ipc.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 194 +-------------------------------------------------- src/server.h | 8 +++ 3 files changed, 205 insertions(+), 191 deletions(-) create mode 100644 src/ipc.c create mode 100644 src/server.h diff --git a/src/ipc.c b/src/ipc.c new file mode 100644 index 0000000..8f4d7d8 --- /dev/null +++ b/src/ipc.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include "syscalls.h" +#include "server.h" + +static HANDLE hPipe = INVALID_HANDLE_VALUE; +static int sock_fd; +DWORD WINAPI winwrite_thread(LPVOID lpvParam); + +int iServerLoop(BOOL bStandalone) +{ + BOOL fConnected = FALSE; + DWORD dwThreadId = 0; + HANDLE hThread = NULL; + LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\discord-ipc-0"); + + // The main loop creates an instance of the named pipe and + // then waits for a client to connect to it. When the client + // connects, a thread is created to handle communications + // with that client, and this loop is free to wait for the + // next client connect request. It is an infinite loop. + + _tprintf( TEXT("Pipe Server: Main thread awaiting client connection on %s\n"), lpszPipename); + hPipe = CreateNamedPipe( + lpszPipename, // pipe name + PIPE_ACCESS_DUPLEX, // read/write access + PIPE_TYPE_BYTE | // message type pipe + PIPE_READMODE_BYTE | // message-read mode + PIPE_WAIT, // blocking mode + 1, // max. instances + BUFSIZE, // output buffer size + BUFSIZE, // input buffer size + 0, // client time-out + NULL); // default security attribute + + if (hPipe == INVALID_HANDLE_VALUE) + { + _tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError()); + return -1; + } + + // Wait for the client to connect; if it succeeds, + // the function returns a nonzero value. If the function + // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. + + fConnected = ConnectNamedPipe(hPipe, NULL) ? + TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + + if (fConnected) + { + printf("Client connected\n"); + + printf("Creating socket\n"); + + if ((sock_fd = l_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + printf("Failed to create socket\n"); + return 1; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + + const char *const temp_path = get_temp_path(); + + char *paths[] = { + "%s/discord-ipc-%d", + "%s/app/com.discordapp.Discord/discord-ipc-%d", + "%s/snap.discord-canary/discord-ipc-%d", + "%s/snap.discord/discord-ipc-%d" + }; + + char connected = 0; + for (int p = 0; p < sizeof(paths) / sizeof(paths[0]); p++) { + for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { + + snprintf(addr.sun_path, sizeof(addr.sun_path), paths[p], temp_path, pipeNum); + printf("Attempting to connect to %s\n", addr.sun_path); + + if (l_connect(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { + printf("Failed to connect\n"); + } else { + connected = 1; + goto breakout; + } + } + } +breakout:; + + if (!connected) { + printf("Could not connect to discord client\n"); + return 1; + } + + + printf("Connected successfully\n"); + + hThread = CreateThread( + NULL, // no security attribute + 0, // default stack size + winwrite_thread, // thread proc + (LPVOID) NULL, // thread parameter + 0, // not suspended + &dwThreadId); // returns thread ID + + if (hThread == NULL) + { + _tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError()); + return 1; + } + + + while(bStandalone) { + char buf[BUFSIZE]; + DWORD bytes_read = 0; + BOOL fSuccess = ReadFile( + hPipe, // handle to pipe + buf, // buffer to receive data + BUFSIZE, // size of buffer + &bytes_read, // number of bytes read + NULL); // not overlapped I/O + if (!fSuccess) { + if (GetLastError() == ERROR_BROKEN_PIPE) { + printf("winread EOF\n"); + return 0; + } else { + printf("Failed to read from pipe\n"); + return 1; + } + } + + printf("%d bytes w->l\n", bytes_read); + /* uncomment to dump the actual data being passed from the pipe to the socket */ + /* for(int i=0;iw\n", bytes_read); + /* uncomment to dump the actual data being passed from the socket to the pipe */ + /* for(int i=0;i -#include -#include #include -#include -#include "syscalls.h" +#include "server.h" -static HANDLE hPipe = INVALID_HANDLE_VALUE; -static int sock_fd; -DWORD WINAPI winwrite_thread(LPVOID lpvParam); - -int _tmain(VOID) -{ - BOOL fConnected = FALSE; - DWORD dwThreadId = 0; - HANDLE hThread = NULL; - LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\discord-ipc-0"); - - // The main loop creates an instance of the named pipe and - // then waits for a client to connect to it. When the client - // connects, a thread is created to handle communications - // with that client, and this loop is free to wait for the - // next client connect request. It is an infinite loop. - - _tprintf( TEXT("Pipe Server: Main thread awaiting client connection on %s\n"), lpszPipename); - hPipe = CreateNamedPipe( - lpszPipename, // pipe name - PIPE_ACCESS_DUPLEX, // read/write access - PIPE_TYPE_BYTE | // message type pipe - PIPE_READMODE_BYTE | // message-read mode - PIPE_WAIT, // blocking mode - 1, // max. instances - BUFSIZE, // output buffer size - BUFSIZE, // input buffer size - 0, // client time-out - NULL); // default security attribute - - if (hPipe == INVALID_HANDLE_VALUE) - { - _tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError()); - return -1; - } - - // Wait for the client to connect; if it succeeds, - // the function returns a nonzero value. If the function - // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. - - fConnected = ConnectNamedPipe(hPipe, NULL) ? - TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); - - if (fConnected) - { - printf("Client connected\n"); - - printf("Creating socket\n"); - - if ((sock_fd = l_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - printf("Failed to create socket\n"); - return 1; - } - - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - - const char *const temp_path = get_temp_path(); - - char *paths[] = { - "%s/discord-ipc-%d", - "%s/app/com.discordapp.Discord/discord-ipc-%d", - "%s/snap.discord-canary/discord-ipc-%d", - "%s/snap.discord/discord-ipc-%d" - }; - - char connected = 0; - for (int p = 0; p < sizeof(paths) / sizeof(paths[0]); p++) { - for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { - - snprintf(addr.sun_path, sizeof(addr.sun_path), paths[p], temp_path, pipeNum); - printf("Attempting to connect to %s\n", addr.sun_path); - - if (l_connect(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { - printf("Failed to connect\n"); - } else { - connected = 1; - goto breakout; - } - } - } -breakout:; - - if (!connected) { - printf("Could not connect to discord client\n"); - return 1; - } - - - printf("Connected successfully\n"); - - hThread = CreateThread( - NULL, // no security attribute - 0, // default stack size - winwrite_thread, // thread proc - (LPVOID) NULL, // thread parameter - 0, // not suspended - &dwThreadId); // returns thread ID - - if (hThread == NULL) - { - _tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError()); - return 1; - } - - - for (;;) { - char buf[BUFSIZE]; - DWORD bytes_read = 0; - BOOL fSuccess = ReadFile( - hPipe, // handle to pipe - buf, // buffer to receive data - BUFSIZE, // size of buffer - &bytes_read, // number of bytes read - NULL); // not overlapped I/O - if (!fSuccess) { - if (GetLastError() == ERROR_BROKEN_PIPE) { - printf("winread EOF\n"); - return 0; - } else { - printf("Failed to read from pipe\n"); - return 1; - } - } - - printf("%d bytes w->l\n", bytes_read); - /* uncomment to dump the actual data being passed from the pipe to the socket */ - /* for(int i=0;iw\n", bytes_read); - /* uncomment to dump the actual data being passed from the socket to the pipe */ - /* for(int i=0;i + +int iServerLoop(BOOL); + +#endif /* __SERVER_H__ */ From bd59b8853367d1e9dbf685d2ca833f18ca0a0052 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Tue, 10 Jan 2023 20:48:37 +0600 Subject: [PATCH 04/12] Add placeholder service management functions Signed-off-by: Mubashshir --- src/ipc.c | 2 +- src/main.c | 13 +++++++++++++ src/server.h | 1 + src/service-manager.c | 26 ++++++++++++++++++++++++++ src/service-manager.h | 8 ++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/service-manager.c create mode 100644 src/service-manager.h diff --git a/src/ipc.c b/src/ipc.c index 8f4d7d8..8d66f41 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -110,7 +110,7 @@ breakout:; } - while(bStandalone) { + while(bStandalone || bListening()) { char buf[BUFSIZE]; DWORD bytes_read = 0; BOOL fSuccess = ReadFile( diff --git a/src/main.c b/src/main.c index ef2abdc..9ab68a8 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,20 @@ #include #include +#include #include "server.h" +#include "service-manager.h" +#define ARGV1(X) (argc > 1 && lstrcmpi( argv[1], TEXT(X)) == 0) +#define basename PathFindFileName(argv[0]) int _tmain(int argc, TCHAR *argv[]) { + if(ARGV1("install")) return iAddService(); + else if(ARGV1("remove")) return iDelService(); + else if(ARGV1("service")) return iRunService(); + else if(argc > 1) + return (_tprintf( + TEXT("Run Standalone : %s\n" + "Install Service: %s install\n" + "Remove Service : %s remove\n"), + basename, basename, basename) * 0); return iServerLoop(TRUE); } diff --git a/src/server.h b/src/server.h index 031a7d1..abfdf4a 100644 --- a/src/server.h +++ b/src/server.h @@ -4,5 +4,6 @@ #include int iServerLoop(BOOL); +BOOL bListening(VOID); #endif /* __SERVER_H__ */ diff --git a/src/service-manager.c b/src/service-manager.c new file mode 100644 index 0000000..3477d5a --- /dev/null +++ b/src/service-manager.c @@ -0,0 +1,26 @@ +#include +#include +#include "server.h" +#include "service-manager.h" + +#define NOT_IMPLEMENTED(X) _tprintf(TEXT("Not Implemented.\n")); return X + +int iAddService() +{ + NOT_IMPLEMENTED(1); +} + +int iDelService(void) +{ + NOT_IMPLEMENTED(1); +} + +int iRunService() +{ + NOT_IMPLEMENTED(1); +} + +BOOL bListening() +{ + NOT_IMPLEMENTED(FALSE); +} diff --git a/src/service-manager.h b/src/service-manager.h new file mode 100644 index 0000000..4cf8513 --- /dev/null +++ b/src/service-manager.h @@ -0,0 +1,8 @@ +#ifndef __SERVICE_MANAGER_H__ +#define __SERVICE_MANAGER_H__ + +int iAddService(void); +int iDelService(void); +int iRunService(void); + +#endif /* __SERVICE_MANAGER_H__ */ From b0d86c81e3a36a4fb616482da7747afcb2c5883d Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Tue, 10 Jan 2023 23:10:20 +0600 Subject: [PATCH 05/12] Implement service (un)install Signed-off-by: Mubashshir --- src/service-manager.c | 83 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/src/service-manager.c b/src/service-manager.c index 3477d5a..fa6f318 100644 --- a/src/service-manager.c +++ b/src/service-manager.c @@ -1,5 +1,6 @@ #include #include +#include #include "server.h" #include "service-manager.h" @@ -7,12 +8,90 @@ int iAddService() { - NOT_IMPLEMENTED(1); + SC_HANDLE schSCManager; + SC_HANDLE schService; + + TCHAR szUnquotedPath[MAX_PATH]; + if( !GetModuleFileName( NULL, szUnquotedPath, MAX_PATH ) ) { + _tprintf(TEXT("Cannot install service (%d)\n"), GetLastError()); + return 1; + } + + TCHAR szPath[MAX_PATH]; + StringCbPrintf(szPath, MAX_PATH, TEXT("\"%s\" service"), szUnquotedPath); + + // Open SCM database handle. + schSCManager = OpenSCManager( + NULL, // local computer + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + if (NULL == schSCManager) { + _tprintf(TEXT("OpenSCManager failed (%d)\n"), GetLastError()); + return 1; + } + + // Register service + schService = CreateService( + schSCManager, // SCM database + SVCNAME, // name of service + SVCNAME, // service name to display + SERVICE_ALL_ACCESS, // desired access + SERVICE_WIN32_OWN_PROCESS, // service type + SERVICE_AUTO_START, // start type + SERVICE_ERROR_IGNORE, // error control type + szPath, // path to service's binary + NULL, // no load ordering group + NULL, // no tag identifier + NULL, // no dependencies + NULL, // LocalSystem account + NULL); // no password + + if (schService == NULL) { + _tprintf(TEXT("CreateService failed (%d)\n"), GetLastError()); + CloseServiceHandle(schSCManager); + return 1; + } else _tprintf(TEXT("Service installed successfully\n")); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return 0; } int iDelService(void) { - NOT_IMPLEMENTED(1); + SC_HANDLE schSCManager; + SC_HANDLE schService; + SERVICE_STATUS ssStatus; + + // Open SCM database handle. + schSCManager = OpenSCManager( + NULL, // local computer + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + if (NULL == schSCManager) { + _tprintf(TEXT("OpenSCManager failed (%d)\n"), GetLastError()); + return 1; + } + + // Open service handle. + schService = OpenService( + schSCManager, // SCM database + SVCNAME, // name of service + DELETE); // need delete access + if (schService == NULL) { + _tprintf(TEXT("OpenService failed (%d)\n"), GetLastError()); + CloseServiceHandle(schSCManager); + return 1; + } + + // Mark service as deleted + if (! DeleteService(schService) ) { + _tprintf(TEXT("DeleteService failed (%d)\n"), GetLastError()); + } else _tprintf(TEXT("Service deleted successfully\n")); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return 0; } int iRunService() From 55c4f017d95e09e2f4a6533c81e51efe6c62a351 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Tue, 10 Jan 2023 23:58:24 +0600 Subject: [PATCH 06/12] Implement Service Runner Signed-off-by: Mubashshir --- src/ipc.c | 2 +- src/server.h | 2 +- src/service-manager.c | 17 +++++--- src/service.c | 90 +++++++++++++++++++++++++++++++++++++++++++ src/service.h | 13 +++++++ 5 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 src/service.c create mode 100644 src/service.h diff --git a/src/ipc.c b/src/ipc.c index 8d66f41..23d0f69 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -110,7 +110,7 @@ breakout:; } - while(bStandalone || bListening()) { + while(bStandalone || bSvcRunning()) { char buf[BUFSIZE]; DWORD bytes_read = 0; BOOL fSuccess = ReadFile( diff --git a/src/server.h b/src/server.h index abfdf4a..fdb7c27 100644 --- a/src/server.h +++ b/src/server.h @@ -4,6 +4,6 @@ #include int iServerLoop(BOOL); -BOOL bListening(VOID); +BOOL bSvcRunning(VOID); #endif /* __SERVER_H__ */ diff --git a/src/service-manager.c b/src/service-manager.c index fa6f318..1d2d94a 100644 --- a/src/service-manager.c +++ b/src/service-manager.c @@ -3,8 +3,7 @@ #include #include "server.h" #include "service-manager.h" - -#define NOT_IMPLEMENTED(X) _tprintf(TEXT("Not Implemented.\n")); return X +#include "service.h" int iAddService() { @@ -96,10 +95,18 @@ int iDelService(void) int iRunService() { - NOT_IMPLEMENTED(1); + SERVICE_TABLE_ENTRY DispatchTable[] = { + { SVCNAME, (LPSERVICE_MAIN_FUNCTION) vSvcMain }, + { NULL, NULL } + }; + + if (StartServiceCtrlDispatcher( DispatchTable )) return 0; + + vReportError(TEXT("StartServiceCtrlDispatcher")); + return 1; } -BOOL bListening() +VOID vReportError(LPTSTR szFunction) { - NOT_IMPLEMENTED(FALSE); + NOT_IMPLEMENTED(); } diff --git a/src/service.c b/src/service.c new file mode 100644 index 0000000..dce45d7 --- /dev/null +++ b/src/service.c @@ -0,0 +1,90 @@ +#include +#include + +#include "service.h" +#include "server.h" +#define PRIVATE // private functions + +static SERVICE_STATUS gSvcStatus; +static SERVICE_STATUS_HANDLE gSvcStatusHandle; +static HANDLE ghSvcStopEvent = NULL; + +PRIVATE VOID vReportState(DWORD, DWORD, DWORD); +PRIVATE VOID WINAPI vHandleEvent(DWORD); + +// decls +BOOL bSvcRunning() +{ + return ( + ghSvcStopEvent == NULL + || WaitForSingleObjectEx(ghSvcStopEvent, 0, TRUE) == WAIT_TIMEOUT + ); +} + +VOID WINAPI vSvcMain(DWORD dw, LPTSTR * str) +{ + // Get Service Status Handle + gSvcStatusHandle = RegisterServiceCtrlHandler( + SVCNAME, + vHandleEvent); + + if( !gSvcStatusHandle ) + return vReportError(TEXT("RegisterServiceCtrlHandler")); + + // These SERVICE_STATUS members remain as set here + gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + gSvcStatus.dwServiceSpecificExitCode = 0; + vReportState(SERVICE_START_PENDING, NO_ERROR, 3000); + + ghSvcStopEvent = CreateEvent( + NULL, // default security attributes + TRUE, // manual reset event + FALSE, // not signaled + NULL); // no name + + if ( ghSvcStopEvent == NULL) { + vReportState( SERVICE_STOPPED, GetLastError(), 0 ); + return; + } + + vReportState( SERVICE_RUNNING, NO_ERROR, 0 ); + while(bSvcRunning()) { + iServerLoop(FALSE); + } + + vReportState( SERVICE_STOPPED, NO_ERROR, 0 ); +} + +PRIVATE VOID vReportState(DWORD dwCState, DWORD dwW32ECode, DWORD dwWHint) +{ + static DWORD dwCheckPoint = 1; + gSvcStatus.dwCurrentState = dwCState; + gSvcStatus.dwWin32ExitCode = dwW32ECode; + gSvcStatus.dwWaitHint = dwWHint; + + if (dwCState == SERVICE_START_PENDING) + gSvcStatus.dwControlsAccepted = 0; + else + gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ( (dwCState == SERVICE_RUNNING) || + (dwCState == SERVICE_STOPPED) ) + gSvcStatus.dwCheckPoint = 0; + else gSvcStatus.dwCheckPoint = dwCheckPoint++; + + // Report the status of the service to the SCM. + SetServiceStatus( gSvcStatusHandle, &gSvcStatus ); +} + +PRIVATE VOID WINAPI vHandleEvent(DWORD dwCtrl) +{ + switch(dwCtrl) { + case SERVICE_CONTROL_STOP: + vReportState(SERVICE_STOP_PENDING, NO_ERROR, 0); + SetEvent(ghSvcStopEvent); + vReportState(gSvcStatus.dwCurrentState, NO_ERROR, 0); + return; + default: + break; + } +} diff --git a/src/service.h b/src/service.h new file mode 100644 index 0000000..a2d41ac --- /dev/null +++ b/src/service.h @@ -0,0 +1,13 @@ +#ifndef __SERVICE_H__ +#define __SERVICE_H__ +#include + +#define SVCNAME TEXT("DiscordIPCBridge") +#define NOT_IMPLEMENTED(X) _tprintf(TEXT("Not Implemented.\n")); return X + +VOID WINAPI + vSvcMain(DWORD, LPTSTR*); // SvcMain +VOID + vReportError(LPTSTR); + +#endif /* __SERVICE_H__ */ From 72564338f96f8eaa15c069e806677186be0986ee Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Wed, 11 Jan 2023 01:35:43 +0600 Subject: [PATCH 07/12] Add compiled resource support Signed-off-by: Mubashshir --- .gitignore | 1 + Makefile | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b883f1f..a61f079 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.exe +/rcs diff --git a/Makefile b/Makefile index 035eed6..599ddc3 100644 --- a/Makefile +++ b/Makefile @@ -2,17 +2,35 @@ OUTPUT ?= winediscordipcbridge.exe CC := i686-w64-mingw32-gcc +MC := i686-w64-mingw32-windmc +RC := i686-w64-mingw32-windres <> := $(wildcard src/*.c) +<> := $(wildcard res/*.mc) +<> := $(wildcard res/*.rc) <> := $(<>:src/%.c=obj/%.o) +<> += $(<>:res/%.mc=obj/%.rc.o) +<> += $(<>:res/%.rc=obj/%.rc.o) << := @echo ifneq ($(shell eval 'echo -e'),-e) << += -e endif +src/%.h rcs/%.rc : res/%.mc + $(<<) " MC\t"$(<) + @mkdir -p rcs && $(MC) -h src -r rcs $(<) + +obj/%.rc.o: res/%.rc + $(<<) " RC\t"$(@) + @$(RC) -I src $(<) $(@) + +obj/%.rc.o: rcs/%.rc + $(<<) " RC\t"$(@) + @$(RC) -I src $(<) $(@) + obj/%.o: src/%.c - $(<<) "CC\t$(<)" + $(<<) " CC\t$(<)" @mkdir -p obj && $(CC) -masm=intel -c $(<) -o $(@) all: $(OUTPUT) @@ -22,6 +40,8 @@ $(OUTPUT): $(<>) @$(CC) $(^) -o $(@) -lshlwapi clean: - @rm -fv $(<>) $(OUTPUT) + @rm -fv $(<>) $(OUTPUT) rcs/* $(<>:res/%.mc=src/%.h) $(<>:res/%.rc=src/%.h) + @rm -rf rcs .PHONY: clean all +.INTERMEDIATE: $(<>:res/%.mc=src/%.h) $(<>:res/%.rc=src/%.h) $(<>:res/%.mc=rcs/%.rc) From 50d4bed34f0124d28656db21234f72ce9652da75 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Wed, 11 Jan 2023 01:40:54 +0600 Subject: [PATCH 08/12] Implement Service Error reporter Signed-off-by: Mubashshir --- Makefile | 6 ++++-- res/error.mc | 26 ++++++++++++++++++++++++++ src/service-manager.c | 23 ++++++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 res/error.mc diff --git a/Makefile b/Makefile index 599ddc3..bce803d 100644 --- a/Makefile +++ b/Makefile @@ -35,13 +35,15 @@ obj/%.o: src/%.c all: $(OUTPUT) +obj/service-manager.o: src/error.h + $(OUTPUT): $(<>) $(<<) "LINK\t$(@)" @$(CC) $(^) -o $(@) -lshlwapi clean: - @rm -fv $(<>) $(OUTPUT) rcs/* $(<>:res/%.mc=src/%.h) $(<>:res/%.rc=src/%.h) - @rm -rf rcs + @rm -fv $(<>) rcs/* $(<>:res/%.mc=src/%.h) $(<>:res/%.rc=src/%.h) $(OUTPUT) + @rm -rf rcs obj .PHONY: clean all .INTERMEDIATE: $(<>:res/%.mc=src/%.h) $(<>:res/%.rc=src/%.h) $(<>:res/%.mc=rcs/%.rc) diff --git a/res/error.mc b/res/error.mc new file mode 100644 index 0000000..4f43955 --- /dev/null +++ b/res/error.mc @@ -0,0 +1,26 @@ +MessageIdTypedef=DWORD + +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS + Informational=0x1:STATUS_SEVERITY_INFORMATIONAL + Warning=0x2:STATUS_SEVERITY_WARNING + Error=0x3:STATUS_SEVERITY_ERROR +) + +FacilityNames=(System=0x0:FACILITY_SYSTEM + Runtime=0x2:FACILITY_RUNTIME + Stubs=0x3:FACILITY_STUBS + Io=0x4:FACILITY_IO_ERROR_CODE +) + +LanguageNames=(English=0x409:MSG00409) + +; +MessageId=0x1 +Severity=Error +Facility=Runtime +SymbolicName=SVC_ERROR +Language=English +An error has occurred (%2). +. + +; diff --git a/src/service-manager.c b/src/service-manager.c index 1d2d94a..1abbed8 100644 --- a/src/service-manager.c +++ b/src/service-manager.c @@ -4,6 +4,7 @@ #include "server.h" #include "service-manager.h" #include "service.h" +#include "error.h" int iAddService() { @@ -108,5 +109,25 @@ int iRunService() VOID vReportError(LPTSTR szFunction) { - NOT_IMPLEMENTED(); + HANDLE hEvSrc; + LPCTSTR lpszStrs[2]; + TCHAR tcBuf[80]; + + hEvSrc = RegisterEventSource(NULL, SVCNAME); + + if(hEvSrc) { + StringCchPrintf(tcBuf, 80, TEXT("%s failed with %d"), szFunction, GetLastError()); + lpszStrs[0] = SVCNAME; + lpszStrs[1] = tcBuf; + + ReportEvent(hEvSrc, // event log handle + EVENTLOG_ERROR_TYPE, // event type + 0, // event category + SVC_ERROR, // event identifier + NULL, // no security identifier + 2, // size of lpszStrings array + 0, // no binary data + lpszStrs, // array of strings + NULL); + } } From 277e7b1960befa639030ecf70deb1dc4b1e82299 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Wed, 11 Jan 2023 02:09:40 +0600 Subject: [PATCH 09/12] Strip output by default Signed-off-by: Mubashshir --- Makefile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index bce803d..4a68be1 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ OUTPUT ?= winediscordipcbridge.exe +DEBUG ?= false CC := i686-w64-mingw32-gcc MC := i686-w64-mingw32-windmc RC := i686-w64-mingw32-windres +STRIP := i686-w64-mingw32-strip + <> := $(wildcard src/*.c) <> := $(wildcard res/*.mc) <> := $(wildcard res/*.rc) @@ -18,19 +21,19 @@ ifneq ($(shell eval 'echo -e'),-e) endif src/%.h rcs/%.rc : res/%.mc - $(<<) " MC\t"$(<) + $(<<) " MC\t"$(<) @mkdir -p rcs && $(MC) -h src -r rcs $(<) obj/%.rc.o: res/%.rc - $(<<) " RC\t"$(@) + $(<<) " RC\t"$(@) @$(RC) -I src $(<) $(@) obj/%.rc.o: rcs/%.rc - $(<<) " RC\t"$(@) + $(<<) " RC\t"$(@) @$(RC) -I src $(<) $(@) obj/%.o: src/%.c - $(<<) " CC\t$(<)" + $(<<) " CC\t$(<)" @mkdir -p obj && $(CC) -masm=intel -c $(<) -o $(@) all: $(OUTPUT) @@ -38,8 +41,10 @@ all: $(OUTPUT) obj/service-manager.o: src/error.h $(OUTPUT): $(<>) - $(<<) "LINK\t$(@)" + $(<<) " LINK\t$(@)" @$(CC) $(^) -o $(@) -lshlwapi + @test "$(DEBUG)" = "true" || $(<<:@%=%) "STRIP\t$(@)" + @test "$(DEBUG)" = "true" || $(STRIP) $(@) clean: @rm -fv $(<>) rcs/* $(<>:res/%.mc=src/%.h) $(<>:res/%.rc=src/%.h) $(OUTPUT) From b15ad26ffe4e64cd753573beac66a4771f388ae1 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Thu, 12 Jan 2023 02:10:11 +0600 Subject: [PATCH 10/12] Update Status messages and formatting Signed-off-by: Mubashshir --- Makefile | 2 +- src/ipc.c | 388 +++++++++++++++++++++++++++----------------------- src/service.h | 5 +- 3 files changed, 211 insertions(+), 184 deletions(-) diff --git a/Makefile b/Makefile index 4a68be1..3abe7d7 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ endif src/%.h rcs/%.rc : res/%.mc $(<<) " MC\t"$(<) - @mkdir -p rcs && $(MC) -h src -r rcs $(<) + @mkdir -p rcs && $(MC) -b -h src -r rcs $(<) obj/%.rc.o: res/%.rc $(<<) " RC\t"$(@) diff --git a/src/ipc.c b/src/ipc.c index 23d0f69..cfad4d3 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -3,192 +3,220 @@ #include #include "syscalls.h" #include "server.h" +#define INFO(FMTSTR, ...) \ + if(bStandalone) \ + _tprintf(TEXT(FMTSTR), ## __VA_ARGS__) +static BOOL bStandalone = FALSE; static HANDLE hPipe = INVALID_HANDLE_VALUE; static int sock_fd; DWORD WINAPI winwrite_thread(LPVOID lpvParam); -int iServerLoop(BOOL bStandalone) +int iServerLoop(BOOL bStandaloneArg) { - BOOL fConnected = FALSE; - DWORD dwThreadId = 0; - HANDLE hThread = NULL; - LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\discord-ipc-0"); - - // The main loop creates an instance of the named pipe and - // then waits for a client to connect to it. When the client - // connects, a thread is created to handle communications - // with that client, and this loop is free to wait for the - // next client connect request. It is an infinite loop. - - _tprintf( TEXT("Pipe Server: Main thread awaiting client connection on %s\n"), lpszPipename); - hPipe = CreateNamedPipe( - lpszPipename, // pipe name - PIPE_ACCESS_DUPLEX, // read/write access - PIPE_TYPE_BYTE | // message type pipe - PIPE_READMODE_BYTE | // message-read mode - PIPE_WAIT, // blocking mode - 1, // max. instances - BUFSIZE, // output buffer size - BUFSIZE, // input buffer size - 0, // client time-out - NULL); // default security attribute - - if (hPipe == INVALID_HANDLE_VALUE) - { - _tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError()); - return -1; - } - - // Wait for the client to connect; if it succeeds, - // the function returns a nonzero value. If the function - // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. - - fConnected = ConnectNamedPipe(hPipe, NULL) ? - TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); - - if (fConnected) - { - printf("Client connected\n"); - - printf("Creating socket\n"); - - if ((sock_fd = l_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - printf("Failed to create socket\n"); - return 1; - } - - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - - const char *const temp_path = get_temp_path(); - - char *paths[] = { - "%s/discord-ipc-%d", - "%s/app/com.discordapp.Discord/discord-ipc-%d", - "%s/snap.discord-canary/discord-ipc-%d", - "%s/snap.discord/discord-ipc-%d" - }; - - char connected = 0; - for (int p = 0; p < sizeof(paths) / sizeof(paths[0]); p++) { - for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { - - snprintf(addr.sun_path, sizeof(addr.sun_path), paths[p], temp_path, pipeNum); - printf("Attempting to connect to %s\n", addr.sun_path); - - if (l_connect(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { - printf("Failed to connect\n"); - } else { - connected = 1; - goto breakout; - } - } - } -breakout:; - - if (!connected) { - printf("Could not connect to discord client\n"); - return 1; - } - - - printf("Connected successfully\n"); - - hThread = CreateThread( - NULL, // no security attribute - 0, // default stack size - winwrite_thread, // thread proc - (LPVOID) NULL, // thread parameter - 0, // not suspended - &dwThreadId); // returns thread ID - - if (hThread == NULL) - { - _tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError()); - return 1; - } - - - while(bStandalone || bSvcRunning()) { - char buf[BUFSIZE]; - DWORD bytes_read = 0; - BOOL fSuccess = ReadFile( - hPipe, // handle to pipe - buf, // buffer to receive data - BUFSIZE, // size of buffer - &bytes_read, // number of bytes read - NULL); // not overlapped I/O - if (!fSuccess) { - if (GetLastError() == ERROR_BROKEN_PIPE) { - printf("winread EOF\n"); - return 0; - } else { - printf("Failed to read from pipe\n"); - return 1; - } - } - - printf("%d bytes w->l\n", bytes_read); - /* uncomment to dump the actual data being passed from the pipe to the socket */ - /* for(int i=0;il\n", bytes_read); + /* uncomment to dump the actual data being passed from the pipe to the socket */ + /* for(int i=0;iw\n", bytes_read); - /* uncomment to dump the actual data being passed from the socket to the pipe */ - /* for(int i=0;iw\n", bytes_read); + /* uncomment to dump the actual data being passed from the socket to the pipe */ + /* for(int i=0;i #define SVCNAME TEXT("DiscordIPCBridge") -#define NOT_IMPLEMENTED(X) _tprintf(TEXT("Not Implemented.\n")); return X VOID WINAPI - vSvcMain(DWORD, LPTSTR*); // SvcMain + vSvcMain(DWORD, LPTSTR*); // Service Entry Point VOID - vReportError(LPTSTR); + vReportError(LPTSTR); // Service Error Reporter #endif /* __SERVICE_H__ */ From eeadbebeeba3d134da60d09fdf3163ff7dfa2711 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Fri, 27 Jan 2023 01:47:11 +0600 Subject: [PATCH 11/12] IPC: Close handles before return Signed-off-by: Mubashshir --- src/ipc.c | 210 +++++++++++++++++++++++++------------------------- src/main.c | 13 ++-- src/server.h | 2 +- src/service.c | 21 ++--- 4 files changed, 127 insertions(+), 119 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index cfad4d3..17533d0 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -3,6 +3,7 @@ #include #include "syscalls.h" #include "server.h" +#define PRIVATE static // private functions #define INFO(FMTSTR, ...) \ if(bStandalone) \ _tprintf(TEXT(FMTSTR), ## __VA_ARGS__) @@ -10,15 +11,16 @@ static BOOL bStandalone = FALSE; static HANDLE hPipe = INVALID_HANDLE_VALUE; static int sock_fd; -DWORD WINAPI winwrite_thread(LPVOID lpvParam); -int iServerLoop(BOOL bStandaloneArg) +// Private Function definitions +PRIVATE DWORD WINAPI winwrite_thread(LPVOID lpvParam); +PRIVATE int iListenPipe(); + +int iServerMain(BOOL bStandaloneArg) { - BOOL fConnected = FALSE; - DWORD dwThreadId = 0; - HANDLE hThread = NULL; LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\discord-ipc-0"); bStandalone = bStandaloneArg; + int ret = 0; // The main loop creates an instance of the named pipe and // then waits for a client to connect to it. When the client @@ -45,137 +47,139 @@ int iServerLoop(BOOL bStandaloneArg) return -1; } + ret = iListenPipe(); + CloseHandle(hPipe); + hPipe = INVALID_HANDLE_VALUE; + + return ret; +} + +PRIVATE int iListenPipe() +{ + BOOL fConnected = FALSE; + DWORD dwThreadId = 0; + HANDLE hThread = NULL; + BOOL connected = FALSE; + + fConnected = ConnectNamedPipe(hPipe, NULL) ? + TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + // Wait for the client to connect; if it succeeds, // the function returns a nonzero value. If the function // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. + if (!fConnected) return 1; - fConnected = ConnectNamedPipe(hPipe, NULL) ? - TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + INFO("Client connected\n"); + INFO("Creating socket\n"); - if (fConnected) + if ((sock_fd = l_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - INFO("Client connected\n"); - - INFO("Creating socket\n"); + INFO("Failed to create socket\n"); + return 1; + } - if ((sock_fd = l_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - INFO("Failed to create socket\n"); - return 1; - } + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; + const char *const temp_path = get_temp_path(); - const char *const temp_path = get_temp_path(); + char *paths[] = + { + "%s/discord-ipc-%d", + "%s/app/com.discordapp.Discord/discord-ipc-%d", + "%s/snap.discord-canary/discord-ipc-%d", + "%s/snap.discord/discord-ipc-%d" + }; - char *paths[] = - { - "%s/discord-ipc-%d", - "%s/app/com.discordapp.Discord/discord-ipc-%d", - "%s/snap.discord-canary/discord-ipc-%d", - "%s/snap.discord/discord-ipc-%d" - }; - - char connected = 0; - for (int p = 0; p < sizeof(paths) / sizeof(paths[0]); p++) + for (int p = 0; p < sizeof(paths) / sizeof(paths[0]) && !connected; p++) + { + for (int pipeNum = 0; pipeNum < 10 && !connected; ++pipeNum) { - for (int pipeNum = 0; pipeNum < 10; ++pipeNum) - { - StringCchPrintf(addr.sun_path, sizeof(addr.sun_path), paths[p], temp_path, pipeNum); - INFO("Attempting to connect to %s\n", addr.sun_path); - - if (l_connect(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) - { - INFO("Failed to connect\n"); - } - else - { - connected = 1; - goto breakout; - } - } - } -breakout: - ; + StringCchPrintf(addr.sun_path, sizeof(addr.sun_path), paths[p], temp_path, pipeNum); + INFO("Attempting to connect to %s\n", addr.sun_path); - if (!connected) - { - INFO("Could not connect to discord client\n"); - return 1; + connected = !(l_connect(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0); + if (!connected) + INFO("Failed to connect\n"); } + } + if (!connected) + { + INFO("Could not connect to discord client\n"); + return 1; + } - INFO("Connected successfully\n"); + INFO("Connected successfully\n"); + hThread = CreateThread( + NULL, // no security attribute + 0, // default stack size + winwrite_thread, // thread proc + (LPVOID) NULL, // thread parameter + 0, // not suspended + &dwThreadId); // returns thread ID - hThread = CreateThread( - NULL, // no security attribute - 0, // default stack size - winwrite_thread, // thread proc - (LPVOID) NULL, // thread parameter - 0, // not suspended - &dwThreadId); // returns thread ID + if (hThread == NULL) + { + INFO("CreateThread failed, GLE=%d.\n", GetLastError()); + return 1; + } - if (hThread == NULL) + while(bStandalone || bSvcRunning()) + { + char buf[BUFSIZE]; + DWORD bytes_read = 0; + BOOL fSuccess = ReadFile( + hPipe, // handle to pipe + buf, // buffer to receive data + BUFSIZE, // size of buffer + &bytes_read, // number of bytes read + NULL); // not overlapped I/O + if (!fSuccess) { - INFO("CreateThread failed, GLE=%d.\n", GetLastError()); - return 1; - } - + CloseHandle(hThread); - while(bStandalone || bSvcRunning()) - { - char buf[BUFSIZE]; - DWORD bytes_read = 0; - BOOL fSuccess = ReadFile( - hPipe, // handle to pipe - buf, // buffer to receive data - BUFSIZE, // size of buffer - &bytes_read, // number of bytes read - NULL); // not overlapped I/O - if (!fSuccess) + if (GetLastError() == ERROR_BROKEN_PIPE) { - if (GetLastError() == ERROR_BROKEN_PIPE) - { - INFO("winread EOF\n"); - return 0; - } - else - { - INFO("Failed to read from pipe\n"); - return 1; - } + INFO("winread EOF\n"); + return 0; } + INFO("Failed to read from pipe\n"); + return 1; + } - INFO("%d bytes w->l\n", bytes_read); - /* uncomment to dump the actual data being passed from the pipe to the socket */ - /* for(int i=0;il\n", bytes_read); + /* pass -D__WDBRIDGE_DUMP_PIPE to gcc + * to dump the actual data being passed + * from the pipe to the socket */ +#ifdef __WDBRIDGE_DUMP_PIPE + for(int i = 0; i < bytes_read; i++) + putchar(buf[i]); + INFO("\n"); +#endif - int total_written = 0, written = 0; + int total_written = 0, written = 0; - while (total_written < bytes_read) + while (total_written < bytes_read) + { + written = l_write(sock_fd, buf + total_written, bytes_read - total_written); + if (written < 0) { - written = l_write(sock_fd, buf + total_written, bytes_read - total_written); - if (written < 0) - { - INFO("Failed to write to socket\n"); - return 1; - } - total_written += written; - written = 0; + INFO("Failed to write to socket\n"); + CloseHandle(hThread); + return 1; } + total_written += written; + written = 0; } } - else - // The client could not connect, so close the pipe. - CloseHandle(hPipe); + CloseHandle(hThread); return 0; } -DWORD WINAPI winwrite_thread(LPVOID lpvParam) +PRIVATE DWORD WINAPI winwrite_thread(LPVOID lpvParam) { for (;;) diff --git a/src/main.c b/src/main.c index 9ab68a8..b5fe2e8 100644 --- a/src/main.c +++ b/src/main.c @@ -6,15 +6,16 @@ #define ARGV1(X) (argc > 1 && lstrcmpi( argv[1], TEXT(X)) == 0) #define basename PathFindFileName(argv[0]) -int _tmain(int argc, TCHAR *argv[]) { +int _tmain(int argc, TCHAR *argv[]) +{ if(ARGV1("install")) return iAddService(); else if(ARGV1("remove")) return iDelService(); else if(ARGV1("service")) return iRunService(); else if(argc > 1) return (_tprintf( - TEXT("Run Standalone : %s\n" - "Install Service: %s install\n" - "Remove Service : %s remove\n"), - basename, basename, basename) * 0); - return iServerLoop(TRUE); + TEXT("Run Standalone : %s\n" + "Install Service: %s install\n" + "Remove Service : %s remove\n"), + basename, basename, basename) * 0); + return iServerMain(TRUE); } diff --git a/src/server.h b/src/server.h index fdb7c27..60b6b6c 100644 --- a/src/server.h +++ b/src/server.h @@ -3,7 +3,7 @@ #include -int iServerLoop(BOOL); +int iServerMain(BOOL); BOOL bSvcRunning(VOID); #endif /* __SERVER_H__ */ diff --git a/src/service.c b/src/service.c index dce45d7..63b85f6 100644 --- a/src/service.c +++ b/src/service.c @@ -3,11 +3,11 @@ #include "service.h" #include "server.h" -#define PRIVATE // private functions +#define PRIVATE static // private functions -static SERVICE_STATUS gSvcStatus; -static SERVICE_STATUS_HANDLE gSvcStatusHandle; -static HANDLE ghSvcStopEvent = NULL; +PRIVATE SERVICE_STATUS gSvcStatus; +PRIVATE SERVICE_STATUS_HANDLE gSvcStatusHandle; +PRIVATE HANDLE ghSvcStopEvent = NULL; PRIVATE VOID vReportState(DWORD, DWORD, DWORD); PRIVATE VOID WINAPI vHandleEvent(DWORD); @@ -42,14 +42,16 @@ VOID WINAPI vSvcMain(DWORD dw, LPTSTR * str) FALSE, // not signaled NULL); // no name - if ( ghSvcStopEvent == NULL) { + if ( ghSvcStopEvent == NULL) + { vReportState( SERVICE_STOPPED, GetLastError(), 0 ); return; } vReportState( SERVICE_RUNNING, NO_ERROR, 0 ); - while(bSvcRunning()) { - iServerLoop(FALSE); + while(bSvcRunning()) + { + iServerMain(FALSE); } vReportState( SERVICE_STOPPED, NO_ERROR, 0 ); @@ -68,7 +70,7 @@ PRIVATE VOID vReportState(DWORD dwCState, DWORD dwW32ECode, DWORD dwWHint) gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; if ( (dwCState == SERVICE_RUNNING) || - (dwCState == SERVICE_STOPPED) ) + (dwCState == SERVICE_STOPPED) ) gSvcStatus.dwCheckPoint = 0; else gSvcStatus.dwCheckPoint = dwCheckPoint++; @@ -78,7 +80,8 @@ PRIVATE VOID vReportState(DWORD dwCState, DWORD dwW32ECode, DWORD dwWHint) PRIVATE VOID WINAPI vHandleEvent(DWORD dwCtrl) { - switch(dwCtrl) { + switch(dwCtrl) + { case SERVICE_CONTROL_STOP: vReportState(SERVICE_STOP_PENDING, NO_ERROR, 0); SetEvent(ghSvcStopEvent); From 15c32743045d534fc24005572453ecc7f9e68635 Mon Sep 17 00:00:00 2001 From: Mubashshir Date: Sat, 11 Mar 2023 09:33:53 +0600 Subject: [PATCH 12/12] Update compilation instructions Signed-off-by: Mubashshir --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fa54a0c..30596b6 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ The way it works is simply by bridging the gap between Windows named pipes Compiling ========= - i686-w64-mingw32-gcc -masm=intel main.c -o winediscordipcbridge +```sh +make +``` Usage (Wine) ============ @@ -24,6 +26,18 @@ Start the bridge first, wait for it to start listening to the pipe, and then launch your program/game. The two programs need to be running under the same wineprefix. +Usage (wine service) +==================== + +```sh +WINEPREFIX= wine ./winediscordipcbridge.exe install +``` + +Run this (^) snippet to install the bridge as a service, next time you start +anything in wine, the bridge will automatically start and connect your game +and discord. + + Usage (Steam Proton) ====================