This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Dazzle\ChannelSocket; |
||
4 | |||
5 | use Dazzle\ChannelSocket\Buffer\Buffer; |
||
6 | use Dazzle\ChannelSocket\Connection\Connection; |
||
7 | use Dazzle\ChannelSocket\Connection\ConnectionPool; |
||
8 | use Dazzle\Channel\Model\ModelInterface; |
||
9 | use Dazzle\Channel\Channel; |
||
10 | use Dazzle\Event\BaseEventEmitter; |
||
11 | use Dazzle\Socket\SocketInterface; |
||
12 | use Dazzle\Socket\SocketListenerInterface; |
||
13 | use Dazzle\Loop\Timer\TimerInterface; |
||
14 | use Dazzle\Loop\LoopInterface; |
||
15 | use Dazzle\Throwable\Exception\Runtime\ExecutionException; |
||
16 | use Error; |
||
17 | use Exception; |
||
18 | |||
19 | class Socket extends BaseEventEmitter implements ModelInterface |
||
20 | { |
||
21 | /** |
||
22 | * @var int |
||
23 | */ |
||
24 | const COMMAND_HEARTBEAT = 1; |
||
25 | |||
26 | /** |
||
27 | * @var int |
||
28 | */ |
||
29 | const COMMAND_MESSAGE = 2; |
||
30 | |||
31 | /** |
||
32 | * @var int |
||
33 | */ |
||
34 | const SEND_STATUS_DROPPED = 0; |
||
35 | |||
36 | /** |
||
37 | * @var int |
||
38 | */ |
||
39 | const SEND_STATUS_SUCCEEDED = 1; |
||
40 | |||
41 | /** |
||
42 | * @var int |
||
43 | */ |
||
44 | const SEND_STATUS_BUFFERED = 2; |
||
45 | |||
46 | /** |
||
47 | * @var LoopInterface |
||
48 | */ |
||
49 | protected $loop; |
||
50 | |||
51 | /** |
||
52 | * @var string |
||
53 | */ |
||
54 | protected $id; |
||
55 | |||
56 | /** |
||
57 | * @var string |
||
58 | */ |
||
59 | protected $endpoint; |
||
60 | |||
61 | /** |
||
62 | * @var int |
||
63 | */ |
||
64 | protected $type; |
||
65 | |||
66 | /** |
||
67 | * @var string[] |
||
68 | */ |
||
69 | protected $hosts; |
||
70 | |||
71 | /** |
||
72 | * @var string[] |
||
73 | */ |
||
74 | protected $flags; |
||
75 | |||
76 | /** |
||
77 | * @var mixed[] |
||
78 | */ |
||
79 | protected $options; |
||
80 | |||
81 | /** |
||
82 | * @var bool |
||
83 | */ |
||
84 | protected $isConnected; |
||
85 | |||
86 | /** |
||
87 | * @var SocketInterface|SocketListenerInterface|null |
||
88 | */ |
||
89 | protected $socket; |
||
90 | |||
91 | /** |
||
92 | * @var ConnectionPool |
||
93 | */ |
||
94 | protected $connectionPool; |
||
95 | |||
96 | /** |
||
97 | * @var Buffer |
||
98 | */ |
||
99 | protected $offlineBuffer; |
||
100 | |||
101 | /** |
||
102 | * @var Buffer |
||
103 | */ |
||
104 | protected $onlineBuffer; |
||
105 | |||
106 | /** |
||
107 | * @var string[] |
||
108 | */ |
||
109 | protected $frameBuffer; |
||
110 | |||
111 | /** |
||
112 | * @var TimerInterface |
||
113 | */ |
||
114 | private $hTimer; |
||
115 | |||
116 | /** |
||
117 | * @var TimerInterface |
||
118 | */ |
||
119 | private $rTimer; |
||
120 | |||
121 | /** |
||
122 | * @param LoopInterface $loop |
||
123 | * @param string[] $params |
||
124 | */ |
||
125 | 40 | public function __construct(LoopInterface $loop, $params) |
|
126 | { |
||
127 | 40 | $id = $params['id']; |
|
128 | 40 | $endpoint = $params['endpoint']; |
|
129 | 40 | $type = $params['type']; |
|
130 | 40 | $hosts = $params['host']; |
|
131 | |||
132 | $flags = [ |
||
133 | 40 | 'enableHeartbeat' => true, |
|
134 | 'enableBuffering' => true, |
||
135 | 'enableTimeRegister' => true |
||
136 | ]; |
||
137 | |||
138 | $options = [ |
||
139 | 40 | 'bufferSize' => isset($params['bufferSize']) ? (int)$params['bufferSize'] : 0, |
|
140 | 40 | 'bufferTimeout' => isset($params['bufferTimeout']) ? (int)$params['bufferTimeout'] : 0, |
|
141 | 40 | 'heartbeatInterval' => isset($params['heartbeatInterval']) ? (int)$params['heartbeatInterval'] : 200, |
|
142 | 40 | 'heartbeatKeepalive' => isset($params['heartbeatKeepalive']) ? (int)$params['heartbeatKeepalive'] : 1000, |
|
143 | 40 | 'timeRegisterInterval' => isset($params['timeRegisterInterval']) ? (int)$params['timeRegisterInterval'] : 400 |
|
144 | ]; |
||
145 | |||
146 | 40 | $this->loop = $loop; |
|
147 | 40 | $this->id = $id; |
|
148 | 40 | $this->endpoint = $endpoint; |
|
149 | 40 | $this->type = $type; |
|
0 ignored issues
–
show
|
|||
150 | 40 | $this->hosts = (array) $hosts; |
|
151 | 40 | $this->flags = $flags; |
|
0 ignored issues
–
show
It seems like
$flags of type array<string,boolean,{"e...meRegister":"boolean"}> is incompatible with the declared type array<integer,string> of property $flags .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
152 | 40 | $this->options = $options; |
|
0 ignored issues
–
show
It seems like
$options of type array<string,integer,{"b...erInterval":"integer"}> is incompatible with the declared type array<integer,*> of property $options .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
153 | 40 | $this->isConnected = false; |
|
154 | 40 | $this->hTimer = null; |
|
155 | 40 | $this->rTimer = null; |
|
156 | |||
157 | 40 | $this->socket = null; |
|
158 | 40 | $this->offlineBuffer = $this->getBuffer(); |
|
159 | 40 | $this->onlineBuffer = $this->getBuffer(); |
|
160 | 40 | $this->frameBuffer = []; |
|
161 | 40 | $this->connectionPool = $this->getConnectionPool(); |
|
162 | 40 | } |
|
163 | |||
164 | /** |
||
165 | * |
||
166 | */ |
||
167 | public function __destruct() |
||
168 | { |
||
169 | $this->stop(); |
||
170 | |||
171 | unset($this->id); |
||
172 | unset($this->endpoint); |
||
173 | unset($this->type); |
||
174 | unset($this->hosts); |
||
175 | unset($this->flags); |
||
176 | unset($this->options); |
||
177 | unset($this->isConnected); |
||
178 | unset($this->hTimer); |
||
179 | unset($this->rTimer); |
||
180 | |||
181 | unset($this->socket); |
||
182 | unset($this->onfflinebuffer); |
||
183 | unset($this->onlinebuffer); |
||
184 | unset($this->frameBuffer); |
||
185 | unset($this->connectionPool); |
||
186 | unset($this->loop); |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * @override |
||
191 | * @inheritDoc |
||
192 | */ |
||
193 | 32 | public function start($blockEvent = false) |
|
194 | { |
||
195 | 32 | if ($this->isStarted()) |
|
196 | { |
||
197 | 6 | return false; |
|
198 | } |
||
199 | |||
200 | 32 | if (!$this->startConnection()) |
|
201 | { |
||
202 | $this->emit('error', [ new ExecutionException('socket not connected.') ]); |
||
203 | return false; |
||
204 | } |
||
205 | |||
206 | 32 | $this->stopHeartbeat(); |
|
207 | 32 | $this->stopTimeRegister(); |
|
208 | |||
209 | 32 | $this->isConnected = true; |
|
210 | |||
211 | 32 | $this->startHeartbeat(); |
|
212 | 32 | $this->startTimeRegister(); |
|
213 | |||
214 | 32 | foreach ($messages = $this->offlineBuffer->pull() as $message) |
|
215 | { |
||
216 | 14 | $this->onlineBuffer->push($message[0], $message[1]); |
|
217 | } |
||
218 | |||
219 | 32 | if (!$blockEvent) |
|
220 | { |
||
221 | 32 | $this->emit('start'); |
|
222 | } |
||
223 | |||
224 | 32 | return true; |
|
225 | } |
||
226 | |||
227 | /** |
||
228 | * @override |
||
229 | * @inheritDoc |
||
230 | */ |
||
231 | 32 | public function stop($blockEvent = false) |
|
232 | { |
||
233 | 32 | if (!$this->isStarted()) |
|
234 | { |
||
235 | 2 | return false; |
|
236 | } |
||
237 | |||
238 | 32 | $this->stopHeartbeat(); |
|
239 | 32 | $this->stopTimeRegister(); |
|
240 | |||
241 | 32 | if (!$this->stopConnection()) |
|
242 | { |
||
243 | $this->emit('error', [ new ExecutionException('socket not disconnected.') ]); |
||
244 | } |
||
245 | |||
246 | 32 | $this->isConnected = false; |
|
247 | |||
248 | 32 | if (!$blockEvent) |
|
249 | { |
||
250 | 32 | $this->emit('stop'); |
|
251 | } |
||
252 | |||
253 | 32 | return true; |
|
254 | } |
||
255 | |||
256 | /** |
||
257 | * @override |
||
258 | * @inheritDoc |
||
259 | */ |
||
260 | 24 | public function unicast($id, $message, $flags = Channel::MODE_STANDARD) |
|
261 | { |
||
262 | 24 | $status = $this->sendMessage($id, self::COMMAND_MESSAGE, $message, $flags); |
|
263 | |||
264 | 24 | if ($status === static::SEND_STATUS_SUCCEEDED) |
|
265 | { |
||
266 | 24 | $this->emit('send', [ $id, (array) $message ]); |
|
267 | } |
||
268 | |||
269 | 24 | return $status > 0; |
|
270 | } |
||
271 | |||
272 | /** |
||
273 | * @override |
||
274 | * @inheritDoc |
||
275 | */ |
||
276 | 2 | public function broadcast($message) |
|
277 | { |
||
278 | 2 | $conns = $this->getConnected(); |
|
279 | 2 | $statuses = []; |
|
280 | |||
281 | 2 | foreach ($conns as $conn) |
|
282 | { |
||
283 | 1 | $statuses[] = $this->sendMessage($conn, self::COMMAND_MESSAGE, $message, Channel::MODE_STANDARD) > 0; |
|
284 | } |
||
285 | |||
286 | 2 | foreach ($conns as $conn) |
|
287 | { |
||
288 | 1 | $this->emit('send', [ $conn, (array) $message ]); |
|
289 | } |
||
290 | |||
291 | 2 | return $statuses; |
|
292 | } |
||
293 | |||
294 | /** |
||
295 | * @override |
||
296 | * @inheritDoc |
||
297 | */ |
||
298 | 32 | public function isStarted() |
|
299 | { |
||
300 | 32 | return $this->isConnected; |
|
301 | } |
||
302 | |||
303 | /** |
||
304 | * @override |
||
305 | * @inheritDoc |
||
306 | */ |
||
307 | 1 | public function isStopped() |
|
308 | { |
||
309 | 1 | return !$this->isConnected; |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * @override |
||
314 | * @inheritDoc |
||
315 | */ |
||
316 | 1 | public function isConnected($id) |
|
317 | { |
||
318 | 1 | return $this->connectionPool->validateConnection($id); |
|
319 | } |
||
320 | |||
321 | /** |
||
322 | * @override |
||
323 | * @inheritDoc |
||
324 | */ |
||
325 | 3 | public function getConnected() |
|
326 | { |
||
327 | 3 | return $this->connectionPool->getConnected(); |
|
328 | } |
||
329 | |||
330 | /** |
||
331 | * Set connection statically to be marked as online until specific timestamp. |
||
332 | * |
||
333 | * @param string $id |
||
334 | * @param float $until |
||
335 | */ |
||
336 | public function markConnectionOnline($id, $until) |
||
337 | { |
||
338 | $this->connectionPool->setConnectionProperty($id, 'timestampIn', $until); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Set connection statically to be marked always as online. |
||
343 | * |
||
344 | * @param string $id |
||
345 | */ |
||
346 | public function markConnectionPersistent($id) |
||
347 | { |
||
348 | $this->connectionPool->setConnectionProperty($id, 'timestampIn', 0); |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * @param string $message |
||
353 | * @return string[] |
||
354 | */ |
||
355 | 30 | View Code Duplication | protected function parseBinderMessage($message) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
356 | { |
||
357 | 30 | $multipart = explode('|', $message, 4); |
|
358 | |||
359 | 30 | $id = $multipart[1]; |
|
360 | 30 | $type = $multipart[2]; |
|
361 | 30 | $message = $multipart[3]; |
|
362 | |||
363 | 30 | return [ $id, $type, $message ]; |
|
364 | } |
||
365 | |||
366 | /** |
||
367 | * @param string $message |
||
368 | * @return string[] |
||
369 | */ |
||
370 | 29 | View Code Duplication | protected function parseConnectorMessage($message) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
371 | { |
||
372 | 29 | $multipart = explode('|', $message, 4); |
|
373 | |||
374 | 29 | $id = $multipart[1]; |
|
375 | 29 | $type = $multipart[2]; |
|
376 | 29 | $message = $multipart[3]; |
|
377 | |||
378 | 29 | return [ $id, $type, $message ]; |
|
379 | } |
||
380 | |||
381 | /** |
||
382 | * @param string $id |
||
383 | * @param string $type |
||
384 | * @return string[] |
||
0 ignored issues
–
show
|
|||
385 | */ |
||
386 | 30 | protected function prepareBinderMessage($id, $type) |
|
387 | { |
||
388 | 30 | return $id . '|' . $this->id . '|' . $type; |
|
389 | } |
||
390 | |||
391 | /** |
||
392 | * @param string $id |
||
393 | * @param string $type |
||
394 | * @return string[] |
||
0 ignored issues
–
show
|
|||
395 | */ |
||
396 | 30 | protected function prepareConnectorMessage($id, $type) |
|
397 | { |
||
398 | 30 | return $id . '|' . $this->id . '|' . $type; |
|
399 | } |
||
400 | |||
401 | /** |
||
402 | * @return SocketListenerInterface |
||
403 | */ |
||
404 | 34 | protected function createBinder() |
|
405 | { |
||
406 | 34 | $binder = $this; |
|
407 | 34 | $socketListener = new \Dazzle\Socket\SocketListener($this->endpoint, $this->loop); |
|
408 | |||
409 | $socketListener->on('connect', function(SocketListenerInterface $server, SocketInterface $client) use($binder) { |
||
410 | $client->on('data', function(SocketInterface $client, $data) use($binder) { |
||
411 | 29 | $binder->onData($client, $data); |
|
412 | 29 | }); |
|
413 | 34 | }); |
|
414 | $socketListener->on('close', function() use($binder) { |
||
415 | 2 | $binder->stop(); |
|
416 | 34 | }); |
|
417 | 34 | $socketListener->start(); |
|
418 | |||
419 | 34 | return $socketListener; |
|
420 | } |
||
421 | |||
422 | /** |
||
423 | * @return SocketInterface |
||
424 | */ |
||
425 | 29 | protected function createConnector() |
|
426 | { |
||
427 | 29 | $connector = $this; |
|
428 | 29 | $loop = $this->loop; |
|
429 | 29 | $socket = new \Dazzle\Socket\Socket($this->endpoint, $loop); |
|
430 | |||
431 | $socket->on('data', function(SocketInterface $client, $data) use($connector) { |
||
432 | 28 | $connector->onData($client, $data); |
|
433 | 29 | }); |
|
434 | $socket->on('close', function() use($connector, $loop) { |
||
435 | 1 | $connector->stop(true); |
|
436 | $loop->addTimer(0.1, function() use($connector) { |
||
437 | 1 | $connector->start(true); |
|
438 | 1 | }); |
|
439 | 29 | }); |
|
440 | |||
441 | 29 | return $socket; |
|
442 | } |
||
443 | |||
444 | /** |
||
445 | * |
||
446 | */ |
||
447 | 32 | protected function destroyBinder() |
|
448 | { |
||
449 | 32 | $this->socket->removeListeners('connect'); |
|
450 | 32 | $this->socket->removeListeners('close'); |
|
451 | 32 | } |
|
452 | |||
453 | /** |
||
454 | * |
||
455 | */ |
||
456 | 29 | protected function destroyConnector() |
|
457 | { |
||
458 | 29 | $this->socket->removeListeners('data'); |
|
459 | 29 | $this->socket->removeListeners('close'); |
|
460 | 29 | } |
|
461 | |||
462 | /** |
||
463 | * @param string $event |
||
464 | * @param callable $callback |
||
465 | */ |
||
466 | protected function setEventListener($event, callable $callback) |
||
467 | { |
||
468 | if ($this->socket !== null) |
||
469 | { |
||
470 | $this->socket->on($event, $callback); |
||
471 | } |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * @param string $event |
||
476 | * @param callable $callback |
||
477 | */ |
||
478 | protected function removeEventListener($event, callable $callback) |
||
479 | { |
||
480 | if ($this->socket !== null) |
||
481 | { |
||
482 | $this->socket->removeListener($event, $callback); |
||
483 | } |
||
484 | } |
||
485 | |||
486 | /** |
||
487 | * @return Buffer |
||
488 | */ |
||
489 | 40 | protected function getBuffer() |
|
490 | { |
||
491 | 40 | return new Buffer($this->options['bufferSize']); |
|
492 | } |
||
493 | |||
494 | /** |
||
495 | * @return ConnectionPool |
||
496 | */ |
||
497 | 40 | protected function getConnectionPool() |
|
498 | { |
||
499 | 40 | return new ConnectionPool($this->options['heartbeatKeepalive'], $this->options['heartbeatInterval']); |
|
500 | } |
||
501 | |||
502 | /** |
||
503 | * @param SocketInterface $client |
||
504 | * @param string $data |
||
505 | */ |
||
506 | 29 | public function onData(SocketInterface $client, $data) |
|
507 | { |
||
508 | 29 | $messages = []; |
|
509 | 29 | $resID = $client->getResourceId(); |
|
510 | 29 | $buffer = ''; |
|
511 | |||
512 | 29 | if (isset($this->frameBuffer[$resID])) |
|
513 | { |
||
514 | $buffer = $this->frameBuffer[$resID]; |
||
515 | unset($this->frameBuffer[$resID]); |
||
516 | } |
||
517 | |||
518 | 29 | $buffer = preg_replace_callback( |
|
519 | 29 | "#(.*?)\r\n#si", |
|
520 | function($matches) use(&$messages) { |
||
521 | 29 | $messages[] = $matches[1]; |
|
522 | 29 | return ''; |
|
523 | 29 | }, |
|
524 | 29 | $buffer . $data |
|
525 | ); |
||
526 | |||
527 | 29 | if ($buffer !== '') |
|
528 | { |
||
529 | $this->frameBuffer[$resID] = $buffer; |
||
530 | unset($buffer); |
||
531 | } |
||
532 | |||
533 | 29 | foreach ($messages as $message) |
|
534 | { |
||
535 | 29 | if ($message !== '') |
|
536 | { |
||
537 | 29 | $this->onMessage($client, $message); |
|
538 | } |
||
539 | } |
||
540 | 29 | } |
|
541 | |||
542 | /** |
||
543 | * @param SocketInterface $client |
||
544 | * @param string $message |
||
545 | */ |
||
546 | 29 | private function onMessage(SocketInterface $client, $message) |
|
547 | { |
||
548 | 29 | if ($this->type === Channel::BINDER) |
|
549 | { |
||
550 | 29 | list($id, $type, $message) = $this->parseBinderMessage($message); |
|
551 | } |
||
552 | 28 | else if ($this->type === Channel::CONNECTOR) |
|
553 | { |
||
554 | 28 | list($id, $type, $message) = $this->parseConnectorMessage($message); |
|
555 | } |
||
556 | else |
||
557 | { |
||
558 | return; |
||
559 | } |
||
560 | |||
561 | 29 | $conn = new Connection($id, $client); |
|
562 | 29 | $message = explode("\n", $message); |
|
563 | |||
564 | switch ($type) |
||
565 | { |
||
566 | 29 | case self::COMMAND_HEARTBEAT: $this->onRecvHeartbeat($conn); break; |
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
567 | 25 | case self::COMMAND_MESSAGE: $this->onRecvMessage($conn, $message); break; |
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
568 | default: return; |
||
0 ignored issues
–
show
The default body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a default statement must start on the line immediately following the statement. switch ($expr) {
default:
doSomething(); //right
break;
}
switch ($expr) {
default:
doSomething(); //wrong
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
569 | } |
||
570 | 29 | } |
|
571 | |||
572 | /** |
||
573 | * @param Connection $conn |
||
574 | * @param string[] $message |
||
575 | */ |
||
576 | 25 | private function onRecvMessage(Connection $conn, $message) |
|
577 | { |
||
578 | 25 | $this->recvHeartbeat($conn); |
|
579 | 25 | $this->recvMessage($conn, $message); |
|
580 | |||
581 | 25 | } |
|
582 | |||
583 | /** |
||
584 | * @param Connection $conn |
||
585 | */ |
||
586 | 29 | private function onRecvHeartbeat(Connection $conn) |
|
587 | { |
||
588 | 29 | $this->recvHeartbeat($conn); |
|
589 | 29 | } |
|
590 | |||
591 | /** |
||
592 | * @param Connection $conn |
||
593 | * @param $message[] |
||
594 | * @return mixed |
||
595 | */ |
||
596 | 25 | private function recvMessage(Connection $conn, $message) |
|
597 | { |
||
598 | 25 | $this->emit('recv', [ $conn->id, $message ]); |
|
599 | 25 | } |
|
600 | |||
601 | /** |
||
602 | * @param Connection $conn |
||
603 | */ |
||
604 | 29 | private function recvHeartbeat(Connection $conn) |
|
605 | { |
||
606 | 29 | if ($this->flags['enableHeartbeat'] !== true) |
|
607 | { |
||
608 | return; |
||
609 | } |
||
610 | |||
611 | 29 | if ($this->connectionPool->setConnection($conn)) |
|
612 | { |
||
613 | 29 | $this->emit('connect', [ $conn->id ]); |
|
614 | } |
||
615 | |||
616 | 29 | if ($this->type === Channel::BINDER) |
|
617 | { |
||
618 | 29 | $this->heartbeat($conn->id); |
|
619 | } |
||
620 | |||
621 | 29 | foreach ($messages = $this->onlineBuffer->pull($conn->id) as $message) |
|
622 | { |
||
623 | 19 | $this->unicast($message[0], $message[1]); |
|
624 | } |
||
625 | 29 | } |
|
626 | |||
627 | /** |
||
628 | * @return bool |
||
629 | */ |
||
630 | 32 | private function startConnection() |
|
631 | { |
||
632 | 32 | if ($this->socket !== null) |
|
633 | { |
||
634 | return false; |
||
635 | } |
||
636 | |||
637 | 32 | $socket = null; |
|
638 | 32 | $ex = null; |
|
639 | |||
640 | try |
||
641 | { |
||
642 | 32 | switch ($this->type) |
|
643 | { |
||
644 | 32 | case Channel::CONNECTOR: |
|
645 | 29 | $socket = $this->createConnector(); |
|
646 | 29 | break; |
|
647 | |||
648 | 32 | case Channel::BINDER: |
|
649 | 32 | $socket = $this->createBinder(); |
|
650 | 32 | break; |
|
651 | |||
652 | default: |
||
653 | 32 | return false; |
|
654 | } |
||
655 | } |
||
656 | catch (Error $ex) |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
657 | {} |
||
658 | catch (Exception $ex) |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
659 | {} |
||
660 | |||
661 | 32 | if ($ex !== null) |
|
662 | { |
||
663 | return false; |
||
664 | } |
||
665 | |||
666 | 32 | $this->socket = $socket; |
|
667 | |||
668 | 32 | return true; |
|
669 | } |
||
670 | |||
671 | /** |
||
672 | * @return bool |
||
673 | */ |
||
674 | 32 | private function stopConnection() |
|
675 | { |
||
676 | 32 | if ($this->socket === null) |
|
677 | { |
||
678 | return false; |
||
679 | } |
||
680 | |||
681 | 32 | $socket = null; |
|
0 ignored issues
–
show
$socket is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
682 | 32 | $ex = null; |
|
683 | |||
684 | try |
||
685 | { |
||
686 | 32 | switch ($this->type) |
|
687 | { |
||
688 | 32 | case Channel::CONNECTOR: $this->destroyConnector(); break; |
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
689 | 32 | case Channel::BINDER: $this->destroyBinder(); break; |
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
690 | 32 | default: return false; |
|
0 ignored issues
–
show
The default body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a default statement must start on the line immediately following the statement. switch ($expr) {
default:
doSomething(); //right
break;
}
switch ($expr) {
default:
doSomething(); //wrong
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
691 | } |
||
692 | } |
||
693 | catch (Error $ex) |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
694 | {} |
||
695 | catch (Exception $ex) |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
696 | {} |
||
697 | |||
698 | 32 | if ($ex !== null) |
|
699 | { |
||
700 | return false; |
||
701 | } |
||
702 | |||
703 | 32 | $this->socket->close(); |
|
704 | 32 | unset($this->socket); |
|
705 | 32 | $this->socket = null; |
|
706 | |||
707 | 32 | return true; |
|
708 | } |
||
709 | |||
710 | /** |
||
711 | * @param string $id |
||
712 | * @param string $type |
||
713 | * @param string $message |
||
714 | * @return null|string |
||
715 | */ |
||
716 | 29 | private function getFrame($id, $type, $message) |
|
717 | { |
||
718 | 29 | if ($this->type === Channel::BINDER) |
|
719 | { |
||
720 | 29 | $frame = $this->prepareBinderMessage($id, $type); |
|
721 | } |
||
722 | 29 | else if ($this->type === Channel::CONNECTOR) |
|
723 | { |
||
724 | 29 | $frame = $this->prepareConnectorMessage($id, $type); |
|
725 | } |
||
726 | else |
||
727 | { |
||
728 | return null; |
||
729 | } |
||
730 | |||
731 | 29 | if ($message !== null) |
|
732 | { |
||
733 | 25 | if (is_object($message)) |
|
734 | { |
||
735 | return null; |
||
736 | } |
||
737 | 25 | else if (is_array($message)) |
|
738 | { |
||
739 | 4 | $message = implode("\n", $message); |
|
740 | } |
||
741 | |||
742 | 25 | $frame .= '|' . $message; |
|
743 | } |
||
744 | else |
||
745 | { |
||
746 | 29 | $frame .= '|'; |
|
747 | } |
||
748 | |||
749 | 29 | return $frame; |
|
750 | } |
||
751 | |||
752 | /** |
||
753 | * @param string $id |
||
754 | * @param string $type |
||
755 | * @param string|string[] $message |
||
756 | * @param int $flags |
||
757 | * @return bool |
||
0 ignored issues
–
show
|
|||
758 | */ |
||
759 | 29 | private function sendMessage($id, $type, $message = null, $flags = Channel::MODE_STANDARD) |
|
760 | { |
||
761 | 29 | if (($frame = $this->getFrame($id, $type, $message)) === null) |
|
0 ignored issues
–
show
It seems like
$message defined by parameter $message on line 759 can also be of type array<integer,string> or null ; however, Dazzle\ChannelSocket\Socket::getFrame() does only seem to accept string , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
762 | { |
||
763 | return static::SEND_STATUS_DROPPED; |
||
764 | } |
||
765 | |||
766 | 29 | $isConnected = $this->isStarted(); |
|
767 | |||
768 | 29 | if (!$isConnected && $this->flags['enableBuffering'] === true && ($flags & Channel::MODE_BUFFER_OFFLINE) === Channel::MODE_BUFFER_OFFLINE) |
|
769 | { |
||
770 | 14 | $frame = $this->parseConnectorMessage($frame); |
|
771 | 14 | $status = $this->offlineBuffer->push($id, $frame[2]); |
|
772 | 14 | return $status ? static::SEND_STATUS_BUFFERED : static::SEND_STATUS_DROPPED; |
|
773 | } |
||
774 | 29 | else if ($type === self::COMMAND_HEARTBEAT) |
|
0 ignored issues
–
show
|
|||
775 | { |
||
776 | 29 | if ($this->writeData($id, $frame . "\r\n")) |
|
777 | { |
||
778 | 29 | $this->connectionPool->registerHeartbeat($id); |
|
779 | 29 | return static::SEND_STATUS_SUCCEEDED; |
|
780 | } |
||
781 | } |
||
782 | 25 | else if ($this->flags['enableHeartbeat'] === false || $this->connectionPool->validateConnection($id) === true) |
|
783 | { |
||
784 | 25 | $this->writeData($id, $frame . "\r\n"); |
|
785 | 25 | $this->connectionPool->registerHeartbeat($id); |
|
786 | 25 | return static::SEND_STATUS_SUCCEEDED; |
|
787 | } |
||
788 | 15 | else if ($this->flags['enableBuffering'] === true && ($flags & Channel::MODE_BUFFER_ONLINE) === Channel::MODE_BUFFER_ONLINE) |
|
789 | { |
||
790 | 10 | $frame = $this->parseConnectorMessage($frame); |
|
791 | 10 | $status = $this->onlineBuffer->push($id, $frame[2]); |
|
792 | 10 | return $status ? static::SEND_STATUS_BUFFERED : static::SEND_STATUS_DROPPED; |
|
793 | } |
||
794 | |||
795 | 6 | return static::SEND_STATUS_DROPPED; |
|
796 | } |
||
797 | |||
798 | /** |
||
799 | * @param string $id |
||
800 | * @param string $data |
||
801 | * @return bool |
||
802 | */ |
||
803 | 29 | private function writeData($id, $data) |
|
804 | { |
||
805 | 29 | if ($this->socket === null) |
|
806 | { |
||
807 | 1 | return false; |
|
808 | } |
||
809 | |||
810 | try |
||
811 | { |
||
812 | 29 | if ($this->type === Channel::CONNECTOR) |
|
813 | { |
||
814 | 29 | return $this->socket->write($data); |
|
0 ignored issues
–
show
The method
write does only exist in Dazzle\Socket\SocketInterface , but not in Dazzle\Socket\SocketListenerInterface .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
815 | } |
||
816 | |||
817 | 29 | if ($this->type === Channel::BINDER && $this->connectionPool->existsConnection($id)) |
|
818 | { |
||
819 | 29 | return $this->connectionPool->getConnection($id)->getSocket()->write($data); |
|
820 | } |
||
821 | } |
||
822 | catch (Error $ex) |
||
823 | { |
||
824 | return false; |
||
825 | } |
||
826 | catch (Exception $ex) |
||
827 | { |
||
828 | return false; |
||
829 | } |
||
830 | |||
831 | return false; |
||
832 | } |
||
833 | |||
834 | /** |
||
835 | * @param string $id |
||
836 | * @return bool |
||
837 | */ |
||
838 | 29 | private function heartbeat($id) |
|
839 | { |
||
840 | 29 | if ($this->connectionPool->isHeartbeatNeeded($id) === true) |
|
841 | { |
||
842 | 29 | return $this->sendMessage($id, self::COMMAND_HEARTBEAT) > 0; |
|
843 | } |
||
844 | |||
845 | 9 | return false; |
|
846 | } |
||
847 | |||
848 | /** |
||
849 | * Start heartbeat. |
||
850 | * |
||
851 | * Heartbeat mechanisms is used to identify online and offline sockets. |
||
852 | */ |
||
853 | 32 | private function startHeartbeat() |
|
854 | { |
||
855 | 32 | if ($this->hTimer === null && $this->flags['enableHeartbeat']) |
|
856 | { |
||
857 | 32 | $this->clearConnectionPool(); |
|
858 | |||
859 | 32 | $proxy = $this; |
|
860 | $this->hTimer = $this->loop->addPeriodicTimer(($this->options['heartbeatInterval']/1000), function() use($proxy) { |
||
861 | |||
862 | 29 | if ($proxy->type === Channel::CONNECTOR) |
|
863 | { |
||
864 | 29 | foreach ($proxy->hosts as $hostid) |
|
865 | { |
||
866 | 29 | $proxy->heartbeat($hostid); |
|
867 | } |
||
868 | } |
||
869 | |||
870 | 29 | $this->clearConnectionPool(); |
|
871 | 32 | }); |
|
872 | } |
||
873 | 32 | } |
|
874 | |||
875 | /** |
||
876 | * Stop hearbeat. |
||
877 | */ |
||
878 | 32 | private function stopHeartbeat() |
|
879 | { |
||
880 | 32 | if ($this->hTimer !== null) |
|
881 | { |
||
882 | 32 | $this->hTimer->cancel(); |
|
883 | 32 | $this->hTimer = null; |
|
884 | } |
||
885 | 32 | } |
|
886 | |||
887 | /** |
||
888 | * Clear connection pool. |
||
889 | */ |
||
890 | 32 | private function clearConnectionPool() |
|
891 | { |
||
892 | 32 | $deleted = $this->connectionPool->removeInvalid(); |
|
893 | |||
894 | 32 | foreach ($deleted as $deletedid) |
|
895 | { |
||
896 | 4 | $this->emit('disconnect', [ $deletedid ]); |
|
897 | } |
||
898 | 32 | } |
|
899 | |||
900 | /** |
||
901 | * Start time register. |
||
902 | * |
||
903 | * Time register purpose is to cyclically increase timestamp representing last time of tick of event loop. This |
||
904 | * method allows model to not mark external sockets wrongly as offline because of its own heavy load. |
||
905 | */ |
||
906 | 32 | private function startTimeRegister() |
|
907 | { |
||
908 | 32 | if ($this->rTimer === null && $this->flags['enableHeartbeat'] === true && $this->flags['enableTimeRegister'] === true) |
|
909 | { |
||
910 | 32 | $proxy = $this; |
|
911 | $this->rTimer = $this->loop->addPeriodicTimer(($this->options['timeRegisterInterval']/1000), function() use($proxy) { |
||
912 | 4 | $now = round(microtime(true)*1000); |
|
913 | 4 | $proxy->connectionPool->setNow(function() use($now) { |
|
914 | 4 | return $now; |
|
915 | 4 | }); |
|
916 | 32 | }); |
|
917 | } |
||
918 | 32 | } |
|
919 | |||
920 | /** |
||
921 | * Stop time register. |
||
922 | */ |
||
923 | 32 | private function stopTimeRegister() |
|
924 | { |
||
925 | 32 | if ($this->rTimer !== null) |
|
926 | { |
||
927 | 32 | $this->rTimer->cancel(); |
|
928 | 32 | $this->rTimer = null; |
|
929 | 32 | $this->connectionPool->resetNow(); |
|
930 | } |
||
931 | 32 | } |
|
932 | } |
||
933 |
This check looks for assignments to scalar types that may be of the wrong type.
To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.