koraktor/steam-condenser-php

View on GitHub
lib/SteamCondenser/Servers/Sockets/SourceSocket.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2015, Sebastian Staudt
 *
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 */

namespace SteamCondenser\Servers\Sockets;

use SteamCondenser\Exceptions\TimeoutException;
use SteamCondenser\Servers\Packets\SteamPacketFactory;

/**
 * This class represents a socket used to communicate with game servers based
 * on the Source engine (e.g. Team Fortress 2, Counter-Strike: Source)
 *
 * @author     Sebastian Staudt
 * @package    steam-condenser
 * @subpackage sockets
 */
class SourceSocket extends SteamSocket {

    /**
     * Creates a new UDP socket to communicate with the Source server on the
     * given IP address and port
     *
     * @param string $ipAddress Either the IP address or the DNS name of the
     *        server
     * @param int $portNumber The port the server is listening on
     */
    public function __construct($ipAddress, $portNumber = 27015) {
        parent::__construct($ipAddress, $portNumber);
    }

    /**
     * Reads a packet from the socket
     *
     * The Source query protocol specifies a maximum packet size of 1,400
     * bytes. Bigger packets will be split over several UDP packets. This
     * method reassembles split packets into single packet objects.
     * Additionally Source may compress big packets using bzip2. Those packets
     * will be compressed.
     *
     * @return SteamPacket The packet replied from the server
     */
    public function getReply() {
        $this->receivePacket(1400);
        $isCompressed = false;

        if($this->buffer->getLong() == -2) {
            do {
                $requestId = $this->buffer->getLong();
                $isCompressed = (($requestId & 0x80000000) != 0);
                $packetCount = $this->buffer->getByte();
                $packetNumber = $this->buffer->getByte() + 1;

                if($isCompressed) {
                    $splitSize = $this->buffer->getLong();
                    $packetChecksum = $this->buffer->getUnsignedLong();
                } else {
                    $splitSize = $this->buffer->getShort();
                }

                $splitPackets[$packetNumber] = $this->buffer->get();

                $this->logger->debug("Received packet $packetNumber of $packetCount for request #$requestId");

                if(sizeof($splitPackets) < $packetCount) {
                    try {
                        $bytesRead = $this->receivePacket();
                    } catch(TimeoutException $e) {
                        $bytesRead = 0;
                    }
                } else {
                    $bytesRead = 0;
                }
            } while($bytesRead > 0 && $this->buffer->getLong() == -2);

            if($isCompressed) {
                $packet = SteamPacketFactory::reassemblePacket($splitPackets, true, $packetChecksum);
            } else {
                $packet = SteamPacketFactory::reassemblePacket($splitPackets);
            }
        } else {
            $packet = SteamPacketFactory::getPacketFromData($this->buffer->get());
        }

        if($isCompressed) {
            $this->logger->debug("Received compressed reply of type \"" . get_class($packet) . "\"");
        } else {
            $this->logger->debug("Received reply of type \"" . get_class($packet) . "\"");
        }

        return $packet;
    }
}