Skip to content

Commit ce2047c

Browse files
committed
[dns] Refactor resolver big time, extract query logic into Query\Executor
* New React\Dns\Query\Executor (and Interface) that handles the actual query logic. * Resolver factory that creates a resolver + executor. * Shitload of tests.
1 parent 80daf91 commit ce2047c

5 files changed

Lines changed: 134 additions & 79 deletions

File tree

Query/Executor.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
namespace React\Dns\Query;
4+
5+
use React\Dns\BadServerException;
6+
use React\Dns\RecordNotFoundException;
7+
use React\Dns\Model\Message;
8+
use React\Dns\Protocol\Parser;
9+
use React\Dns\Protocol\BinaryDumper;
10+
use React\EventLoop\LoopInterface;
11+
use React\Socket\Connection;
12+
13+
class Executor implements ExecutorInterface
14+
{
15+
private $loop;
16+
private $parser;
17+
private $dumper;
18+
19+
public function __construct(LoopInterface $loop, Parser $parser, BinaryDumper $dumper)
20+
{
21+
$this->loop = $loop;
22+
$this->parser = $parser;
23+
$this->dumper = $dumper;
24+
}
25+
26+
public function query($nameserver, Query $query, $callback)
27+
{
28+
$request = $this->prepareRequest($query);
29+
30+
$queryData = $this->dumper->toBinary($request);
31+
$transport = strlen($queryData) > 512 ? 'tcp' : 'udp';
32+
33+
$this->doQuery($nameserver, $transport, $queryData, $callback);
34+
}
35+
36+
public function prepareRequest(Query $query)
37+
{
38+
$request = new Message();
39+
$request->header->set('id', rand());
40+
$request->header->set('rd', 1);
41+
$request->questions[] = (array) $query;
42+
$request->prepare();
43+
44+
return $request;
45+
}
46+
47+
public function doQuery($nameserver, $transport, $queryData, $callback)
48+
{
49+
$that = $this;
50+
$parser = $this->parser;
51+
52+
$response = new Message();
53+
54+
$retryWithTcp = function () use ($that, $nameserver, $queryData, $callback) {
55+
$that->doQuery($nameserver, 'tcp', $queryData, $callback);
56+
};
57+
58+
$conn = $this->createConnection($nameserver, $transport);
59+
$conn->on('data', function ($data) use ($that, $retryWithTcp, $conn, $parser, $response, $transport, $callback) {
60+
$responseReady = $parser->parseChunk($data, $response);
61+
62+
if (!$responseReady) {
63+
return;
64+
}
65+
66+
if ($response->header->isTruncated()) {
67+
if ('tcp' === $transport) {
68+
throw new BadServerException('The server set the truncated bit although we issued a TCP request');
69+
}
70+
71+
$conn->end();
72+
$retryWithTcp();
73+
return;
74+
}
75+
76+
$conn->end();
77+
$callback($response);
78+
});
79+
$conn->write($queryData);
80+
}
81+
82+
protected function createConnection($nameserver, $transport)
83+
{
84+
$fd = stream_socket_client("$transport://$nameserver");
85+
$conn = new Connection($fd, $this->loop);
86+
87+
return $conn;
88+
}
89+
}

Query/ExecutorInterface.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace React\Dns\Query;
4+
5+
interface ExecutorInterface
6+
{
7+
public function query($nameserver, Query $query, $callback);
8+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace React\Dns\Resolver;
3+
namespace React\Dns\Query;
44

55
class Query
66
{

Resolver/Factory.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace React\Dns\Resolver;
4+
5+
use React\Dns\Query\Executor;
6+
use React\Dns\Protocol\Parser;
7+
use React\Dns\Protocol\BinaryDumper;
8+
use React\EventLoop\LoopInterface;
9+
10+
class Factory
11+
{
12+
public function create($nameserver, LoopInterface $loop)
13+
{
14+
$nameserver = $this->addPortToServerIfMissing($nameserver);
15+
$executor = new Executor($loop, new Parser(), new BinaryDumper());
16+
17+
return new Resolver($nameserver, $executor);
18+
}
19+
20+
protected function addPortToServerIfMissing($nameserver)
21+
{
22+
return false === strpos($nameserver, ':') ? "$nameserver:53" : $nameserver;
23+
}
24+
}

Resolver/Resolver.php

Lines changed: 12 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace React\Dns\Resolver;
44

5+
use React\Dns\Query\ExecutorInterface;
6+
use React\Dns\Query\Query;
57
use React\Dns\BadServerException;
68
use React\Dns\RecordNotFoundException;
79
use React\Dns\Model\Message;
@@ -13,16 +15,12 @@
1315
class Resolver
1416
{
1517
private $nameserver;
16-
private $loop;
17-
private $parser;
18-
private $dumper;
18+
private $executor;
1919

20-
public function __construct($nameserver, LoopInterface $loop, Parser $parser = null, BinaryDumper $dumper = null)
20+
public function __construct($nameserver, ExecutorInterface $executor)
2121
{
22-
$this->nameserver = $this->addPortToServerIfMissing($nameserver);
23-
$this->loop = $loop;
24-
$this->parser = $parser ?: new Parser();
25-
$this->dumper = $dumper ?: new BinaryDumper();
22+
$this->nameserver = $nameserver;
23+
$this->executor = $executor;
2624
}
2725

2826
public function resolve($domain, $callback, $errback = null)
@@ -31,11 +29,9 @@ public function resolve($domain, $callback, $errback = null)
3129

3230
$query = new Query($domain, Message::TYPE_A, Message::CLASS_IN);
3331

34-
$this->query($this->nameserver, $query, function (Message $response) use ($that, $callback, $errback) {
32+
$this->executor->query($this->nameserver, $query, function (Message $response) use ($that, $callback, $errback) {
3533
try {
36-
$answer = $that->pickRandomAnswerOfType($response, Message::TYPE_A);
37-
$address = $answer->data;
38-
$callback($address);
34+
$that->extractAddress($response, Message::TYPE_A, $callback);
3935
} catch (RecordNotFoundException $e) {
4036
if (!$errback) {
4137
throw $e;
@@ -46,14 +42,11 @@ public function resolve($domain, $callback, $errback = null)
4642
});
4743
}
4844

49-
public function query($nameserver, Query $query, $callback)
45+
public function extractAddress(Message $response, $type, $callback)
5046
{
51-
$request = $this->prepareRequest($query);
52-
53-
$queryData = $this->dumper->toBinary($request);
54-
$transport = strlen($queryData) > 512 ? 'tcp' : 'udp';
55-
56-
$this->doQuery($nameserver, $transport, $queryData, $callback);
47+
$answer = $this->pickRandomAnswerOfType($response, $type);
48+
$address = $answer->data;
49+
$callback($address);
5750
}
5851

5952
public function pickRandomAnswerOfType(Message $response, $type)
@@ -71,63 +64,4 @@ public function pickRandomAnswerOfType(Message $response, $type)
7164

7265
return $answer;
7366
}
74-
75-
public function prepareRequest(Query $query)
76-
{
77-
$request = new Message();
78-
$request->header->set('id', rand());
79-
$request->header->set('rd', 1);
80-
$request->questions[] = (array) $query;
81-
$request->prepare();
82-
83-
return $request;
84-
}
85-
86-
public function doQuery($nameserver, $transport, $queryData, $callback)
87-
{
88-
$that = $this;
89-
$parser = $this->parser;
90-
91-
$response = new Message();
92-
93-
$retryWithTcp = function () use ($that, $nameserver, $queryData, $callback) {
94-
$that->doQuery($nameserver, 'tcp', $queryData, $callback);
95-
};
96-
97-
$conn = $this->createConnection($nameserver, $transport);
98-
$conn->on('data', function ($data) use ($that, $retryWithTcp, $conn, $parser, $response, $transport, $callback) {
99-
$responseReady = $parser->parseChunk($data, $response);
100-
101-
if (!$responseReady) {
102-
return;
103-
}
104-
105-
if ($response->header->isTruncated()) {
106-
if ('tcp' === $transport) {
107-
throw new BadServerException('The server set the truncated bit although we issued a TCP request');
108-
}
109-
110-
$conn->end();
111-
$retryWithTcp();
112-
return;
113-
}
114-
115-
$conn->end();
116-
$callback($response);
117-
});
118-
$conn->write($queryData);
119-
}
120-
121-
protected function createConnection($nameserver, $transport)
122-
{
123-
$fd = stream_socket_client("$transport://$nameserver");
124-
$conn = new Connection($fd, $this->loop);
125-
126-
return $conn;
127-
}
128-
129-
protected function addPortToServerIfMissing($nameserver)
130-
{
131-
return false === strpos($nameserver, ':') ? "$nameserver:53" : $nameserver;
132-
}
13367
}

0 commit comments

Comments
 (0)