This project implements a NIF library to support Unix Domain Sockets.
UPDATE: this project will be deprecated beginning with Erlang 19RC2, which will include native support for Unix Domain Sockets.
The implementation uses two C functions (do_bind
, do_connect
) to setup
a socket, and then Erlang implementation assigns an open file descriptor
to either gen_tcp
or gen_udp
Erlang socket. This allows to reuse
existing Erlang send/receive API on file descriptors set up externally.
From the academic point of view TCP and UDP protocols are not implemented
over Unix Domain Sockets (UDS). Rather, UDS use stream and datagram
transports that have identical library API to TCP and UDP. For this reason
a UDS file descriptor can be passed to gen_tcp
or gen_udp
to handle
stream
or dgram
communications.
Additionally this NIF library has functions send_fd/2
and recv_fd/1
do
send and receive file descriptors through a Unix Domain Socket.
Note: there is a bug in the OTP socket management which requires the Erlang distribution to be patched in order for this project to work. The patch can be found here: https://github.com/saleyn/otp/compare/uds. It was submitted in the form of a pull request to the Erlang/OTP team: erlang/otp#612.
See these instructions
if you need to debug the Erlang's inet_drv.c
network driver.
Once the above-stated patch is applied, rebuild the OTP distribution, and
check that erts/preloaded/src/*.erl
have been compiled into
erts/preloaded/ebin/*.beam
(note that the Makefile
in that directory
tends to place compiled files in the same directory where the sources are
instead of creating them in ebin/
(see this closed issue that illustrates
this solution: #1).
Serge Aleynikov <saleyn at gmail dot com>
- Apply the following patch to the latest Erlang release: https://github.com/saleyn/otp/compare/uds.patch
- Ensure you have a local installation of
rebar
. - git clone https://github.com/saleyn/euds.git
- make
% TCP Unix Domain Socket Server:
1> file:delete("/tmp/test.sock").
ok
2> {ok, S} = gen_uds:listen("/tmp/test.sock", [stream]).
{ok,#Port<0.980>}
3> {ok, CS} = gen_tcp:accept(S).
{ok,#Port<0.981>}
4> inet:setopts(CS, [{active, false}]).
ok
5> gen_tcp:recv(CS, 0).
{ok,"abc"}
6> gen_tcp:close(CS).
ok
7> gen_tcp:close(S).
ok
% TCP Unix Domain Socket Client:
1> {ok, S} = gen_uds:connect("/tmp/test.sock", [stream]).
{ok,#Port<0.949>}
2> gen_tcp:send(S, "abc").
ok
3> gen_tcp:close(S).
ok
% UDP Unix Domain Socket Server:
1> file:delete("/tmp/test.sock").
ok
2> {ok, S} = gen_uds:listen("/tmp/test.sock", [dgram]).
{ok,#Port<0.980>}
3> inet:setopts(S, [{active, once}]).
4> receive Msg -> Msg end,
{udp,#Port<0.980>,"/tmp/test.sock",0,"abc"}
5> inet:setopts(S, [{active, false}]).
ok
6> gen_udp:recv(S, 0).
{ok,{"/tmp/test.sock", 0, "efg"}}
7> gen_udp:close(S).
ok
% UDP Unix Domain Socket Client:
1> {ok, S} = gen_uds:connect("/tmp/test.sock", [dgram]).
{ok,#Port<0.949>}
2> gen_udp:send(S, "abc").
ok
3> gen_udp:send(S, "efg").
ok
4> gen_udp:close(S).
ok