예제 #1
0
        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
              {

              }
        }
예제 #4
0
        /// <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;
        }