Mic1780
Mic1780

Reputation: 1794

Websocket new frame byte

I am currently writing a Visual Basic script that opens a TcpListener on local machine ip (127.0.0.1) and on port 8181. I connect to my websocket server (via the AcceptSocket method) from Google Chrome. From Chrome i do a send request to the server and the server can read it and everything. When I send the message back (like an echo) I can send it the first time but the second time I get an error:

Received unexpected continuation frame.

What i need is a CByte that tells the frame to start a new one or end the open one (without closing the socket connection)

Is this achieveable and if so what is the solution?

I call the Sub with SendMessage(sck, "test")

Here is the code for my message sender:

Sub SendMessage(sck As Socket, message As String)
    Dim rawData = System.Text.Encoding.UTF8.GetBytes(message)
    Dim frameCount = 0
    Dim frame(10) As Byte
    frame(0) = CByte(129)

    If rawData.Length <= 125 Then
        frame(1) = CByte(rawData.Length)
        frameCount = 2
    ElseIf rawData.Length >= 126 AndAlso rawData.Length <= 65535 Then
        frame(1) = CByte(126)
        Dim len = CByte(rawData.Length)
        frame(2) = CByte(((len >> 8) & CByte(255)))
        frame(3) = CByte((len & CByte(255)))
        frameCount = 4
    Else
        frame(1) = CByte(127)
        Dim len = CByte(rawData.Length)
        frame(2) = CByte(((len >> 56) & CByte(255)))
        frame(3) = CByte(((len >> 48) & CByte(255)))
        frame(4) = CByte(((len >> 40) & CByte(255)))
        frame(5) = CByte(((len >> 32) & CByte(255)))
        frame(6) = CByte(((len >> 24) & CByte(255)))
        frame(7) = CByte(((len >> 16) & CByte(255)))
        frame(8) = CByte(((len >> 8) & CByte(255)))
        frame(9) = CByte((len & CByte(255)))
        frameCount = 10
    End If
    Dim bLength = frameCount + rawData.Length
    Console.WriteLine(frameCount)
    Console.WriteLine(rawData.Length)
    Dim reply(bLength + 1) As Byte

    Dim bLim = 0
    For i = 0 To frameCount - 1
        Console.WriteLine(bLim)
        reply(bLim) = frame(i)
        bLim += 1
    Next

    For i = 0 To rawData.Length - 1
        Console.WriteLine(bLim)
        reply(bLim) = rawData(i)
        bLim += 1
    Next
    For i = 0 To reply.Length - 1
        Console.WriteLine("Byte: " & reply(i))
        Console.WriteLine("Char: " & CByte(reply(i)))
    Next
    sck.Send(reply, reply.Length, 0)
End Sub

Update:

After changing the line Dim reply(bLength + 1) As Byte to Dim reply(bLength) As Byte i dont get the continuous frame error, but instead i get a new error:

A server must not mask any frames that it sends to the client.

Hopefully this information can point to the problem.

Update 2:

Below is the entire client Sub the does everything with the clients. From accept to handshake to message stuff.

Private Sub clientStarter(ByVal sck As Socket)
    Dim netStream As New NetworkStream(sck)
    Dim netReader As New IO.StreamReader(netStream)
    Dim netWriter As New IO.StreamWriter(netStream)

    Dim key As String = ""

    Console.WriteLine("Accept new connection ...")

    '' Reading handshake message
    While (True)
        Dim line As String = netReader.ReadLine()
        If line.Length = 0 Then
            Exit While
        End If

        If (line.StartsWith("Sec-WebSocket-Key: ")) Then
            key = line.Split(":")(1).Trim()
        End If

        Console.WriteLine("Data: " & line)
    End While

    '' Calculate accept-key
    key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
    key = getSHA1Hash(key)

    '' Response handshake message
    Dim response As String
    response = "HTTP/1.1 101 Switching Protocols" & vbCrLf
    response &= "Upgrade: websocket" & vbCrLf
    response &= "Connection: Upgrade" & vbCrLf
    response &= "Sec-WebSocket-Accept: " & key & vbCrLf & vbCrLf
    netWriter.Write(response)
    netWriter.Flush()
    Dim dataSent As [Byte]() = Nothing
    Dim dataRecieved(1024) As [Byte]
    Dim bytes As Int32
    Console.WriteLine(dataRecieved)
    Dim message As String = Nothing
    While (True)
        If (sck.Connected = False) Then
            Exit While
        End If
        bytes = sck.Receive(dataRecieved, dataRecieved.Length, 0)
        'Console.WriteLine(bytes)
        While (bytes > 0)
            Console.WriteLine("recieved Data")
            message = System.Text.Encoding.UTF8.GetString(dataRecieved, 0, bytes)
            Console.WriteLine(bytes)
            bytes = 0
            If (bytes = 0) Then
                Console.WriteLine("test")
                Console.WriteLine(message)

                dataSent = System.Text.Encoding.UTF8.GetBytes(message, 0, bytes)
                SendMessage(sck, "test")
                message = Nothing
            End If
        End While
    End While
End Sub

Update 3 (solution):

I have figured out my problem. By changing frame(1) = CByte(rawData.Length) to frame(1) = CByte(rawData.Length + 1) it incorperates the end 0 byte and now the proper length of the message is correct and rids me of my masking problem. I guess the end of the message byte is supposed to be included in the message length.

Upvotes: 0

Views: 1637

Answers (1)

simonc
simonc

Reputation: 42165

It looks like you're including an extra byte at the end of your message. Shouldn't the line

Dim reply(bLength + 1) As Byte

be changed to

Dim reply(bLength) As Byte

instead? All you need in your message is opcode + length (frameCount) + message (rawData.Length). A websocket client will read these bytes as a full, valid message. It will then read the remaining byte from your message as the start of a new message, effectively corrupting the next message you actually send.

Upvotes: 1

Related Questions