Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/generic/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ abstract class Session{

private int $id;

private int $protocol;

private float $lastUpdate;
private float $disconnectionTime = 0;

Expand All @@ -75,6 +77,7 @@ public function __construct(
InternetAddress $address,
int $clientId,
int $mtuSize,
int $protocol,
int $recvMaxSplitParts = PHP_INT_MAX,
int $recvMaxConcurrentSplits = PHP_INT_MAX
){
Expand All @@ -84,6 +87,7 @@ public function __construct(
$this->logger = new \PrefixedLogger($logger, "Session: " . $address->toString());
$this->address = $address;
$this->id = $clientId;
$this->protocol = $protocol;

$this->lastUpdate = microtime(true);

Expand Down Expand Up @@ -167,6 +171,10 @@ public function getID() : int{
return $this->id;
}

public function getProtocol() : int{
return $this->protocol;
}

public function getState() : int{
return $this->state;
}
Expand Down
36 changes: 36 additions & 0 deletions src/server/PendingConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of RakLib.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/RakLib>
*
* RakLib is not affiliated with Jenkins Software LLC nor RakNet.
*
* RakLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/

declare(strict_types=1);

namespace raklib\server;

class PendingConnection{

private float $createdAt;

public function __construct(
private int $protocol
){
$this->createdAt = microtime(true);
}

public function getProtocol() : int{
return $this->protocol;
}

public function getCreatedAt() : float{
return $this->createdAt;
}
}
7 changes: 4 additions & 3 deletions src/server/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ private function tick() : void{
$this->removeSessionInternal($session);
}
}
$this->unconnectedMessageHandler->update($time);

$this->ipSec = [];

Expand Down Expand Up @@ -410,7 +411,7 @@ public function sessionExists(InternetAddress $address) : bool{
return isset($this->sessionsByAddress[$address->toString()]);
}

public function createSession(InternetAddress $address, int $clientId, int $mtuSize) : ServerSession{
public function createSession(InternetAddress $address, int $clientId, int $mtuSize, int $protocol) : ServerSession{
$existingSession = $this->sessionsByAddress[$address->toString()] ?? null;
if($existingSession !== null){
$existingSession->forciblyDisconnect(DisconnectReason::CLIENT_RECONNECT);
Expand All @@ -424,7 +425,7 @@ public function createSession(InternetAddress $address, int $clientId, int $mtuS
$this->nextSessionId &= 0x7fffffff; //we don't expect more than 2 billion simultaneous connections, and this fits in 4 bytes
}

$session = new ServerSession($this, $this->logger, clone $address, $clientId, $mtuSize, $this->nextSessionId, $this->recvMaxSplitParts, $this->recvMaxConcurrentSplits);
$session = new ServerSession($this, $this->logger, clone $address, $clientId, $mtuSize, $protocol, $this->nextSessionId, $this->recvMaxSplitParts, $this->recvMaxConcurrentSplits);
$this->sessionsByAddress[$address->toString()] = $session;
$this->sessions[$this->nextSessionId] = $session;
$this->logger->debug("Created session for $address with MTU size $mtuSize");
Expand All @@ -438,7 +439,7 @@ private function removeSessionInternal(ServerSession $session) : void{

public function openSession(ServerSession $session) : void{
$address = $session->getAddress();
$this->eventListener->onClientConnect($session->getInternalId(), $address->getIp(), $address->getPort(), $session->getID());
$this->eventListener->onClientConnect($session->getInternalId(), $address->getIp(), $address->getPort(), $session->getID(), $session->getProtocol());
}

private function checkSessions() : void{
Expand Down
2 changes: 1 addition & 1 deletion src/server/ServerEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

interface ServerEventListener{

public function onClientConnect(int $sessionId, string $address, int $port, int $clientID) : void;
public function onClientConnect(int $sessionId, string $address, int $port, int $clientID, int $protocol) : void;

/**
* @param int $reason one of the DisconnectReason constants
Expand Down
3 changes: 2 additions & 1 deletion src/server/ServerSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ public function __construct(
InternetAddress $address,
int $clientId,
int $mtuSize,
int $protocol,
int $internalId,
int $recvMaxSplitParts = self::DEFAULT_MAX_SPLIT_PART_COUNT,
int $recvMaxConcurrentSplits = self::DEFAULT_MAX_CONCURRENT_SPLIT_COUNT
){
$this->server = $server;
$this->internalId = $internalId;
parent::__construct($logger, $address, $clientId, $mtuSize, $recvMaxSplitParts, $recvMaxConcurrentSplits);
parent::__construct($logger, $address, $clientId, $mtuSize, $protocol, $recvMaxSplitParts, $recvMaxConcurrentSplits);
}

/**
Expand Down
23 changes: 22 additions & 1 deletion src/server/UnconnectedMessageHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class UnconnectedMessageHandler{
* @phpstan-var \SplFixedArray<OfflineMessage>
*/
private \SplFixedArray $packetPool;
/** @var PendingConnection[] */
private array $pendingConnections = [];

public function __construct(
private Server $server,
Expand Down Expand Up @@ -81,6 +83,8 @@ private function handle(OfflineMessage $packet, InternetAddress $address) : bool
$this->server->sendPacket(IncompatibleProtocolVersion::create($this->protocolAcceptor->getPrimaryVersion(), $this->server->getID()), $address);
$this->server->getLogger()->notice("Refused connection from $address due to incompatible RakNet protocol version (version $packet->protocol)");
}else{
$this->pendingConnections[$address->toString()] = new PendingConnection($packet->protocol);

//IP header size (20 bytes) + UDP header size (8 bytes)
$this->server->sendPacket(OpenConnectionReply1::create($this->server->getID(), false, $packet->mtuSize + 28), $address);
}
Expand All @@ -97,9 +101,17 @@ private function handle(OfflineMessage $packet, InternetAddress $address) : bool
$this->server->getLogger()->debug("Not creating session for $address due to session already opened");
return true;
}
if(!isset($this->pendingConnections[$address->toString()])){
// we should always except OpenConnectionRequest1 before OpenConnectionRequeqst2
$this->server->getLogger()->debug("Not creating session for $address due to no pending connection");;
return true;
}
$pendingConnection = $this->pendingConnections[$address->toString()];
unset($this->pendingConnections[$address->toString()]);

$mtuSize = min($packet->mtuSize, $this->server->getMaxMtuSize()); //Max size, do not allow creating large buffers to fill server memory
$this->server->sendPacket(OpenConnectionReply2::create($this->server->getID(), $address, $mtuSize, false), $address);
$this->server->createSession($address, $packet->clientID, $mtuSize);
$this->server->createSession($address, $packet->clientID, $mtuSize, $pendingConnection->getProtocol());
}else{
$this->server->getLogger()->debug("Not creating session for $address due to mismatched port, expected " . $this->server->getPort() . ", got " . $packet->serverAddress->getPort());
}
Expand All @@ -110,6 +122,15 @@ private function handle(OfflineMessage $packet, InternetAddress $address) : bool
return true;
}

public function update(float $time) : void{
foreach($this->pendingConnections as $address => $pendingConnection){
if($pendingConnection->getCreatedAt() + 10 < $time){
$this->server->getLogger()->debug("Timed out pending connection from $address");
unset($this->pendingConnections[$address]);
}
}
}

/**
* @phpstan-param class-string<OfflineMessage> $class
*/
Expand Down