Forwarder::forwardAll()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 6
ccs 0
cts 4
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 4
crap 2
1
<?php
2
3
namespace SamIT\Proxy;
4
5
use Evenement\EventEmitterInterface;
6
use Evenement\EventEmitterTrait;
7
use React\Promise\Promise;
8
use React\Socket\Connection;
9
use React\Socket\ConnectionInterface;
10
use React\Socket\ServerInterface;
11
use React\SocketClient\TcpConnector;
12
use React\Stream\Stream;
13
14
/**
15
 * Class Forwarder
16
 * Implements a connection where the remote end thinks it is talking to another server.
17
 * @package SamIT\Proxy
18
 */
19
class Forwarder implements EventEmitterInterface
20
{
21
    use EventEmitterTrait;
22
    protected $connector;
23
24 1
    public function __construct(TcpConnector $connector)
25
    {
26 1
        $this->connector = $connector;
27 1
    }
28
29
    /**
30
     * Forwards a connection to the specified host / port using the proxy protocol.
31
     * @param ConnectionInterface $connection
32
     * @param string $forwardAddress The host to forward to
33
     * @param int $forwardPort The port to forward to
34
     * @return Promise
35
     */
36
    public function forward(ConnectionInterface $connection, $forwardAddress, $forwardPort, $protocolVersion = 2)
37
    {
38
        if ($connection instanceof PortConnection) {
39
            $sourceAddress = $connection->getSourceAddress();
40
            $sourcePort = $connection->getSourcePort();
41
            $targetAddress = $connection->getTargetAddress();
42
            $targetPort = $connection->getTargetPort();
43
        } elseif ($connection instanceof Connection) {
44
            list($sourceAddress, $sourcePort) = explode(':', stream_socket_get_name($connection->stream, true));
45
            list($targetAddress, $targetPort) = explode(':', stream_socket_get_name($connection->stream, false));
46
        } else {
47
            throw new \InvalidArgumentException("This connection type is not supported.");
48
        }
49
50
        $connection->pause();
51
52
        $header = Header::createForward4($sourceAddress, $sourcePort, $targetAddress, $targetPort, $protocolVersion);
53
        /** @var Promise $promise */
54
        $promise = $this->connector->create($forwardAddress, $forwardPort);
55
        return $promise
56
            ->then(function(Stream $forwardedConnection) use (
57
                $connection, $header,
58
                $sourceAddress, $sourcePort,
59
                $targetAddress, $targetPort
60
            ) {
61
                $forwardedConnection->pause();
62
                $forwardedConnection->getBuffer()->once('full-drain', function() use ($connection, $forwardedConnection) {
63
                    $this->emit('forward', [$connection, $forwardedConnection]);
64
                    $connection->pipe($forwardedConnection);
65
                    $forwardedConnection->pipe($connection);
66
                    $connection->resume();
67
                    $forwardedConnection->resume();
68
                });
69
                $forwardedConnection->write($header);
70
71
        });
72
    }
73
74
    public function forwardAll(ServerInterface $server, $forwardAddress, $forwardPort, $protocolVersion = 2)
75
    {
76
        $server->on('connection', function(ConnectionInterface $connection) use ($forwardAddress, $forwardPort, $protocolVersion) {
77
            $this->forward($connection, $forwardAddress, $forwardPort, $protocolVersion);
78
        });
79
    }
80
81
}