PocketMine-MP 5.21.1 git-2ff647079265e7c600203af4fd902b15e99d49a4
raklib/src/protocol/PacketSerializer.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\protocol;
18
22use function assert;
23use function count;
24use function explode;
25use function inet_ntop;
26use function inet_pton;
27use function strlen;
28use const AF_INET6;
29
30final class PacketSerializer extends BinaryStream{
31
35 public function getString() : string{
36 return $this->get($this->getShort());
37 }
38
42 public function getAddress() : InternetAddress{
43 $version = $this->getByte();
44 if($version === 4){
45 $addr = ((~$this->getByte()) & 0xff) . "." . ((~$this->getByte()) & 0xff) . "." . ((~$this->getByte()) & 0xff) . "." . ((~$this->getByte()) & 0xff);
46 $port = $this->getShort();
47 return new InternetAddress($addr, $port, $version);
48 }elseif($version === 6){
49 //http://man7.org/linux/man-pages/man7/ipv6.7.html
50 $this->getLShort(); //Family, AF_INET6
51 $port = $this->getShort();
52 $this->getInt(); //flow info
53 $addr = inet_ntop($this->get(16));
54 if($addr === false){
55 throw new BinaryDataException("Failed to parse IPv6 address");
56 }
57 $this->getInt(); //scope ID
58 return new InternetAddress($addr, $port, $version);
59 }else{
60 throw new BinaryDataException("Unknown IP address version $version");
61 }
62 }
63
64 public function putString(string $v) : void{
65 $this->putShort(strlen($v));
66 $this->put($v);
67 }
68
69 public function putAddress(InternetAddress $address) : void{
70 $version = $address->getVersion();
71 $this->putByte($version);
72 if($version === 4){
73 $parts = explode(".", $address->getIp());
74 assert(count($parts) === 4, "Wrong number of parts in IPv4 IP, expected 4, got " . count($parts));
75 foreach($parts as $b){
76 $this->putByte((~((int) $b)) & 0xff);
77 }
78 $this->putShort($address->getPort());
79 }elseif($version === 6){
80 $this->putLShort(AF_INET6);
81 $this->putShort($address->getPort());
82 $this->putInt(0);
83 $rawIp = inet_pton($address->getIp());
84 if($rawIp === false){
85 throw new \InvalidArgumentException("Invalid IPv6 address could not be encoded");
86 }
87 $this->put($rawIp);
88 $this->putInt(0);
89 }else{
90 throw new \InvalidArgumentException("IP version $version is not supported");
91 }
92 }
93}