PocketMine-MP 5.21.1 git-2ff647079265e7c600203af4fd902b15e99d49a4
UnconnectedMessageHandler.php
1<?php
2
3/*
4 * This file is part of RakLib.
5 * Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/RakLib>
6 *
7 * RakLib is not affiliated with Jenkins Software LLC nor RakNet.
8 *
9 * RakLib is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 */
14
15declare(strict_types=1);
16
17namespace raklib\server;
18
33use function get_class;
34use function min;
35use function ord;
36use function strlen;
37use function substr;
38
44 private \SplFixedArray $packetPool;
45
46 public function __construct(
47 private Server $server,
48 private ProtocolAcceptor $protocolAcceptor
49 ){
50 $this->registerPackets();
51 }
52
56 public function handleRaw(string $payload, InternetAddress $address) : bool{
57 if($payload === ""){
58 return false;
59 }
60 $pk = $this->getPacketFromPool($payload);
61 if($pk === null){
62 return false;
63 }
64 $reader = new PacketSerializer($payload);
65 $pk->decode($reader);
66 if(!$pk->isValid()){
67 return false;
68 }
69 if(!$reader->feof()){
70 $remains = substr($reader->getBuffer(), $reader->getOffset());
71 $this->server->getLogger()->debug("Still " . strlen($remains) . " bytes unread in " . get_class($pk) . " from $address");
72 }
73 return $this->handle($pk, $address);
74 }
75
76 private function handle(OfflineMessage $packet, InternetAddress $address) : bool{
77 if($packet instanceof UnconnectedPing){
78 $this->server->sendPacket(UnconnectedPong::create($packet->sendPingTime, $this->server->getID(), $this->server->getName()), $address);
79 }elseif($packet instanceof OpenConnectionRequest1){
80 if(!$this->protocolAcceptor->accepts($packet->protocol)){
81 $this->server->sendPacket(IncompatibleProtocolVersion::create($this->protocolAcceptor->getPrimaryVersion(), $this->server->getID()), $address);
82 $this->server->getLogger()->notice("Refused connection from $address due to incompatible RakNet protocol version (version $packet->protocol)");
83 }else{
84 //IP header size (20 bytes) + UDP header size (8 bytes)
85 $this->server->sendPacket(OpenConnectionReply1::create($this->server->getID(), false, $packet->mtuSize + 28), $address);
86 }
87 }elseif($packet instanceof OpenConnectionRequest2){
88 if($packet->serverAddress->getPort() === $this->server->getPort() or !$this->server->portChecking){
89 if($packet->mtuSize < Session::MIN_MTU_SIZE){
90 $this->server->getLogger()->debug("Not creating session for $address due to bad MTU size $packet->mtuSize");
91 return true;
92 }
93 $existingSession = $this->server->getSessionByAddress($address);
94 if($existingSession !== null && $existingSession->isConnected()){
95 //for redundancy, in case someone rips up Server - we really don't want connected sessions getting
96 //overwritten
97 $this->server->getLogger()->debug("Not creating session for $address due to session already opened");
98 return true;
99 }
100 $mtuSize = min($packet->mtuSize, $this->server->getMaxMtuSize()); //Max size, do not allow creating large buffers to fill server memory
101 $this->server->sendPacket(OpenConnectionReply2::create($this->server->getID(), $address, $mtuSize, false), $address);
102 $this->server->createSession($address, $packet->clientID, $mtuSize);
103 }else{
104 $this->server->getLogger()->debug("Not creating session for $address due to mismatched port, expected " . $this->server->getPort() . ", got " . $packet->serverAddress->getPort());
105 }
106 }else{
107 return false;
108 }
109
110 return true;
111 }
112
116 private function registerPacket(int $id, string $class) : void{
117 $this->packetPool[$id] = new $class;
118 }
119
120 public function getPacketFromPool(string $buffer) : ?OfflineMessage{
121 $pk = $this->packetPool[ord($buffer[0])];
122 if($pk !== null){
123 return clone $pk;
124 }
125
126 return null;
127 }
128
129 private function registerPackets() : void{
130 $this->packetPool = new \SplFixedArray(256);
131
132 $this->registerPacket(MessageIdentifiers::ID_UNCONNECTED_PING, UnconnectedPing::class);
133 $this->registerPacket(MessageIdentifiers::ID_UNCONNECTED_PING_OPEN_CONNECTIONS, UnconnectedPingOpenConnections::class);
134 $this->registerPacket(MessageIdentifiers::ID_OPEN_CONNECTION_REQUEST_1, OpenConnectionRequest1::class);
135 $this->registerPacket(MessageIdentifiers::ID_OPEN_CONNECTION_REQUEST_2, OpenConnectionRequest2::class);
136 }
137
138}
handleRaw(string $payload, InternetAddress $address)