6
6
namespace libproxy ;
7
7
8
8
use Error ;
9
+ use ErrorException ;
9
10
use Exception ;
10
11
use libproxy \data \LatencyData ;
11
12
use libproxy \data \TickSyncPacket ;
17
18
use libproxy \protocol \ProxyPacketSerializer ;
18
19
use pmmp \thread \Thread as NativeThread ;
19
20
use pmmp \thread \ThreadSafeArray ;
21
+ use pocketmine \network \mcpe \compression \DecompressionException ;
22
+ use pocketmine \network \mcpe \compression \ZlibCompressor ;
20
23
use pocketmine \network \mcpe \convert \TypeConverter ;
21
24
use pocketmine \network \mcpe \EntityEventBroadcaster ;
22
25
use pocketmine \network \mcpe \NetworkSession ;
23
26
use pocketmine \network \mcpe \PacketBroadcaster ;
27
+ use pocketmine \network \mcpe \protocol \PacketDecodeException ;
24
28
use pocketmine \network \mcpe \protocol \PacketPool ;
29
+ use pocketmine \network \mcpe \protocol \serializer \PacketBatch ;
25
30
use pocketmine \network \mcpe \protocol \serializer \PacketSerializerContext ;
31
+ use pocketmine \network \mcpe \protocol \types \CompressionAlgorithm ;
26
32
use pocketmine \network \mcpe \raklib \PthreadsChannelReader ;
27
33
use pocketmine \network \mcpe \raklib \PthreadsChannelWriter ;
28
34
use pocketmine \network \NetworkInterface ;
32
38
use pocketmine \Server ;
33
39
use pocketmine \snooze \SleeperHandlerEntry ;
34
40
use pocketmine \thread \ThreadCrashException ;
41
+ use pocketmine \timings \Timings ;
35
42
use pocketmine \utils \Binary ;
36
43
use pocketmine \utils \BinaryDataException ;
44
+ use pocketmine \utils \BinaryStream ;
37
45
use Socket ;
38
46
use ThreadedArray ;
39
47
use WeakMap ;
48
+ use function base64_encode ;
40
49
use function bin2hex ;
50
+ use function ord ;
41
51
use function socket_close ;
42
52
use function socket_create_pair ;
43
53
use function socket_last_error ;
46
56
use function strlen ;
47
57
use function substr ;
48
58
use function trim ;
59
+ use function zstd_uncompress ;
49
60
use const AF_INET ;
50
61
use const AF_UNIX ;
51
62
use const SOCK_STREAM ;
@@ -214,7 +225,7 @@ private function onPacketReceive(string $buffer): void
214
225
break ; // might be data arriving from the client after the server has closed the connection
215
226
}
216
227
217
- $ session ->handleEncoded ($ pk ->payload );
228
+ $ this ->handleEncoded ($ session , $ pk ->payload );
218
229
$ this ->receiveBytes += strlen ($ pk ->payload );
219
230
break ;
220
231
}
@@ -225,6 +236,70 @@ private function onPacketReceive(string $buffer): void
225
236
}
226
237
}
227
238
239
+ /**
240
+ * @throws PacketHandlingException
241
+ */
242
+ public function handleEncoded (NetworkSession $ session , string $ payload ): void
243
+ {
244
+ if (!(fn () => $ this ->connected )->call ($ session )) {
245
+ return ;
246
+ }
247
+
248
+ Timings::$ playerNetworkReceive ->startTiming ();
249
+ try {
250
+ (fn () => $ this ->packetBatchLimiter ->decrement ())->call ($ session );
251
+
252
+ if (strlen ($ payload ) < 1 ) {
253
+ throw new PacketHandlingException ("No bytes in payload " );
254
+ }
255
+
256
+ Timings::$ playerNetworkReceiveDecompress ->startTiming ();
257
+ $ compressionType = ord ($ payload [0 ]);
258
+ $ compressed = substr ($ payload , 1 );
259
+
260
+ try {
261
+ $ decompressed = match ($ compressionType ) {
262
+ CompressionAlgorithm::NONE => $ compressed ,
263
+ CompressionAlgorithm::ZLIB => $ session ->getCompressor ()->decompress ($ compressed ),
264
+ CompressionAlgorithm::NONE - 1 => ($ d = zstd_uncompress ($ compressed )) === false ? throw new DecompressionException ("Failed to decompress packet " ) : $ d ,
265
+ default => throw new PacketHandlingException ("Packet compressed with unexpected compression type $ compressionType " )
266
+ };
267
+ } catch (ErrorException |DecompressionException $ e ) {
268
+ $ session ->getLogger ()->debug ("Failed to decompress packet: " . base64_encode ($ compressed ));
269
+ throw PacketHandlingException::wrap ($ e , "Compressed packet batch decode error " );
270
+ } finally {
271
+ Timings::$ playerNetworkReceiveDecompress ->stopTiming ();
272
+ }
273
+
274
+ try {
275
+ $ stream = new BinaryStream ($ decompressed );
276
+ $ count = 0 ;
277
+ foreach (PacketBatch::decodeRaw ($ stream ) as $ buffer ) {
278
+ (fn () => $ this ->gamePacketLimiter ->decrement ())->call ($ session );
279
+ if (++$ count > 100 ) {
280
+ throw new PacketHandlingException ("Too many packets in batch " );
281
+ }
282
+ $ packet = PacketPool::getInstance ()->getPacket ($ buffer );
283
+ if ($ packet === null ) {
284
+ $ session ->getLogger ()->debug ("Unknown packet: " . base64_encode ($ buffer ));
285
+ throw new PacketHandlingException ("Unknown packet received " );
286
+ }
287
+ try {
288
+ $ session ->handleDataPacket ($ packet , $ buffer );
289
+ } catch (PacketHandlingException $ e ) {
290
+ $ session ->getLogger ()->debug ($ packet ->getName () . ": " . base64_encode ($ buffer ));
291
+ throw PacketHandlingException::wrap ($ e , "Error processing " . $ packet ->getName ());
292
+ }
293
+ }
294
+ } catch (PacketDecodeException |BinaryDataException $ e ) {
295
+ $ session ->getLogger ()->logException ($ e );
296
+ throw PacketHandlingException::wrap ($ e , "Packet batch decode error " );
297
+ }
298
+ } finally {
299
+ Timings::$ playerNetworkReceive ->stopTiming ();
300
+ }
301
+ }
302
+
228
303
public function tick (): void
229
304
{
230
305
if (!$ this ->proxy ->isRunning ()) {
@@ -295,20 +370,13 @@ public function createSession(int $socketId, string $ip, int $port): NetworkSess
295
370
new ProxyPacketSender ($ socketId , $ this ),
296
371
$ this ->packetBroadcaster ,
297
372
$ this ->entityEventBroadcaster ,
298
- MultiCompressor ::getInstance (),
373
+ ZlibCompressor ::getInstance (),
299
374
TypeConverter::getInstance (),
300
375
$ ip ,
301
376
$ port
302
377
);
303
378
304
379
$ this ->sessions [$ socketId ] = $ session ;
305
-
306
- // Set the LoginPacketHandler, since compression is handled by the proxy
307
- (function (): void {
308
- /** @noinspection PhpUndefinedFieldInspection */
309
- $ this ->onSessionStartSuccess ();
310
- })->call ($ session );
311
-
312
380
return $ session ;
313
381
}
314
382
0 commit comments