Completed
Push — master ( d1fbec...e5c8d5 )
by Eugene
06:56
created

SocketConnection::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
cc 3
eloc 3
nc 4
nop 2
crap 3
1
<?php
2
3
namespace Tarantool\Connection;
4
5
use Tarantool\Exception\ConnectionException;
6
use Tarantool\IProto;
7
use Tarantool\Packer\PackUtils;
8
9
class SocketConnection implements Connection
10
{
11
    const DEFAULT_HOST = '127.0.0.1';
12
    const DEFAULT_PORT = 3301;
13
14
    private $host;
15
    private $port;
16
    private $socket;
17
18
    /**
19
     * @param string|null $host Default to 'localhost'.
20
     * @param int|null    $port Default to 3301.
21
     */
22 18
    public function __construct($host = null, $port = null)
23
    {
24 18
        $this->host = null === $host ? self::DEFAULT_HOST : $host;
25 18
        $this->port = null === $port ? self::DEFAULT_PORT : $port;
26 18
    }
27
28 33
    public function open()
29
    {
30 33
        $this->close();
31
32 33
        if (false === $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
33
            throw new ConnectionException(sprintf(
34
                'Unable to create socket: %s.', socket_strerror(socket_last_error())
35
            ));
36
        }
37
38 33
        if (false === @socket_connect($socket, $this->host, $this->port)) {
39 2
            throw new ConnectionException(sprintf(
40 2
                'Unable to connect: %s.', socket_strerror(socket_last_error($socket))
41 2
            ));
42
        }
43
44 31
        $this->socket = $socket;
45
46 31
        $greeting = socket_read($socket, IProto::GREETING_SIZE);
47
48 31
        return IProto::parseSalt($greeting);
49
    }
50
51 33
    public function close()
52
    {
53 33
        if ($this->socket) {
54 16
            socket_close($this->socket);
55 16
            $this->socket = null;
56 16
        }
57 33
    }
58
59 95
    public function isClosed()
60
    {
61 95
        return null === $this->socket;
62
    }
63
64 94
    public function send($data)
65
    {
66 94
        if (false === socket_write($this->socket, $data, strlen($data))) {
67
            throw $this->createConnectionException();
68 94
        }
69 94
70
        $length = null;
71 94
        if (false === socket_recv($this->socket, $length, IProto::LENGTH_SIZE, MSG_WAITALL)) {
72
            throw $this->createConnectionException();
73 94
        }
74
75
        $length = PackUtils::unpackLength($length);
76
77
        $data = null;
78
        if (false === socket_recv($this->socket, $data, $length, MSG_WAITALL)) {
79
            throw $this->createConnectionException();
80
        }
81
82
        return $data;
83
    }
84
85
    private function createConnectionException()
86
    {
87
        $errorCode = socket_last_error($this->socket);
88
89
        return new ConnectionException(socket_strerror($errorCode), $errorCode);
90
    }
91
}
92