FPSadmin.com (http://www.fpsadmin.com/forum/index.php)
-   BF3 Remote Admin Tool Support (http://www.fpsadmin.com/forum/forumdisplay.php?f=155)
-   -   C++ How to set the RCON packet format (http://www.fpsadmin.com/forum/showthread.php?t=24280)

JogDiveZero 01-23-2012 05:38 AM

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:


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?

PapaCharlie9 01-29-2012 12:24 PM


Originally Posted by JogDiveZero (Post 108081)
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.

JogDiveZero 01-29-2012 01:22 PM

hi !
thanks for your reply. i already figured everything out and my client works good now

TimSad 01-29-2012 06:33 PM

Can you guys point me in the right direction here?... http://www.fpsadmin.com/forum/showpo...25&postcount=5

TimSad 01-29-2012 07:54 PM

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.

JogDiveZero 01-31-2012 06:46 PM

@Tim Sad
here comes a C++ example how i make a valid rcon packet:


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();

TimSad 01-31-2012 11:50 PM

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.

TimSad 02-01-2012 02:57 AM

Haha! It's working now! I used your function like this...


vector<std::string> myWords;

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...


  iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
  if (iResult > 0)
    printf("Bytes received: %d\n", iResult);
  else if (iResult == 0)
    printf("Connection closed\n");
    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!

Kalms 02-01-2012 05:40 AM

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.

JogDiveZero 02-01-2012 06:29 AM

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?

JogDiveZero 02-01-2012 07:01 AM

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?

Kalms 02-01-2012 07:32 AM


And ... what do you think happens when you attempt to encode the sequence nr 0x00000001?

JogDiveZero 02-01-2012 02:33 PM

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

Kalms 02-01-2012 05:46 PM

Quoting from above,


    // 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,


        // 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.

JogDiveZero 02-01-2012 06:49 PM

Now, i tried this:


std::vector<std::string> Words;
std::string Packet = make_packet( 0x00000001, Words );

But it works.....



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


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

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

All times are GMT -4. The time now is 01:45 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Creative Commons License
This work by www.fpsadmin.com is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
About The real Rudedog