SourceRcon::fullConstruct()   A
last analyzed

Complexity

Conditions 2
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 6
nc 3
nop 0
1
<?php
2
3
/**
4
 * This file is part of Dedipanel project
5
 *
6
 * (c) 2010-2015 Dedipanel <http://www.dedicated-panel.net>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace DP\GameServer\SteamServerBundle\SteamQuery;
13
14
use DP\GameServer\GameServerBundle\Socket\Socket;
15
use DP\GameServer\GameServerBundle\Socket\Packet;
16
use DP\GameServer\GameServerBundle\Socket\PacketCollection;
17
use DP\GameServer\GameServerBundle\Socket\Exception\ConnectionFailedException;
18
use DP\GameServer\GameServerBundle\Socket\Exception\NotConnectedException;
19
use DP\GameServer\GameServerBundle\Socket\Exception\RecvTimeoutException;
20
use DP\GameServer\SteamServerBundle\SteamQuery\Exception\ServerTimeoutException;
21
use DP\GameServer\GameServerBundle\Query\RconInterface;
22
23
class SourceRcon implements RconInterface
24
{
25
    protected $socket;
26
    protected $packetFactory;
27
    protected $rconPassword;
28
    protected $authenticated = null;
29
    protected $fullyConstructed = false;
30
    
31 View Code Duplication
    public function __construct($container, $host, $port, $rconPassword)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
32
    {
33
        /*$callback = function(Packet $packet, Socket $socket) {
34
            if (is_null($packet) || $packet->isEmpty()) return false;
35
            
36
            $remaining = $packet->getLong(false);
37
            $packet->setPos(4);
38
            $id = $packet->getLong(false);
39
            
40
            if ($remaining > 0) {
41
                $splittedPackets = new PacketCollection();
42
                $respId = null;
43
                
44
                do {
45
                    if (!$respId) {
46
                        $respId = $id;
47
                    }
48
                    elseif ($respId != $id) {
49
                        $packet = $socket->recv(false);
50
                        continue;
51
                    }
52
                    
53
                    $splittedPackets->add($packet->rewind());
54
                    $packet = $socket->recv(false, $remaining);
55
                    $remaining -= $packet->getLength();
56
                } while ($remaining > 0);
57
                
58
                return $splittedPackets->reassemble(
59
                    function(Packet $bigPacket, Packet $packet) {
60
                        if ($bigPacket->isEmpty()) {
61
                            $bigPacket->addContent($packet->getContent());
62
                            $bigPacket->setPos($packet->getLength()-2);
63
                        }
64
                        else {
65
                            $bigPacket->addContent($packet);
66
                        }
67
                        
68
                        return $bigPacket;
69
                    }
70
                )->rewind();
71
            }
72
            else {
73
                return $packet;
74
            }
75
        };*/
76
        $callbacks = array();
77
        // Permet de déterminé s'il s'agit d'une réponse multi-paquet
78
        $callbacks[Socket::MULTI_DETECTOR] = function(Packet $packet) {
79
            if (is_null($packet) || $packet->isEmpty()) return false;
80
            
81
            // Récupération de la longueur de la réponse
82
            $len = $packet->getLong(false);
83
            // Il faut rajouter 4 puisque la taille récupéré correspondant 
84
            // A la taille du paquet sans l'entier contenant la taille
85
            $remaining = $len - $packet->getLength() + 4;
86
            
87
            if ($remaining > 0) {                
88
                return true;
89
            }
90
            else {
91
                return false;
92
            }
93
        };
94
        // Permet de récupérer les différents paquets qui composent une réponse
95
        $callbacks[Socket::MULTI_RECEIVER] = function(Packet $packet, Socket $socket) {
96
            if (is_null($packet) || $packet->isEmpty()) return false;
97
            
98
            // Récupération de la longueur de la réponse
99
            $len = $packet->getLong(false);
100
            // Il faut rajouter 4 puisque la taille récupéré correspondant 
101
            // A la taille du paquet sans l'entier contenant la taille
102
            $remaining = $len - $packet->getLength() + 4;
103
            
104
            while ($remaining > 0) {
105
                // Récupération du prochain paquet et calcul de la taille restante à récupérer
106
                $newPacket = $socket->recv(false, $remaining);
107
                $remaining = $remaining - $newPacket->getLength();
108
109
                // Ajout du paquet au paquet originel
110
                $packet->setPos($packet->getLength() - 2);
111
                $packet->addContent($newPacket->getContent());
112
            }
113
            
114
            return $packet;
115
        };
116
        
117
        $this->rconPassword = $rconPassword;
118
        $this->socket = $container->get('socket')->getTCPSocket($host, $port, $callbacks);
119
        $this->packetFactory = $container->get('packet.factory.rcon.source');
120
    }
121
122
    /**
123
     * Permet de ne finaliser la création du rcon qu'en cas d'utilisation de celui-ci
124
     * Permet ainsi à la classe d'être instancié un certains nombre de fois sans pour autant être utilisé 
125
     * (utile pour le QueryInjector)
126
     */
127
    protected function fullConstruct()
128
    {
129
        $this->fullyConstructed = true;
130
        
131
        try {
132
            $this->socket->connect();
133
            $this->auth();
134
        }
135
        catch (ConnectionFailedException $e) {}
136
    }
137
    
138 View Code Duplication
    private function auth()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
    {
140
        if (!$this->fullyConstructed) {
141
            $this->fullConstruct();
142
        }
143
        
144
        if ($this->authenticated == null) {
145
            $id = null;
146
            $packet = $this->packetFactory->getAuthPacket($id, $this->rconPassword);
147
                        
148
            $this->socket->send($packet);
149
            $resp = $this->socket->recv(false);
150
            
151
            if ($resp->isEmpty()) {
152
                $this->authenticated = false;
153
                return;
154
            }
155
            
156
            $infos = $resp->extract(array(
157
                'size' => 'long', 
158
                'id' => 'long', 
159
                'type' => 'long', 
160
                's1' => 'string', 
161
                's2' => 'string'
162
            ));
163
            
164
            if ($infos['type'] == $this->packetFactory->SERVER_RESPONSE_VALUE) {
165
                $resp = $this->socket->recv(false);
166
                $infos = $resp->extract(array(
167
                    'size' => 'long', 
168
                    'id' => 'long', 
169
                    'type' => 'long', 
170
                    's1' => 'string', 
171
                    's2' => 'string'
172
                ));
173
            }
174
            
175
            if ($infos['id'] == $id && 
176
                $infos['type'] == $this->packetFactory->SERVER_AUTH_RESPONSE) {
177
                $this->authenticated = true;
178
            }
179
            else {
180
                $this->authenticated = false;
181
            }
182
        }
183
    }
184
    
185
    public function sendCmd($cmd)
186
    {
187
        if (!$this->fullyConstructed) {
188
            $this->fullConstruct();
189
        }
190
        
191
        if ($this->authenticated) {
192
            $id = null;
193
            $packet = $this->packetFactory->getCmdPacket($id, $cmd);
194
            
195
            $this->socket->send($packet);
196
            $resp = $this->recv();
197
            
198
            if ($resp == null) {
199
                return false;
200
            }
201
            
202
            $resp = $resp->rewind()->extract(array(
203
                'size' => 'long', 
204
                'id' => 'long', 
205
                'type' => 'long', 
206
                'body' => 'string', 
207
            ));
208
            
209 View Code Duplication
            if ($resp['id'] != $id || $resp['type'] != $this->packetFactory->SERVER_RESPONSE_VALUE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
                return false;
211
            }
212
            
213
            return $resp['body'];
214
        }
215
        else {
216
            return false;
217
        }
218
    }
219
    
220
    /**
221
     * Get mulitple packets from socket recv method
222
     * Return reassembled packets if there is reponses
223
     * Or return null if there is a RecvTimeoutException catched and any response recovered
224
     * before any content has been received.
225
     * 
226
     * @return \DP\GameServer\GameServerBundle\Socket\Packet|null
227
     */
228 View Code Duplication
    private function recv()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
229
    {
230
        $packets = new PacketCollection();
231
        
232
        do {
233
            try {
234
                $resp = $this->socket->recv();
235
                $packets->add($resp->rewind());
236
            }
237
            catch (RecvTimeoutException $e) {
238
                $resp = null;
239
            }
240
        } while ($resp != null);
241
        
242
        // Verif que tous les paquets ont bien été reçus
243
        // Si c'est le cas on renvoie les données reçus, sinon on renvoie rien
244
        if ($packets->count() > 0 && $this->verifyAllPacketsReceived()) {
245
            $packetFactory = $this->packetFactory;
246
247
            return $packets->reassemble(function (Packet $bigPacket, Packet $packet) use ($packetFactory) {
248
                if ($bigPacket->isEmpty()) {
249
                    $bigPacket->addContent($packet);
250
                }
251
                else {
252
                    $bigPacket->rewind();
253
254
                    // Ajout de la taille du packet au bigPacket
255
                    $packetSize = $packet->getLong(false);
256
                    $bigPacketSize = $bigPacket->getLong();
257
                    $newSize = $packetSize + $bigPacketSize;
258
259
                    $bigPacket->rewind()->addContent(
260
                        $packetFactory->transformLong($newSize)
261
                    );
262
263
                    // Ajout du contenu au bigPacket                
264
                    $bigPacket->setPos($bigPacket->getLength()-4)->addContent(
265
                        substr($packet->setPos(12)->getString(), 0, -4)
266
                    );
267
                }
268
269
                return $bigPacket;
270
            });
271
        }
272
        
273
        return null;
274
    }
275
    
276
    public function verifyAllPacketsReceived()
277
    {
278
        $id = null;
279
        $packet = $this->packetFactory->getEmptyResponsePacket($id);
280
        
281
        $this->socket->send($packet);
282
        $resp = $this->socket->recv(false);
283
        
284
        if ($resp == $packet) {
285
            $resp = $this->socket->recv(false);
286
            $resp->setPos(13);
287
            
288
            if ($resp->getByte() == 1) {
289
                return true;
290
            }
291
        }
292
        
293
        return false;
294
        
295
    }
296
}
297