Game server admin's helping the community setup and maintain great dedicated game servers.
----Home----Submit News ----Forum--------Guides----


Go Back   FPSadmin.com > BattleField > BattleField 3 > BF3 Remote Admin Tool Support

Reply
 
Thread Tools Display Modes
  #1  
Old 01-23-2012, 05:38 AM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
C++ How to set the RCON packet format

Hello guys!
I tried the last days to get a packet send to our BF3 Server. The first command i tried was login.plaintext password. But it wont work. I dont get any response from the BF3 Server, but im valid connected via TCP Socket.

This ist my first try to setup the packet to send commands to the BF3 rcon port:

Code:
unsigned char *RCON_Packet(String Command, int ServerData)
{

    unsigned char *Packet = (unsigned char*) malloc (13 + Command.Length() + 1); //Set Packet length (bytes)

    Packet[0] = Command.Length() + 9; //Packet Size (Integer)
    Packet[4] = 0; //Request Id (Integer)
    Packet[8] = ServerData; //SERVERDATA_EXECCOMMAND / SERVERDATA_AUTH (Integer)  //SERVERDATA_AUTH is currently 3


                                                                                     //SERVERDATA_EXECCOMMAND is currently 2
    for (int x = 1; x <= Command.Length(); x++)
    {
                Packet[12 + x] = Command[x];

    }


    return Packet;

}
Can anyone tell me what im doing wrong please?
Reply With Quote
  #2  
Old 01-29-2012, 12:24 PM
PapaCharlie9's Avatar
PapaCharlie9 PapaCharlie9 is offline
Senior Member
 
Join Date: Jan 2011
Posts: 155
Rep Power: 8
PapaCharlie9 is on a distinguished road
Quote:
Originally Posted by JogDiveZero View Post
This ist my first try to setup the packet to send commands to the BF3 rcon port:
I'm no BF3 protocol expert -- all I know is what I read in the docs. That said, I see a few things wrong in your code.

You are mixing up bytes and int32 in your code. For example, this code:

Packet[0] = Command.Length() + 9; //Packet Size (Integer)

... computes an int32 value (I'm not sure of sign of Length()), implicitly casts it to an unsigned char and assigns that value to the first byte in the packet. I think you intended to assign to the first 4 bytes of the packet, but that's not what your code does.

According to the doc, the first 4 bytes of a protocol packet are a bit indicating the origin of the command (server or client), another bit indicating request or response, and then bits 29...0 are used for the request ID.

At a higher level, why are you writing this code? There is an excellent open source platform for BF3 admin tools already out there called PRoCon. I don't know anything about C#, but it's close enough to Java that I can do whatever I need as a plugin, or hack existing plugins, or just use Insane Limits, a plugin platform that makes most things possible with a dozen lines of code.

At the very least, do yourself a favor and download the PRoCon source code at http://procon.codeplex.com/ and read the protocol management code to see how correct code should work.
Reply With Quote
  #3  
Old 01-29-2012, 01:22 PM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
hi !
thanks for your reply. i already figured everything out and my client works good now
Reply With Quote
  #4  
Old 01-29-2012, 06:33 PM
TimSad's Avatar
TimSad TimSad is offline
Member
 
Join Date: Nov 2008
Posts: 75
Rep Power: 10
TimSad is on a distinguished road
Can you guys point me in the right direction here?... http://www.fpsadmin.com/forum/showpo...25&postcount=5
__________________

Reply With Quote
  #5  
Old 01-29-2012, 07:54 PM
TimSad's Avatar
TimSad TimSad is offline
Member
 
Join Date: Nov 2008
Posts: 75
Rep Power: 10
TimSad is on a distinguished road
Yeah, I'm coming to believe that I'm doing everything right and that it's just a problem with the way I'm trying to use Winsock2.
__________________

Reply With Quote
  #6  
Old 01-31-2012, 06:46 PM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
@Tim Sad
here comes a C++ example how i make a valid rcon packet:

Code:
std::string make_packet( unsigned int Sequence, const std::vector<std::string>& words ) 
{ 
    // 1. Schritt: Calculating packet length 
    unsigned int TotalSize = 4;    // 4 Byte fr Paketheader 
    for( std::vector<std::string>::const_iterator it = words.begin(); it != words.end(); ++it ) 
    { 
        TotalSize    += 4;                // 4 Byte for word length 
        TotalSize    += it->size(); // count bytes in word
        TotalSize    += 1;                // 1 Byte for terminating 0 
    } 
    TotalSize += 4;    // 4 Byte count the words
    TotalSize += 4;    // 4 Byte Total size of the whole packet
 
    std::ostringstream oss; 
 
    // Write Sequence ID
    oss << static_cast<char>( Sequence & 0xff ) 
         << static_cast<char>( (Sequence >> 8) & 0xff ) 
         << static_cast<char>( (Sequence >> 16) & 0xff ) 
         << static_cast<char>( (Sequence >> 24) & 0xff ); 
 
    //Write total packet size
    oss << static_cast<char>( TotalSize & 0xff ) 
         << static_cast<char>( (TotalSize >> 8) & 0xff ) 
         << static_cast<char>( (TotalSize >> 16) & 0xff ) 
         << static_cast<char>( (TotalSize >> 24) & 0xff ); 
 
    // Write word count
    oss << static_cast<char>( words.size() & 0xff ) 
         << static_cast<char>( (words.size() >> 8) & 0xff ) 
         << static_cast<char>( (words.size() >> 16) & 0xff ) 
         << static_cast<char>( (words.size() >> 24) & 0xff ); 
 
    // Write words 
    for( std::vector<std::string>::const_iterator it = words.begin(); it != words.end(); ++it ) 
    { 
        // Summary of chars in the word 
        oss << static_cast<char>( it->size() & 0xff ) 
             << static_cast<char>( (it->size() >> 8) & 0xff ) 
             << static_cast<char>( (it->size() >> 16) & 0xff ) 
             << static_cast<char>( (it->size() >> 24) & 0xff ); 
 
        // Write word itself 
        oss << *it; 
 
        // Write terminating 0 
        oss << static_cast<char>( 0 ); 
    } 
    return oss.str(); 
}
Reply With Quote
  #7  
Old 01-31-2012, 11:50 PM
TimSad's Avatar
TimSad TimSad is offline
Member
 
Join Date: Nov 2008
Posts: 75
Rep Power: 10
TimSad is on a distinguished road
Thanks a bunch, man! I'll see if I can get this working now. If so, it means that somehow I was constructing packets incorrectly. If not, it would seem as if I need to learn a bit more about Winsock2 and programming with TCP protocol.
__________________

Reply With Quote
  #8  
Old 02-01-2012, 02:57 AM
TimSad's Avatar
TimSad TimSad is offline
Member
 
Join Date: Nov 2008
Posts: 75
Rep Power: 10
TimSad is on a distinguished road
Haha! It's working now! I used your function like this...

Code:
vector<std::string> myWords;
myWords.push_back("serverInfo");

string temp = make_packet(1, myWords);
char* mySendBuf = &temp[0];
  
// Send an initial buffer
iResult = send(ConnectSocket, mySendBuf, temp.size(), 0);
Then, I got a response. I received 243 bytes of data with the Winsock receive function...

Code:
do
{
  iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
  if (iResult > 0)
    printf("Bytes received: %d\n", iResult);
  else if (iResult == 0)
    printf("Connection closed\n");
  else
    printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
I seriously don't see what went wrong with my method of constructing a packet (I'll keep looking into it) but at least I've finally got a response now! Yay! Thanks very much, JogDiveZero!
__________________

Reply With Quote
  #9  
Old 02-01-2012, 05:40 AM
Kalms Kalms is offline
Senior Member
 
Join Date: Feb 2010
Posts: 262
Rep Power: 9
Kalms is on a distinguished road
You are using std::strings, and ostringstreams, to construct and contain a sequence of bytes.
This works as long as you don't try to put any 0x00 bytes into the sequence. Once you start doing so, you are on very shaky ground.

Either the resulting sequence will get cut off at the first 0x00 byte, or mystring.size() will be larger than strlen(mystring.c_str()). That way lies madness and bugs that are difficult to track down.

Besides, you are aware that the 'char' datatype may be either signed or unsigned, depending on which compiler you are using? Normally it is signed. This does not cause any problems for the code that builds the sequence, but may cause problems for the code that decodes a sequence into C++ datastructures.


You are better off using an std::vector<uint8_t> as your container, dropping the ostringstream, and using some custom code for constructing the sequence.
Reply With Quote
  #10  
Old 02-01-2012, 06:29 AM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
Hello Mr Kalms,
does it mean that any 0 in the whole sequence can interrupt the code at that point? im not right into it what you are talking about exactly. Can you give us an example at wich point the code may fail please?
Reply With Quote
  #11  
Old 02-01-2012, 07:01 AM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
Ahh, i think i know what you mean.
0x00 is a non value byte in hex. 0x00 will do
the same as /0 or /n. A termination leading byte
whithin strings.

I think this case will not be present in the
usage of sending commands or querys to
the server. Or do you think that case can happen
in the normal usage of a rcon task?
Reply With Quote
  #12  
Old 02-01-2012, 07:32 AM
Kalms Kalms is offline
Senior Member
 
Join Date: Feb 2010
Posts: 262
Rep Power: 9
Kalms is on a distinguished road
Exactly.

And ... what do you think happens when you attempt to encode the sequence nr 0x00000001?
Reply With Quote
  #13  
Old 02-01-2012, 02:33 PM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
I encode sequenz numbers like 1-123456
as a string and not hex 0x00000001. I can't
see the problem within rcon specific tasks
right now
Reply With Quote
  #14  
Old 02-01-2012, 05:46 PM
Kalms Kalms is offline
Senior Member
 
Join Date: Feb 2010
Posts: 262
Rep Power: 9
Kalms is on a distinguished road
Quoting from above,

Code:
    // Write Sequence ID
    oss << static_cast<char>( Sequence & 0xff ) 
         << static_cast<char>( (Sequence >> 8) & 0xff ) 
         << static_cast<char>( (Sequence >> 16) & 0xff ) 
         << static_cast<char>( (Sequence >> 24) & 0xff );
That bit right there takes a 32-byte integer, splits it up into 4 bytes, and stuffs each of the 4 bytes into an ostringstream object. Raw. So if Sequence == 0x00000001, the code will be stuffing 0x00's into the ostringstream.

Also quoting from above,

Code:
        // Write terminating 0 
        oss << static_cast<char>( 0 );
This will clearly stuff an 0x00 into the ostringstream.

Both these code sections violate the principle: do not stuff 0x00s into strings.
Reply With Quote
  #15  
Old 02-01-2012, 06:49 PM
JogDiveZero JogDiveZero is offline
Member
 
Join Date: Jan 2012
Posts: 64
Rep Power: 7
JogDiveZero is on a distinguished road
Now, i tried this:

Code:
std::vector<std::string> Words;
Words.push_back("login.plainText");
Words.push_back("mypassword");
std::string Packet = make_packet( 0x00000001, Words );
But it works.....

Also

Code:
 std::string Packet = make_packet( 1, Words );
works..........

Code:
 std::string Packet = make_packet( 0x00, Words );
works..........



I see the problem theoretical youre talking about. But it has no effect on the code right now
Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 12:10 AM.


Powered by: vBulletin Copyright ©2000, Jelsoft Enterprises Ltd.