-
-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #148 from clue-labs/selective-transport
Add SelectiveTransportExecutor to retry with TCP if UDP is truncated and automatically select transport protocol when no explicit scheme is given in Factory
- Loading branch information
Showing
8 changed files
with
426 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
|
||
namespace React\Dns\Query; | ||
|
||
use React\Promise\Promise; | ||
|
||
/** | ||
* Send DNS queries over a UDP or TCP/IP stream transport. | ||
* | ||
* This class will automatically choose the correct transport protocol to send | ||
* a DNS query to your DNS server. It will always try to send it over the more | ||
* efficient UDP transport first. If this query yields a size related issue | ||
* (truncated messages), it will retry over a streaming TCP/IP transport. | ||
* | ||
* For more advanced usages one can utilize this class directly. | ||
* The following example looks up the `IPv6` address for `reactphp.org`. | ||
* | ||
* ```php | ||
* $executor = new SelectiveTransportExecutor($udpExecutor, $tcpExecutor); | ||
* | ||
* $executor->query( | ||
* new Query($name, Message::TYPE_AAAA, Message::CLASS_IN) | ||
* )->then(function (Message $message) { | ||
* foreach ($message->answers as $answer) { | ||
* echo 'IPv6: ' . $answer->data . PHP_EOL; | ||
* } | ||
* }, 'printf'); | ||
* ``` | ||
* | ||
* Note that this executor only implements the logic to select the correct | ||
* transport for the given DNS query. Implementing the correct transport logic, | ||
* implementing timeouts and any retry logic is left up to the given executors, | ||
* see also [`UdpTransportExecutor`](#udptransportexecutor) and | ||
* [`TcpTransportExecutor`](#tcptransportexecutor) for more details. | ||
* | ||
* Note that this executor is entirely async and as such allows you to execute | ||
* any number of queries concurrently. You should probably limit the number of | ||
* concurrent queries in your application or you're very likely going to face | ||
* rate limitations and bans on the resolver end. For many common applications, | ||
* you may want to avoid sending the same query multiple times when the first | ||
* one is still pending, so you will likely want to use this in combination with | ||
* a `CoopExecutor` like this: | ||
* | ||
* ```php | ||
* $executor = new CoopExecutor( | ||
* new SelectiveTransportExecutor( | ||
* $datagramExecutor, | ||
* $streamExecutor | ||
* ) | ||
* ); | ||
* ``` | ||
*/ | ||
class SelectiveTransportExecutor implements ExecutorInterface | ||
{ | ||
private $datagramExecutor; | ||
private $streamExecutor; | ||
|
||
public function __construct(ExecutorInterface $datagramExecutor, ExecutorInterface $streamExecutor) | ||
{ | ||
$this->datagramExecutor = $datagramExecutor; | ||
$this->streamExecutor = $streamExecutor; | ||
} | ||
|
||
public function query(Query $query) | ||
{ | ||
$stream = $this->streamExecutor; | ||
$pending = $this->datagramExecutor->query($query); | ||
|
||
return new Promise(function ($resolve, $reject) use (&$pending, $stream, $query) { | ||
$pending->then( | ||
$resolve, | ||
function ($e) use (&$pending, $stream, $query, $resolve, $reject) { | ||
if ($e->getCode() === (\defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90)) { | ||
$pending = $stream->query($query)->then($resolve, $reject); | ||
} else { | ||
$reject($e); | ||
} | ||
} | ||
); | ||
}, function () use (&$pending) { | ||
$pending->cancel(); | ||
$pending = null; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.