Ok, looks like I've figured out what's going on.
I have been reproducing the same issue in regular nodejs, that translate 
pretty easily to the relevant uv_udp_* calls as the dgram module is a tiny 
wrapper around libuv facilities for udp.

const dgram = require('dgram');
const os = require('os');
var UDP_BROADCAST_PORT = 17584;
var UDP_BROADCAST_ADDRESS = "255.255.255.255";
var clients = [];
var server = dgram.createSocket('udp4');


var boundNetAddresses = [];
var listOfInterfaces = os.networkInterfaces();
for(var netInterface in listOfInterfaces)
{
  var currInterface = listOfInterfaces[netInterface];
  for(var ipAddress in currInterface)
  {
    if(currInterface[ipAddress].family == 'IPv4')
    {
      var address = currInterface[ipAddress].address;
      if(address != '127.0.0.1')
      {
        boundNetAddresses.push(address);
      }
    }     
  }
}


server.on('error', function(err)
{
    console.log("server error:\n" + err.stack);
    server.close();
});


server.on('message', function(msg, rinfo) 
{
    console.log("server got: " + msg + " from " + rinfo.address + ":" + 
rinfo.port);
});


function createUDPAndSendData(boundAddress)
{
  var client = dgram.createSocket('udp4');
  client.on('error', function(err) 
  {
    console.log("client error:\n" + err.stack);
    client.close();
  });


  client.bind(0, boundAddress, function()
  {
    client.setBroadcast(true);
    var message = new Buffer('TEST UDP DATA');


    client.send(message, 0, message.length, UDP_BROADCAST_PORT, 
UDP_BROADCAST_ADDRESS, function(err, bytes) 
    {
        if (err) throw err;
        console.log('UDP message sent to ' + UDP_BROADCAST_ADDRESS +':'+ 
UDP_BROADCAST_PORT);
        console.time("clientClose " + boundAddress);
        client.close();
        console.timeEnd("clientClose " + boundAddress);
        clients.splice(clients.indexOf(client), 1);
    });
    clients.push(client);
  });
}


server.bind(UDP_BROADCAST_PORT, function() 
{
  setInterval(function()
  {
      for(addr in boundNetAddresses)
        createUDPAndSendData(boundNetAddresses[addr]);
  }, 3000);
});


The output of this program shows the issue clearly, but only on one network 
interface, for a test system that has two net cards:

node --debug-brk=19008 --nolazy app.js 
debugger listening on port 19008
UDP message sent to 255.255.255.255:17584
*clientClose **205.168.1.1: 999ms*
UDP message sent to 255.255.255.255:17584
clientClose 192.168.1.52: 0ms
server got: TEST UDP DATA from 205.168.1.1:53892
server got: TEST UDP DATA from 192.168.1.52:53893
UDP message sent to 255.255.255.255:17584
*clientClose **205.168.1.1: 1000ms*
UDP message sent to 255.255.255.255:17584
clientClose 192.168.1.52: 0ms
server got: TEST UDP DATA from 205.168.1.1:53894
server got: TEST UDP DATA from 192.168.1.52:53895
UDP message sent to 255.255.255.255:17584
*clientClose **205.168.1.1: 557ms*
UDP message sent to 255.255.255.255:17584
clientClose 192.168.1.52: 0ms
server got: TEST UDP DATA from 205.168.1.1:53896
server got: TEST UDP DATA from 192.168.1.52:53897
UDP message sent to 255.255.255.255:17584
*clientClose **205.168.1.1: 995ms*
UDP message sent to 255.255.255.255:17584
clientClose 192.168.1.52: 0ms


The issue only exists on a test VM, a Windows 7 inside Parallels Desktop 
running on macOS Yosemite with two virtual network cards.
It only happens if you setup a network adapter using shared network. 
Setting up as a bridged adapter doesn't exhibit this behaviour.

On a regular windows PC with two network cards client.close() always takes 
0ms, so that's probably a VM fault or probably something at driver level.

Thankfully this is a non issue, I am sharing what I've found here just in 
case someone could find it useful.

Thanks anyway.

Stefano


Il giorno martedì 8 novembre 2016 17:59:08 UTC+1, Stefano Cristiano ha 
scritto:
>
> Hi,
>
> My library is wrapping Libuv UDP to bind to some port, set broadcast to 
> true and send some data.
> Randomly my close() function (that is in turn calling uv_close) is 
> blocking to something slightly smaller than 1000 ms.
>
> The small piece of code extracted from my project is the following, even 
> if of course it's not straight uv code but should be relatively easy to 
> understand.
> The first function creates, binds, and sends the data on UDP, and the 
> later is the callback called when the write is done.
> After the write is done I would like to dispose the UDP socket of course, 
> and I am doing it after 100 ms from the write done callback.
>
>  void internalSend(bool broadcast, rrNode::stringView listen, int 
> listenOnPort,
>  rrNode::stringView whereToSend, int whereToConnect, rrNode::buffer buf) 
> { 
>
>   using namespace rrNode; 
>   udp client = udp::create(); 
>   client.bind(listen, listenOnPort); 
>   client.setBroadcast(broadcast); 
>   logINFO("Client.send"); 
>   client.send(buf, 0, buf.length(), whereToConnect, whereToSend, 
> bindMemLast(&this_class::writeDone, this, client)); 
>   clients.push_back(client); 
>
> } 
>
> void writeDone(rrNode::error /*err*/, rrNode::udp client)
> { 
>
>   using namespace rrNode; 
>   container::removeFirst(clients, client); 
>   timer t = setTimeout(100); 
>   t = [client]()mutable{client.close(); }; 
>   logINFO("Client.writeDone"); 
> }
>
> Debugger shows that *closesocket* function call (on Windows) is randomly 
> blocking for the above mentioned milliseconds (between 900 and 1000)
>
>
> void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
> uv_udp_recv_stop(handle);
> closesocket(handle->socket);
> handle->socket = INVALID_SOCKET;
> uv__handle_closing(handle);
> if (handle->reqs_pending == 0) {
> uv_want_endgame(loop, (uv_handle_t*) handle);
> }
> }
>
>
> Is this an intended behaviour or do you think that I could have been 
> hitting a bug in libuv?
>
> The closesocket documentation says that one should use the SO_LINGER 
> sockopt to control behaviour on close
>
>
> https://msdn.microsoft.com/en-us/library/windows/desktop/ms737582(v=vs.85).aspx
>
> I've tried without success to change the SO_LINGER sockopt.
>
> Any hints?
>
> Reason for this post is that I would like some feedback from the library 
> masters to understand if I'm hitting expected/known behaviour or not.
> If this doesn't look right I will be spending some time building a repro 
> in pure libuv.
>
> Thanks!
>

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.

Reply via email to