Skip to content

Commit 3d0d91e

Browse files
committed
Add posix sockets proxying option.
1 parent 0a1d02d commit 3d0d91e

27 files changed

+4216
-1
lines changed

embuilder.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,20 @@ def is_flag(arg):
255255
build_port('regal', libname('libregal'), ['-s', 'USE_REGAL=1'])
256256
elif what == 'boost_headers':
257257
build_port('boost_headers', libname('libboost_headers'), ['-s', 'USE_BOOST_HEADERS=1'])
258+
elif what == 'libsockets':
259+
build('''
260+
#include <sys/socket.h>
261+
int main() {
262+
return socket(0,0,0);
263+
}
264+
''', [libname('libsockets')])
265+
elif what == 'libsockets_proxy':
266+
build('''
267+
#include <sys/socket.h>
268+
int main() {
269+
return socket(0,0,0);
270+
}
271+
''', [libname('libsockets_proxy')], ['-s', 'PROXY_POSIX_SOCKETS=1', '-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1'])
258272
else:
259273
logger.error('unfamiliar build target: ' + what)
260274
return 1

site/source/docs/porting/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The topics in this section cover the main integration points that you need to co
1717
Audio
1818
Debugging
1919
pthreads
20+
networking
2021
simd
2122
asyncify
2223
emterpreter
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.. Networking:
2+
3+
==============================
4+
Networking
5+
==============================
6+
7+
Emscripten compiled applications have a number of ways to connect with online servers. Check the subtopics here to learn about the different strategies that are available.
8+
9+
If you are familiar with networking concepts provided by different web APIs, such as XmlHttpRequest, Fetch, WebSockets and WebRTC, you can quickly get started by leveraging what you already know: by calling out from C/C++ code to JavaScript (see the "Connecting C++ and JavaScript" section), you can establish networked connections by writing regular JavaScript. For C/C++ developers, Emscripten provides a few approaches, described here.
10+
11+
Emscripten WebSockets API
12+
=========================
13+
14+
WebSockets API provides connection-oriented message-framed bidirectional asynchronous networking communication to the browser. It is the closest to TCP on the web that web sites can access, direct access to TCP sockets is not possible from web browsers.
15+
16+
Emscripten provides a passthrough API for accessing the WebSockets API from C/C++ code. This is useful for developers who would prefer not to write any JavaScript code, or deal with the C/C++ and JavaScript language interop. See the system include file <emscripten/websocket.h> for details. One benefit that the Emscripten WebSockets API provides over manual WebSockets access in JavaScript is the ability to share access to a WebSocket handle across multiple threads, something that can be time consuming to develop from scratch.
17+
18+
To target Emscripten WebSockets API, you must link it in with a "-lwebsocket.js" linker directive.
19+
20+
Emulated POSIX TCP Sockets over WebSockets
21+
==========================================
22+
23+
If you have existing TCP networking code written in C/C++ that utilizes the Posix Sockets API, by default Emscripten attempts to emulate such connections to take place over the WebSocket protocol instead. For this to work, you will need to use something like WebSockify on the server side to enable the TCP server stack to receive incoming WebSocket connections. This emulation is not very complete at the moment, it is likely that you will run into problems out of the box and need to adapt the code to work within the limitations that this emulation provides.
24+
25+
This is the default build mode for POSIX sockets, no linker flags or option settings are needed to enable it.
26+
27+
Full POSIX Sockets over WebSocket Proxy Server
28+
==============================================
29+
30+
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.
31+
32+
To use POSIX sockets proxying, link the application with flags "-lwebsocket.js -s PROXY_POSIX_SOCKETS=1 -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1". That is, POSIX sockets proxying builds on top of the Emscripten WebSockets library, and requires multithreading and proxying the application main() to a pthread.
33+
34+
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.
35+
36+
XmlHttpRequests and Fetch API
37+
=============================
38+
39+
For HTTP transfers, one can use the browser built-in XmlHttpRequest (XHR) API and the newer Fetch API. These can be accessed directly from JavaScript. Emscripten also provides passthrough APIs to perform HTTP requests. For more information, see the emscripten_async_wget*() C API and the Emscripten Fetch API.
40+
41+
WebRTC and UDP
42+
==============
43+
44+
Direct UDP communication is not available in browsers, but as a close alternative, the WebRTC specification provides a mechanism to perform UDP-like communication with WebRTC Data Channels. Currently Emscripten does not provide a C/C++ API for interacting with WebRTC.

src/library.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,7 @@ LibraryManager.library = {
32133213
// arpa/inet.h
32143214
// ==========================================================================
32153215

3216+
#if PROXY_POSIX_SOCKETS == 0
32163217
// old ipv4 only functions
32173218
inet_addr__deps: ['_inet_pton4_raw'],
32183219
inet_addr: function(ptr) {
@@ -3950,6 +3951,8 @@ LibraryManager.library = {
39503951
0x0b00000a, 0x0c00000a, 0x0d00000a, 0x0e00000a] /* 0x0100000a is reserved */
39513952
},
39523953

3954+
#endif // PROXY_POSIX_SOCKETS == 0
3955+
39533956
// pwd.h
39543957

39553958
getpwnam: function() { throw 'getpwnam: TODO' },

src/library_syscall.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ var SyscallsLibrary = {
512512
__syscall97: function(which, varargs) { // setpriority
513513
return -{{{ cDefine('EPERM') }}};
514514
},
515+
#if PROXY_POSIX_SOCKETS == 0
515516
__syscall102__deps: ['$SOCKFS', '$DNS', '_read_sockaddr', '_write_sockaddr'],
516517
__syscall102: function(which, varargs) { // socketcall
517518
var call = SYSCALLS.get(), socketvararg = SYSCALLS.get();
@@ -728,6 +729,7 @@ var SyscallsLibrary = {
728729
}
729730
}
730731
},
732+
#endif // ~PROXY_POSIX_SOCKETS==0
731733
__syscall104: function(which, varargs) { // setitimer
732734
return -{{{ cDefine('ENOSYS') }}}; // unsupported feature
733735
},
@@ -1393,9 +1395,17 @@ var SyscallsLibrary = {
13931395
var stream = SYSCALLS.getStreamFromFD(fd);
13941396
FS.close(stream);
13951397
#else
1398+
#if PROXY_POSIX_SOCKETS
1399+
// close() is a tricky function because it can be used to close both regular file descriptors
1400+
// and POSIX network socket handles, hence an implementation would need to track for each
1401+
// file descriptor which kind of item it is. To simplify, when using PROXY_POSIX_SOCKETS
1402+
// option, use shutdown() to close a socket, and this function should behave like a no-op.
1403+
warnOnce('To close sockets with PROXY_POSIX_SOCKETS bridge, prefer to use the function shutdown() that is proxied, instead of close()')
1404+
#else
13961405
#if ASSERTIONS
13971406
abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM');
13981407
#endif
1408+
#endif
13991409
#endif
14001410
return 0;
14011411
},

src/settings.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,10 @@ var SOCKET_WEBRTC = 0;
350350
// where addr and port are derived from the socket connect/bind/accept calls.
351351
var WEBSOCKET_URL = 'ws://';
352352

353+
// If 1, the POSIX sockets API uses a native bridge process server to proxy sockets calls
354+
// from browser to native world.
355+
var PROXY_POSIX_SOCKETS = 0;
356+
353357
// A string containing a comma separated list of WebSocket subprotocols
354358
// as would be present in the Sec-WebSocket-Protocol header.
355359
// You can set 'null', if you don't want to specify it.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#include "websocket.h"
4+
5+
#ifdef __cplusplus
6+
extern "C" {
7+
#endif
8+
9+
extern EMSCRIPTEN_RESULT emscripten_init_websocket_to_posix_socket_bridge(const char *bridgeUrl);
10+
11+
#ifdef __cplusplus
12+
}
13+
#endif

system/lib/libc-sockets.symbols

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
U __errno_location
2+
U __syscall102
3+
U __syscall221
4+
U __syscall_ret
5+
U free
6+
-------- T accept
7+
-------- T bind
8+
-------- T connect
9+
-------- T freeaddrinfo
10+
-------- T getpeername
11+
-------- T getsockname
12+
-------- T getsockopt
13+
-------- T listen
14+
-------- T recv
15+
-------- T recvfrom
16+
-------- T recvmsg
17+
-------- T send
18+
-------- T sendmsg
19+
-------- T sendto
20+
-------- T setsockopt
21+
-------- T shutdown
22+
-------- T socket
23+
-------- T socketpair

0 commit comments

Comments
 (0)