Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebSocket Server isn't firing the handshake

I'm trying to use a simple HTML WebSocket within Unity, but the socket won't receive the handshake from the server.

Let me know if did something wrong in my code.

index.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript">
            var noSupportMessage = "Your browser cannot support WebSocket!";
            var ws;

            function appendMessage(message) {
                $('body').append(message);
            }

            function connectSocketServer() {
                var support = "MozWebSocket" in window ? 'MozWebSocket' : ("WebSocket" in window ? 'WebSocket' : null);

                if (support == null) {
                    appendMessage("* " + noSupportMessage + "<br/>");
                    return;
                }

                appendMessage("* Connecting to server ..<br/>");
                // create a new websocket and connect
                ws = new window[support]('ws://127.0.0.1:13000/websession');

                // when data is comming from the server, this metod is called
                ws.onmessage = function (evt) {
                    appendMessage("# " + evt.data + "<br />");
                };

                ws.onerror = function(evt){
                    appendMessage("# " + evt.data + "<br />");  
                };

                // when the connection is established, this method is called
                ws.onopen = function () {
                    appendMessage('* Connection open<br/>');
                    $('#messageInput').attr("disabled", "");
                    $('#sendButton').attr("disabled", "");
                    $('#connectButton').attr("disabled", "disabled");
                    $('#disconnectButton').attr("disabled", "");
                };

                // when the connection is closed, this method is called
                ws.onclose = function () {
                    appendMessage('* Connection closed<br/>');
                    $('#messageInput').attr("disabled", "disabled");
                    $('#sendButton').attr("disabled", "disabled");
                    $('#connectButton').attr("disabled", "");
                    $('#disconnectButton').attr("disabled", "disabled");
                }
            }

            function sendMessage() {
                if (ws) {
                    var messageBox = document.getElementById('messageInput');
                    ws.send(messageBox.value);
                    messageBox.value = "";
                }
            }

            function disconnectWebSocket() {
                if (ws) {
                    ws.close();
                }
            }

            function connectWebSocket() {
                connectSocketServer();
            }

            window.onload = function () {
                $('#messageInput').attr("disabled", "disabled");
                $('#sendButton').attr("disabled", "disabled");
                $('#disconnectButton').attr("disabled", "disabled");
            }

    </script>
    </head>
    <body>
        <input type="button" id="connectButton" value="Connect" onclick="connectWebSocket()"/> <input type="button" id="disconnectButton" value="Disconnect" onclick="disconnectWebSocket()"/> <input type="text" id="messageInput" /> <input type="button" id="sendButton" value="Send" onclick="sendMessage()"/> <br />
    </body>
</html>

Unity TCPServer.cs

using UnityEngine;
using System.Threading;
using System.Net.Sockets;
using System.IO;
using System;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Collections.Generic;

class TCPServer : MonoBehaviour
{
    public static List<SocketClient> ClientList = new List<SocketClient>();
    Thread mThread;

    void Start()
    {
        ThreadStart ts = new ThreadStart(Main);
        mThread = new Thread(ts);
        mThread.Start();
        print("Thread done...");
    }

    void Update(){
    }


    public static void Main()
    { 

        TcpListener socketServer = null;

        try
        {
            // Set the TcpListener on port 13000.
            Int32 port = 13000;
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");

            // TcpListener server = new TcpListener(port);
            socketServer = new TcpListener(localAddr, port);

            print("Server has started on " + localAddr.ToString() + ":" + port.ToString() + "." + Environment.NewLine + "Waiting for a connection...");

            // Start listening for client requests.
            socketServer.Start();

            // counter
            int counter = 0;

            // Enter the listening loop.
            while(true) 
            {
                // check for any incoming pending connections
                // create new socket client for new connection
                TcpClient socketConnection = socketServer.AcceptTcpClient();

                counter++;

                DateTime now = DateTime.Now;

                //write message to console to indicate new connection
                print("New Client Connected - " + now.ToString("MM/dd/yyyy h:mm:ss tt"));

                // create new client object for this connection
                new SocketClient(socketConnection);
            }
        }
        catch(SocketException e)
        {
            print("SocketException: " + e);
        }
        finally
        {
            // Stop listening for new clients.
            socketServer.Stop();
        }


        print("Hit enter to continue...");
        Console.Read();
    }

    public static void CloseClient(SocketClient whichClient)
    {
        ClientList.Remove(whichClient);
        whichClient.Client.Close();

            // dispose of the client object
        whichClient.Dispose();
        whichClient = null;
        print("Client Disconnected");
    }

    public static void SendTextToClient(SocketClient sc, string text)
    {
        StreamWriter writer = new StreamWriter(sc.Client.GetStream());
            // check if client is still connected, then send the text string
        try
        {
            if (sc.Client.Connected)
            {
                writer.WriteLine(text);
                writer.Flush();
                writer = null;
            }
        }
        catch
        {
            CloseClient(sc);
        }

    }

    public static void LOG(string a ){
        print(a);
    }

    public static void SendBroadcast(string text)
    {
        StreamWriter writer;
            // loop through the array and send text to all clients
        foreach (SocketClient client in ClientList)
        {
            if (client.Client.Connected)
            {
                try
                {
                    writer = new StreamWriter(client.Client.GetStream());
                    writer.WriteLine(text);
                    writer.Flush();
                    writer = null;

                }
                catch
                {
                    CloseClient(client);
                }
            }
        }
    }


}

class SocketClient
{
    public TcpClient Client;
    StreamReader reader;
    StreamWriter writer;


    public SocketClient(TcpClient client)
    {
        Client = client;
        Thread clientThread = new Thread(new ThreadStart(StartClient));
        clientThread.Start();
    }


    private void StartClient()
    {
        TCPServer.ClientList.Add(this);

            // create a reader for this client
        reader = new StreamReader(Client.GetStream());
            // create a writer for this client
        writer = new StreamWriter(Client.GetStream());

        var headers = new Dictionary<string, string>();

        string line = "";
        while ((line = reader.ReadLine()) != string.Empty)
        {
            if (!string.IsNullOrEmpty(line))
            {
                var tokens = line.Split(new char[] { ':' }, 2);
                if (!string.IsNullOrEmpty(line) && tokens.Length > 1)
                {
                    headers[tokens[0]] = tokens[1].Trim();
                }
            }
        }

        String secWebSocketAccept = ComputeWebSocketHandshakeSecurityHash09(headers["Sec-WebSocket-Key"]);

            // send handshake to this client only
        writer.WriteLine("HTTP/1.1 101 Switching Protocols");
        writer.WriteLine("Upgrade: websocket");
        writer.WriteLine("Connection: Upgrade");
        writer.WriteLine("WebSocket-Origin: http://localhost");
        writer.WriteLine("WebSocket-Location: ws://127.0.0.1:13000/websession");
        writer.WriteLine("Sec-WebSocket-Accept: " + secWebSocketAccept);
        writer.WriteLine("Sec-WebSocket-Protocol: chat");
        writer.WriteLine("");
        writer.Flush();

        TCPServer.SendBroadcast("New Client Connected");

        Thread clientRun = new Thread(new ThreadStart(RunClient));
        clientRun.Start();
    }

    public static String ComputeWebSocketHandshakeSecurityHash09(String secWebSocketKey)
    {
        const String MagicKEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        String secWebSocketAccept = String.Empty;

            // 1. Combine the request Sec-WebSocket-Key with magic key.
        String ret = secWebSocketKey + MagicKEY;

            // 2. Compute the SHA1 hash
        SHA1 sha = new SHA1CryptoServiceProvider(); 
        byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret));

            // 3. Base64 encode the hash
        secWebSocketAccept = Convert.ToBase64String(sha1Hash);

        return secWebSocketAccept;
    }


    private void RunClient()
    {
        try
        {
            string line = "";
            while (true)
            {
                line = reader.ReadLine();
                if (!string.IsNullOrEmpty(line))
                {
                    if(!string.IsNullOrEmpty(line.Trim(' '))){
                        TCPServer.SendBroadcast(line);
                    }
                }
            }
        }
        catch
        {
            TCPServer.CloseClient(this);
        }
    }

    public void Dispose()
    {
        System.GC.SuppressFinalize(this);
    }
}
like image 987
GTSouza Avatar asked Oct 02 '22 05:10

GTSouza


2 Answers

WebSocket is not raw TCP. You need a WebSocket server.

If you choose a WebSocket server, you might check it's compliance to the WebSocket protocol standard (IETF RFC6455) by running AutobahnTestsuite (in fuzzing client mode) against your server. This will give you a detailed report like this (including wirelogs) of issues encountered.

Disclosure: I am original author of Autobahn and work for Tavendo.

like image 184
oberstet Avatar answered Oct 05 '22 23:10

oberstet


C# + Unity3d + HTML WebSocket

This works fine,

https://github.com/sta/websocket-sharp

Thanks, anyway,

like image 30
GTSouza Avatar answered Oct 05 '22 23:10

GTSouza