Compare commits

..

No commits in common. "d065019137ca6a47a92ddfc4f82e166825dfbfd0" and "9d2440f6161b87b14ceb517800ed34983962d401" have entirely different histories.

10 changed files with 87 additions and 121 deletions

View File

@ -21,11 +21,11 @@ Steps to reproduce the behavior:
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Log File** **Log File**
Located in `/path/to/prefix/drive_c/windows/logs/bridge.log` or a screenshot with the terminal should suffice. Located in `/path/to/prefix/drive_c/windows/logs/bridge.log`
**System Info (please complete the following information):** **Device (please complete the following information):**
- OS: [e.g. SteamOS 3.0, Ubuntu 22.04, macOS 15, or output from command `uname -srm`] - OS: [e.g. SteamOS, Ubuntu, macOS]
- Wine: [e.g. 10.5] - Version [e.g. 22.04]
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View File

@ -1,21 +1,29 @@
name: Deploy Documentation name: Build and Deploy docs
on: on:
push: push:
branches: [ master ] branches: [ "master" ]
paths:
- docs/**
- mkdocs.yml
pull_request: pull_request:
branches: [ "master" ] branches: [ "master" ]
paths:
- docs/**
- mkdocs.yml
permissions: permissions:
contents: write contents: write
jobs: jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: dependencies
run: sudo apt update && sudo apt -y install gcc-mingw-w64 make
- name: make
run: make
- name: artifact
uses: actions/upload-artifact@v4
with:
name: bridge
path: build
deploy: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -1,35 +0,0 @@
name: Build Project
on:
push:
branches: [ "master" ]
paths-ignore:
- 'ISSUE_TEMPLATE/**'
- 'workflows/**'
- '.vsocde/**'
- 'docs/**'
pull_request:
branches: [ "master" ]
paths-ignore:
- 'ISSUE_TEMPLATE/**'
- 'workflows/**'
- '.vsocde/**'
- 'docs/**'
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: dependencies
run: sudo apt update && sudo apt -y install gcc-mingw-w64 make
- name: make
run: make
- name: artifact
uses: actions/upload-artifact@v4
with:
name: bridge
path: build

View File

@ -5,7 +5,7 @@ GIT_COMMIT = $(shell git rev-parse --short HEAD)
GIT_BRANCH = $(shell git rev-parse --abbrev-ref HEAD) GIT_BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
CFLAGS = -std=c17 -Wno-int-conversion -DGIT_COMMIT='"$(GIT_COMMIT)"' -DGIT_BRANCH='"$(GIT_BRANCH)"' CFLAGS = -std=c17 -Wno-int-conversion -DGIT_COMMIT='"$(GIT_COMMIT)"' -DGIT_BRANCH='"$(GIT_BRANCH)"'
LFLAGS = -lgdi32 -lws2_32 LFLAGS = -lgdi32
# DBGFLAGS = -Wl,--export-all-symbols -g -O0 -ggdb3 -Wall # DBGFLAGS = -Wl,--export-all-symbols -g -O0 -ggdb3 -Wall

109
bridge.c
View File

@ -195,7 +195,11 @@ char *native_getenv(const char *name)
/* I hope the 0x20000 is okay */ /* I hope the 0x20000 is okay */
if (environStr == NULL) if (environStr == NULL)
environStr = sys_mmap(0x20000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); {
environStr = sys_mmap(0x20000, 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
print("Allocated 4096 bytes at %#lx\n", environStr);
}
if ((uintptr_t)environStr > 0x7effffff) if ((uintptr_t)environStr > 0x7effffff)
print("Warning: environStr %#lx is above 2GB\n", environStr); print("Warning: environStr %#lx is above 2GB\n", environStr);
@ -205,17 +209,18 @@ char *native_getenv(const char *name)
int fd = sys_open(environStr, O_RDONLY, 0); int fd = sys_open(environStr, O_RDONLY, 0);
// sys_munmap(environStr, 4096);
if (fd < 0) if (fd < 0)
{ {
print("Failed to open /proc/self/environ: %d\n", fd); print("Failed to open /proc/self/environ: %d\n", fd);
return NULL; return NULL;
} }
char *buffer = sys_mmap(0x22000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); char buffer[4096];
char *result = NULL; char *result = NULL;
int bytesRead; int bytesRead;
while ((bytesRead = sys_read(fd, buffer, 0x1000 - 1)) > 0) while ((bytesRead = sys_read(fd, buffer, sizeof(buffer) - 1)) > 0)
{ {
buffer[bytesRead] = '\0'; buffer[bytesRead] = '\0';
char *env = buffer; char *env = buffer;
@ -285,8 +290,8 @@ void ConnectToSocket(int fd)
"%s/snap.discord-canary/discord-ipc-%d", "%s/snap.discord-canary/discord-ipc-%d",
}; };
struct sockaddr_un *socketAddr = sys_mmap(0x23000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); struct sockaddr_un socketAddr;
socketAddr->sun_family = AF_UNIX; socketAddr.sun_family = AF_UNIX;
int sockRet = 0; int sockRet = 0;
for (int i = 0; i < sizeof(discordUnixSockets) / sizeof(discordUnixSockets[0]); i++) for (int i = 0; i < sizeof(discordUnixSockets) / sizeof(discordUnixSockets[0]); i++)
@ -297,20 +302,15 @@ void ConnectToSocket(int fd)
for (int j = 0; j < 16; j++) for (int j = 0; j < 16; j++)
{ {
snprintf(pipePath, pipePathLen, discordUnixSockets[i], runtime, j); snprintf(pipePath, pipePathLen, discordUnixSockets[i], runtime, j);
strcpy_s(socketAddr->sun_path, sizeof(socketAddr->sun_path), pipePath); strcpy_s(socketAddr.sun_path, sizeof(socketAddr.sun_path), pipePath);
print("Probing %s\n", pipePath); print("Probing %s\n", pipePath);
if (IsLinux) if (IsLinux)
{ {
// unsigned long socketArgs[] = { unsigned long socketArgs[] = {
// (unsigned long)fd, (unsigned long)fd,
// (unsigned long)(intptr_t)&socketAddr, (unsigned long)(intptr_t)&socketAddr,
// sizeof(socketAddr)}; sizeof(socketAddr)};
unsigned long *socketArgs = sys_mmap(0x24000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
socketArgs[0] = (unsigned long)fd;
socketArgs[1] = (unsigned long)(intptr_t)socketAddr;
socketArgs[2] = sizeof(struct sockaddr_un);
socketArgs[3] = 0;
sockRet = sys_socketcall(SYS_CONNECT, socketArgs); sockRet = sys_socketcall(SYS_CONNECT, socketArgs);
} }
@ -345,17 +345,18 @@ void ConnectToSocket(int fd)
void PipeBufferInThread(LPVOID lpParam) void PipeBufferInThread(LPVOID lpParam)
{ {
bridge_thread *bt = (bridge_thread *)lpParam; bridge_thread *bt = (bridge_thread *)lpParam;
print("In thread started using fd %d and pipe %#x\n", bt->fd, bt->hPipe); print("In thread started using fd %d and pipe %#x\n",
bt->fd, bt->hPipe);
int EOFCount = 0; int EOFCount = 0;
char *l_buffer = sys_mmap(0x25000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
while (TRUE) while (TRUE)
{ {
char buffer[BUFFER_LENGTH]; char buffer[BUFFER_LENGTH];
int read = sys_read(bt->fd, l_buffer, BUFFER_LENGTH); int read = sys_read(bt->fd, buffer, sizeof(buffer));
if (unlikely(read < 0)) if (unlikely(read < 0))
{ {
print("Failed to read from unix pipe: %d\n", read); print("Failed to read from unix pipe: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
@ -377,16 +378,14 @@ void PipeBufferInThread(LPVOID lpParam)
} }
EOFCount = 0; EOFCount = 0;
memcpy(buffer, l_buffer, read);
print("Reading %d bytes from unix pipe: \"", read); print("Reading %d bytes from unix pipe: \"", read);
for (int i = 0; i < read; i++) for (int i = 0; i < read; i++)
print("%c", buffer[i]); print("%c", buffer[i]);
print("\"\n"); print("\"\n");
DWORD dwWritten; DWORD dwWritten;
WINBOOL bResult = WriteFile(bt->hPipe, buffer, read, &dwWritten, NULL); if (unlikely(!WriteFile(bt->hPipe, buffer, read,
if (unlikely(bResult == FALSE)) &dwWritten, NULL)))
{ {
if (GetLastError() == ERROR_BROKEN_PIPE) if (GetLastError() == ERROR_BROKEN_PIPE)
{ {
@ -395,14 +394,16 @@ void PipeBufferInThread(LPVOID lpParam)
break; break;
} }
print("Failed to read from pipe: %s\n", GetErrorMessage()); print("Failed to read from pipe: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
if (unlikely(dwWritten < 0)) if (unlikely(dwWritten < 0))
{ {
print("Failed to write to pipe: %s\n", GetErrorMessage()); print("Failed to write to pipe: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
@ -410,8 +411,8 @@ void PipeBufferInThread(LPVOID lpParam)
while (dwWritten < read) while (dwWritten < read)
{ {
int last_written = dwWritten; int last_written = dwWritten;
WINBOOL bResult = WriteFile(bt->hPipe, buffer + dwWritten, read - dwWritten, &dwWritten, NULL); if (unlikely(!WriteFile(bt->hPipe, buffer + dwWritten,
if (unlikely(bResult == FALSE)) read - dwWritten, &dwWritten, NULL)))
{ {
if (GetLastError() == ERROR_BROKEN_PIPE) if (GetLastError() == ERROR_BROKEN_PIPE)
{ {
@ -420,14 +421,16 @@ void PipeBufferInThread(LPVOID lpParam)
break; break;
} }
print("Failed to read from pipe: %s\n", GetErrorMessage()); print("Failed to read from pipe: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
if (unlikely(last_written == dwWritten)) if (unlikely(last_written == dwWritten))
{ {
print("Failed to write to pipe: %s\n", GetErrorMessage()); print("Failed to write to pipe: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
@ -438,14 +441,15 @@ void PipeBufferInThread(LPVOID lpParam)
void PipeBufferOutThread(LPVOID lpParam) void PipeBufferOutThread(LPVOID lpParam)
{ {
bridge_thread *bt = (bridge_thread *)lpParam; bridge_thread *bt = (bridge_thread *)lpParam;
print("Out thread started using fd %d and pipe %#x\n", bt->fd, bt->hPipe); print("Out thread started using fd %d and pipe %#x\n",
char *l_buffer = sys_mmap(0x25000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); bt->fd, bt->hPipe);
while (TRUE) while (TRUE)
{ {
char buffer[BUFFER_LENGTH]; char buffer[BUFFER_LENGTH];
DWORD dwRead; DWORD dwRead;
WINBOOL bResult = ReadFile(bt->hPipe, buffer, BUFFER_LENGTH, &dwRead, NULL);
if (unlikely(bResult == FALSE)) if (unlikely(!ReadFile(bt->hPipe, buffer, sizeof(buffer),
&dwRead, NULL)))
{ {
if (GetLastError() == ERROR_BROKEN_PIPE) if (GetLastError() == ERROR_BROKEN_PIPE)
{ {
@ -454,7 +458,8 @@ void PipeBufferOutThread(LPVOID lpParam)
break; break;
} }
print("Failed to read from pipe: %s\n", GetErrorMessage()); print("Failed to read from pipe: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
@ -464,11 +469,11 @@ void PipeBufferOutThread(LPVOID lpParam)
print("%c", buffer[i]); print("%c", buffer[i]);
print("\"\n"); print("\"\n");
memcpy(l_buffer, buffer, dwRead); int written = sys_write(bt->fd, buffer, dwRead);
int written = sys_write(bt->fd, l_buffer, dwRead);
if (unlikely(written < 0)) if (unlikely(written < 0))
{ {
print("Failed to write to socket: %d\n", written); print("Failed to write to socket: %d\n",
written);
continue; continue;
} }
@ -478,7 +483,8 @@ void PipeBufferOutThread(LPVOID lpParam)
written += sys_write(bt->fd, buffer + written, dwRead - written); written += sys_write(bt->fd, buffer + written, dwRead - written);
if (unlikely(last_written == written)) if (unlikely(last_written == written))
{ {
print("Failed to write to socket: %s\n", GetErrorMessage()); print("Failed to write to socket: %d\n",
GetErrorMessage());
Sleep(1000); Sleep(1000);
continue; continue;
} }
@ -541,31 +547,16 @@ NewConnection:
int fd; int fd;
if (IsLinux) if (IsLinux)
{ {
// unsigned long socketArgs[] = { unsigned long socketArgs[] = {
// (unsigned long)AF_UNIX, (unsigned long)AF_UNIX,
// (unsigned long)SOCK_STREAM, (unsigned long)SOCK_STREAM,
// 0}; 0};
unsigned long *socketArgs = sys_mmap(0x21000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
socketArgs[0] = (unsigned long)AF_UNIX;
socketArgs[1] = (unsigned long)SOCK_STREAM;
socketArgs[2] = 0;
fd = sys_socketcall(SYS_SOCKET, socketArgs); fd = sys_socketcall(SYS_SOCKET, socketArgs);
/* FIXME: WSAEAFNOSUPPORT: https://gitlab.winehq.org/wine/wine/-/merge_requests/2786 */
// WSADATA wsaData;
// int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// if (iResult != 0)
// printf("WSAStartup failed: %d\n", iResult);
// fd = socket(AF_UNIX, SOCK_STREAM, 0);
} }
else else
fd = sys_socket(AF_UNIX, SOCK_STREAM, 0); fd = sys_socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == INVALID_SOCKET) print("Socket %d created\n", fd);
{
print("invalid socket: %d %d\n", fd, WSAGetLastError());
ExitProcess(1);
}
if (fd < 0) if (fd < 0)
{ {
@ -576,8 +567,6 @@ NewConnection:
ExitProcess(1); ExitProcess(1);
} }
print("Socket %d created\n", fd);
ConnectToSocket(fd); ConnectToSocket(fd);
print("Connected to Discord\n"); print("Connected to Discord\n");

View File

@ -19,7 +19,7 @@ BEGIN
VALUE "FileDescription", "Simple bridge that allows you to use Discord Rich Presence with Wine games/software." VALUE "FileDescription", "Simple bridge that allows you to use Discord Rich Presence with Wine games/software."
VALUE "FileVersion", VER_VERSION_STR VALUE "FileVersion", VER_VERSION_STR
VALUE "InternalName", "bridge" VALUE "InternalName", "bridge"
VALUE "LegalCopyright", "Copyright (c) 2025 EnderIce2" VALUE "LegalCopyright", "Copyright (c) 2024 EnderIce2"
VALUE "OriginalFilename", "bridge.exe" VALUE "OriginalFilename", "bridge.exe"
VALUE "ProductName", "rpc-bridge" VALUE "ProductName", "rpc-bridge"
VALUE "ProductVersion", VER_VERSION_STR VALUE "ProductVersion", VER_VERSION_STR

View File

@ -9,7 +9,7 @@ Simple bridge that allows you to use Discord Rich Presence with Wine games/softw
[Download latest release](https://github.com/EnderIce2/rpc-bridge/releases/latest/download/bridge.zip "Recommended"){ .md-button .md-button--primary } [Download latest release](https://github.com/EnderIce2/rpc-bridge/releases/latest/download/bridge.zip "Recommended"){ .md-button .md-button--primary }
[Download latest pre-release](https://github.com/EnderIce2/rpc-bridge/releases "Unstable builds with experimental features"){ .md-button } [Download latest pre-release](https://github.com/EnderIce2/rpc-bridge/releases "Unstable builds with experimental features"){ .md-button }
[Download latest build](https://github.com/EnderIce2/rpc-bridge/actions/workflows/build.yml "Builds from the latest commits, here be dragons!"){ .md-button } <!-- [Download latest build](https://github.com/EnderIce2/rpc-bridge/actions "Builds from the latest commits, here be dragons!"){ .md-button } -->
Works by running a small program in the background that creates a [named pipe](https://learn.microsoft.com/en-us/windows/win32/ipc/named-pipes) `\\.\pipe\discord-ipc-0` inside the prefix and forwards all data to the pipe `/run/user/1000/discord-ipc-0`. Works by running a small program in the background that creates a [named pipe](https://learn.microsoft.com/en-us/windows/win32/ipc/named-pipes) `\\.\pipe\discord-ipc-0` inside the prefix and forwards all data to the pipe `/run/user/1000/discord-ipc-0`.

View File

@ -84,17 +84,21 @@ In Lutris, you can achieve this by adding the path to `bridge.exe` in the `Execu
=== "Without bridge" === "Without bridge"
- Executable ```
- `/mnt/games/lutris/league-of-legends/drive_c/Riot Games/League of Legends/LeagueClient.exe` Executable
- Arguments /mnt/games/lutris/league-of-legends/drive_c/Riot Games/League of Legends/LeagueClient.exe
- `--locale=en_US --launch-product=league_of_legends --launch-patchline=live` Arguments
--locale=en_US --launch-product=league_of_legends --launch-patchline=live
```
=== "With bridge" === "With bridge"
- Executable ```
- `/mnt/games/lutris/league-of-legends/drive_c/bridge.exe` Executable
- Arguments /mnt/games/lutris/league-of-legends/drive_c/bridge.exe
- `"C:\Riot Games\League of Legends\LeagueClient.exe" --locale=en_US --launch-product=league_of_legends --launch-patchline=live` Arguments
"C:\Riot Games\League of Legends\LeagueClient.exe" --locale=en_US --launch-product=league_of_legends --launch-patchline=live
```
In Wine, all you need to do is run `bridge.exe` and select `Start`. In Wine, all you need to do is run `bridge.exe` and select `Start`.

2
main.c
View File

@ -59,7 +59,7 @@ void DetectWine()
if (!GetProcAddress(hNTdll, "wine_get_version")) if (!GetProcAddress(hNTdll, "wine_get_version"))
{ {
MessageBox(NULL, "This program is only intended to run under Wine.", MessageBox(NULL, "This program is only intended to run under Wine.",
"Error", MB_OK | MB_ICONINFORMATION); GetErrorMessage(), MB_OK | MB_ICONINFORMATION);
ExitProcess(1); ExitProcess(1);
} }

View File

@ -5,5 +5,5 @@
#define IDM_HELP_ABOUT 40003 #define IDM_HELP_ABOUT 40003
#define IDM_VIEW_LOG 40004 #define IDM_VIEW_LOG 40004
#define VER_VERSION 1, 4, 0, 0 #define VER_VERSION 1, 3, 0, 0
#define VER_VERSION_STR "1.4.0.0\0" #define VER_VERSION_STR "1.3\0"