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 declare(strict_types=1); |
||
2 | |||
3 | namespace Igni\Network; |
||
4 | |||
5 | use Igni\Exception\RuntimeException; |
||
6 | use Igni\Network\Exception\ClientException; |
||
7 | use Igni\Network\Exception\ServerException; |
||
8 | use Igni\Network\Server\Client; |
||
9 | use Igni\Network\Server\Configuration; |
||
10 | use Igni\Network\Server\HandlerFactory; |
||
11 | use Igni\Network\Server\Listener; |
||
12 | use Igni\Network\Server\LogWriter; |
||
13 | use Igni\Network\Server\OnCloseListener; |
||
14 | use Igni\Network\Server\OnConnectListener; |
||
15 | use Igni\Network\Server\OnReceiveListener; |
||
16 | use Igni\Network\Server\OnShutdownListener; |
||
17 | use Igni\Network\Server\OnStartListener; |
||
18 | use Igni\Network\Server\ServerStats; |
||
19 | use Psr\Log\LoggerInterface; |
||
20 | use SplQueue; |
||
21 | use Swoole\Server as SwooleServer; |
||
22 | |||
23 | use function extension_loaded; |
||
24 | |||
25 | /** |
||
26 | * Http server implementation based on swoole extension. |
||
27 | * |
||
28 | * @package Igni\Http |
||
29 | */ |
||
30 | class Server implements HandlerFactory |
||
31 | { |
||
32 | private const SWOOLE_EXT_NAME = 'swoole'; |
||
33 | |||
34 | /** |
||
35 | * @var SwooleServer|null |
||
36 | */ |
||
37 | protected $handler; |
||
38 | |||
39 | /** |
||
40 | * @var Configuration |
||
41 | */ |
||
42 | protected $configuration; |
||
43 | |||
44 | /** |
||
45 | * @var SplQueue[] |
||
46 | */ |
||
47 | protected $listeners = []; |
||
48 | |||
49 | /** |
||
50 | * @var LoggerInterface |
||
51 | */ |
||
52 | protected $logger; |
||
53 | |||
54 | /** |
||
55 | * @var HandlerFactory |
||
56 | */ |
||
57 | protected $handlerFactory; |
||
58 | |||
59 | /** |
||
60 | * @var Client[] |
||
61 | */ |
||
62 | private $clients = []; |
||
63 | |||
64 | /** |
||
65 | * @var bool |
||
66 | */ |
||
67 | private $running = false; |
||
68 | |||
69 | 15 | public function __construct( |
|
70 | Configuration $settings = null, |
||
71 | LoggerInterface $logger = null, |
||
72 | HandlerFactory $handlerFactory = null |
||
73 | ) { |
||
74 | 15 | if (!extension_loaded(self::SWOOLE_EXT_NAME)) { |
|
75 | throw new RuntimeException('Swoole extenstion is missing, please install it and try again.'); |
||
76 | } |
||
77 | |||
78 | 15 | $this->handlerFactory = $handlerFactory ?? $this; |
|
79 | 15 | $this->configuration = $settings ?? new Configuration(); |
|
80 | 15 | $this->logger = new LogWriter($logger); |
|
81 | 15 | } |
|
82 | |||
83 | /** |
||
84 | * Return server configuration. |
||
85 | * |
||
86 | * @return Configuration |
||
87 | */ |
||
88 | 2 | public function getConfiguration(): Configuration |
|
89 | { |
||
90 | 2 | return $this->configuration; |
|
91 | } |
||
92 | |||
93 | /** |
||
94 | * @param int $id |
||
95 | * @return Client |
||
96 | * @throws ClientException if client was not found |
||
97 | */ |
||
98 | 6 | public function getClient(int $id): Client |
|
99 | { |
||
100 | 6 | if (!isset($this->clients[$id])) { |
|
101 | 1 | throw ClientException::forInactiveClient($id); |
|
102 | } |
||
103 | 6 | return $this->clients[$id]; |
|
104 | } |
||
105 | |||
106 | /** |
||
107 | * Adds listener that is attached to server once it is run. |
||
108 | * |
||
109 | * @param Listener $listener |
||
110 | */ |
||
111 | 11 | public function addListener(Listener $listener): void |
|
112 | { |
||
113 | 11 | $this->addListenerByType($listener, OnStartListener::class); |
|
114 | 11 | $this->addListenerByType($listener, OnCloseListener::class); |
|
115 | 11 | $this->addListenerByType($listener, OnConnectListener::class); |
|
116 | 11 | $this->addListenerByType($listener, OnShutdownListener::class); |
|
117 | 11 | $this->addListenerByType($listener, OnReceiveListener::class); |
|
118 | 11 | } |
|
119 | |||
120 | 11 | protected function addListenerByType(Listener $listener, string $type): void |
|
121 | { |
||
122 | 11 | if ($listener instanceof $type) { |
|
123 | 11 | if (!isset($this->listeners[$type])) { |
|
124 | 11 | $this->listeners[$type] = new SplQueue(); |
|
125 | } |
||
126 | 11 | $this->listeners[$type]->push($listener); |
|
127 | } |
||
128 | 11 | } |
|
129 | |||
130 | /** |
||
131 | * Checks if listener exists. |
||
132 | * |
||
133 | * @param Listener $listener |
||
134 | * @return bool |
||
135 | */ |
||
136 | 1 | public function hasListener(Listener $listener): bool |
|
137 | { |
||
138 | /** @var SplQueue $listenerCollection */ |
||
139 | 1 | foreach ($this->listeners as $listenerCollection) { |
|
140 | 1 | foreach ($listenerCollection as $current) { |
|
141 | 1 | if ($current === $listener) { |
|
142 | 1 | return true; |
|
143 | } |
||
144 | } |
||
145 | } |
||
146 | |||
147 | 1 | return false; |
|
148 | } |
||
149 | |||
150 | /** |
||
151 | * Returns information about server. |
||
152 | * |
||
153 | * @return ServerStats |
||
154 | */ |
||
155 | 1 | public function getServerStats(): ServerStats |
|
156 | { |
||
157 | 1 | if (!$this->running) { |
|
158 | 1 | throw ServerException::forMethodCallOnIdleServer(__METHOD__); |
|
159 | } |
||
160 | return new ServerStats($this->handler->stats()); |
||
161 | } |
||
162 | |||
163 | public function createHandler(Configuration $configuration) |
||
164 | { |
||
165 | $flags = SWOOLE_TCP; |
||
166 | if ($configuration->isSslEnabled()) { |
||
167 | $flags |= SWOOLE_SSL; |
||
168 | } |
||
169 | $settings = $configuration->toArray(); |
||
170 | $handler = new SwooleServer($settings['address'], $settings['port'], SWOOLE_PROCESS, $flags); |
||
171 | $handler->set($settings); |
||
172 | |||
173 | return $handler; |
||
174 | } |
||
175 | |||
176 | 10 | public function start(): void |
|
177 | { |
||
178 | 10 | $this->addListener($this->logger); |
|
0 ignored issues
–
show
|
|||
179 | 10 | $this->handler = $this->handlerFactory->createHandler($this->configuration); |
|
180 | 10 | $this->createListeners(); |
|
181 | 10 | $this->handler->start(); |
|
182 | 10 | $this->running = true; |
|
183 | 10 | } |
|
184 | |||
185 | 1 | public function stop(): void |
|
186 | { |
||
187 | 1 | if ($this->handler !== null) { |
|
188 | 1 | $this->handler->shutdown(); |
|
189 | 1 | $this->handler = null; |
|
190 | } |
||
191 | 1 | $this->running = false; |
|
192 | 1 | } |
|
193 | |||
194 | 1 | public function isRunning(): bool |
|
195 | { |
||
196 | 1 | return $this->running; |
|
197 | } |
||
198 | |||
199 | 10 | protected function createListeners(): void |
|
200 | { |
||
201 | 10 | $this->createOnConnectListener(); |
|
202 | 10 | $this->createOnCloseListener(); |
|
203 | 10 | $this->createOnShutdownListener(); |
|
204 | 10 | $this->createOnStartListener(); |
|
205 | 10 | $this->createOnReceiveListener(); |
|
206 | 10 | } |
|
207 | |||
208 | 6 | private function createClient($handler, int $clientId): Client |
|
209 | { |
||
210 | 6 | return $this->clients[$clientId] = new Client($handler, $clientId); |
|
211 | } |
||
212 | |||
213 | 4 | private function destroyClient(int $clientId): void |
|
214 | { |
||
215 | 4 | unset($this->clients[$clientId]); |
|
216 | 4 | } |
|
217 | |||
218 | 10 | protected function createOnConnectListener(): void |
|
219 | { |
||
220 | $this->handler->on('Connect', function($handler, int $clientId) { |
||
221 | 6 | $this->createClient($handler, $clientId); |
|
222 | |||
223 | 6 | if (!isset($this->listeners[OnConnectListener::class])) { |
|
224 | return; |
||
225 | } |
||
226 | |||
227 | 6 | $queue = clone $this->listeners[OnConnectListener::class]; |
|
228 | /** @var OnConnectListener $listener */ |
||
229 | 6 | while (!$queue->isEmpty() && $listener = $queue->pop()) { |
|
230 | 6 | $listener->onConnect($this, $this->getClient($clientId)); |
|
231 | } |
||
232 | 10 | }); |
|
233 | 10 | } |
|
234 | |||
235 | 10 | protected function createOnCloseListener(): void |
|
236 | { |
||
237 | $this->handler->on('Close', function($handler, int $clientId) { |
||
238 | 4 | if (isset($this->listeners[OnCloseListener::class])) { |
|
239 | |||
240 | 4 | $queue = clone $this->listeners[OnCloseListener::class]; |
|
241 | /** @var OnCloseListener $listener */ |
||
242 | 4 | while (!$queue->isEmpty() && $listener = $queue->pop()) { |
|
243 | 4 | $listener->onClose($this, $this->getClient($clientId)); |
|
244 | } |
||
245 | } |
||
246 | |||
247 | 4 | $this->destroyClient($clientId); |
|
248 | 10 | }); |
|
249 | 10 | } |
|
250 | |||
251 | 10 | protected function createOnShutdownListener(): void |
|
252 | { |
||
253 | $this->handler->on('Shutdown', function() { |
||
254 | 1 | if (!isset($this->listeners[OnShutdownListener::class])) { |
|
255 | return; |
||
256 | } |
||
257 | |||
258 | 1 | $queue = clone $this->listeners[OnShutdownListener::class]; |
|
259 | |||
260 | /** @var OnShutdownListener $listener */ |
||
261 | 1 | while (!$queue->isEmpty() && $listener = $queue->pop()) { |
|
262 | 1 | $listener->onShutdown($this); |
|
263 | } |
||
264 | 1 | $this->clients = []; |
|
265 | 10 | }); |
|
266 | 10 | } |
|
267 | |||
268 | 10 | protected function createOnStartListener(): void |
|
269 | { |
||
270 | $this->handler->on('Start', function() { |
||
271 | 1 | if (!isset($this->listeners[OnStartListener::class])) { |
|
272 | return; |
||
273 | } |
||
274 | |||
275 | 1 | $queue = clone $this->listeners[OnStartListener::class]; |
|
276 | /** @var OnStartListener $listener */ |
||
277 | 1 | while (!$queue->isEmpty() && $listener = $queue->pop()) { |
|
278 | 1 | $listener->onStart($this); |
|
279 | } |
||
280 | 10 | }); |
|
281 | 10 | } |
|
282 | |||
283 | 10 | protected function createOnReceiveListener(): void |
|
284 | { |
||
285 | $this->handler->on('Receive', function ($handler, int $clientId, int $fromId, string $data) { |
||
286 | 1 | if (!isset($this->listeners[OnReceiveListener::class])) { |
|
287 | return; |
||
288 | } |
||
289 | |||
290 | 1 | $queue = clone $this->listeners[OnReceiveListener::class]; |
|
291 | |||
292 | /** @var OnReceiveListener $listener */ |
||
293 | 1 | while (!$queue->isEmpty() && $listener = $queue->pop()) { |
|
294 | 1 | $listener->onReceive($this, $this->getClient($clientId), $data); |
|
295 | } |
||
296 | 10 | }); |
|
297 | 10 | } |
|
298 | } |
||
299 |
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: