UDPRelays::connect()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 11
nc 2
nop 2
dl 0
loc 16
rs 9.9
c 2
b 0
f 0
1
<?php
2
/**
3
 * UDP Relays
4
 * User: moyo
5
 * Date: Jul 23, 2019
6
 * Time: 10:41
7
 */
8
9
namespace Carno\Traced\Transport;
10
11
use Carno\Net\Address;
12
use Carno\Promise\Promise;
13
use Carno\Promise\Promised;
14
use Carno\Tracing\Contracts\Transport;
15
use Swoole\Client;
0 ignored issues
show
Bug introduced by
The type Swoole\Client was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Closure;
17
18
class UDPRelays implements Transport
19
{
20
    public const MAGIC = '  ZU';
21
22
    /**
23
     * @var Address
24
     */
25
    private $endpoint = null;
26
27
    /**
28
     * @var string
29
     */
30
    private $identify = 'unknown';
31
32
    /**
33
     * @var bool
34
     */
35
    private $uxdomain = false;
36
37
    /**
38
     * @var Closure
39
     */
40
    private $sender = null;
41
42
    /**
43
     * @var resource
44
     */
45
    private $socket = null;
46
47
    /**
48
     * @var Client
49
     */
50
    private $client = null;
51
52
    /**
53
     */
54
    private function mkSwoole() : void
55
    {
56
        $this->client = new Client(
57
            $this->uxdomain ? SWOOLE_SOCK_UNIX_DGRAM : SWOOLE_SOCK_UDP,
0 ignored issues
show
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_UNIX_DGRAM was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_UDP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
58
            ($async = PHP_SAPI === 'cli') ? SWOOLE_SOCK_ASYNC : SWOOLE_SOCK_SYNC
0 ignored issues
show
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_ASYNC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_SYNC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
59
        );
60
        $async && $this->client->on('connect', static function () {
61
            // do nothing
62
        });
63
        $async && $this->client->on('receive', static function () {
64
            // do nothing
65
        });
66
        $this->client->connect($this->endpoint->host(), $this->endpoint->port());
67
        $this->sender = function (string $data) {
68
            @$this->client->send($data);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for send(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

68
            /** @scrutinizer ignore-unhandled */ @$this->client->send($data);

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.');
}
Loading history...
69
        };
70
    }
71
72
    /**
73
     */
74
    private function mkSockets() : void
75
    {
76
        $this->socket = socket_create(
77
            $this->uxdomain ? AF_UNIX : AF_INET,
78
            SOCK_DGRAM,
79
            $this->uxdomain ? IPPROTO_IP : SOL_UDP
80
        );
81
        $this->sender = function (string $data) {
82
            @socket_sendto(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for socket_sendto(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

82
            /** @scrutinizer ignore-unhandled */ @socket_sendto(

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.');
}
Loading history...
83
                $this->socket,
84
                $data,
85
                strlen($data),
86
                MSG_EOF,
87
                $this->endpoint->host(),
88
                $this->endpoint->port()
89
            );
90
        };
91
    }
92
93
    /**
94
     */
95
    private function initialize() : void
96
    {
97
        if (class_exists('\\Swoole\\Client')) {
98
            $this->mkSwoole();
99
        } elseif (function_exists('socket_create')) {
100
            $this->mkSockets();
101
        }
102
    }
103
104
    /**
105
     * @param Address $endpoint
106
     * @param string $identify
107
     */
108
    public function connect(Address $endpoint, string $identify = null) : void
109
    {
110
        $trim = " /\t\n";
111
112
        if ($endpoint->host() === '~') {
113
            $identify = rtrim($identify, $trim);
114
            $this->uxdomain = true;
115
            $this->identify = substr($identify, ($ips = strrpos($identify, '/')) + 1);
116
            $this->endpoint = new Address(substr($identify, 0, $ips));
117
        } else {
118
            $identify = trim($identify, $trim);
119
            $this->identify = $identify;
120
            $this->endpoint = $endpoint;
121
        }
122
123
        $this->initialize();
124
    }
125
126
    /**
127
     * @return Promised
128
     */
129
    public function disconnect() : Promised
130
    {
131
        if ($this->socket) {
132
            @socket_close($this->socket);
0 ignored issues
show
Bug introduced by
Are you sure the usage of socket_close($this->socket) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition for socket_close(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

132
            /** @scrutinizer ignore-unhandled */ @socket_close($this->socket);

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.');
}
Loading history...
133
        }
134
135
        if ($this->client) {
136
            @$this->client->close();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for close(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

136
            /** @scrutinizer ignore-unhandled */ @$this->client->close();

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.');
}
Loading history...
137
            $this->client = null;
138
        }
139
140
        return Promise::resolved();
141
    }
142
143
    /**
144
     * @param string $data
145
     */
146
    public function loading(string $data) : void
147
    {
148
        $this->sender && ($this->sender)($this->packing($data));
149
    }
150
151
    /**
152
     * @param string $payload
153
     * @return string
154
     */
155
    private function packing(string $payload) : string
156
    {
157
        return
158
            self::MAGIC .
159
            pack('N', strlen($this->identify)) .
160
            $this->identify .
161
            pack('N', strlen($payload)) .
162
            $payload
163
        ;
164
    }
165
166
    /**
167
     */
168
    public function flushing() : void
169
    {
170
    }
171
}
172