public override WebSocketServerConnection GetConnectionInstance( TcpClient aClient, WebSocketHeaders aHeaders, string aHost, string aPort, string aResourceName, string aOrigin, string aCookie, string aVersion, ref string aProtocol, ref string aExtension, ref int aHttpCode ) { aProtocol = "-"; aExtension = "-"; return new WebSocketServerConnection(aClient, this); }
/// <summary> /// start client connection /// </summary> /// <param name="aHost"></param> /// <param name="aPort"></param> /// <param name="aResourceName"></param> /// <param name="aSsl"></param> /// <param name="aOrigin"></param> /// <param name="aProtocol"></param> /// <param name="aExtension"></param> /// <param name="aCookie"></param> /// <param name="aVersion"></param> /// <returns></returns> public bool Start(string aHost, string aPort, string aResourceName, bool aSsl, string aOrigin, string aProtocol, string aExtension, string aCookie, int aVersion) { fHost = aHost; fPort = aPort; fResourceName = aResourceName; fSsl = aSsl; fOrigin = aOrigin; fProtocol = aProtocol; fExtension = aExtension; fCookie = aCookie; fVersion = aVersion; fHeaders = new WebSocketHeaders(); try { fClient = new TcpClient(aHost, int.Parse(aPort)); if (fSsl) { fSslStream = new SslStream(fClient.GetStream(), false, new RemoteCertificateValidationCallback (validateServerCertificate), null); fSslStream.AuthenticateAsClient(fHost); } Stream stream = getStream(fClient); StreamReader sr = new StreamReader(stream); StreamWriter sw = new StreamWriter(stream); string key = ""; Random rand = new Random(); String get; String line; Char[] separator = new char[] { ':' }; Char[] separator2 = new char[] { ' ' }; string[] parts; SHA1 sha = new SHA1CryptoServiceProvider(); /* string cookie = "-"; string extension = "-"; string origin = "-"; string protocol = "-"; */ sw.Write(String.Format("GET {0} HTTP/1.1\r\n", fResourceName)); sw.Write(String.Format("Upgrade: websocket\r\n")); sw.Write(String.Format("Connection: Upgrade\r\n")); sw.Write(String.Format("Host: {0}:{1}\r\n", fHost, fPort)); while (key.Length < 16) key += (char)(rand.Next(85) + 32); key = Convert.ToBase64String(Encoding.ASCII.GetBytes(key)); sw.Write(String.Format("Sec-WebSocket-Key: {0}\r\n", key)); sw.Write(String.Format("Sec-WebSocket-Version: {0}\r\n", fVersion)); if (fProtocol != "-") sw.Write(String.Format("Sec-WebSocket-Protocol: {0}\r\n", fProtocol)); if (fOrigin != "-") { if (fVersion < 13) sw.Write(String.Format("Sec-WebSocket-Origin: {0}\r\n", fOrigin)); else sw.Write(String.Format("Origin: {0}\r\n", fOrigin)); } if (fExtension != "-") sw.Write(String.Format("Sec-WebSocket-Extensions: {0}\r\n", fExtension)); if (fCookie != "-") sw.Write(String.Format("Cookie: {0}\r\n", fCookie)); sw.Write("\r\n"); sw.Flush(); get = sr.ReadLine(); if (get.ToLower().IndexOf("http/1.1 101") > -1) { do { line = sr.ReadLine(); if (!String.IsNullOrEmpty(line)) { parts = line.Split(separator, 2); fHeaders.Append(parts[0].ToLower(), parts.Length == 2 ? parts[1] : ""); } } while (!String.IsNullOrEmpty(line)); if ((fHeaders.Contains("upgrade")) && (fHeaders["upgrade"].Trim().ToLower() == "websocket".ToLower()) && (fHeaders.Contains("connection")) && (fHeaders["connection"].Trim().ToLower().IndexOf("upgrade") > -1)) { fProtocol = "-"; fExtension = "-"; if (fHeaders.Contains("sec-websocket-protocol")) fProtocol = fHeaders["sec-websocket-protocol"].Trim(); if (fHeaders.Contains("sec-websocket-extensions")) fExtension = fHeaders["sec-websocket-extensions"].Trim(); if (fHeaders.Contains("sec-websocket-accept")) { get = fHeaders["sec-websocket-accept"].Trim(); key = Convert.ToBase64String(sha.ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))); if (get == key) { fHandshake = true; StartRead(); return true; } } } } } catch { } try { fClient.Close(); } catch { } return false; }
/* protected void DoLog(string aData) { if (Log != null) Log(aData); } */ /// <summary> /// basic function to add WebSocket connection to list of connections /// </summary> /// <param name="aClient">incomming connection</param> /// <returns>new WebSocket connection class or null</returns> protected WebSocketServerConnection AddConnection(TcpClient aClient, Stream aStream) { WebSocketHeaders headers = new WebSocketHeaders(); //NetworkStream stream = aClient.GetStream(); Stream stream = aStream == null ? aClient.GetStream() : aStream; //getStream(aClient); StreamReader sr = new StreamReader(stream); StreamWriter sw = new StreamWriter(stream); string line = String.Empty; string get = String.Empty; string[] parts; string cookie = "-"; string extension = "-"; string origin = "-"; string protocol = "-"; string host = ""; string port = ""; string resourceName = ""; string version = ""; Char[] separator = new char[] {':'}; Char[] separator2 = new char[] {' '}; bool doCreate = true; WebSocketServerConnection result = null; string key = String.Empty; string tmpS; byte[] tmpB; int resultHTTP = 101; SHA1 sha = new SHA1CryptoServiceProvider(); bool canAdd = true; int iversion; stream.ReadTimeout = 60 * 1000; //sr. try { // read resourceName get = sr.ReadLine(); if (get != null) { parts = get.Split(separator2); if ((get.ToUpper().IndexOf("GET ") > -1) && (get.ToUpper().IndexOf(" HTTP/1.1") > -1) && (parts.Length >= 3)) { parts = get.Split(separator2, 2); resourceName = parts[1].Trim(); parts = resourceName.Split(separator2, 2); resourceName = parts[0].Trim(); } } doCreate = resourceName != String.Empty; // read all headers if (doCreate) { do { line = sr.ReadLine(); if (!String.IsNullOrEmpty(line)) { parts = line.Split(separator, 2); headers.Append(parts[0].ToLower(), parts.Length == 2 ? parts[1] : ""); //headers.Add("brona", "klucka"); } } while (!String.IsNullOrEmpty(line)); if (line == null) { doCreate = false; } } //host & port if (doCreate) { if (headers.Contains("host")) { parts = headers["host"].Split(separator); host = parts[0].Trim(); if (parts.Length > 1) { port = parts[1].Trim(); } } doCreate = doCreate && (host != String.Empty); } //websocket key if (doCreate) { if (headers.Contains("sec-websocket-key")) { tmpS = headers["sec-websocket-key"].Trim(); tmpB = Convert.FromBase64String(tmpS); tmpS = Encoding.ASCII.GetString(tmpB); if (tmpS.Length == 16) { key = headers["sec-websocket-key"].Trim(); } } doCreate = doCreate && (key != String.Empty); } //websocket version iversion = 0; if (doCreate) { if (headers.Contains("sec-websocket-version")) { tmpS = headers["sec-websocket-version"].Trim(); if ((tmpS == "8") || (tmpS == "7") || (tmpS == "13")) { version = tmpS; iversion = int.Parse(version); } } doCreate = doCreate && (version != String.Empty); } //upgrade and connection if (doCreate) { doCreate = doCreate && (headers.Contains("upgrade")) && (headers["upgrade"].Trim().ToLower() == "websocket".ToLower()) && (headers.Contains("connection")) && (headers["connection"].Trim().ToLower().IndexOf("upgrade") > -1); } if (doCreate) { if (iversion < 13) { if (headers.Contains("sec-websocket-origin")) origin = headers["sec-websocket-origin"].Trim(); } else { if (headers.Contains("origin")) origin = headers["origin"].Trim(); } if (headers.Contains("sec-websocket-protocol")) protocol = headers["sec-websocket-protocol"].Trim(); if (headers.Contains("sec-websocket-extensions")) extension = headers["sec-websocket-extensions"].Trim(); if (headers.Contains("cookie")) cookie = headers["cookie"].Trim(); } } catch (SocketException e) { if (SocketError != null) SocketError(this, e); doCreate = false; } catch (Exception) { doCreate = false; } finally { } result = GetConnectionInstance(aClient, headers, host, port, resourceName, origin, cookie, version, ref protocol, ref extension, ref resultHTTP); if (result == null) { if (resultHTTP == 101) resultHTTP = 404; } try { doCreate = doCreate && stream.CanWrite; if (doCreate) { if (resultHTTP != 101) { sw.Write(String.Format("HTTP/1.1 {0} {1}\r\n", resultHTTP, this.httpCode(resultHTTP))); sw.Write(String.Format("{0} {1}\r\n", resultHTTP, this.httpCode(resultHTTP))); sw.Write("\r\n"); sw.Flush(); doCreate = false; } } if (!doCreate) { //DoLog("close"); aClient.Close(); return null; } else { //result = new WebSocketServerConnection(aClient); result.fCookie = cookie; result.fExtension = extension; result.fOrigin = origin; result.fProtocol = protocol; result.fHost = host; result.fPort = port; result.fResourceName = resourceName; result.fVersion = int.Parse(version); result.fHeaders = headers; result.fSsl = fSsl; result.fHandshake = true; if (fSsl) { result.fSslStream = (SslStream)aStream; } if (BeforeAddConnection != null) { canAdd = true; BeforeAddConnection(this, result, ref canAdd); doCreate = canAdd; } if (doCreate) { tmpB = System.Text.Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); key = Convert.ToBase64String(sha.ComputeHash(tmpB)); sw.Write("HTTP/1.1 101 Switching Protocols\r\n"); sw.Write("Upgrade: websocket\r\n"); sw.Write("Connection: Upgrade\r\n"); sw.Write(String.Format("Sec-WebSocket-Accept: {0}\r\n", key)); if (protocol != "-") sw.Write(String.Format("Sec-WebSocket-Protocol: {0}\r\n", protocol)); //if (extension != "-") // sw.Write(String.Format("Sec-WebSocket-Extensions: {0}\r\n", extension)); sw.Write("\r\n"); sw.Flush(); return result; } else { aClient.Close(); return null; } } } catch (SocketException e) { if (SocketError != null) SocketError(this, e); aClient.Close(); return null; } catch (Exception) { aClient.Close(); return null; } finally { } }
/// <summary> /// start client connection /// </summary> /// <param name="aHost"></param> /// <param name="aPort"></param> /// <param name="aResourceName"></param> /// <param name="aSsl"></param> /// <param name="aOrigin"></param> /// <param name="aProtocol"></param> /// <param name="aExtension"></param> /// <param name="aCookie"></param> /// <param name="aVersion"></param> /// <returns></returns> public bool Start(string aHost, string aPort, string aResourceName, bool aSsl, string aOrigin, string aProtocol, string aExtension, string aCookie, int aVersion) { fHost = aHost; fPort = aPort; fResourceName = aResourceName; fSsl = aSsl; fOrigin = aOrigin; fProtocol = aProtocol; fExtension = aExtension; fCookie = aCookie; fVersion = aVersion; fHeaders = new WebSocketHeaders(); try { // try connect directly try { fClient = new TcpClient(); IAsyncResult result = fClient.BeginConnect(aHost, int.Parse(aPort), null, null); bool success = result.AsyncWaitHandle.WaitOne(30000); if (!success || !fClient.Connected) { fClient.Close(); throw new SocketException(); } else { Logger.Debug("Connected directly to " + aHost + ":" + aPort); } } catch (SocketException e) { Logger.Warn("Failed to connect to host, attempting to find a proxy"); var proxy = WebRequest.DefaultWebProxy.GetProxy(new Uri("https://" + aHost + ":" + aPort)); if (proxy != null && !aHost.Equals(proxy.Host)) { Logger.Debug("Found a web proxy at " + proxy); fClient = new TcpClient(proxy.Host, proxy.Port); StreamReader proxyReader = new StreamReader(fClient.GetStream()); StreamWriter proxyWriter = new StreamWriter(fClient.GetStream()); proxyWriter.WriteLine("CONNECT " + aHost + ":" + aPort + " HTTP/1.0"); proxyWriter.WriteLine(""); proxyWriter.Flush(); String readerOut = proxyReader.ReadLine(); if (!String.IsNullOrEmpty(readerOut) && readerOut.StartsWith("HTTP/1.0 200")) { // Now clear other data from it until we get a blank line while (!String.IsNullOrEmpty(readerOut)) { readerOut = proxyReader.ReadLine(); } // now we are ready to proceed normally through the proxied tunnel } else { Logger.Error("Failed to connect via proxy, proxy responded with " + readerOut); throw e; } } else { Logger.Error("No system proxy setup, cannot continue"); throw e; } } fClient.ReceiveTimeout = 300000; // if we don't read anything for 5 minutes if (fSsl) { fSslStream = new SslStream(fClient.GetStream(), false, new RemoteCertificateValidationCallback(validateServerCertificate), null); fSslStream.AuthenticateAsClient(fHost); } Stream stream = getStream(fClient); StreamReader sr = new StreamReader(stream); StreamWriter sw = new StreamWriter(stream); string key = ""; Random rand = new Random(); String get; String line; Char[] separator = new char[] { ':' }; Char[] separator2 = new char[] { ' ' }; string[] parts; SHA1 sha = new SHA1CryptoServiceProvider(); /* string cookie = "-"; string extension = "-"; string origin = "-"; string protocol = "-"; */ sw.Write(String.Format("GET {0} HTTP/1.1\r\n", fResourceName)); sw.Write(String.Format("Upgrade: websocket\r\n")); sw.Write(String.Format("Connection: Upgrade\r\n")); sw.Write(String.Format("Host: {0}:{1}\r\n", fHost, fPort)); while (key.Length < 16) key += (char)(rand.Next(85) + 32); key = Convert.ToBase64String(Encoding.ASCII.GetBytes(key)); sw.Write(String.Format("Sec-WebSocket-Key: {0}\r\n", key)); sw.Write(String.Format("Sec-WebSocket-Version: {0}\r\n", fVersion)); if (fProtocol != "-") sw.Write(String.Format("Sec-WebSocket-Protocol: {0}\r\n", fProtocol)); if (fOrigin != "-") { if (fVersion < 13) sw.Write(String.Format("Sec-WebSocket-Origin: {0}\r\n", fOrigin)); else sw.Write(String.Format("Origin: {0}\r\n", fOrigin)); } if (fExtension != "-") sw.Write(String.Format("Sec-WebSocket-Extensions: {0}\r\n", fExtension)); if (fCookie != "-") sw.Write(String.Format("Cookie: {0}\r\n", fCookie)); sw.Write("\r\n"); sw.Flush(); get = sr.ReadLine(); if (get.ToLower().IndexOf("http/1.1 101") > -1) { do { line = sr.ReadLine(); if (!String.IsNullOrEmpty(line)) { parts = line.Split(separator, 2); fHeaders.Append(parts[0].ToLower(), parts.Length == 2 ? parts[1] : ""); } } while (!String.IsNullOrEmpty(line)); if ( (fHeaders.Contains("upgrade")) && (fHeaders["upgrade"].Trim().ToLower() == "websocket".ToLower()) && (fHeaders.Contains("connection")) && (fHeaders["connection"].Trim().ToLower().IndexOf("upgrade") > -1)) { fProtocol = "-"; fExtension = "-"; if (fHeaders.Contains("sec-websocket-protocol")) fProtocol = fHeaders["sec-websocket-protocol"].Trim(); if (fHeaders.Contains("sec-websocket-extensions")) fExtension = fHeaders["sec-websocket-extensions"].Trim(); if (fHeaders.Contains("sec-websocket-accept")) { get = fHeaders["sec-websocket-accept"].Trim(); key = Convert.ToBase64String(sha.ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))); if (get == key) { fHandshake = true; StartRead(); Logger.Debug("Upgrade succceeded, connection complete."); return true; } } } else { Logger.Error("Failed to upgrade connection, server did not return correct headers [" + fHeaders.ToHeaders() + "]"); throw new Exception("Failed to upgrade connection"); } } } catch (Exception e) { Logger.Error("Failed to connect to server", e); throw e; } try { fClient.Close(); } catch (Exception e) { Logger.Warn("Error closing connection : " + e.Message); } return false; }