Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

full_posix_sockets #7672

Merged
merged 10 commits into from
Dec 10, 2019
Merged

full_posix_sockets #7672

merged 10 commits into from
Dec 10, 2019

Conversation

juj
Copy link
Collaborator

@juj juj commented Dec 14, 2018

This adds full POSIX sockets API support via a -s PROXY_POSIX_SOCKETS=1 option. This is implemented by proxying out the sockets API calls to a separate proxy bridge process running on localhost. (that one needs to separately spawn)

This can be useful for special occassions, e.g. when building unit test harnesses or similar, where one just wants to compile existing POSIX sockets code and "have it work" locally. A web browser page can then be simulated to act as a TCP or UDP server, for example.

The feature builds on top of #7670, and can only land after #7670 lands.

Will need splitting out libc to two .bc library parts, one for proxy sockets variant, and another one with the musl stubs.

@juj
Copy link
Collaborator Author

juj commented Jan 31, 2019

This PR would now be good to land, but this is producing some errors on the upstream bots that I do not understand, and am unable to reproduce. @kripken Does any of that make sense to you?

@kripken
Copy link
Member

kripken commented Jan 31, 2019

I can reproduce those errors locally, using the LLVM wasm backend. E.g. other.test_export_all_ fails on

error: undefined symbol: accept
warning: To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`
error: undefined symbol: bind
error: undefined symbol: connect
error: undefined symbol: getsockname
error: undefined symbol: recv
error: undefined symbol: recvfrom
error: undefined symbol: send
error: undefined symbol: sendto
error: undefined symbol: setsockopt
error: undefined symbol: socket
Error: Aborting compilation due to previous errors

@juj
Copy link
Collaborator Author

juj commented Feb 1, 2019

Hmm, I wonder why that would occur only on the wasm backend.. Those symbols are moved from libc.bc over to libc-sockets.bc, and a libc-sockets.symbols file is provided, which declares those symbols for linking.

@juj
Copy link
Collaborator Author

juj commented Feb 1, 2019

Oh, perhaps I need to also update the libc.symbols and wasm-libc.symbols files, let's see if that does it.

@juj juj force-pushed the full_posix_sockets branch 4 times, most recently from 80189a4 to 52ce4d5 Compare February 5, 2019 10:35
@juj
Copy link
Collaborator Author

juj commented Feb 5, 2019

Updated this PR and it now passes. Ready for a second review?

@kripken
Copy link
Member

kripken commented Feb 6, 2019

I don't understand the motivation here yet. What does "proxy" mean - what is proxied where? Is this related to threading proxying?

@juj
Copy link
Collaborator Author

juj commented Feb 6, 2019

Proxying here means that instead of implementing the POSIX sockets calls in the browser, each sockets API call is serialized out via WebSockets pipe over to a native "websockify" style intermediate process, which natively performs those exact sockets calls, and returns the results back - making the Emscripten page look like it has full sockets API access available to it. In order to pull it off, it does require threading proxying, because this only works in multithreaded PROXY_TO_PTHREAD builds, since the command proxying is synchronous.

@juj
Copy link
Collaborator Author

juj commented Feb 10, 2019

Updated this PR, and it now looks green to merge. Good for a review pass?

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, so this lets you use normal C sockets code, and it synchronously proxies commands to a websockets server that does the actual sockets operations? And you say it's useful for things like test harnesses etc. - this seems like quite a lot of work for just that? I feel like I'm missing the use case.

Emscripten provides a native POSIX Sockets proxy server program, located in directory tools/websocket_to_posix_proxy/, that allows full POSIX Sockets API access from a web browser. This support works by proxying all POSIX Sockets API calls from the browser to the Emscripten POSIX Sockets proxy server (via transparent use of WebSockets API), and the proxy server then performs the native TCP/UDP calls on behalf of the page. This allows a web browser page to run full TCP & UDP connections, act as a server to accept incoming connections, and perform host name lookups and reverse lookups. Because all API calls are individually proxied, this support can be slow. This support is mostly useful for developing testing infrastructure and debugging.

For an example of how the POSIX Sockets proxy server works in an Emscripten client program, see the file tests/websocket/tcp_echo_client.cpp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs don't seem to mention the new proxy option from this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated docs with linker settings for each case.

@@ -1,310 +1,541 @@
-------- C h_errno
-------- C __hwcap
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this diff so large? I think the symbols should be sorted - maybe you didn't sort them before applying?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an as-is result from calling llvm-nm on new generated libc.bc. Is there some special process that one must do instead of dumping them? Perhaps there should be an automatic script that updates the symbol files from already built cache?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably add a script, but basically just pipe it through | sort

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah gotcha, updated the symbols files (using embuilder to build them, then llvm-nm ~/.emscripten_cache/asmjs/libc.bc | sort > system/lib/libc.symbols

LIBC_SOCKETS = ['socket.c', 'socketpair.c', 'shutdown.c', 'bind.c', 'connect.c',
'listen.c', 'accept.c', 'getsockname.c', 'getpeername.c', 'send.c',
'recv.c', 'sendto.c', 'recvfrom.c', 'sendmsg.c', 'recvmsg.c',
'getsockopt.c', 'setsockopt.c', 'freeaddrinfo.c']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are included in those builds - so what is proxied here, the syscalls called by those?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These different API calls are proxied through a WebSocket server. I.e. instead of socket() calling musl which calls socketcall(), the musl functions are replaced with C implemented functions that proxy each call through the WebSockets bridge.

@juj
Copy link
Collaborator Author

juj commented Feb 11, 2019

Thanks, so this lets you use normal C sockets code, and it synchronously proxies commands to a websockets server that does the actual sockets operations? And you say it's useful for things like test harnesses etc. - this seems like quite a lot of work for just that? I feel like I'm missing the use case.

We use this to target an existing sockets utilizing debug suite over to HTML5, retaining the same codebase for portability. This lets one reuse existing POSIX sockets code as is, and one only needs to add one API call at the start of the program to the bridge server, and then you get full sockets. This way we are able to locally connect a Unity page to all sorts of existing harness tools that are running on local developer's machine (e.g. debugger, profiler, inspector)

@juj juj force-pushed the full_posix_sockets branch 4 times, most recently from 0e6b9d9 to 9542cc6 Compare February 14, 2019 15:16
@juj
Copy link
Collaborator Author

juj commented Nov 27, 2019

For the tests, I think another job like this one, and right after it:

Thanks, good pointer, followed that pattern and added a sockets tests suite, which seems to pass nicely.

@jakogut
Copy link
Contributor

jakogut commented Nov 27, 2019

Brought this PR up to latest now, looks like all is passing nicely. This should be ready to land now.

@juj There appears to be a problem with a program I'm attempting to compile that usesgetpeername. Upon being called, the proxy server reports: Received too small sockets call message! size: 0 bytes, expected at least 8 bytes, and upon investigating, the size passed to emscripten_websocket_send_binary is negative. I'm looking into it.

Thanks for taking a look at this. I had a detour for a while working on other things, and now coming back to this one. I think if there's a bug in this one, let's look at that as a followup, preferably with a test case? (if you're still interested/active on this?)

Yeah, I think I did end up fixing this one, and I can follow up with a PR and test case after this lands.

@jakogut
Copy link
Contributor

jakogut commented Nov 27, 2019

I'm unsure what the code under tools/websocket_* is. How does that relate to the other code (in system/)?

This is the server application that proxies socket calls made by clients over websockets to the native system. I've successfully used this, for example, to play a video stream over HTTP using FFplay compiled to WebAssembly.

@juj
Copy link
Collaborator Author

juj commented Dec 3, 2019

Ping @kripken for approval?

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with switching to upstream as mentioned in the comment.

hopefully these tests are not flakey, but if they are, we can revisit this later...

CHROME_FLAGS_NOCACHE: "--disk-cache-dir=/dev/null --disk-cache-size=1 --media-cache-size=1 --disable-application-cache --incognito"
command: |
export EMTEST_BROWSER="/usr/bin/google-chrome $CHROME_FLAGS_BASE $CHROME_FLAGS_HEADLESS $CHROME_FLAGS_WASM $CHROME_FLAGS_NOCACHE"
python tests/runner.py sockets

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish there was a way to share this code instead of copying it, but I'm not sure if there is in circleci...

.circleci/config.yml Show resolved Hide resolved
@juj
Copy link
Collaborator Author

juj commented Dec 10, 2019

Test failures are unrelated, looks like LLVM has added indentation checking to freetype code.

@hortonelectric
Copy link

Hey you guys, I'm working on something that uses POSIX, and I am still getting missing function: sigaltstack . I am doing -s PROXY_POSIX_SOCKETS=1

I'm not sure if I can actually get around this or not.

@hortonelectric
Copy link

error: undefined symbol: emscripten_websocket_send_binary ...hmmm..?

belraquib pushed a commit to belraquib/emscripten that referenced this pull request Dec 23, 2020
* Add posix sockets proxying option.

* Add test for emscripten_websocket_get_url_length().

* Update docs on which sockets functions are proxied

* Add sockets tests for chrome

* Install websockets before sockets test run

* Install node before ws

* Try to fix ws installation

* Fix websocket send test

* Fix bad _strlen dep in _formatString function.

* Add formatString dep
sbc100 added a commit to sbc100/emscripten that referenced this pull request Mar 14, 2024
Update `test_websocket_send.c` such that it checks that both text
and binary messages are received.

Also, delete `websocket.c` which I think was supposed to be removed
as part of emscripten-core#7672 (where it was renamed to test_websocket_send.c).

Fixes: emscripten-core#21515
sbc100 added a commit that referenced this pull request Mar 14, 2024
Update `test_websocket_send.c` such that it checks that both text
and binary messages are received.

Also, delete `websocket.c` which I think was supposed to be removed
as part of #7672 (where it was renamed to test_websocket_send.c).

Fixes: #21515
stbergmann added a commit to stbergmann/emscripten that referenced this pull request Aug 22, 2024
It appears that ever since 31309a8
"full_posix_sockets (emscripten-core#7672)", the _proxy side sent back a result that included
an explicit option_len while the _socket side computes that value from the
overall result size.
stbergmann added a commit to stbergmann/emscripten that referenced this pull request Aug 22, 2024
…socket.c

...that appears to have been bogus ever since
31309a8 "full_posix_sockets (emscripten-core#7672)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants