RCON Protocol on PB

Just starting out? Need help? Post your questions and find answers here.
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Post by cas »

registrymechanic22 wrote: PB gives the error on:
Length = ReceiveNetworkData(Con, *Bufffer, 8192)
error: The specified buffer is 0.
I am much grateful to you for your help!!!
Remove one "f" from *Bufffer so it will look like this:

Code: Select all

Length = ReceiveNetworkData(Con, *Buffer, 8192)
and look in the manual for EnableExplicit
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

cas wrote:
registrymechanic22 wrote: PB gives the error on:
Length = ReceiveNetworkData(Con, *Bufffer, 8192)
error: The specified buffer is 0.
I am much grateful to you for your help!!!
Remove one "f" from *Bufffer so it will look like this:

Code: Select all

Length = ReceiveNetworkData(Con, *Buffer, 8192)
and look in the manual for EnableExplicit
Yes, thanks, I saw, corrected ...
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

Hi infratec.

now gives the following lines:
"Received something"
"Authentication failed"

P.S.: CommandResponse=0
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Post by infratec »

Hi registrymechanic22,

after reading in your provided link,
I noticed that the first answer to the auth request is not always the
auth response.

So I modified the sourcecode again.
I also added more debug output.

So test it and use -v -v as additional parameters, so that you can see
the hex listing as output.


Best regards,

Bernd
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

infratec wrote: So test it and use -v -v as additional parameters, so that you can see
the hex listing as output.
*************************************
Server : 172.16.254.10
Port : 27016
Password: mypass
Command : status
ID : 0
Verbose : 2
************************************

Sending:
10 00 00 00 00 00 00 00 - 03 00 00 00 6D 79 70 61 ........ ....mypa
73 73 00 00 ss..

Received:
0A 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 ........ .......

Received something

Authentication failed
*********************************************************


but if the increase in "Procedure RConReceive"

Delay(10) at >Delay(100) =>
=>
Received:
0A 00 00 00 00 00 00 00 - 00 00 00 00 00 0A 00 ........ ........
00 00 00 00 00 00 02 00 - 00 00 00 00 00 ........ .....
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Post by infratec »

Hi,

since it was impossible to test something, I decided to write a small
RCon emulator:

Code: Select all

EnableExplicit


#SERVERDATA_AUTH = 3
#SERVERDATA_AUTH_RESPONSE = 2
#SERVERDATA_EXECCOMMAND = 2
#SERVERDATA_RESPONSE_VALUE = 0


Structure RCONPacketHeaderStructure
  Size.l
  ID.l
  Type.l
EndStructure


Procedure AnswerAuth(ClientID.i, RConID.i)
  
  Protected *Buf.RCONPacketHeaderStructure
  
  
  *Buf = AllocateMemory(14)
  If *Buf
    *Buf\Size = 10
    *Buf\ID = RConID
    *Buf\Type = #SERVERDATA_RESPONSE_VALUE
    
    AddGadgetItem(0, -1, "Sending auth 1 to " + IPString(GetClientIP(ClientID)))
    
    SendNetworkData(ClientID, *Buf, 14)
    
    Delay(100)
    
    *Buf\Type = #SERVERDATA_AUTH_RESPONSE
    AddGadgetItem(0, -1, "Sending auth 2 to " + IPString(GetClientIP(ClientID)))
    SendNetworkData(ClientID, *Buf, 14)
    
    FreeMemory(*Buf)
  EndIf
  
EndProcedure




Procedure AnswerDataShort(ClientID, RConID)
  
  Protected Length.i, *Buf.RCONPacketHeaderStructure
  
  
  *Buf = AllocateMemory(40)
  If *Buf
    Length = SizeOf(RCONPacketHeaderStructure)
    
    PokeS(*Buf + Length, "A short answer", -1, #PB_Ascii)
    Length + StringByteLength("A short answer", #PB_Ascii) + 1
    
    PokeS(*Buf + Length, "", -1, #PB_Ascii)
    Length + 1
    
    *Buf\Size = Length - SizeOf(Long)
    *Buf\ID = RConID
    *Buf\Type = #SERVERDATA_RESPONSE_VALUE
    
    AddGadgetItem(0, -1, "Sending a short answer to " + IPString(GetClientIP(ClientID)))
    SendNetworkData(ClientID, *Buf, Length)
    
    FreeMemory(*Buf)
  EndIf
  
EndProcedure




Procedure AnswerDataSplit(ClientID.i, RConID.i)
  
  Protected Length.i, *Buf.RCONPacketHeaderStructure
  
  
  *Buf = AllocateMemory(40)
  If *Buf
    Length = SizeOf(RCONPacketHeaderStructure)
    
    PokeS(*Buf + Length, "Packet is splitted", -1, #PB_Ascii)
    Length + StringByteLength("Packet is splitted", #PB_Ascii) + 1
    
    PokeS(*Buf + Length, "", -1, #PB_Ascii)
    Length + 1
    
    *Buf\Size = Length - SizeOf(Long)
    *Buf\ID = RConID
    *Buf\Type = #SERVERDATA_RESPONSE_VALUE
    
    AddGadgetItem(0, -1, "Sending an answer in 2 pieces to " + IPString(GetClientIP(ClientID)))
    
    SendNetworkData(ClientID, *Buf, Length - 3)
    Delay(100)
    SendNetworkData(ClientID, *Buf + Length - 3, 3)
    
    FreeMemory(*Buf)
  EndIf
  
EndProcedure




Procedure AnswerDataLong(ClientID.i, RConID.i)
  
  Protected Length.i, *Buf.RCONPacketHeaderStructure, String$, i.i, j.i
  
  
  *Buf = AllocateMemory(4200)
  If *Buf
    Length = SizeOf(RCONPacketHeaderStructure)
    
    For i = 1 To 100
      For j = 65 To 90
        String$ + Chr(j)
      Next j
      String$ + #CRLF$
    Next i
    
    PokeS(*Buf + Length, String$, -1, #PB_Ascii)
    Length + StringByteLength(String$, #PB_Ascii) + 1
    
    PokeS(*Buf + Length, "", -1, #PB_Ascii)
    Length + 1
    
    *Buf\Size = Length - SizeOf(Long)
    *Buf\ID = RConID
    *Buf\Type = #SERVERDATA_RESPONSE_VALUE
    
    AddGadgetItem(0, -1, "Sending a long answer to " + IPString(GetClientIP(ClientID)))
    
    SendNetworkData(ClientID, *Buf, Length) 
    
    FreeMemory(*Buf)
  EndIf
  
EndProcedure



;-main
Define *Buffer.RCONPacketHeaderStructure, SEvent.i, ClientID.i


If InitNetwork()
  
  If CreateNetworkServer(0, 27015)
    
    If OpenWindow(0, 0, 0, 350, 300, "RCon Server Emulator V1.10 by Infratec", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget)
      
      TextGadget(1, 10, 10, 280, 20, "The server is listening on port 27015")
      TextGadget(2, 10, 30, 280, 20, "You can send an authentication request")
      TextGadget(3, 10, 50, 280, 20, "You can send the following comands:")
      TextGadget(4, 10, 70, 280, 20, "split     - generates a short message in 2 packets")
      TextGadget(5, 10, 90, 280, 20, "long      - generates a long message in many packets")
      TextGadget(6, 10, 110, 280, 20, "all other - generates a short message in one packet")
      
      EditorGadget(0, 10, 130 , 330, 160, #PB_Editor_ReadOnly)
      
      *Buffer = AllocateMemory(1024)
      If *Buffer
        
        Repeat
          
          SEvent = NetworkServerEvent()
          
          If SEvent
            
            ClientID = EventClient()
            
            Select SEvent
              Case #PB_NetworkEvent_Connect
                ClearGadgetItems(0)
                AddGadgetItem(0, -1, "A new client has connected: "+ IPString(GetClientIP(ClientID)))
                
              Case #PB_NetworkEvent_Data
                ReceiveNetworkData(ClientID, *Buffer, 1024)
                
                Select *Buffer\Type
                  Case #SERVERDATA_AUTH
                    AddGadgetItem(0, -1, "Client "+ IPString(GetClientIP(ClientID)) +" has send an auth request")
                    AnswerAuth(ClientID, PeekL(*Buffer + 4))
                  
                  Case #SERVERDATA_EXECCOMMAND
                    AddGadgetItem(0, -1, "Client "+ IPString(GetClientIP(ClientID)) +" has the command: " + PeekS(*Buffer + 12))
                    Select PeekS(*Buffer + SizeOf(RCONPacketHeaderStructure), -1, #PB_Ascii)
                      Case "split"
                        AnswerDataSplit(ClientID, *Buffer\ID)
                        
                      Case "long"
                        AnswerDataLong(ClientID, *Buffer\ID)
                        
                      Default
                        AnswerDataShort(ClientID, *Buffer\ID)
                        
                    EndSelect
                EndSelect
                
              Case #PB_NetworkEvent_Disconnect
                AddGadgetItem(0, -1, "The client has closed the connection.")
                
            EndSelect
            
          Else
            Delay(10)   ; to avoid 100% CPU load!
          EndIf
          
        Until WindowEvent() = #PB_Event_CloseWindow
        
        FreeMemory(*Buffer)
        
        CloseNetworkServer(0)
        
      EndIf
    EndIf
  EndIf
EndIf


Now the modified code on page 1 should work.
It works with this emulator.

If you want to send something with spaces inside do it this way:

RCon -p password "This is the command I want to send"


Best regards,

Bernd

P.S.: You owe me a beer now :!:
Last edited by infratec on Wed Dec 23, 2015 11:02 pm, edited 6 times in total.
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

infratec wrote:Hi,
P.S.: You owe me a beer now :!:
!!!!!!!!!!!!
super, great work, many thanks to you !!!!!!!
you are super_brain!!!!!!
this protocol, ~1/40 part of my program, without it my program would not make sense.......


About the beer: :P
1) Tell me by webmoney, which in rubles (or Yandex Money)
2) the price of beer that you drink!!!

Once again, thank you very much!! :D
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

sorry, but another small question:
"Game server" replies a few packages (more information) on one request (command).
in the code information is dropped,
that need to add so can take from the "game server" a lot of packages?????

of RCON format:
"SERVERDATA_RESPONSE_VALUE is sent in response to a SERVERDATA_EXECCOMMAND command. string1 contains the response to the command and string2 is null (""). string1 is at most 4096 characters, so a single SERVERDATA_EXECCOMMAND command may result in multiple SERVERDATA_RESPONSE_VALUE response packets.
Make sure that you code the ability to handle multiple response "packets". With a 64-player server, it will use these commonly for status commands (for instance), just as HLDS often did. Also, keep in mind that you won't be able to read the whole "packet" at one time -- you need to keep reading in a loop until you receive the entire packet before processing it. "
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Post by infratec »

Hi,

to test this I modified my 'emulator' above, and as result I changed the code on page 1.

To test the function you can run rcon against the emu with:

rcon -p passwrd test -v -v

You can see than, that the result comes out of 2 packets.
I hope it works now also in reality.

Best regards,

Bernd
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

Hi infratec.

there is an error:
ProcedureReturn Result (in Procedure RConProcessResponse):
can not access memory (error reading on adress ...)

-v -v:
Server : 172.16.254.10
Port : 27016
Password: mypass
Command : status
ID : 0
Verbose : 2

RConSend
Sending:
10 00 00 00 00 00 00 00 - 03 00 00 00 6D 79 70 61 ........ ....mypa
73 73 00 00 ss..

RConProcessResponse
RConReceive
Received:
0A 00 00 00 00 00 00 00 - 00 00 00 00 00 00 ........ .......

Received something

RConReceive
Received:
0A 00 00 00 00 00 00 00 - 02 00 00 00 00 00 ........ .......

Password accepted
RConSend
Sending:
10 00 00 00 00 00 00 00 - 02 00 00 00 73 74 61 74 ........ ....stat
75 73 00 00 us..

RConProcessResponse
RConReceive
Received:
4B 03 00 00 00 00 00 - 00 00 00 00 68 6F 73 74
........................
Here the full result of the command status
a lot of lines!
........................

Received something
hostname: CS:Source|DEATHMATCH
version : 1.0.0.34/7 3698 secure
udp/ip : 172.16.254.10:27016
map : de_nuke at:
RCon answer:
hostname: CS:Source|DEATHMATCH
version : 1.0.0.34/7 3698 secure
udp/ip : 172.16.254.10:27016
map : de_nuke at:

****************************************************
in hex show full, but "PrintN" (in console) is issued does not fully.


P.S.: so is the result of the command "status" to the "console game server" and this code:
http://depositfiles.com/files/y1grgqf2q
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Post by infratec »

Good morning,

I changed the emu and also the code of rcon.

now you can test 3 things:

rcon -p password test
rcon -p password split
rcon -p password long

It works now with long answers (I hope so)

Bernd
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

infratec wrote:Good morning,
I changed the emu and also the code of rcon.
It works now with long answers (I hope so)
Bernd
good time of day, infratec
Once again thank you
Thank You very much!!!!!
works fine!
I still would like to know your ruble account in vebmaney :!:
Thank you friend!
:D
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Post by infratec »

Hi,

the stuff with 'you owe me a beer' was just a choke :!:

In reality I don't drink alcohol :lol:


I'm glad, that I can help here someone, because when I ask something,
I always got a response from one of the friendly forum members.

So this is my tribute to the forum.

And now my wife means that I should do the usual homework instead of
sitting always in front of the PC :cry:


Best regards and happy coding,

Bernd
registrymechanic22
Enthusiast
Enthusiast
Posts: 176
Joined: Sun Jun 28, 2009 7:07 pm
Location: RUS

Post by registrymechanic22 »

not necessarily alcohol, you can juice with vitamins!
you can patent the program on PB :D
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Post by infratec »

Hi, my last favour for you:

Code: Select all

;
; RConWin
;

EnableExplicit

#SERVERDATA_AUTH = 3
#SERVERDATA_AUTH_RESPONSE = 2
#SERVERDATA_EXECCOMMAND = 2
#SERVERDATA_RESPONSE_VALUE = 0


Structure RCONPacketHeaderStructure
  Size.l
  ID.l
  Type.l
EndStructure


Procedure.i RConSend(Con, ID.l, Type.l, Str1$, Str2$="")
  
  Protected Result.i, PacketSize.l, *Buffer.RCONPacketHeaderStructure
  
  
  PacketSize = SizeOf(RCONPacketHeaderStructure) + StringByteLength(Str1$, #PB_Ascii) + 1 + StringByteLength(Str2$, #PB_Ascii) + 1 ; + 1s for the terminating 0s
  
  *Buffer = AllocateMemory(PacketSize)
  If *Buffer
    *Buffer\Size = PacketSize - SizeOf(Long)
    *Buffer\ID = ID
    *Buffer\Type = Type
    PokeS(*Buffer + SizeOf(RCONPacketHeaderStructure), Str1$, -1, #PB_Ascii)
    PokeS(*Buffer + SizeOf(RCONPacketHeaderStructure) + StringByteLength(Str1$, #PB_Ascii) + 1, Str2$, -1, #PB_Ascii) ; + 1 for the terminating 0 of Str1$
    
    Result = SendNetworkData(Con, *Buffer, PacketSize)
    
    FreeMemory(*Buffer)
    
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




Procedure.i RConReceive(Con, *ID, *CommandResponse, *Str1, *Str2, MaxWait)
  
  Protected Result.i, Answer.i, BuffPtr.i, Received.i, Length.i, *Buffer.RCONPacketHeaderStructure
  
  
  *Buffer = AllocateMemory(8192)
  If *Buffer
    
    Repeat
      
      Select NetworkClientEvent(Con)
        Case #PB_NetworkEvent_None
          Delay(10)
          MaxWait - 10
          
        Case #PB_NetworkEvent_Data
          Length = ReceiveNetworkData(Con, *Buffer + BuffPtr, 8192 - BuffPtr)
          If Length
            
            Received + Length
            
            If Result = 0 And Length > 3
              Result = *Buffer\Size
            EndIf
            
            If Received >= Result + 4
              
              PokeL(*ID, *Buffer\ID)
              PokeL(*CommandResponse, *Buffer\Type)
              PokeS(*Str1, PeekS(*Buffer + 12, -1, #PB_Ascii), -1, #PB_Ascii)
              PokeS(*Str2, PeekS(*Buffer + 12 + StringByteLength(PeekS(*Buffer + 12), #PB_Ascii) + 1), -1, #PB_Ascii)
              
              Answer = #True
              
            EndIf
            
            BuffPtr + Length
            
          EndIf
          
        Case #PB_NetworkEvent_Disconnect
          Break
          
      EndSelect
      
    Until MaxWait <= 0 Or Answer
    
    FreeMemory(*Buffer)
    
    If MaxWait < 0
      MessageRequester("Error", "Receive timeout!")
      Result = 0
    EndIf
    
    If Not Answer
      Result = 0
    EndIf
    
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




Procedure RConProcessResponse(Con, OurID, CommandExpectedAnswer, EditGadgetNo)
  
  Protected Result.i, ID.l, CommandResponse.l, *Str1, *Str2
  
  
  *Str1 = AllocateMemory(4096)
  If *Str1
    *Str2 = AllocateMemory(4096)
    If *Str2
      While RConReceive(Con, @ID, @CommandResponse, *Str1, *Str2, 1000) > 0
        
        If CommandResponse = CommandExpectedAnswer
          
          Select CommandResponse
            
            Case #SERVERDATA_AUTH_RESPONSE
              If ID = OurID
                Result = 1
              ElseIf ID = -1
                AddGadgetItem(EditGadgetNo, -1, "Password refused")
              Else
                AddGadgetItem(EditGadgetNo, -1, "Bad Auth Response ID: " + Str(ID))
              EndIf
              
            Case #SERVERDATA_RESPONSE_VALUE
              AddGadgetItem(EditGadgetNo, -1, PeekS(*Str1, -1, #PB_Ascii))
              Result = 2
              
            Default
              AddGadgetItem(EditGadgetNo, -1, "Unexpected command response: " + Str(CommandResponse))
              
          EndSelect
          
          Break
          
        EndIf
        
      Wend
      FreeMemory(*Str2)
    EndIf
    FreeMemory(*Str1)
  EndIf
    
  ProcedureReturn Result
  
EndProcedure



Procedure Send(Server$, Port, OurID, Passwd$, Command$, EditGadgetNo)
  
  Protected Con.i
  
  
  Con = OpenNetworkConnection(Server$, Port, #PB_Network_TCP)
  If Con
    
    If RconSend(Con, OurID, #SERVERDATA_AUTH, Passwd$, "")
      If RConProcessResponse(Con, OurID, #SERVERDATA_AUTH_RESPONSE, EditGadgetNo) = 1    
        If RConSend(Con, OurID, #SERVERDATA_EXECCOMMAND, Command$, "")
          If RConProcessResponse(Con, OurID, #SERVERDATA_RESPONSE_VALUE, EditGadgetNo) <> 2
            MessageRequester("Error", "No answer received For: " + Command$)
          EndIf
        Else
          MessageRequester("Error", "Was Not possible To send: " + Command$)
        EndIf
      Else
        MessageRequester("Error", "Authentication failed")
      EndIf
    Else
      MessageRequester("Error", "Send failed")
    EndIf
    
    CloseNetworkConnection(Con)
    
  Else
    MessageRequester("Error", "Was Not able To establish a connection To " + Server$ + " at port " + Str(Port))
  EndIf
  
EndProcedure



Define EventID.i


If InitNetwork()

 If OpenWindow(0, 0, 0, 400, 440, "RConWin V1.10 by Infratec", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget)
  
  TextGadget(0, 10, 10, 60, 20, "Server")
  StringGadget(1, 80, 10, 100, 20, "127.0.0.1")
  
  TextGadget(2, 200, 10, 60, 20, "Port")
  StringGadget(3, 290, 10, 100, 20, "27015", #PB_String_Numeric)
  
  TextGadget(4, 10, 30, 60, 20, "Password")
  StringGadget(5, 80, 30, 100, 20, "", #PB_String_Password)
  
  TextGadget(6, 200, 30, 60, 20, "ID")
  StringGadget(7, 290, 30, 100, 20, "0", #PB_String_Numeric)
  
  TextGadget(8, 10, 70, 60, 20, "Command")
  StringGadget(9, 80, 70, 310, 20, "")
  
  ButtonGadget(100, 10, 100, 380, 20, "Send")
  
  EditorGadget(200, 10, 130, 380, 300, #PB_Editor_ReadOnly)
  
  Repeat
   
   EventID = WaitWindowEvent() 
   
   If EventID = #PB_Event_Gadget
    
    Select EventGadget()
     
     Case 100     
      ClearGadgetItems(200)
     ;Send(Server$, Port, OurID, Passwd$, Command$, EditGadgetNo)
      Send(GetGadgetText(1), Val(GetGadgetText(3)), Val(GetGadgetText(7)), GetGadgetText(5), GetGadgetText(9), 200)
      
    EndSelect
    
   EndIf
   
  Until EventID = #PB_Event_CloseWindow
  
 EndIf
 
Else
 MessageRequester("Error", "Was not able to initialize the network!")
EndIf

Best regards,

Bernd
Last edited by infratec on Wed Dec 23, 2015 10:23 pm, edited 3 times in total.
Post Reply