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 | namespace PHPDaemon\Network; |
||
3 | |||
4 | use PHPDaemon\BoundSocket\Generic; |
||
5 | use PHPDaemon\BoundSocket\TCP; |
||
6 | use PHPDaemon\Cache\CappedStorage; |
||
7 | use PHPDaemon\Cache\CappedStorageHits; |
||
8 | use PHPDaemon\Config; |
||
9 | use PHPDaemon\Core\Daemon; |
||
10 | use PHPDaemon\Structures\StackCallbacks; |
||
11 | |||
12 | /** |
||
13 | * Connection |
||
14 | * @package PHPDaemon\Network |
||
15 | * @author Vasily Zorin <[email protected]> |
||
16 | */ |
||
17 | abstract class Connection extends IOStream |
||
18 | { |
||
19 | /** |
||
20 | * @var string Path |
||
21 | */ |
||
22 | protected $path; |
||
23 | |||
24 | /** |
||
25 | * @var string Hostname |
||
26 | */ |
||
27 | protected $host; |
||
28 | |||
29 | /** |
||
30 | * @var string Real host |
||
31 | */ |
||
32 | protected $hostReal; |
||
33 | |||
34 | /** |
||
35 | * @var integer Port number |
||
36 | */ |
||
37 | protected $port; |
||
38 | |||
39 | /** |
||
40 | * @var string User name |
||
41 | */ |
||
42 | protected $user; |
||
43 | |||
44 | /** |
||
45 | * @var string Password |
||
46 | */ |
||
47 | protected $password; |
||
48 | |||
49 | /** |
||
50 | * @var string Address |
||
51 | */ |
||
52 | protected $addr; |
||
53 | |||
54 | /** |
||
55 | * @var object Stack of callbacks called when connection is established |
||
56 | */ |
||
57 | protected $onConnected = null; |
||
58 | |||
59 | /** |
||
60 | * @var boolean Connected? |
||
61 | */ |
||
62 | protected $connected = false; |
||
63 | |||
64 | /** |
||
65 | * @var boolean Failed? |
||
66 | */ |
||
67 | protected $failed = false; |
||
68 | |||
69 | /** |
||
70 | * @var integer Timeout |
||
71 | */ |
||
72 | protected $timeout = 120; |
||
73 | |||
74 | /** |
||
75 | * @var string Local address |
||
76 | */ |
||
77 | protected $locAddr; |
||
78 | |||
79 | /** |
||
80 | * @var integer Local port |
||
81 | */ |
||
82 | protected $locPort; |
||
83 | |||
84 | /** |
||
85 | * @var boolean Keepalive? |
||
86 | */ |
||
87 | protected $keepalive = false; |
||
88 | |||
89 | /** |
||
90 | * @var string Type |
||
91 | */ |
||
92 | protected $type; |
||
93 | |||
94 | /** |
||
95 | * @var Generic Parent socket |
||
96 | */ |
||
97 | protected $parentSocket; |
||
98 | |||
99 | /** |
||
100 | * @var boolean Dgram connection? |
||
101 | */ |
||
102 | protected $dgram = false; |
||
103 | |||
104 | /** |
||
105 | * @var boolean Enable bevConnect? |
||
106 | */ |
||
107 | protected $bevConnectEnabled = true; |
||
108 | |||
109 | /** |
||
110 | * @var array URI information |
||
111 | */ |
||
112 | protected $uri; |
||
113 | |||
114 | /** |
||
115 | * @var string Scheme |
||
116 | */ |
||
117 | protected $scheme; |
||
118 | |||
119 | /** |
||
120 | * @var string Private key file |
||
121 | */ |
||
122 | protected $pkfile; |
||
123 | |||
124 | /** |
||
125 | * @var string Certificate file |
||
126 | */ |
||
127 | protected $certfile; |
||
128 | |||
129 | /** |
||
130 | * @var string Passphrase |
||
131 | */ |
||
132 | protected $passphrase; |
||
133 | |||
134 | /** |
||
135 | * @var boolean Verify peer? |
||
136 | */ |
||
137 | protected $verifypeer = false; |
||
138 | |||
139 | /** |
||
140 | * @var boolean Allow self-signed? |
||
141 | */ |
||
142 | protected $allowselfsigned = true; |
||
143 | |||
144 | /** |
||
145 | * @var CappedStorage Context cache |
||
146 | */ |
||
147 | protected static $contextCache; |
||
148 | |||
149 | /** |
||
150 | * @var number Context cache size |
||
151 | */ |
||
152 | protected static $contextCacheSize = 64; |
||
153 | |||
154 | /** |
||
155 | * Connected? |
||
156 | * @return boolean |
||
157 | */ |
||
158 | public function isConnected() |
||
159 | { |
||
160 | return $this->connected; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Sets DGRAM mode |
||
165 | * @param boolean $bool DGRAM Mode |
||
166 | * @return void |
||
167 | */ |
||
168 | public function setDgram($bool) |
||
169 | { |
||
170 | $this->dgram = $bool; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Sets peer name |
||
175 | * @param string $host Hostname |
||
176 | * @param integer $port Port |
||
177 | * @return void |
||
178 | */ |
||
179 | public function setPeername($host, $port) |
||
180 | { |
||
181 | $this->host = $host; |
||
182 | $this->port = $port; |
||
183 | $this->addr = '[' . $this->host . ']:' . $this->port; |
||
184 | if ($this->pool->allowedClients !== null) { |
||
185 | if (!TCP::netMatch($this->pool->allowedClients, $this->host)) { |
||
186 | Daemon::log('Connection is not allowed (' . $this->host . ')'); |
||
187 | $this->ready = false; |
||
188 | $this->finish(); |
||
189 | } |
||
190 | } |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Getter |
||
195 | * @param string $name Name |
||
196 | * @return mixed |
||
197 | */ |
||
198 | public function __get($name) |
||
199 | { |
||
200 | if ($name === 'connected' |
||
201 | || $name === 'hostReal' |
||
202 | || $name === 'host' |
||
203 | || $name === 'port' |
||
204 | ) { |
||
205 | return $this->{$name}; |
||
206 | } |
||
207 | return parent::__get($name); |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * Get socket name |
||
212 | * @param string &$addr Addr |
||
213 | * @param srting &$port Port |
||
214 | * @return void |
||
215 | */ |
||
216 | public function getSocketName(&$addr, &$port) |
||
217 | { |
||
218 | if (func_num_args() === 0) { |
||
219 | \EventUtil::getSocketName($this->bev->fd, $this->locAddr, $this->locPort); |
||
220 | return; |
||
221 | } |
||
222 | \EventUtil::getSocketName($this->bev->fd, $addr, $port); |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Sets parent socket |
||
227 | * @param \PHPDaemon\BoundSocket\Generic $sock |
||
228 | * @return void |
||
229 | */ |
||
230 | public function setParentSocket(Generic $sock) |
||
231 | { |
||
232 | $this->parentSocket = $sock; |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Called when new UDP packet received |
||
237 | * @param object $pct Packet |
||
238 | * @return void |
||
239 | */ |
||
240 | public function onUdpPacket($pct) |
||
241 | { |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Called when the connection is handshaked (at low-level), and peer is ready to recv. data |
||
246 | * @return void |
||
247 | */ |
||
248 | public function onReady() |
||
249 | { |
||
250 | $this->connected = true; |
||
251 | if ($this->onConnected) { |
||
252 | $this->onConnected->executeAll($this); |
||
253 | $this->onConnected = null; |
||
254 | } |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * Called if we inherit connection from request |
||
259 | * @param Request $req Parent Request |
||
260 | * @return void |
||
261 | */ |
||
262 | public function onInheritanceFromRequest($req) |
||
263 | { |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Called when the connection failed to be established |
||
268 | * @return void |
||
269 | */ |
||
270 | public function onFailure() |
||
271 | { |
||
272 | if ($this->onConnected) { |
||
273 | $this->onConnected->executeAll($this); |
||
274 | $this->onConnected = null; |
||
275 | } |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Called when the connection failed |
||
280 | * @param EventBufferEvent $bev |
||
0 ignored issues
–
show
|
|||
281 | * @return void |
||
282 | */ |
||
283 | public function onFailureEv($bev = null) |
||
0 ignored issues
–
show
|
|||
284 | { |
||
285 | try { |
||
286 | if (!$this->connected && !$this->failed) { |
||
287 | $this->failed = true; |
||
288 | $this->onFailure(); |
||
289 | } |
||
290 | $this->connected = false; |
||
291 | } catch (\Throwable $e) { |
||
0 ignored issues
–
show
The class
Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
292 | Daemon::uncaughtExceptionHandler($e); |
||
293 | } |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Destructor |
||
298 | * @return void |
||
299 | */ |
||
300 | public function __destruct() |
||
301 | { |
||
302 | if ($this->dgram && $this->parentSocket) { |
||
303 | $this->parentSocket->unassignAddr($this->addr); |
||
0 ignored issues
–
show
The method
unassignAddr does not exist on object<PHPDaemon\BoundSocket\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
304 | } |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Send data to the connection. Note that it just writes to buffer that flushes at every baseloop |
||
309 | * @param string $data Data to send |
||
310 | * @return boolean Success |
||
311 | */ |
||
312 | public function write($data) |
||
313 | { |
||
314 | if ($this->dgram) { |
||
315 | return $this->parentSocket->sendTo($data, $this->finished ? MSG_EOF : 0, $this->host, $this->port); |
||
0 ignored issues
–
show
The method
sendTo does not exist on object<PHPDaemon\BoundSocket\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
316 | } |
||
317 | return parent::write($data); |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Executes the given callback when/if the connection is handshaked |
||
322 | * @param callable $cb Callback |
||
323 | * @return void |
||
324 | */ |
||
325 | public function onConnected($cb) |
||
326 | { |
||
327 | if ($this->connected) { |
||
328 | $cb($this); |
||
329 | } else { |
||
330 | if (!$this->onConnected) { |
||
331 | $this->onConnected = new StackCallbacks; |
||
332 | } |
||
333 | $this->onConnected->push($cb); |
||
334 | } |
||
335 | } |
||
336 | |||
337 | protected function importParams() |
||
338 | { |
||
339 | View Code Duplication | foreach ($this->uri['params'] as $key => $val) { |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
340 | if (isset($this->{$key}) && is_bool($this->{$key})) { |
||
341 | $this->{$key} = (bool)$val; |
||
342 | continue; |
||
343 | } |
||
344 | if (!property_exists($this, $key)) { |
||
345 | Daemon::log(get_class($this) . ': unrecognized setting \'' . $key . '\''); |
||
346 | continue; |
||
347 | } |
||
348 | $this->{$key} = $val; |
||
349 | } |
||
350 | if (!$this->ctxname) { |
||
351 | return; |
||
352 | } |
||
353 | View Code Duplication | if (!isset(Daemon::$config->{'TransportContext:' . $this->ctxname})) { |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
354 | Daemon::log(get_class($this) . ': undefined transport context \'' . $this->ctxname . '\''); |
||
355 | return; |
||
356 | } |
||
357 | $ctx = Daemon::$config->{'TransportContext:' . $this->ctxname}; |
||
358 | View Code Duplication | foreach ($ctx as $key => $entry) { |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
359 | $value = ($entry instanceof Config\Entry\Generic) ? $entry->value : $entry; |
||
360 | if (isset($this->{$key}) && is_bool($this->{$key})) { |
||
361 | $this->{$key} = (bool)$value; |
||
362 | continue; |
||
363 | } |
||
364 | if (!property_exists($this, $key)) { |
||
365 | Daemon::log(get_class($this) . ': unrecognized setting in transport context \'' . $this->ctxname . '\': \'' . $key . '\''); |
||
366 | continue; |
||
367 | } |
||
368 | $this->{$key} = $value; |
||
369 | } |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * Initialize SSL context |
||
374 | * @return object|false Context |
||
375 | */ |
||
376 | protected function initSSLContext() |
||
377 | { |
||
378 | View Code Duplication | if (!\EventUtil::sslRandPoll()) { |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
379 | Daemon::$process->log(get_class($this->pool) . ': EventUtil::sslRandPoll failed'); |
||
380 | return false; |
||
381 | } |
||
382 | |||
383 | $params = [ |
||
384 | \EventSslContext::OPT_VERIFY_PEER => $this->verifypeer, |
||
385 | \EventSslContext::OPT_ALLOW_SELF_SIGNED => $this->allowselfsigned, |
||
386 | ]; |
||
387 | if ($this->certfile !== null) { |
||
388 | $params[\EventSslContext::OPT_LOCAL_CERT] = $this->certfile; |
||
389 | } |
||
390 | if ($this->pkfile !== null) { |
||
391 | $params[\EventSslContext::OPT_LOCAL_PK] = $this->pkfile; |
||
392 | } |
||
393 | if ($this->passphrase !== null) { |
||
394 | $params[\EventSslContext::OPT_PASSPHRASE] = $this->passphrase; |
||
395 | } |
||
396 | $hash = igbinary_serialize($params); |
||
397 | if (!self::$contextCache) { |
||
398 | self::$contextCache = new CappedStorageHits(self::$contextCacheSize); |
||
399 | } elseif ($ctx = self::$contextCache->getValue($hash)) { |
||
400 | return $ctx; |
||
401 | } |
||
402 | $ctx = new \EventSslContext(\EventSslContext::TLS_CLIENT_METHOD, $params); |
||
403 | self::$contextCache->put($hash, $ctx); |
||
404 | return $ctx; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * Get URL |
||
409 | * @return string |
||
410 | */ |
||
411 | public function getUrl() |
||
412 | { |
||
413 | return $this->url; |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Get host |
||
418 | * @return string |
||
419 | */ |
||
420 | public function getHost() |
||
421 | { |
||
422 | return $this->host; |
||
423 | } |
||
424 | |||
425 | /** |
||
426 | * Get port |
||
427 | * @return integer |
||
428 | */ |
||
429 | public function getPort() |
||
430 | { |
||
431 | return $this->port; |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * Connects to URL |
||
436 | * @param string $url URL |
||
437 | * @param callable $cb Callback |
||
0 ignored issues
–
show
Should the type for parameter
$cb not be callable|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
438 | * @param \Closure $beforeConnect Callback |
||
0 ignored issues
–
show
Should the type for parameter
$beforeConnect not be null|\Closure ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
439 | * @return boolean Success |
||
440 | */ |
||
441 | public function connect($url, $cb = null, \Closure $beforeConnect = null) |
||
442 | { |
||
443 | $this->uri = Config\_Object::parseCfgUri($url); |
||
0 ignored issues
–
show
It seems like
\PHPDaemon\Config\_Object::parseCfgUri($url) can also be of type false . However, the property $uri is declared as type array . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
444 | $u =& $this->uri; |
||
445 | if (!$u) { |
||
446 | return false; |
||
447 | } |
||
448 | if ($beforeConnect !== null) { |
||
449 | $beforeConnect->call($this); |
||
450 | } |
||
451 | $this->importParams(); |
||
452 | if (!isset($u['port'])) { |
||
453 | if ($this->ssl) { |
||
454 | View Code Duplication | if (isset($this->pool->config->sslport->value)) { |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
455 | $u['port'] = $this->pool->config->sslport->value; |
||
456 | } |
||
457 | View Code Duplication | } else { |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
458 | if (isset($this->pool->config->port->value)) { |
||
459 | $u['port'] = $this->pool->config->port->value; |
||
460 | } |
||
461 | } |
||
462 | } |
||
463 | if (isset($u['user'])) { |
||
464 | $this->user = $u['user']; |
||
465 | } |
||
466 | |||
467 | if ($this->ssl) { |
||
468 | $this->setContext($this->initSSLContext(), \EventBufferEvent::SSL_CONNECTING); |
||
0 ignored issues
–
show
|
|||
469 | } |
||
470 | |||
471 | $this->url = $url; |
||
472 | $this->scheme = strtolower($u['scheme']); |
||
473 | $this->host = isset($u['host']) ? $u['host'] : null; |
||
474 | $this->port = isset($u['port']) ? $u['port'] : 0; |
||
475 | |||
476 | if (isset($u['pass'])) { |
||
477 | $this->password = $u['pass']; |
||
478 | } |
||
479 | |||
480 | if (isset($u['path'])) { |
||
481 | $this->path = ltrim($u['path'], '/'); |
||
482 | } |
||
483 | |||
484 | if ($cb !== null) { |
||
485 | $this->onConnected($cb); |
||
486 | } |
||
487 | |||
488 | if ($this->scheme === 'unix') { |
||
489 | return $this->connectUnix($u['path']); |
||
490 | } |
||
491 | if ($this->scheme === 'raw') { |
||
492 | return $this->connectRaw($u['host']); |
||
493 | } |
||
494 | if ($this->scheme === 'udp') { |
||
495 | return $this->connectUdp($this->host, $this->port); |
||
496 | } |
||
497 | if ($this->scheme === 'tcp') { |
||
498 | return $this->connectTcp($this->host, $this->port); |
||
499 | } |
||
500 | Daemon::log(get_class($this) . ': connect(): unrecoginized scheme \'' . $this->scheme . '\' (not unix/raw/udp/tcp) in URL: ' . $url); |
||
501 | return false; |
||
502 | } |
||
503 | |||
504 | /** |
||
505 | * Establish UNIX socket connection |
||
506 | * @param string $path Path |
||
507 | * @return boolean Success |
||
508 | */ |
||
509 | public function connectUnix($path) |
||
510 | { |
||
511 | $this->type = 'unix'; |
||
512 | |||
513 | if (!$this->bevConnectEnabled) { |
||
514 | $fd = socket_create(AF_UNIX, SOCK_STREAM, 0); |
||
515 | if (!$fd) { |
||
516 | return false; |
||
517 | } |
||
518 | socket_set_nonblock($fd); |
||
519 | @socket_connect($fd, $path, 0); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
520 | $this->setFd($fd); |
||
521 | return true; |
||
522 | } |
||
523 | $this->bevConnect = true; |
||
524 | $this->addr = 'unix:' . $path; |
||
525 | $this->setFd(null); |
||
0 ignored issues
–
show
null is of type null , but the function expects a resource .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
526 | return true; |
||
527 | } |
||
528 | |||
529 | /** |
||
530 | * Establish raw socket connection |
||
531 | * @param string $host Hostname |
||
532 | * @return boolean Success |
||
533 | */ |
||
534 | public function connectRaw($host) |
||
535 | { |
||
536 | $this->type = 'raw'; |
||
537 | if (@inet_pton($host) === false) { // dirty check |
||
538 | \PHPDaemon\Clients\DNS\Pool::getInstance()->resolve($host, function ($result) use ($host) { |
||
539 | if ($result === false) { |
||
540 | Daemon::log(get_class($this) . '->connectRaw : unable to resolve hostname: ' . $host); |
||
541 | $this->onFailureEv(); |
||
542 | return; |
||
543 | } |
||
544 | // @TODO stack of addrs |
||
545 | if (is_array($result)) { |
||
546 | srand(Daemon::$process->getPid()); |
||
547 | $real = $result[rand(0, sizeof($result) - 1)]; |
||
548 | srand(); |
||
549 | } else { |
||
550 | $real = $result; |
||
551 | } |
||
552 | $this->connectRaw($real); |
||
553 | }); |
||
554 | return true; |
||
555 | } |
||
556 | $this->hostReal = $host; |
||
557 | if ($this->host === null) { |
||
558 | $this->host = $this->hostReal; |
||
559 | } |
||
560 | $this->addr = $this->hostReal . ':raw'; |
||
561 | $fd = socket_create(\EventUtil::AF_INET, \EventUtil::SOCK_RAW, 1); |
||
562 | if (!$fd) { |
||
563 | return false; |
||
564 | } |
||
565 | socket_set_nonblock($fd); |
||
566 | @socket_connect($fd, $host, 0); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
567 | $this->setFd($fd); |
||
568 | if (!$this->bev) { |
||
0 ignored issues
–
show
|
|||
569 | return false; |
||
570 | } |
||
571 | return true; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Establish UDP connection |
||
576 | * @param string $host Hostname |
||
577 | * @param integer $port Port |
||
578 | * @return boolean Success |
||
579 | */ |
||
580 | public function connectUdp($host, $port) |
||
581 | { |
||
582 | $this->type = 'udp'; |
||
583 | $pton = @inet_pton($host); |
||
584 | View Code Duplication | if ($pton === false) { // dirty check |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
585 | \PHPDaemon\Clients\DNS\Pool::getInstance()->resolve($host, function ($result) use ($host, $port) { |
||
586 | if (!$result) { |
||
587 | Daemon::log(get_class($this) . '->connectUdp : unable to resolve hostname: ' . $host); |
||
588 | $this->onStateEv($this->bev, \EventBufferEvent::ERROR); |
||
589 | return; |
||
590 | } |
||
591 | // @todo stack of addrs |
||
592 | if (is_array($result)) { |
||
593 | srand(Daemon::$process->getPid()); |
||
594 | $real = $result[rand(0, sizeof($result) - 1)]; |
||
595 | srand(); |
||
596 | } else { |
||
597 | $real = $result; |
||
598 | } |
||
599 | $this->connectUdp($real, $port); |
||
600 | }); |
||
601 | return true; |
||
602 | } |
||
603 | $this->hostReal = $host; |
||
604 | if ($this->host === null) { |
||
605 | $this->host = $this->hostReal; |
||
606 | } |
||
607 | $l = mb_orig_strlen($pton); |
||
608 | if ($l === 4) { |
||
609 | $this->addr = $host . ':' . $port; |
||
610 | /* @TODO: use EventUtil::SOCK_DGRAM */ |
||
611 | $fd = socket_create(\EventUtil::AF_INET, SOCK_DGRAM, \EventUtil::SOL_UDP); |
||
612 | } elseif ($l === 16) { |
||
613 | $this->addr = '[' . $host . ']:' . $port; |
||
614 | $fd = socket_create(\EventUtil::AF_INET6, SOCK_DGRAM, \EventUtil::SOL_UDP); |
||
615 | } else { |
||
616 | return false; |
||
617 | } |
||
618 | if (!$fd) { |
||
619 | return false; |
||
620 | } |
||
621 | socket_set_nonblock($fd); |
||
622 | @socket_connect($fd, $host, $port); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
623 | socket_getsockname($fd, $this->locAddr, $this->locPort); |
||
624 | $this->setFd($fd); |
||
625 | if (!$this->bev) { |
||
0 ignored issues
–
show
|
|||
626 | return false; |
||
627 | } |
||
628 | return true; |
||
629 | } |
||
630 | |||
631 | /** |
||
632 | * Establish TCP connection |
||
633 | * @param string $host Hostname |
||
634 | * @param integer $port Port |
||
635 | * @return boolean Success |
||
636 | */ |
||
637 | public function connectTcp($host, $port) |
||
638 | { |
||
639 | $this->type = 'tcp'; |
||
640 | $pton = @inet_pton($host); |
||
641 | $fd = null; |
||
642 | View Code Duplication | if ($pton === false) { // dirty check |
|
0 ignored issues
–
show
This code seems to be duplicated across 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. ![]() |
|||
643 | \PHPDaemon\Clients\DNS\Pool::getInstance()->resolve($this->host, function ($result) use ($host, $port) { |
||
644 | if (!$result) { |
||
645 | Daemon::log(get_class($this) . '->connectTcp : unable to resolve hostname: ' . $host); |
||
646 | $this->onStateEv($this->bev, \EventBufferEvent::ERROR); |
||
647 | return; |
||
648 | } |
||
649 | // @todo stack of addrs |
||
650 | if (is_array($result)) { |
||
651 | if (!sizeof($result)) { |
||
652 | return; |
||
653 | } |
||
654 | srand(Daemon::$process->getPid()); |
||
655 | $real = $result[rand(0, sizeof($result) - 1)]; |
||
656 | srand(); |
||
657 | } else { |
||
658 | $real = $result; |
||
659 | } |
||
660 | $this->connectTcp($real, $port); |
||
661 | }); |
||
662 | return true; |
||
663 | } |
||
664 | $this->hostReal = $host; |
||
665 | if ($this->host === null) { |
||
666 | $this->host = $this->hostReal; |
||
667 | } |
||
668 | // TCP |
||
669 | $l = mb_orig_strlen($pton); |
||
670 | if ($l === 4) { |
||
671 | $this->addr = $host . ':' . $port; |
||
672 | if (!$this->bevConnectEnabled) { |
||
673 | $fd = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); |
||
674 | } |
||
675 | } elseif ($l === 16) { |
||
676 | $this->addr = '[' . $host . ']:' . $port; |
||
677 | if (!$this->bevConnectEnabled) { |
||
678 | $fd = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP); |
||
679 | } |
||
680 | } else { |
||
681 | return false; |
||
682 | } |
||
683 | if (!$this->bevConnectEnabled && !$fd) { |
||
684 | return false; |
||
685 | } |
||
686 | if (!$this->bevConnectEnabled) { |
||
687 | socket_set_nonblock($fd); |
||
688 | } |
||
689 | if (!$this->bevConnectEnabled) { |
||
690 | $this->fd = $fd; |
||
691 | $this->setTimeouts( |
||
692 | $this->timeoutRead !== null ? $this->timeoutRead : $this->timeout, |
||
693 | $this->timeoutWrite !== null ? $this->timeoutWrite : $this->timeout |
||
694 | ); |
||
695 | socket_connect($fd, $host, $port); |
||
696 | socket_getsockname($fd, $this->locAddr, $this->locPort); |
||
697 | } else { |
||
698 | $this->bevConnect = true; |
||
699 | } |
||
700 | $this->setFd($fd); |
||
0 ignored issues
–
show
It seems like
$fd defined by null on line 641 can also be of type null ; however, PHPDaemon\Network\IOStream::setFd() does only seem to accept resource , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
701 | if (!$this->bev) { |
||
0 ignored issues
–
show
|
|||
702 | return false; |
||
703 | } |
||
704 | return true; |
||
705 | } |
||
706 | |||
707 | /** |
||
708 | * Set keepalive |
||
709 | * @param boolean $bool |
||
710 | * @return void |
||
711 | */ |
||
712 | public function setKeepalive($bool) |
||
713 | { |
||
714 | $this->keepalive = (bool)$bool; |
||
715 | $this->setOption(\EventUtil::SOL_SOCKET, \EventUtil::SO_KEEPALIVE, $this->keepalive ? true : false); |
||
716 | } |
||
717 | |||
718 | /** |
||
719 | * Close the connection |
||
720 | * @return void |
||
721 | */ |
||
722 | public function close() |
||
723 | { |
||
724 | parent::close(); |
||
725 | if (is_resource($this->fd)) { |
||
726 | socket_close($this->fd); |
||
727 | } |
||
728 | } |
||
729 | |||
730 | /** |
||
731 | * Set timeouts |
||
732 | * @param integer $read Read timeout in seconds |
||
733 | * @param integer $write Write timeout in seconds |
||
734 | * @return void |
||
735 | */ |
||
736 | public function setTimeouts($read, $write) |
||
737 | { |
||
738 | parent::setTimeouts($read, $write); |
||
739 | if ($this->fd !== null) { |
||
740 | $this->setOption( |
||
741 | \EventUtil::SOL_SOCKET, |
||
742 | \EventUtil::SO_SNDTIMEO, |
||
743 | ['sec' => $this->timeoutWrite, 'usec' => 0] |
||
744 | ); |
||
745 | $this->setOption( |
||
746 | \EventUtil::SOL_SOCKET, |
||
747 | \EventUtil::SO_RCVTIMEO, |
||
748 | ['sec' => $this->timeoutRead, 'usec' => 0] |
||
749 | ); |
||
750 | } |
||
751 | } |
||
752 | |||
753 | /** |
||
754 | * Set socket option |
||
755 | * @param integer $level Level |
||
756 | * @param integer $optname Option |
||
757 | * @param mixed $val Value |
||
758 | * @return void |
||
759 | */ |
||
760 | public function setOption($level, $optname, $val) |
||
761 | { |
||
762 | if (is_resource($this->fd)) { |
||
763 | socket_set_option($this->fd, $level, $optname, $val); |
||
764 | } else { |
||
765 | \EventUtil::setSocketOption($this->fd, $level, $optname, $val); |
||
766 | } |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * Called when connection finishes |
||
771 | * @return void |
||
772 | */ |
||
773 | public function onFinish() |
||
774 | { |
||
775 | if (!$this->connected) { |
||
776 | if ($this->onConnected) { |
||
777 | $this->onConnected->executeAll($this); |
||
778 | $this->onConnected = null; |
||
779 | } |
||
780 | } |
||
781 | parent::onFinish(); |
||
782 | } |
||
783 | } |
||
784 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.