[Delphi] Cannot Catch All Packets

07/30/2013 02:11 Sadronis#1
I'm working on a tool which receives packets from phconnector and send again to phconnector. I was working on getting charlist, getting mp/hp of the char when its loaded and they are done. However recently i cannot capture the packet '3020'. I was able to catch it but now i'm not able to do it again.

PHP Code:
data := stringtohex(socket.ReceiveText);  //where i receive whole packet
data := stringreplace(data' ''', [rfReplaceAll]);  //delete all spaces
size := hexatoint(copy(data,3,2)+copy(data12)); //get the size
opcode:=(copy(data,7,2)+copy(data52));  //this never gives me 3020
security:=copy(data,11,2)+copy(data92);  //security byte
listbox1.items.Add('['+inttostr(size)+'] ['+opcode+'] ['+security+']');
packetdata:=copy(data,13,size*2);  //this is the the data part of packet
listbox1.Items.Add('Data: 'packetdata);
listbox1.Items.add('------------------------'); 
An example of output:
PHP Code:
[16] [2001] [0000]
Dara0D004761746577617953657276657200 
But this doesnt seem like its right? What do i miss?
07/30/2013 11:02 qkuh#2
It is right.
Opcode 0x2001:
2 Bytes - ServerNameLen (here: 0x0D)
ServerNameLen Bytes - ServerName (here: GatewayServer)
2 Bytes - ServerId (here: 0x72)

If some packets are missing you should check if they are sticked together. This happens from time to time. I am not sure if phConnector handles that.

Sorry writing from my phone.
07/30/2013 11:36 Sadronis#3
Thank you ! As i can see 3020 packet's content seems in b602 and 30bf packet. And i think they are stricted together. I wonder how can i separate them? There is no example of separating stricted packets?
07/30/2013 19:44 qkuh#4
Just use the packet length and a loop to parse the sticked packets.
07/30/2013 20:05 lesderid#5
Quote:
Originally Posted by Sadronis View Post
Thank you ! As i can see 3020 packet's content seems in b602 and 30bf packet. And i think they are stricted together. I wonder how can i separate them? There is no example of separating stricted packets?
TCP is a low-level streaming protocol. The SRO packet protocol is built on top of TCP. This means that one physical (i.e. TCP) packet can contain more logical (i.e. SRO) packets. Substract the length (first 16 bits of the SRO packet's header) from each SRO packet received from the actual number of bytes received. If the result is above zero, there are multiple SRO packets in the TCP packet.
07/30/2013 21:14 Sadronis#6
I have been trying to do it when i saw your message. But i thought that merged packet can contain only 2 packet. I was wrong as i can see. Then i changed my code to;

Receive function:
PHP Code:
size := hexatoint(copy(data,3,2)+copy(data12));
opcode:=(copy(data,7,2)+copy(data52));
security:=copy(data,11,2)+copy(data92);
listbox1.items.Add('['+inttostr(size)+'] ['+opcode+'] ['+security+']');
packetdata:=copy(data,13,size*2);
otherdata:=copy(data,(size*2)+2,length(data));
if 
length(otherdata) > 1 then
begin
PacketMerged
(otherdata);
end
PacketMerged function;

PHP Code:
size := hexatoint(copy(data,3,2)+copy(data12));
opcode:=(copy(data,7,2)+copy(data52));
security:=copy(data,11,2)+copy(data92);
listbox1.items.Add('['+inttostr(size)+'] ['+opcode+'] ['+security+']');
packetdata:=copy(data,13,size*2);
otherdata:=copy(data,(size*2)+2,length(data));
if 
length(otherdata) > 1 then
begin
PacketMerged
(otherdata);
end
But it still doesn't find all of the 3020 packets. I cant see any problem right now. Do you see any logical mistake?
07/30/2013 21:28 qkuh#7
I cannot code in Delphi. But you got the size, opcode, security and packetdata of a packet. And you know how long the fields are. Substract this packet length from length(data). If the value is not zero continue parsing the packet.
07/30/2013 22:12 Sadronis#8
I can get every other packet without any problem. But this 3020 code doesn't appear sometimes. But instead of 3020 i get B602 code which contains char id. So does B602 a real packet or do i see it by mistake of any code?
07/30/2013 23:51 qkuh#9
I guess this opcode does not exist. Post the packet here. And send me your Skype name please.
07/31/2013 01:53 Sadronis#10
090002B6000001496B1C0000000000

This is what i receive. "01496B1C0000000000" this is the data part and 496B1C00 this part is the char_id from 3020
08/01/2013 15:54 Ehab.Hamed#11
I think your problem is receiving Text instead of receiving Buffer. try something like that
Code:
function TForm1.SocketRecive(Socket: TCustomWinSocket; var Buffer : Pointer): Integer;
var
  N : Integer;
begin
  FreeMem(Buffer);
  N := Socket.ReceiveLength;
  GetMem(Buffer, N);
  Socket.ReceiveBuf(Buffer^, N);
  Result := N;
end;
then in your socket onread event do
Code:
procedure TForm1.ClientSocketRead(Sender: TObject;  Socket: TCustomWinSocket);
var
  N : Integer;
  packet   : PPacket;
  Pd       : pointer;
  IsEnc    : Boolean;
begin

  N : Integer;
  Nw : Word;
  packet_size : integer;
  packet   : PPacket;
  P       : pointer;
  IsEnc    : Boolean;
begin
  // Read the data avaliable on the socket
  N := SocketRecive(Socket, P);
  
  try
    // Now handle the packets
    Packet := PPacket(P);
    IsEnc := ((Packet.Size and $8000) <> 0);
    case packet.opcode of
    $3020 : 
      do something here
    end;
  finally
    FreeMem(P);
  end;
end;
in your interface section you define the Packet record and pointer like that :

Code:
Type
  // Generic packet structure
  PPacket = ^TPacket;
  TPacket = packed Record
    Size            : WORD ;                      // Size of this packet.
    Opcode          : WORD ;                      // Opcode of this packet
    SecurityCount   : BYTE ;                      // Security count byte 
    SecurityCRC     : BYTE ;                      // Security crc 
    Data            : BYTE ;
  end;
08/01/2013 20:32 kevin_owner#12
To extend lesderid's answer. The packets "sticking" together is because of Nagle's algorithm to reduce the amount of overhead on small packets.

Also TCP only guarantees the order that you're receiving the packets. It doesn't guarantee that the packets are complete. So your code could work most of the time but it isn't very reliable.

A way (not the only one) to fix this is to append all received data to a second buffer. This way if you receive an incomplete packet or multiple packets at once it gets added to the second buffer.

Then read the buffer (First two bytes in the SRO protocol is always the size) and check if the buffer contains that amount of bytes. If so, then you have received a full packet and can read it. If it doesn't then you just wait for the rest of the packet to be received.

Note: The above method isn't the most optimal method to handle this situation but it was the only one I could think of right now. Maybe some else can give you a better method to handle this situation.
08/02/2013 14:39 Sadronis#13
Ehab.Hamed i think this looks better than my code. But i think it wont solve the sticked packets. I have managed seperating packets but again i have a problem with incomplete packets i think i'm going to make a check for if its completed or incomplete then if its incomplete i'm going to work on it. By the way thank you everybody :)
11/12/2013 18:52 Skullsoil#14
what was the opcode ?
11/25/2013 00:19 asuradoll#15
can you share your proxy of delphi version?