inet:fdopen/2 fix for supporting externally open fd's of AF_LOCAL address family

Serge Aleynikov <[email protected]> Thu, 29 Jan 2015 21:03:01 -0500
Newsgroups gmane.comp.lang.erlang.patches
Message-ID <CANt451nPq7RoR4CQRVu4qwuzYDPcA_4i+snQ7-ZJCK0EYSOHAw@mail.gmail.com>
--===============8780832223456816713==
Content-Type: multipart/alternative; boundary=047d7bae438459407d050dd50208

--047d7bae438459407d050dd50208
Content-Type: text/plain; charset=UTF-8

When a AF_LOCAL (a.k.a. AF_UNIX) file descriptor is created externally
(e.g. Unix Domain Socket) and passed to `gen_tcp:listen(0, [{fd, FD}])`, the
present implementation incorrectly assigns the address family to be equal
to `inet`, which in the inet_drv driver translats to AF_INET instead
of AF_LOCAL (or AF_UNIX), and an `einval` error code is returned.

This patch fixes this problem such that the file descriptors of the
`local` address family are properly supported when such a file descriptor
is passed to the inet:fdopen/5, gen_tcp:connect/3, gen_tcp:listen/2,
gen_udp:open/2
calls via {fd, FD::integer()} option.

In order to connect a socket to a Unix Domain file descriptor use the
following options:

    1> FD = ... % Open the AF_LOCAL *server* file descriptor
    2> {ok, Sock} = gen_tcp:listen(0, [local, {fd,FD} | OtherOptions]).
    % Now use the socket using gen_tcp module:
    3> gen_tcp:send(Sock, <<"abc">>).

    FD = ... % Open the AF_LOCAL *client* file descriptor
    2> {ok, Sock} = gen_tcp:connect(0, [local, {fd,FD} | OtherOptions]).
    % Now use the socket using gen_tcp module:
    3> inet:setopts(S, [{active, once}]),
    4> receive Msg -> Msg end.
    {tcp,#Port<0.1195>,"abc"}
    5> inet:setopts(S, [{active, false}]).
    6> gen_tcp:recv(S,0,1000).
    {ok,"efg"}

Note that in case of UDP client in order to preserve the active socket
signature {udp, ErlPort, Addr, Port, Data} and passive socket's
gen_udp:recv3 return signature ({ok, {Address, Port, Packet}}), the Address
on local socket family is a string containing the underlying socket's
filename, and Port=0. E.g.:

    {ok, {"/tmp/test.sock", 0, <<"some data">>}} = gen_udp:recv(S, 0, 1000).

git fetch https://github.com/saleyn/otp uds

https://github.com/saleyn/otp/compare/erlang:maint...uds
https://github.com/saleyn/otp/compare/erlang:maint...uds.patch

A sample project using this patch can be found here:
https://github.com/saleyn/euds. It uses a NIF library to create and FD of
AF_LOCAL family, and passes it to either gen_tcp or gen_udp for further
handling.

Regards,

Serge

--047d7bae438459407d050dd50208
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_default"><font face=3D"arial, helvetic=
a, sans-serif"><div class=3D"gmail_default">When a AF_LOCAL (a.k.a. AF_UNIX=
) file descriptor is created externally</div></font><font face=3D"arial, he=
lvetica, sans-serif"><div class=3D"gmail_default">(e.g. Unix Domain Socket)=
 and passed to `gen_tcp:listen(0, [{fd, FD}])`, the</div><div class=3D"gmai=
l_default">present implementation incorrectly assigns the address family to=
 be equal</div><div class=3D"gmail_default">to `inet`, which in the inet_dr=
v driver translats to AF_INET instead</div><div class=3D"gmail_default">of =
AF_LOCAL (or AF_UNIX), and an `einval` error code is returned.</div><div cl=
ass=3D"gmail_default"><br></div><div class=3D"gmail_default">This patch fix=
es this problem such that the file descriptors of the</div><div class=3D"gm=
ail_default">`local` address family are properly supported when such a file=
 descriptor</div><div class=3D"gmail_default">is passed to the inet:fdopen/=
5, gen_tcp:connect/3, gen_tcp:listen/2, gen_udp:open/2</div><div class=3D"g=
mail_default">calls via {fd, FD::integer()} option.</div><div class=3D"gmai=
l_default"><br></div><div class=3D"gmail_default">In order to connect a soc=
ket to a Unix Domain file descriptor use the following options:</div><div c=
lass=3D"gmail_default"><br></div><div class=3D"gmail_default"><div class=3D=
"gmail_default">=C2=A0 =C2=A0 1&gt; FD =3D ... % Open the AF_LOCAL *server*=
 file descriptor</div><div class=3D"gmail_default">=C2=A0 =C2=A0 2&gt; {ok,=
 Sock} =3D gen_tcp:listen(0, [local, {fd,FD} | OtherOptions]).</div><div cl=
ass=3D"gmail_default">=C2=A0 =C2=A0 % Now use the socket using gen_tcp modu=
le:<br></div><div class=3D"gmail_default">=C2=A0 =C2=A0 3&gt; gen_tcp:send(=
Sock, &lt;&lt;&quot;abc&quot;&gt;&gt;).</div><div><br></div><div>=C2=A0 =C2=
=A0 FD =3D ... % Open the AF_LOCAL *client* file descriptor<br></div></div>=
<div class=3D"gmail_default">=C2=A0 =C2=A0 2&gt; {ok, Sock} =3D gen_tcp:con=
nect(0, [local, {fd,FD} | OtherOptions]).</div><div class=3D"gmail_default"=
>=C2=A0 =C2=A0 % Now use the socket using gen_tcp module:<br></div><div cla=
ss=3D"gmail_default">=C2=A0 =C2=A0 3&gt; inet:setopts(S, [{active, once}]),=
<br></div></font><font face=3D"arial, helvetica, sans-serif"><div class=3D"=
gmail_default">=C2=A0 =C2=A0 4&gt; receive Msg -&gt; Msg end.</div><div cla=
ss=3D"gmail_default">=C2=A0 =C2=A0=C2=A0{tcp,#Port&lt;0.1195&gt;,&quot;abc&=
quot;}</div><div class=3D"gmail_default">=C2=A0 =C2=A0 5&gt;=C2=A0inet:seto=
pts(S, [{active, false}]).</div><div class=3D"gmail_default">=C2=A0 =C2=A0 =
6&gt;=C2=A0gen_tcp:recv(S,0,1000).</div><div class=3D"gmail_default">=C2=A0=
 =C2=A0=C2=A0{ok,&quot;efg&quot;}</div><div class=3D"gmail_default"><br></d=
iv><div class=3D"gmail_default">Note that in case of UDP client in order to=
 preserve the active socket signature {udp, ErlPort, Addr, Port, Data} and =
passive socket&#39;s gen_udp:recv3 return signature ({ok, {Address, Port, P=
acket}}), the Address on local socket family is a string containing the und=
erlying socket&#39;s filename, and Port=3D0. E.g.:</div><div class=3D"gmail=
_default"><br></div><div class=3D"gmail_default">=C2=A0 =C2=A0 {ok, {&quot;=
/tmp/test.sock&quot;, 0, &lt;&lt;&quot;some data&quot;&gt;&gt;}} =3D gen_ud=
p:recv(S, 0, 1000).</div></font><font face=3D"arial, helvetica, sans-serif"=
><div class=3D"gmail_default"><br></div></font></div><div class=3D"gmail_de=
fault"><font face=3D"arial, helvetica, sans-serif">git fetch=C2=A0</font><s=
pan style=3D"font-family:arial,helvetica,sans-serif"><a href=3D"https://git=
hub.com/saleyn/otp" target=3D"_blank">https://github.com/saleyn/otp</a> uds=
</span></div><div class=3D"gmail_default"><span style=3D"font-family:arial,=
helvetica,sans-serif"><br></span></div><div class=3D"gmail_default"><font f=
ace=3D"arial, helvetica, sans-serif"><a href=3D"https://github.com/saleyn/o=
tp/compare/erlang:maint...uds" target=3D"_blank">https://github.com/saleyn/=
otp/compare/erlang:maint...uds</a></font><br></div><div class=3D"gmail_defa=
ult"><font face=3D"arial, helvetica, sans-serif"><a href=3D"https://github.=
com/saleyn/otp/compare/erlang:maint...uds.patch" target=3D"_blank">https://=
github.com/saleyn/otp/compare/erlang:maint...uds.patch</a><br></font></div>=
<div class=3D"gmail_default"><font face=3D"arial, helvetica, sans-serif"><b=
r></font></div><div class=3D"gmail_default"><font face=3D"arial, helvetica,=
 sans-serif">A sample project using this patch can be found here:=C2=A0</fo=
nt><a href=3D"https://github.com/saleyn/euds" target=3D"_blank" style=3D"fo=
nt-family:arial,helvetica,sans-serif">https://github.com/saleyn/euds</a>. I=
t uses a NIF library to create and FD of AF_LOCAL family, and passes it to =
either gen_tcp or gen_udp for further handling.</div><div class=3D"gmail_de=
fault"><br></div><div class=3D"gmail_default">Regards,</div><div class=3D"g=
mail_default"><br></div><div class=3D"gmail_default">Serge</div><div class=
=3D"gmail_default"><font face=3D"arial, helvetica, sans-serif"><br></font><=
/div><div class=3D"gmail_default"><font face=3D"arial, helvetica, sans-seri=
f"><br></font></div></div>

--047d7bae438459407d050dd50208--

--===============8780832223456816713==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
erlang-patches mailing list
[email protected]
http://erlang.org/mailman/listinfo/erlang-patches

--===============8780832223456816713==--