|
-
Dec 14th, 2010, 02:26 PM
#1
PHP to C# - Sockets, or whatever, I dunno
Hi,
Sorry for the confusing title, as will become clear shortly this is completely unfamiliar territory for me, so I have really no clue what I'm doing.
Anyway, I am trying to interact with a game server for Call of Duty: Black Ops, this is usually called 'remote console'. I had no idea where to start so I googled around a bit and found a complete web-based remote console implementation (I did not try it but I am assuming it works). Unfortunately, it is in PHP, about which I know absolutely nothing.
The most important file in the PHP implementation, I think, is this:
php Code:
<?php defined('SYSPATH') or die('No direct script access.'); /** * Remote console connection * * @author EpicLegion * @package rcon * @subpackage lib */ class Rcon { /** * Socket res * * @var resource */ protected $socket = NULL; /** * Password * * @var string */ protected $password = ''; /** * Host (IP) * * @var string */ protected $host = ''; /** * Serve port * @var int */ protected $port = 3074; /** * Constructor * * @param string $host * @param int $port * @param string $password */ public function __construct($host = '', $port = 3074, $password = '') { $this->host = $host; $this->port = $port; $this->password = $password; } /** * Send command * * @param string $command * @param bool $return_response * @throws Exception * @return mixed */ public function command($command, $return_response = TRUE) { // No connection if(!$this->socket OR !is_resource($this->socket)) { throw new Exception('You must connect to remote console before issuing commands'); } // Send command fwrite($this->socket, "\xff\xff\xff\xff\x00".$this->password.' '.$command."\x00"); // Wait for response? if($return_response) { // Retrieve reponse $response = $this->get_response(); // Invalid password? if(trim($response) == 'Invalid password.') { throw new Exception('Invalid remote console password.'); } return $response; } } /** * Connect to rcon * * @throws Exception */ public function connect() { // Errors $errno = 0; $errstr = ''; // Open socket $this->socket = fsockopen('udp://'.$this->host, $this->port, $errno, $errstr, 5); // Invalid? if(!$this->socket) { throw new Exception('Cannot connect to remote console'); } } /** * Disconnect */ public function disconnect() { fclose($this->socket); } /** * Read response * * @return string */ public function get_response() { // Var containing response $response = ''; // Set socket timeout stream_set_timeout($this->socket, 0, 7e5); // Lol how rare do { // Read 8kb $stream_read = fread($this->socket, 8192); // End of response? if(strpos($stream_read, "\x00") !== FALSE) { // Cut $stream_read = substr($stream_read, 0, strpos($stream_read, "\x00")); } // Get socket info $stream_info = stream_get_meta_data($this->socket); // Append $response .= substr(trim($stream_read, "\x0a"), 11); } while(!$stream_info['timed_out']); // Return return $response; } /** * Get socket resource * * @return resource */ public function get_socket() { return $this->socket; } /** * Set RCON password * * @param string $password */ public function set_password($password = '') { $this->password = $password; } /** * Set server connection details * * @param string $host * @param int $port */ public function set_server_info($host = '', $port = 3074) { $this->host = $host; $this->port = $port; } }
I can logically split this file into three parts:
- 'Properties' like Host, Port and Password, including setters / getters / constructor, etc. I can manage this obviously.
- Connecting and sending commands to the host, as well as receiving a response. This is what I'm having trouble with.
- Parsing the response into readable chunks. I am not here yet (though I might need some help with that too), I'd rather get item 2 working first.
So, I looked around a bit and found the UdpClient class. The command to connect in the PHP source uses "udp:// ..." so I thought that would be a good place to start.
I wrote this class as a translation of the PHP code, at least the connecting and sending a command part:
csharp Code:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace BlackOpsRconTest { public class Rcon { public Rcon(string host, string password) { this.Host = host; this.Port = 3074; // I don't think this can ever change for this game this.Password = password; client = new UdpClient(); } public string Host { get; set; } public int Port { get; set; } public string Password { get; set; } private readonly UdpClient client; private static bool messageReceived = false; public void Connect() { client.Connect(this.Host, this.Port); } public void Disconnect() { client.Close(); } public void SendCommand(string command) { // preCommand is supposed to be the '\xff\xff\xff\xff\x00' stuff... string preCommand = new String(Convert.ToChar(0xff), 4); preCommand += Convert.ToChar(0x00); // get the bytes to send // this spells \xff\xff\xff\xff\x00<password> <command>\x00 // as in the PHP source... var commandBytes = Encoding.ASCII.GetBytes(String.Format("{0}{1} {2}{3}", preCommand, this.Password, command, Convert.ToChar(0x00))); // Send it! client.Send(commandBytes, commandBytes.Length); // Now listen for response. IPEndPoint e = new IPEndPoint(IPAddress.Any, this.Port); UdpState s = new UdpState(); s.e = e; s.u = client; Console.WriteLine("listening for messages"); client.BeginReceive(new AsyncCallback(ReceiveCallback), s); // Do some work while we wait for a message. For this example, // we'll just sleep while (!messageReceived) { Thread.Sleep(100); } } private static void ReceiveCallback(IAsyncResult ar) { UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u; IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e; Byte[] receiveBytes = u.EndReceive(ar, ref e); string receiveString = Encoding.ASCII.GetString(receiveBytes); Console.WriteLine("Received: {0}", receiveString); messageReceived = true; } struct UdpState { public UdpClient u; public IPEndPoint e; } } }
The sending part is mostly 'made up', I assumed that the \xff and \x00 stuff was hex so I used Convert.ToChar to convert those hex numbers to characters and insert them before the actual command to send, just like the PHP source code does (at least: i think it does that, I may be completely wrong here as I have no clue how PHP works).
The receiving part is straight from MSDN.
I am trying to use it as such:
csharp Code:
Rcon r = new Rcon("173.199.111.167", "mypassword"); r.Connect(); r.SendCommand("teamstatus");
"teamstatus" is supposed to be a valid command that should result in the server returning the players and their status (name, id, score, ping, etc).
When I try to run this, nothing happens. The console displays "listening for messages" but nothing after that. I waited a few minutes but no response ever came.
What am I doing wrong? As I said, I am completely new to this (both the PHP and to 'socket' stuff in general) so I really have no clue what I'm doing. At this point basically I'm trying to hack together a translation and I'm just looking to get A response, no matter what.
Thanks!
-
Dec 15th, 2010, 03:09 AM
#2
Re: PHP to C# - Sockets, or whatever, I dunno
Why not post this in the PHP section? Penagate is fluent with both languages (php and C#), I believe he will be of help.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|