ImtsSrl/KUKAVARPROXY

What does Split message means ?

Opened this issue · 2 comments

Hello,

I'm working on a C# client for KukavarProxy. So far I came up with a yet almost working solution using the sparse info I've found on the net about this tool (specially here).

My first question is would you be able to share in few lines the structure of the TCP packets that we should adopt to discuss with KukavarProxy ? For readquery, writequery and answer ? So far, I came up with this :

readquery

  • 2 bytes ID (uint16)
  • 2 bytes content length (uint16)
  • 1 byte for read (0) or write (1) mode
  • 2 bytes for the variable name length (uint16)
  • N bytes for the variable name to be read (ASCII -> bytes)

writequery

  • 2 bytes ID (uint16)
  • 2 bytes content length (uint16)
  • 1 byte for read (0) or write (1) mode
  • 2 bytes for the variable name length (uint16)
  • N bytes for the variable name to be read (ASCII -> bytes)
  • 2 bytes for the variable value length (uint16)
  • M bytes for the variable value to be written (ASCII -> bytes)

answer

  • 2 bytes ID (uint16)
  • 2 bytes content length (uint16)
  • 1 byte for read (0) or write (1) mode
  • 2 bytes for the variable value length (uint16)
  • M bytes for the variable value to be written (ASCII -> bytes)
  • 3 bytes tail [0, 1, 1]

=> Can you confirm I've correctly understood all this ?
=> Can you tell us more about the tail ? Is it always 011 ? Does it have any meaning or is it just a separator ?

=> When I send very fast requests to the server, In the debug window I see some messages are "Split". When I read the answers back, wherever a message were marked "Split" the Id is not incremented correctly. How can I prevent this to happen other than slowing down my queries ?

This what I send to the proxy :

Query 1 : 01 03 0 00
Query 2 : 02 03 0 00
Query 3 : 03 03 0 00
Query 4 : 04 03 0 00
Query 5 : 05 03 0 00 => Message Split
Query 6 : 06 03 0 00 => Message Split
Query 7 : 07 03 0 00
Query 8 : 08 03 0 00 => Message Split
Query 9 : 09 03 0 00 => Message Split
Query 10 : 10 03 0 00

When I read back the stream I get :

Msg[1] with Id = 1 : 01 06 0 00 110 
Msg[2] with Id = 2 :  02 06 0 00 110 
Msg[3] with Id = 3 :  03 06 0 00 110  
Msg[4] with Id = 4 :  04 06 0 00 110 
Msg[5] with Id = 4 :  04 06 0 00 110 
Msg[6] with Id = 4 :  04 06 0 00 110 
Msg[7] with Id = 7 :  07 06 0 00 110 
Msg[8] with Id = 7 :  07 06 0 00 110 
Msg[9] with Id = 7 :  07 06 0 00 110 
Msg[10] with Id = 10 :  10 06 0 00 110 

capture d ecran 2019-01-25 a 11 44 26
capture d ecran 2019-01-25 a 12 35 59

Ok, so looking carefully at the code I think I effectively found a bug !

Split message is when the buffer is filled with several messages so the byte stream is "splitted" between each messages. Nothing wrong with that.

However, while the variable nMsg is correctly incremented, the string to write is built each time with sMsgID which is set at the beginning of the loop but is never updated when splits occurred.

I'll try to make a pull request for that next week.

Private Sub sockServer_Read(Index As Integer, DataLength As Integer, IsUrgent As Integer)
    Dim strBuffer As String
    Dim cchBuffer As Integer
    
    Static bReadPending As Boolean
    
    On Error GoTo errRead
    
    ' read the first 2048 bytes in the socket buffer 
    ' put the received bytes (n <= 2048) in strBuffer
    cchBuffer = sockServer(Index).Read(strBuffer, 2048)
   
    If (cchBuffer < 0) Then
        
        'If a would block error occurs exit the sub and let
        'another read event read when the client is ready
        If (sockServer(Index).LastError = WSAEWOULDBLOCK) Then
            Exit Sub
        End If
        
        'If an in progress error occurs exit the sub and let
        'another read event read when the client is ready
        If (sockServer(Index).LastError = WSAEINPROGRESS) Then
            Exit Sub
        End If

        'There has been an error in the read
        'print the error and quit
        DropClient Index, "Error occurred durring the read event: Error #", sockServer(Index).LastError
        UpdateForm
        Exit Sub
    End If
        
    Dim sValueToWrite As String             
    Dim lLunghezzaBlocco As Long            ' Length of the bloc
    Dim lLunghezzaBloccoToWrite As Long     ' Length of the bloc to write 
    Dim sAzione As String                   ' Action
    Dim lMsgID As Long                      ' Msg Id
    Dim sMsgID As String
    Dim nFunction As Integer
        
    ' the first 2 bytes indicate the ID of the received message
    lMsgID = CLng(Asc(Mid(strBuffer, 1, 1))) * &H100 + Asc(Mid(strBuffer, 2, 1))
    sMsgID = Mid(strBuffer, 1, 2)
    
    ' the next 2 bytes indicate the length of the bloc
    lLunghezzaBlocco = Asc(Mid(strBuffer, 3, 1)) * &H100 + Asc(Mid(strBuffer, 4, 1))
    
    ' then walk byte by byte until the end of the bloc
    nMsg = 0
    
    While Len(strBuffer) >= lLunghezzaBlocco
        'DoEvents
        nMsg = nMsg + 1

        ' extract the message content as a string (froom byte 6 to byte lLunghezzaBlocco) 
        strMsg = Mid(strBuffer, 6, lLunghezzaBlocco)
        
        ' extract the query function (0=READ, 1=WRITE)
        nFunction = CInt(Asc(Mid(strBuffer, 5, 1)))
        
        If Not bReadPending Then 
            
            ' is this a lock to prevent concurrent reading operations ?
            ' shouldn't we wait here until bReadPending = false ?

            ' gets the lock ?
            bReadPending = True 

            ' read the msg
            If readMsg(nFunction, strMsg, sValueToWrite, sAzione) Then
            
                
                lLunghezzaBloccoToWrite = Len(sValueToWrite)
                sValueToWrite = sMsgID & longToWord(lLunghezzaBloccoToWrite) & sValueToWrite
                
                If frmMain.sockServer(Index).Write(sValueToWrite, Len(sValueToWrite)) < 0 Then
                    DropClient Index, "Error occurred durring the read event: Error #", sockServer(Index).LastError
                End If
                
                If frmMain.chkDebug.Value = 1 Then
                    addMessage "ID=" & lMsgID & " " & sAzione
                End If
            
            End If
            
            bReadPending = False
            
        Else
        
            addMessage "!!Lettura pendente!!"
        
        End If
        
        ' remove the message from strBuffer (msg = ID + Len + bloc) / even if we skip the read because bReadPending was true ?
        strBuffer = Right(strBuffer, Len(strBuffer) - (lLunghezzaBlocco + 4))

        ' if they are enough bytes in the buffer => should be > 3 no ?
        If Len(strBuffer) > 2 Then

            ' the first 2 bytes indicate the ID of the received message
            lMsgID = CLng(Asc(Mid(strBuffer, 1, 1))) * &H100 + Asc(Mid(strBuffer, 2, 1))

            ' the next 2 bytes indicate the length of the bloc
            lLunghezzaBlocco = Asc(Mid(strBuffer, 3, 1)) * &H100 + Asc(Mid(strBuffer, 4, 1))
            
            ' display debug msg
            If frmMain.chkDebug.Value = 1 Then
                addMessage "Split msg: " & nMsg & " ID=" & lMsgID & " " & sAzione
            End If
            
            Debug.Print "Msg separato numero " & nMsg & ": " & strMsg
        End If
        
    Wend
    
    'Debug.Print "Lunghezza attesa: " & lLunghezzaBlocco & " lunghezza ricevuta: " & Len(strBuffer)
        
    'memorizzo il tempo di arrivo del messaggio
    lLastReciveTime(Index) = GetTickCount()
    
    On Error GoTo 0
    Exit Sub
    
errRead:
    On Error GoTo 0
    
    addMessage "Errore in Read"
    addMessage "Msg ID " & lMsgID
    addMessage "Msg Len " & lLunghezzaBlocco
    addMessage "Buffer Len " & Len(strBuffer)
    addMessage strMsg
    
    bReadPending = False
    
End Sub