1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Dazzle\Socket; |
4
|
|
|
|
5
|
|
|
use Dazzle\Event\BaseEventEmitter; |
6
|
|
|
use Dazzle\Throwable\Exception\Runtime\ReadException; |
7
|
|
|
use Dazzle\Throwable\Exception\Logic\InstantiationException; |
8
|
|
|
use Dazzle\Throwable\Exception\LogicException; |
9
|
|
|
use Dazzle\Loop\LoopAwareTrait; |
10
|
|
|
use Dazzle\Loop\LoopInterface; |
11
|
|
|
use Error; |
12
|
|
|
use Exception; |
13
|
|
|
|
14
|
|
|
class SocketListener extends BaseEventEmitter implements SocketListenerInterface |
15
|
|
|
{ |
16
|
|
|
use LoopAwareTrait; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* @var int |
20
|
|
|
*/ |
21
|
|
|
const DEFAULT_BACKLOG = 1024; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var mixed |
25
|
|
|
*/ |
26
|
|
|
const CONFIG_DEFAULT_SSL = false; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var mixed |
30
|
|
|
*/ |
31
|
|
|
const CONFIG_DEFAULT_SSL_METHOD = STREAM_CRYPTO_METHOD_TLSv1_2_SERVER; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var mixed |
35
|
|
|
*/ |
36
|
|
|
const CONFIG_DEFAULT_SSL_NAME = ''; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var mixed |
40
|
|
|
*/ |
41
|
|
|
const CONFIG_DEFAULT_SSL_VERIFY_SIGN = false; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var mixed |
45
|
|
|
*/ |
46
|
|
|
const CONFIG_DEFAULT_SSL_VERIFY_PEER = false; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var mixed |
50
|
|
|
*/ |
51
|
|
|
const CONFIG_DEFAULT_SSL_VERIFY_DEPTH = 10; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var resource |
55
|
|
|
*/ |
56
|
|
|
protected $socket; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var bool |
60
|
|
|
*/ |
61
|
|
|
protected $started; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var bool |
65
|
|
|
*/ |
66
|
|
|
protected $paused; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @var array |
70
|
|
|
*/ |
71
|
|
|
protected $config; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @var string|resource |
75
|
|
|
*/ |
76
|
|
|
protected $endpoint; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @param string|resource $endpointOrResource |
80
|
|
|
* @param LoopInterface $loop |
81
|
|
|
* @param mixed[] $config |
82
|
|
|
* @throws InstantiationException |
83
|
|
|
*/ |
84
|
30 |
|
public function __construct($endpointOrResource, LoopInterface $loop, $config = []) |
85
|
|
|
{ |
86
|
30 |
|
$this->configure($config); |
87
|
30 |
|
$this->endpoint = $endpointOrResource; |
88
|
30 |
|
$this->socket = null; |
89
|
30 |
|
$this->loop = $loop; |
90
|
30 |
|
$this->started = false; |
91
|
30 |
|
$this->paused = true; |
92
|
30 |
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* |
96
|
|
|
*/ |
97
|
27 |
|
public function __destruct() |
98
|
|
|
{ |
99
|
27 |
|
$this->handleClose(); |
100
|
|
|
|
101
|
27 |
|
parent::__destruct(); |
102
|
|
|
|
103
|
27 |
|
unset($this->socket); |
104
|
27 |
|
unset($this->loop); |
105
|
27 |
|
unset($this->started); |
106
|
27 |
|
unset($this->paused); |
107
|
27 |
|
unset($this->config); |
108
|
27 |
|
unset($this->endpoint); |
109
|
27 |
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @override |
113
|
|
|
* @inheritDoc |
114
|
|
|
*/ |
115
|
16 |
|
public function start() |
116
|
|
|
{ |
117
|
16 |
|
if ($this->isOpen()) |
118
|
|
|
{ |
119
|
2 |
|
return; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
try |
123
|
|
|
{ |
124
|
16 |
|
if (!is_resource($this->endpoint)) |
125
|
|
|
{ |
126
|
16 |
|
$this->socket = $this->createServer($this->endpoint, $this->config); |
127
|
|
|
} |
128
|
|
|
else |
129
|
|
|
{ |
130
|
|
|
$this->socket = &$this->endpoint; |
131
|
|
|
} |
132
|
|
|
|
133
|
14 |
|
$this->resume(); |
134
|
14 |
|
$this->started = true; |
135
|
|
|
} |
136
|
2 |
|
catch (Error $ex) |
137
|
|
|
{ |
138
|
|
|
throw new InstantiationException('SocketListener could not be created.', 0, $ex); |
139
|
|
|
} |
140
|
2 |
|
catch (Exception $ex) |
141
|
|
|
{ |
142
|
2 |
|
throw new InstantiationException('SocketListener could not be created.', 0, $ex); |
143
|
|
|
} |
144
|
14 |
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* @override |
148
|
|
|
* @inheritDoc |
149
|
|
|
*/ |
150
|
|
|
public function stop() |
151
|
|
|
{ |
152
|
|
|
$this->close(); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* @override |
157
|
|
|
* @inheritDoc |
158
|
|
|
*/ |
159
|
4 |
|
public function getLocalEndpoint() |
160
|
|
|
{ |
161
|
4 |
|
return $this->parseEndpoint(); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @override |
166
|
|
|
* @inheritDoc |
167
|
|
|
*/ |
168
|
3 |
|
public function getLocalAddress() |
169
|
|
|
{ |
170
|
3 |
|
$endpoint = explode('://', $this->getLocalEndpoint(), 2); |
171
|
|
|
|
172
|
3 |
|
return isset($endpoint[1]) ? $endpoint[1] : $endpoint[0]; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* @override |
177
|
|
|
* @inheritDoc |
178
|
|
|
*/ |
179
|
1 |
|
public function getLocalHost() |
180
|
|
|
{ |
181
|
1 |
|
$address = explode(':', $this->getLocalAddress(), 2); |
182
|
|
|
|
183
|
1 |
|
return $address[0]; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @override |
188
|
|
|
* @inheritDoc |
189
|
|
|
*/ |
190
|
1 |
|
public function getLocalPort() |
191
|
|
|
{ |
192
|
1 |
|
$address = explode(':', $this->getLocalAddress(), 2); |
193
|
|
|
|
194
|
1 |
|
return isset($address[1]) ? $address[1] : ''; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @override |
199
|
|
|
* @inheritDoc |
200
|
|
|
*/ |
201
|
|
|
public function getLocalProtocol() |
202
|
|
|
{ |
203
|
|
|
$endpoint = explode('://', $this->getLocalEndpoint(), 2); |
204
|
|
|
|
205
|
|
|
return isset($endpoint[0]) ? $endpoint[0]:''; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @override |
210
|
|
|
* @inheritDoc |
211
|
|
|
*/ |
212
|
1 |
|
public function getResource() |
213
|
|
|
{ |
214
|
1 |
|
return $this->socket; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* @override |
219
|
|
|
* @inheritDoc |
220
|
|
|
*/ |
221
|
1 |
|
public function getResourceId() |
222
|
|
|
{ |
223
|
1 |
|
return (int) $this->socket; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* @override |
228
|
|
|
* @inheritDoc |
229
|
|
|
*/ |
230
|
16 |
|
public function getMetadata() |
231
|
|
|
{ |
232
|
16 |
|
if ($this->isOpen()) |
233
|
|
|
{ |
234
|
9 |
|
return stream_get_meta_data($this->socket); |
235
|
|
|
} |
236
|
7 |
|
return []; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* @override |
241
|
|
|
* @inheritDoc |
242
|
|
|
*/ |
243
|
14 |
|
public function getStreamType() |
244
|
|
|
{ |
245
|
14 |
|
$data = $this->getMetadata(); |
246
|
|
|
|
247
|
14 |
|
return isset($data['stream_type']) ? $data['stream_type'] : 'undefined'; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* @override |
252
|
|
|
* @inheritDoc |
253
|
|
|
*/ |
254
|
1 |
|
public function getWrapperType() |
255
|
|
|
{ |
256
|
1 |
|
$data = $this->getMetadata(); |
257
|
|
|
|
258
|
1 |
|
return isset($data['wrapper_type']) ? $data['wrapper_type'] : 'undefined'; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* @override |
263
|
|
|
* @inheritDoc |
264
|
|
|
*/ |
265
|
22 |
|
public function isOpen() |
266
|
|
|
{ |
267
|
22 |
|
return $this->started; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* @override |
272
|
|
|
* @inheritDoc |
273
|
|
|
*/ |
274
|
5 |
|
public function isPaused() |
275
|
|
|
{ |
276
|
5 |
|
return $this->paused; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* @override |
281
|
|
|
* @inheritDoc |
282
|
|
|
*/ |
283
|
|
|
public function isEncrypted() |
284
|
|
|
{ |
285
|
|
|
return isset($this->config['ssl']) && $this->config['ssl'] === true; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* @override |
290
|
|
|
* @inheritDoc |
291
|
|
|
*/ |
292
|
5 |
|
public function close() |
293
|
|
|
{ |
294
|
5 |
|
if (!$this->isOpen()) |
295
|
|
|
{ |
296
|
|
|
return; |
297
|
|
|
} |
298
|
|
|
|
299
|
5 |
|
$this->started = false; |
300
|
|
|
|
301
|
5 |
|
$this->emit('close', [ $this ]); |
302
|
5 |
|
$this->handleClose(); |
303
|
5 |
|
$this->emit('done', [ $this ]); |
304
|
5 |
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* @override |
308
|
|
|
* @inheritDoc |
309
|
|
|
*/ |
310
|
30 |
|
public function pause() |
311
|
|
|
{ |
312
|
30 |
|
if (!$this->paused) |
313
|
|
|
{ |
314
|
16 |
|
$this->paused = true; |
315
|
|
|
|
316
|
16 |
|
if (isset($this->loop)) |
317
|
|
|
{ |
318
|
16 |
|
$this->loop->removeReadStream($this->socket); |
319
|
|
|
} |
320
|
|
|
} |
321
|
30 |
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* @override |
325
|
|
|
* @inheritDoc |
326
|
|
|
*/ |
327
|
16 |
|
public function resume() |
328
|
|
|
{ |
329
|
16 |
|
if ($this->paused) |
330
|
|
|
{ |
331
|
16 |
|
$this->paused = false; |
332
|
|
|
|
333
|
16 |
|
if (isset($this->loop)) |
334
|
|
|
{ |
335
|
16 |
|
$this->loop->addReadStream($this->socket, [ $this, 'handleConnect' ]); |
336
|
|
|
} |
337
|
|
|
} |
338
|
16 |
|
} |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* Create the server resource. |
342
|
|
|
* |
343
|
|
|
* This method creates server resource for socket connections. |
344
|
|
|
* |
345
|
|
|
* @param string $endpoint |
346
|
|
|
* @param mixed[] $config |
347
|
|
|
* @return resource |
348
|
|
|
* @throws LogicException |
349
|
|
|
*/ |
350
|
16 |
|
protected function createServer($endpoint, $config = []) |
351
|
|
|
{ |
352
|
16 |
|
if (stripos($endpoint, 'unix://') !== false) |
353
|
|
|
{ |
354
|
1 |
|
if ($endpoint[7] === DIRECTORY_SEPARATOR) |
355
|
|
|
{ |
356
|
|
|
$path = substr($endpoint, 7); |
357
|
|
|
} |
358
|
|
|
else |
359
|
|
|
{ |
360
|
1 |
|
$path = getcwd() . DIRECTORY_SEPARATOR . substr($endpoint, 7); |
361
|
1 |
|
$endpoint = 'unix://' . $path; |
362
|
|
|
} |
363
|
|
|
|
364
|
1 |
|
if (file_exists($path)) |
365
|
|
|
{ |
366
|
|
|
unlink($path); |
367
|
|
|
} |
368
|
|
|
} |
369
|
|
|
|
370
|
16 |
|
$ssl = $this->config['ssl']; |
371
|
16 |
|
$name = $this->config['ssl_name']; |
372
|
16 |
|
$verifySign = $this->config['ssl_verify_sign']; |
373
|
16 |
|
$verifyPeer = $this->config['ssl_verify_peer']; |
374
|
16 |
|
$verifyDepth = $this->config['ssl_verify_depth']; |
375
|
|
|
|
376
|
16 |
|
$backlog = (int) (isset($config['backlog']) ? $config['backlog'] : self::DEFAULT_BACKLOG); |
377
|
16 |
|
$reuseaddr = (bool) (isset($config['reuseaddr']) ? $config['reuseaddr'] : false); |
378
|
16 |
|
$reuseport = (bool) (isset($config['reuseport']) ? $config['reuseport'] : false); |
379
|
|
|
|
380
|
16 |
|
$context = []; |
381
|
16 |
|
$context['socket'] = [ |
382
|
16 |
|
'bindto' => $endpoint, |
383
|
16 |
|
'backlog' => $backlog, |
384
|
|
|
'ipv6_v6only' => true, |
385
|
16 |
|
'so_reuseaddr' => $reuseaddr, |
386
|
16 |
|
'so_reuseport' => $reuseport, |
387
|
|
|
]; |
388
|
16 |
|
$context['ssl'] = [ |
389
|
16 |
|
'allow_self_signed' => !$verifySign, |
390
|
16 |
|
'verify_peer' => $verifyPeer, |
391
|
16 |
|
'verify_peer_name' => $verifyPeer, |
392
|
16 |
|
'verify_depth' => $verifyDepth, |
393
|
|
|
'disable_compression' => true, |
394
|
16 |
|
'SNI_enabled' => $name !== '', |
395
|
16 |
|
'SNI_server_name' => $name, |
396
|
16 |
|
'peer_name' => $name, |
397
|
|
|
]; |
398
|
|
|
|
399
|
16 |
|
if ($ssl && isset($config['ssl_cert'])) |
400
|
|
|
{ |
401
|
4 |
|
$context['ssl']['local_cert'] = $config['ssl_cert']; |
402
|
|
|
} |
403
|
|
|
|
404
|
16 |
|
if ($ssl && isset($config['ssl_key'])) |
405
|
|
|
{ |
406
|
4 |
|
$context['ssl']['local_pk'] = $config['ssl_key']; |
407
|
|
|
} |
408
|
|
|
|
409
|
16 |
|
if ($ssl && isset($config['ssl_secret'])) |
410
|
|
|
{ |
411
|
4 |
|
$context['ssl']['passphrase'] = $config['ssl_secret']; |
412
|
|
|
} |
413
|
|
|
|
414
|
16 |
|
$bitmask = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; |
415
|
|
|
|
416
|
16 |
|
$context = stream_context_create($context); |
417
|
|
|
|
418
|
|
|
// Error reporting suppressed since stream_socket_server() emits an E_WARNING on failure. |
419
|
16 |
|
$socket = @stream_socket_server( |
420
|
16 |
|
$endpoint, |
421
|
16 |
|
$errno, |
422
|
16 |
|
$errstr, |
423
|
16 |
|
$bitmask, |
424
|
16 |
|
$context |
425
|
|
|
); |
426
|
|
|
|
427
|
16 |
View Code Duplication |
if (!$socket || $errno > 0) |
|
|
|
|
428
|
|
|
{ |
429
|
2 |
|
throw new LogicException( |
430
|
2 |
|
sprintf('Could not bind socket [%s] because of error [%d; %s]', $endpoint, $errno, $errstr) |
431
|
|
|
); |
432
|
|
|
} |
433
|
|
|
|
434
|
14 |
|
return $socket; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Create the client resource. |
439
|
|
|
* |
440
|
|
|
* This method creates client resource for socket connections. |
441
|
|
|
* |
442
|
|
|
* @param resource $resource |
443
|
|
|
* @param string[] $config |
444
|
|
|
* @return SocketInterface |
445
|
|
|
*/ |
446
|
3 |
|
protected function createClient($resource, $config = []) |
447
|
|
|
{ |
448
|
3 |
|
return new Socket($resource, $this->loop, $config); |
|
|
|
|
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
/** |
452
|
|
|
* Handle the new connection. |
453
|
|
|
* |
454
|
|
|
* @internal |
455
|
|
|
*/ |
456
|
3 |
|
public function handleConnect() |
457
|
|
|
{ |
458
|
3 |
|
$socket = @stream_socket_accept($this->socket); |
459
|
|
|
|
460
|
3 |
|
if ($socket === false) |
461
|
|
|
{ |
462
|
|
|
$this->emit('error', [ $this, new ReadException('Socket could not accept new connection.') ]); |
463
|
|
|
return; |
464
|
|
|
} |
465
|
|
|
|
466
|
3 |
|
$client = null; |
467
|
3 |
|
$ex = null; |
468
|
|
|
|
469
|
|
|
try |
470
|
|
|
{ |
471
|
3 |
|
$client = $this->createClient($socket, [ |
472
|
3 |
|
'ssl' => $this->config['ssl'], |
473
|
3 |
|
'ssl_method' => $this->config['ssl_method'], |
474
|
|
|
]); |
475
|
|
|
|
476
|
3 |
|
$this->emit('connect', [ $this, $client ]); |
477
|
|
|
} |
478
|
|
|
catch (Error $ex) |
|
|
|
|
479
|
|
|
{} |
480
|
|
|
catch (Exception $ex) |
|
|
|
|
481
|
|
|
{} |
482
|
|
|
|
483
|
3 |
|
if ($ex !== null) |
484
|
|
|
{ |
485
|
|
|
$this->handleDisconnect($socket); |
486
|
|
|
$this->emit('error', [ $this, new ReadException('Socket could not wrap new connection!') ]); |
487
|
|
|
} |
488
|
3 |
|
} |
489
|
|
|
|
490
|
|
|
private function handleDisconnect($resource) |
491
|
|
|
{ |
492
|
|
|
if (is_resource($resource)) |
493
|
|
|
{ |
494
|
|
|
// http://chat.stackoverflow.com/transcript/message/7727858#7727858 |
495
|
|
|
stream_socket_shutdown($resource, STREAM_SHUT_RDWR); |
496
|
|
|
stream_set_blocking($resource, 0); |
497
|
|
|
fclose($resource); |
498
|
|
|
} |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
/** |
502
|
|
|
* Handle closing event. |
503
|
|
|
* |
504
|
|
|
* @internal |
505
|
|
|
*/ |
506
|
30 |
|
public function handleClose() |
507
|
|
|
{ |
508
|
30 |
|
$this->pause(); |
509
|
|
|
|
510
|
30 |
|
if (is_resource($this->socket)) |
511
|
|
|
{ |
512
|
14 |
|
if ($this->getStreamType() === Socket::TYPE_UNIX) |
513
|
|
|
{ |
514
|
|
|
$path = substr($this->parseEndpoint(), 7); |
515
|
|
|
unlink($path); |
516
|
|
|
} |
517
|
14 |
|
fclose($this->socket); |
518
|
|
|
} |
519
|
30 |
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Configure socket. |
523
|
|
|
* |
524
|
|
|
* @param string[] $config |
525
|
|
|
*/ |
526
|
30 |
View Code Duplication |
private function configure($config = []) |
|
|
|
|
527
|
|
|
{ |
528
|
30 |
|
$this->config = $config; |
529
|
|
|
|
530
|
30 |
|
$this->configureVariable('ssl'); |
531
|
30 |
|
$this->configureVariable('ssl_method'); |
532
|
30 |
|
$this->configureVariable('ssl_name'); |
533
|
30 |
|
$this->configureVariable('ssl_verify_sign'); |
534
|
30 |
|
$this->configureVariable('ssl_verify_peer'); |
535
|
30 |
|
$this->configureVariable('ssl_verify_depth'); |
536
|
30 |
|
} |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* Configure static key |
540
|
|
|
* |
541
|
|
|
* @param $configKey |
542
|
|
|
*/ |
543
|
30 |
|
private function configureVariable($configKey) |
544
|
|
|
{ |
545
|
30 |
|
$configStaticKey = 'CONFIG_DEFAULT_' . strtoupper($configKey); |
546
|
30 |
|
$this->config[$configKey] = isset($this->config[$configKey]) ? $this->config[$configKey] : constant("static::$configStaticKey"); |
547
|
30 |
|
} |
548
|
|
|
|
549
|
|
|
/** |
550
|
|
|
* @return string |
551
|
|
|
*/ |
552
|
4 |
|
private function parseEndpoint() |
553
|
|
|
{ |
554
|
4 |
|
if ($this->isOpen()) |
555
|
|
|
{ |
556
|
|
|
$name = stream_socket_get_name($this->socket, false); |
557
|
|
|
$type = $this->getStreamType(); |
558
|
|
|
|
559
|
|
View Code Duplication |
switch ($type) |
|
|
|
|
560
|
|
|
{ |
561
|
|
|
case Socket::TYPE_UNIX: |
562
|
|
|
$transport = 'unix://'; |
563
|
|
|
$endpoint = $transport . $name; |
564
|
|
|
break; |
565
|
|
|
|
566
|
|
|
case Socket::TYPE_TCP: |
567
|
|
|
$transport = 'tcp://'; |
568
|
|
|
if (substr_count($name, ':') > 1) |
569
|
|
|
{ |
570
|
|
|
$parts = explode(':', $name); |
571
|
|
|
$count = count($parts); |
572
|
|
|
$port = $parts[$count - 1]; |
573
|
|
|
unset($parts[$count - 1]); |
574
|
|
|
$endpoint = $transport.'[' . implode(':', $parts) . ']:' . $port; |
575
|
|
|
} |
576
|
|
|
else |
577
|
|
|
{ |
578
|
|
|
$endpoint = $transport . $name; |
579
|
|
|
} |
580
|
|
|
break; |
581
|
|
|
|
582
|
|
|
case Socket::TYPE_UDP: |
583
|
|
|
$transport = 'udp://'; |
584
|
|
|
$endpoint = $transport . $name; |
585
|
|
|
break; |
586
|
|
|
|
587
|
|
|
default: |
588
|
|
|
$endpoint = ''; |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
return $endpoint; |
592
|
|
|
} |
593
|
|
|
else |
594
|
|
|
{ |
595
|
4 |
|
return is_string($this->endpoint) ? $this->endpoint : ''; |
596
|
|
|
} |
597
|
|
|
} |
598
|
|
|
} |
599
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.