Socket::reset()   A
last analyzed

Complexity

Conditions 2
Paths 3

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 9
loc 9
ccs 0
cts 6
cp 0
rs 9.9666
c 0
b 0
f 0
cc 2
nc 3
nop 0
crap 6
1
<?php
2
3
/**
4
 * This file is part of the PHP Generics package.
5
 *
6
 * @package Generics
7
 */
8
namespace Generics\Socket;
9
10
use Generics\Streams\SocketStream;
11
use Generics\ResetException;
12
use Exception;
13
14
/**
15
 * This abstract class provides basic socket functionality
16
 *
17
 * @author Maik Greubel <[email protected]>
18
 */
19
abstract class Socket implements SocketStream
20
{
21
22
    /**
23
     * The socket handle
24
     *
25
     * @var resource
26
     */
27
    protected $handle;
28
29
    /**
30
     * The socket endpoint
31
     *
32
     * @var Endpoint
33
     */
34
    protected $endpoint;
35
36
    /**
37
     * Create a new socket
38
     *
39
     * @param Endpoint $endpoint
40
     *            The endpoint for the socket
41
     */
42 16
    public function __construct(Endpoint $endpoint)
43
    {
44 16
        $this->endpoint = $endpoint;
45 16
        $this->open();
46 16
    }
47
48
    /**
49
     * Opens a socket
50
     *
51
     * @throws SocketException
52
     */
53 16
    private function open()
54
    {
55 16
        $this->handle = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
56
        
57 16
        if (! is_resource($this->handle)) {
58
            $code = socket_last_error();
59
            throw new SocketException(socket_strerror($code), array(), $code);
60
        }
61 16
    }
62
63
    /**
64
     * Clean up
65
     */
66 16
    public function __destruct()
67
    {
68 16
        $this->close();
69 16
    }
70
71
    /**
72
     *
73
     * {@inheritdoc}
74
     * @see \Generics\Streams\Stream::close()
75
     */
76 16
    public function close()
77
    {
78 16
        if (is_resource($this->handle)) {
79 16
            socket_close($this->handle);
80 16
            $this->handle = null;
81
        }
82 16
    }
83
84
    /**
85
     *
86
     * {@inheritdoc}
87
     * @see \Generics\Streams\Stream::ready()
88
     */
89 11 View Code Duplication
    public function ready(): bool
90
    {
91 11
        if (! is_resource($this->handle)) {
92 1
            return false;
93
        }
94
        
95
        $read = array(
96 10
            $this->handle
97
        );
98 10
        $write = null;
99 10
        $except = null;
100
        
101 10
        $num = @socket_select($read, $write, $except, 0);
102
        
103 10
        if ($num === false) {
104
            $code = socket_last_error($this->handle);
105
            throw new SocketException(socket_strerror($code), array(), $code);
106
        }
107
        
108 10
        if ($num < 1) {
109 10
            return false;
110
        }
111
        
112 9
        if (! in_array($this->handle, $read)) {
113
            return false;
114
        }
115
        
116 9
        return true;
117
    }
118
119
    /**
120
     *
121
     * {@inheritdoc}
122
     * @see \Generics\Streams\OutputStream::isWriteable()
123
     */
124 1 View Code Duplication
    public function isWriteable(): bool
125
    {
126 1
        if (! is_resource($this->handle)) {
127
            return false;
128
        }
129
        
130 1
        $read = null;
131
        $write = array(
132 1
            $this->handle
133
        );
134 1
        $except = null;
135
        
136 1
        $num = @socket_select($read, $write, $except, 0, 0);
137
        
138 1
        if ($num === false) {
139
            $code = socket_last_error($this->handle);
140
            throw new SocketException(socket_strerror($code), array(), $code);
141
        }
142
        
143 1
        if ($num < 1) {
144
            return false;
145
        }
146
        
147 1
        if (! in_array($this->handle, $write)) {
148
            return false;
149
        }
150
        
151 1
        return true;
152
    }
153
154
    /**
155
     *
156
     * {@inheritdoc}
157
     * @see \Countable::count()
158
     */
159
    public function count()
160
    {
161
        throw new SocketException("Cannot count elements of socket");
162
    }
163
164
    /**
165
     *
166
     * {@inheritdoc}
167
     * @see \Generics\Streams\InputStream::read()
168
     */
169 9
    public function read($length = 1, $offset = null): string
170
    {
171 9
        if (($buf = @socket_read($this->handle, $length)) === false) {
172
            $buf = "";
173
            $code = socket_last_error();
174
            if ($code != 0) {
175
                if ($code != 10053) {
176
                    throw new SocketException(socket_strerror($code), array(), $code);
177
                } else {
178
                    $this->handle = null;
179
                }
180
            }
181
        }
182
        
183 9
        return $buf;
184
    }
185
186
    /**
187
     *
188
     * {@inheritdoc}
189
     * @see \Generics\Streams\OutputStream::write()
190
     */
191 10
    public function write($buffer)
192
    {
193 10
        if (($written = @socket_write($this->handle, "{$buffer}")) === false) {
194
            $code = socket_last_error();
195
            throw new SocketException(socket_strerror($code), array(), $code);
196
        }
197
        
198 10
        if ($written != strlen($buffer)) {
199
            throw new SocketException("Could not write all {bytes} bytes to socket ({written} written)", array(
200
                'bytes' => strlen($buffer),
201
                'written' => $written
202
            ));
203
        }
204 10
    }
205
206
    /**
207
     * Get the socket endpoint
208
     *
209
     * @return \Generics\Socket\Endpoint
210
     */
211 11
    public function getEndpoint(): Endpoint
212
    {
213 11
        return $this->endpoint;
214
    }
215
216
    /**
217
     *
218
     * {@inheritdoc}
219
     * @see \Generics\Streams\OutputStream::flush()
220
     */
221
    public function flush()
222
    {
223
        // There is no function to flush a socket. This is only possible for file descriptors.
224
    }
225
226
    /**
227
     *
228
     * {@inheritdoc}
229
     * @see \Generics\Streams\Stream::isOpen()
230
     */
231 1
    public function isOpen(): bool
232
    {
233 1
        return is_resource($this->handle);
234
    }
235
236
    /**
237
     *
238
     * {@inheritdoc}
239
     * @see \Generics\Resettable::reset()
240
     */
241 View Code Duplication
    public function reset()
242
    {
243
        try {
244
            $this->close();
245
            $this->open();
246
        } catch (Exception $ex) {
247
            throw new ResetException($ex->getMessage(), array(), $ex->getCode(), $ex);
248
        }
249
    }
250
}
251