<div dir="ltr"><div dir="ltr"><br></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Mi., 25. Nov. 2020 um 11:37 Uhr schrieb Raimo Niskanen <<a href="mailto:raimo%2Berlang-questions@erlang.org">raimo+erlang-questions@erlang.org</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Is it so that recvmsg(fd, &msg, MSG_ERRQUEUE) only receives from<br>
the error queue, and never any regular data?<br></blockquote><div><br></div><div>That is my understanding from the man page. Experiments also confirm this.</div><div><br></div><div>Reading the errqueue is actually quite hard to test. The behavior for local errors and remote errors (e.g. reception of ICMP errors) is sometimes different.</div><div>Small sample:</div><div><br></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div class="gmail_quote">1> {ok, Socket} = socket:open(inet, dgram, udp).</div><div class="gmail_quote">{ok,{'$socket',#Ref<0.1577644963.140640257.162512>}}</div><div class="gmail_quote">2> ok = socket:setopt(Socket, ip, recverr, true).</div><div class="gmail_quote">ok</div><div class="gmail_quote">3> Dest = #{family => inet, addr => {127,0,0,1}, port => 1234}.</div><div class="gmail_quote">#{addr => {127,0,0,1},family => inet,port => 1234}</div><div class="gmail_quote">4> socket:sendto(Socket, <<"Data">>, Dest, nowait).</div><div class="gmail_quote">ok</div><div class="gmail_quote">5> socket:sendto(Socket, <<"Data">>, Dest, nowait).</div><div class="gmail_quote">{error,{econnrefused,[<<"Data">>]}}</div></blockquote><div><br></div>The first sendto returns `ok`, the error can be read in subsequent recvmsg. The second sendto returns the error immediately because the kernel has learned that the local endpoint does not exist.<div><br><div class="gmail_quote"><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Today there is no VM support for a NIF do differ between POLLIN<br>
and POLLERR.  I have asked the VM guys to have a look at that.<br>
<br>
Without that you can as your response to receiving<br>
{'$socket',Socket,select,SelectHandle}<br>
call socket:recvmsg(Socket, [errqueue], 0), to poll, and then<br>
if the poll gave {error,timeout} call socket:recvmsg(Socket, 0, nowait).<br></blockquote><div><br></div><div>If was actually thinking about doing `socket:recvmsg(Socket, [errqueue], nowait)`</div><div>if </div><div>   a) just received a select message and</div><div>   b) socket:recvfrom returned a new select info instead of reading any data</div><div><br></div><div>That should capture the situation where only data in the errqueue is present without having to</div><div>use the 0 timeout.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Then we will have to optimize Timeout =:= 0, and maybe introduce<br>
Timeout =:= poll with a nicer return value for no data.<br></blockquote><div><br></div><div>I like the general idea, but the `nowait` option now feels a  bit wrong. We end up with `nowait == do a select` and `poll == just check if there is data`.</div><div>It might be too late for changing `nowait`, but what about adding `select` as an alias to `nowait` ?</div><div><br></div><div>Regards,</div><div>Andreas</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Timeout =:= 0 today causes quite some overhead, but it should work.<br>
<br>
Cheers<br>
/ Raimo<br>
<br>
<br>
On Mon, Nov 23, 2020 at 05:42:23PM +0100, Andreas Schultz wrote:<br>
> Hi,<br>
> <br>
> If setup a socket with:<br>
> <br>
>     socket:setopt(Socket, ip, recverr, true)<br>
> <br>
> If then started a asynchronous recvmsg with:<br>
> <br>
>     {select, SelectInfo} = socket:recvfrom(Socket, 0, [], nowait)<br>
> <br>
> When now something arrives in the error queue, I'll get a select info<br>
> message with:<br>
> <br>
>     {'$socket', Socket, select, SelectInfo}<br>
> <br>
> The problem is, nothing in there tells me to read from the error queue. The<br>
> underlying OS poll/epoll call would have this information, but it is lost<br>
> in the Erlang message.<br>
> <br>
> When I now try to read from the socket with:<br>
> <br>
>    socket:recvfrom(Socket, 0, [], nowait)<br>
> <br>
> all I get is another `{select, SelectInfo}` tuple, followed by another<br>
> `{'$socket', Socket, select, SelectInfo}` messages.<br>
> This can actually end up in an endless busy loop.<br>
> <br>
> To actually clear this I would to do a:<br>
> <br>
>     socket:recvmsg(Socket, [errqueue], nowait)<br>
> <br>
> On an POSIX socket, I would have to actually poll for POLLIN | POLLERR to<br>
> get a similar behavior. But the return of the poll would tell me whether it<br>
> was POLLIN or POLLERR (similar for epoll).<br>
> For the Erlang API it might sense to always poll for both conditions, but<br>
> we then should get an indication what exactly it was.<br>
> <br>
> Would it be possible to change the $socket message to something like:<br>
> <br>
>     {'$socket', Socket, error, SelectInfo}<br>
> <br>
> for POLLERR/EPOLLERR ???<br>
> <br>
> Regards<br>
> Andreas<br>
> --<br>
> <br>
> Andreas Schultz<br>
<br>
-- <br>
<br>
/ Raimo Niskanen, Erlang/OTP, Ericsson AB<br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><p><span style="font-family:verdana,geneva,sans-serif;font-size:10pt">Andreas Schultz</span></p>
</div></div></div>