Passed
Push — master ( b15770...fe0caa )
by Sam
03:52
created

Forwarder::forward()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 32
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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