Completed
Push — master ( a7af36...1cb211 )
by Evgenij
02:42
created

AbstractSocket   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 98.36%

Importance

Changes 27
Bugs 1 Features 7
Metric Value
wmc 17
c 27
b 1
f 7
lcom 1
cbo 3
dl 0
loc 184
ccs 60
cts 61
cp 0.9836
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A __destruct() 0 4 1
createSocketResource() 0 1 ?
createIoInterface() 0 1 ?
B open() 0 26 3
A close() 0 9 2
A read() 0 9 2
A write() 0 9 2
A getStreamResource() 0 4 1
B resolveSocketType() 0 24 4
A setDisconnectedState() 0 4 1
1
<?php
2
/**
3
 * Async sockets
4
 *
5
 * @copyright Copyright (c) 2015, Efimov Evgenij <[email protected]>
6
 *
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace AsyncSockets\Socket;
12
13
use AsyncSockets\Exception\ConnectionException;
14
use AsyncSockets\Frame\FramePickerInterface;
15
use AsyncSockets\Socket\Io\DisconnectedIo;
16
use AsyncSockets\Socket\Io\IoInterface;
17
18
/**
19
 * Class AbstractSocket
20
 */
21
abstract class AbstractSocket implements SocketInterface
22
{
23
    /**
24
     * Tcp socket type
25
     */
26
    const SOCKET_TYPE_TCP = 'tcp';
27
28
    /**
29
     * Udp socket type
30
     */
31
    const SOCKET_TYPE_UDP = 'udp';
32
33
    /**
34
     * Unix socket type
35
     */
36
    const SOCKET_TYPE_UNIX = 'unix';
37
38
    /**
39
     * Unix datagram socket type
40
     */
41
    const SOCKET_TYPE_UDG = 'udg';
42
43
    /**
44
     * Unknown type of socket
45
     */
46
    const SOCKET_TYPE_UNKNOWN = '';
47
48
    /**
49
     * This socket resource
50
     *
51
     * @var resource
52
     */
53
    private $resource;
54
55
    /**
56
     * I/O interface
57
     *
58
     * @var IoInterface
59
     */
60
    private $ioInterface;
61
62
    /**
63
     * AbstractSocket constructor.
64
     */
65 83
    public function __construct()
66
    {
67 83
        $this->setDisconnectedState();
68 83
    }
69
70
    /**
71
     * Destructor
72
     */
73 4
    public function __destruct()
74
    {
75 4
        $this->close();
76 4
    }
77
78
    /**
79
     * Create certain socket resource
80
     *
81
     * @param string   $address Network address to open in form transport://path:port
82
     * @param resource $context Valid stream context created by function stream_context_create or null
83
     *
84
     * @return resource
85
     */
86
    abstract protected function createSocketResource($address, $context);
87
88
    /**
89
     * Create I/O interface for socket
90
     *
91
     * @param string $type Type of this socket, one of SOCKET_TYPE_* consts
92
     * @param string $address Address passed to open method
93
     *
94
     * @return IoInterface
95
     */
96
    abstract protected function createIoInterface($type, $address);
97
98
    /** {@inheritdoc} */
99 47
    public function open($address, $context = null)
100
    {
101 47
        $this->close();
102
103 47
        $this->resource = $this->createSocketResource(
104 47
            $address,
105 47
            $context ?: stream_context_get_default()
106 47
        );
107
108 43
        $result = false;
109 43
        if (is_resource($this->resource)) {
110 43
            $result = true;
111
            // https://bugs.php.net/bug.php?id=51056
112 43
            stream_set_blocking($this->resource, 0);
113
114
            // https://bugs.php.net/bug.php?id=52602
115 43
            stream_set_timeout($this->resource, 0, 0);
116
117 43
            $this->ioInterface = $this->createIoInterface(
118 43
                $this->resolveSocketType(),
119
                $address
120 43
            );
121 43
        }
122
123 43
        return $result;
124
    }
125
126
    /** {@inheritdoc} */
127 47
    public function close()
128
    {
129 47
        $this->setDisconnectedState();
130 47
        if ($this->resource) {
131 9
            stream_socket_shutdown($this->resource, STREAM_SHUT_RDWR);
132 9
            fclose($this->resource);
133 9
            $this->resource = null;
134 9
        }
135 47
    }
136
137
    /** {@inheritdoc} */
138 22
    public function read(FramePickerInterface $picker)
139
    {
140
        try {
141 22
            return $this->ioInterface->read($picker);
142 8
        } catch (ConnectionException $e) {
143 4
            $this->setDisconnectedState();
144 4
            throw $e;
145
        }
146
    }
147
148
    /** {@inheritdoc} */
149 8
    public function write($data)
150
    {
151
        try {
152 8
            return $this->ioInterface->write($data);
153 8
        } catch (ConnectionException $e) {
154 4
            $this->setDisconnectedState();
155 4
            throw $e;
156
        }
157
    }
158
159
    /** {@inheritdoc} */
160 31
    public function getStreamResource()
161
    {
162 31
        return $this->resource;
163
    }
164
165
    /**
166
     * Get current socket type
167
     *
168
     * @return string One of SOCKET_TYPE_* consts
169
     */
170 43
    private function resolveSocketType()
171
    {
172 43
        $info = stream_get_meta_data($this->resource);
173 43
        if (!isset($info['stream_type'])) {
174
            return self::SOCKET_TYPE_UNKNOWN;
175
        }
176
177 43
        $parts = explode('/', $info['stream_type']);
178
        $map   = [
179 43
            'tcp'  => self::SOCKET_TYPE_TCP,
180 43
            'udp'  => self::SOCKET_TYPE_UDP,
181 43
            'udg'  => self::SOCKET_TYPE_UDG,
182 43
            'unix' => self::SOCKET_TYPE_UNIX,
183 43
        ];
184
185 43
        $regexp = '#^('. implode('|', array_keys($map)) . ')_socket$#';
186 43
        foreach ($parts as $part) {
187 43
            if (preg_match($regexp, $part, $pockets)) {
188 29
                return $map[$pockets[1]];
189
            }
190 14
        }
191
192 14
        return self::SOCKET_TYPE_UNKNOWN;
193
    }
194
195
    /**
196
     * Set disconnected state for socket
197
     *
198
     * @return void
199
     */
200 83
    private function setDisconnectedState()
201
    {
202 83
        $this->ioInterface = new DisconnectedIo($this);
203 83
    }
204
}
205