amphp / dns

Async DNS resolution for PHP based on Amp.

Home Page:https://amphp.org/dns

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Timeout not working

chrisleavoy opened this issue · comments

I've discovered the timeout mechanism isn't working. In some tests, the reactor will run forever, but most of the time the test will take about ~1 minute. The timeout value seems to be ignored. I've stepped through with xdebug, but it gets lost and i can't seem to identify the issue. Example:

$promise = \Amp\Dns\resolve('www.google.ca', ['timeout' => 100, 'server' => 'tcp://8.8.8.0:53', 
  'types' => Record::A, 'cache' => false ]);

try {
    $result = \Amp\wait($promise);
    $this->fail("Resolve did not timeout when expected {$result}");
} catch (\Exception $e) {
    $this->assertInstanceOf(\Exception::class, $e);
}

I've tried with and without ev extension. I've tried with regular IP, udp scheme, smaller/larger values, cache on/off.

This is with php version 5.5.30. and amphp/dns 0.8.10

Any ideas or recommendations to get this working?

You have to reset the DNS resolver in every test where you reset the reactor.

Amp\Dns\resolver(Amp\Dns\driver());

Unless we can store reactor bound state, that's the only way to go.

I'm not sure what that means... I tried \Amp\Dns\resolver(\Amp\Dns\driver()); prior to calling resolve() and it still doesn't honor the timeout. I don't think this is a test artifact because it happens without phpunit as well.

I discovered:
['server' => 'udp://8.8.8.8:53', 'timeout' => 5] fails correctly within 6 ms
['server' => 'udp://8.8.8.0:53', 'timeout' => 5] takes 1 minute to fail, if at all.

I managed to get the debugger working and narrowed it down. The issue is that DefaultResolver.php calls stream_socket_client() without a connection timeout, causing it to block for 1 minute. I'll look into it further tomorrow and perhaps submit a PR.

Ah, right. It's falling back to TCP mode because the response is truncated. and when tcp mode does not work, yeah…
It should do an async connect here (i.e. not block at all).

If you want to submit a PR, you're more than welcome, else I'll have a look at it tomorrow evening.

I see.. It was 7276474 (0.8.2) that introduced the tcp fallback that is blocking. A few options I can see:

  • Introduce a config variable to disable tcp fallback (probably a good idea anyway)
  • Introduce a config variable that sets a CONNECT_TIMEOUT on stream_socket_client (needed for next option anyway)
  • Use amphp/socket instead of stream_socket_client (ideal)

I took a stab at using amphp/socket instead but couldn't quite get it working. Perhaps someone with more experience can take a look?