/// <summary> /// Initializes a new instance of the <see cref="PeaRoxyClient" /> class. /// </summary> /// <param name="client"> /// The client's socket. /// </param> /// <param name="parent"> /// The parent controller object. /// </param> /// <param name="encType"> /// The sending encryption type. /// </param> /// <param name="comTypes"> /// The sending compression type. /// </param> /// <param name="receivePacketSize"> /// The receiving packet size. /// </param> /// <param name="sendPacketSize"> /// The sending packet size. /// </param> /// <param name="selectedAuthMode"> /// The selected authentication mode. /// </param> /// <param name="noDataTimeout"> /// The no data timeout value. /// </param> /// <param name="clientSupportedEncryptionType"> /// The supported client encryption types. /// </param> /// <param name="clientSupportedCompressionType"> /// The supported client compression types. /// </param> public PeaRoxyClient( Socket client, PeaRoxyController parent, Common.EncryptionTypes encType = Common.EncryptionTypes.None, Common.CompressionTypes comTypes = Common.CompressionTypes.None, int receivePacketSize = 8192, int sendPacketSize = 1024, Common.AuthenticationMethods selectedAuthMode = Common.AuthenticationMethods.Invalid, int noDataTimeout = 6000, Common.EncryptionTypes clientSupportedEncryptionType = Common.EncryptionTypes.None | Common.EncryptionTypes.SimpleXor | Common.EncryptionTypes.TripleDes, Common.CompressionTypes clientSupportedCompressionType = Common.CompressionTypes.None | Common.CompressionTypes.GZip | Common.CompressionTypes.Deflate) { this.Username = "******"; // Use Anonymous as temporary user name until client introduce it-self this.CurrentStage = RequestStages.JustConnected; this.SelectedAuthMode = selectedAuthMode; this.NoDataTimeout = noDataTimeout; this.Controller = parent; this.UnderlyingSocket = client; this.UnderlyingSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true); this.UnderlyingSocket.Blocking = false; this.underlyingClientEncryption = encType; this.underlyingClientCompression = comTypes; this.ClientSupportedEncryptionType = clientSupportedEncryptionType; this.ClientSupportedCompressionType = clientSupportedCompressionType; this.underlyingClientReceivePacketSize = receivePacketSize; this.underlyingClientSendPacketSize = sendPacketSize; this.currentTimeout = this.NoDataTimeout * 1000; }
/// <summary> /// Initializes a new instance of the <see cref="PeaRoxyProtocol" /> class. /// </summary> /// <param name="client"> /// The underlying socket. /// </param> /// <param name="encType"> /// The encryption type. /// </param> /// <param name="comType"> /// The compression type. /// </param> public PeaRoxyProtocol( Socket client, Common.EncryptionTypes encType = Common.EncryptionTypes.None, Common.CompressionTypes comType = Common.CompressionTypes.None) { this.encryptionType = encType; this.compressionType = comType; switch (this.compressionType) { case Common.CompressionTypes.GZip: this.compressor = new GZipCompressor(); break; case Common.CompressionTypes.Deflate: this.compressor = new DeflateCompressor(); break; } this.ReceivePacketSize = 8192; this.SendPacketSize = 8192; this.PocketSent = 0; this.PocketReceived = 0; this.ClientSupportedEncryptionType = Common.EncryptionTypes.None | Common.EncryptionTypes.SimpleXor | Common.EncryptionTypes.TripleDes; this.ClientSupportedCompressionType = Common.CompressionTypes.None | Common.CompressionTypes.GZip | Common.CompressionTypes.Deflate; this.UnderlyingSocket = client; this.UnderlyingSocket.Blocking = false; }
/// <summary> /// Initializes a new instance of the <see cref="PeaRoxy" /> class. /// </summary> /// <param name="address"> /// The server address. /// </param> /// <param name="port"> /// The server port. /// </param> /// <param name="domain"> /// The server domain identifier. /// </param> /// <param name="username"> /// The user name to authenticate, leave empty for no authentication. /// </param> /// <param name="password"> /// The password to authenticate, leave empty for no authentication. /// </param> /// <param name="encType"> /// The client encryption type. /// </param> /// <param name="comTypes"> /// The client compression type. /// </param> /// <exception cref="ArgumentException"> /// Invalid server address, port number, encryption or compression type /// </exception> public PeaRoxy( string address, ushort port, string domain, string username = "", string password = "", Common.EncryptionTypes encType = Common.EncryptionTypes.None, Common.CompressionTypes comTypes = Common.CompressionTypes.None) { if (string.IsNullOrEmpty(address)) { throw new ArgumentException(@"Invalid value.", "address"); } IPAddress ip; if (IPAddress.TryParse(address, out ip)) { address = ip.ToString(); } else { try { ip = Dns.GetHostAddresses(address)[0]; address = ip.ToString(); } catch { } } this.ServerDomain = domain.ToLower().Trim(); this.IsServerValid = false; this.ServerAddress = address; this.ServerPort = port; this.Username = username; this.Password = password; this.encryptionType = encType; this.compressionTypes = comTypes; this.NoDataTimeout = 60; this.IsDataSent = false; this.IsClosed = false; }
/// <summary> /// Initializes a new instance of the <see cref="PeaRoxyWeb" /> class. /// </summary> /// <param name="address"> /// The address of the server script. /// </param> /// <param name="username"> /// The user name to authenticate, leave empty for no authentication. /// </param> /// <param name="password"> /// The password to authenticate, leave empty for no authentication. /// </param> /// <param name="encType"> /// The client encryption type. /// </param> /// <param name="addressChecked"> /// The address checked boolean shows if we already sure about the script address or if we need to try and get the /// correct address our-self. /// </param> /// <exception cref="ArgumentException"> /// Invalid server address or encryption type /// </exception> public PeaRoxyWeb( string address, string username = "", string password = "", Common.EncryptionTypes encType = Common.EncryptionTypes.None, bool addressChecked = false) { if (string.IsNullOrEmpty(address)) { throw new ArgumentException(@"Invalid value.", "address"); } if (encType != Common.EncryptionTypes.SimpleXor && encType != Common.EncryptionTypes.None) { throw new ArgumentException(@"Invalid value.", "encType"); } this.IsServerValid = false; this.ServerUri = new Uri(address); if (!addressChecked) { HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(this.ServerUri); wreq.AllowAutoRedirect = true; wreq.Proxy = null; wreq.Method = "HEAD"; wreq.Headers.Add("X-Requested-With", "NOREDIRECT"); HttpWebResponse wres = (HttpWebResponse)wreq.GetResponse(); wres.Close(); if (wres.StatusCode != HttpStatusCode.OK) { throw new ArgumentException(@"Server responded with status code " + wres.StatusCode, "address"); } this.ServerUri = wres.ResponseUri; } this.Username = username; this.Password = password; this.encryptionType = encType; this.NoDataTimeout = 60; this.IsDataSent = false; this.IsClosed = false; }
/// <summary> /// This method let us know if there is new data available to read from the underlying client. Should be executed /// repeatedly. /// </summary> /// <param name="syncWait"> /// Indicates if we should wait until we have something to read. /// </param> /// <returns> /// Indicates if we have new data available to read. /// </returns> public bool IsDataAvailable(bool syncWait = false) { try { if ((this.UnderlyingSocket.Available > 0 || syncWait) && this.waitingBuffer.Length == 0) { int i = 10; // Time out by second, This timeout is about the max seconds that we wait for something if we don't have anything i = i * 1000; int i2 = i; byte[] buffer = new byte[0]; while (i > 0) { if (!Common.IsSocketConnected(this.UnderlyingSocket)) { this.Close(); return(false); } if (this.UnderlyingSocket.Available > 0) { i = i2; int bufferLastLength = buffer.Length; Array.Resize(ref buffer, bufferLastLength + this.ReceivePacketSize); int bytes = this.UnderlyingSocket.Receive( buffer, bufferLastLength, buffer.Length - bufferLastLength, SocketFlags.None); if (bytes == 0) { this.Close(); return(false); } Array.Resize(ref buffer, bytes + bufferLastLength); bool doNext = true; while (doNext) { doNext = false; if (this.neededBytes == 0) { if (this.workingBuffer.Length > 0) { if (!this.ClientSupportedEncryptionType.HasFlag(this.peerEncryptionType)) { // Check if we support this type of encryption this.Close("Protocol 1. Unsupported encryption type."); return(false); } if (this.peerEncryptionType != Common.EncryptionTypes.None) { this.peerCryptor.SetSalt(this.pearEncryptionSalt); this.workingBuffer = this.peerCryptor.Decrypt(this.workingBuffer); } if (!this.ClientSupportedCompressionType.HasFlag(this.peerCompressionType)) { // Check if we support this type of compression this.Close("Protocol 2. Unsupported compression type."); return(false); } this.workingBuffer = this.peerCompressor.Decompress(this.workingBuffer); Array.Resize( ref this.waitingBuffer, this.waitingBuffer.Length + this.workingBuffer.Length); Array.Copy( this.workingBuffer, 0, this.waitingBuffer, this.waitingBuffer.Length - this.workingBuffer.Length, this.workingBuffer.Length); this.workingBuffer = new byte[0]; } if (buffer.Length >= 10) { if (this.PocketReceived == 65535) { this.PocketReceived = 0; } if ((Common.CompressionTypes)buffer[1] != this.peerCompressionType) { this.peerCompressionType = (Common.CompressionTypes)buffer[1]; switch (this.peerCompressionType) { case Common.CompressionTypes.GZip: this.peerCompressor = new GZipCompressor(); break; case Common.CompressionTypes.Deflate: this.peerCompressor = new DeflateCompressor(); break; } } int receiveCounter = (buffer[2] * 256) + buffer[3]; this.neededBytes = (buffer[4] * 256) + buffer[5]; Array.Copy(buffer, 6, this.pearEncryptionSalt, 0, 4); if ((Common.EncryptionTypes)buffer[0] != this.peerEncryptionType) { this.peerEncryptionType = (Common.EncryptionTypes)buffer[0]; switch (this.peerEncryptionType) { case Common.EncryptionTypes.TripleDes: if (this.EncryptionKey.Length == 0) { this.EncryptionKey = this.pearEncryptionSalt; } this.peerCryptor = new TripleDesCryptor(this.encryptionKey); break; case Common.EncryptionTypes.SimpleXor: if (this.EncryptionKey.Length == 0) { this.EncryptionKey = this.pearEncryptionSalt; } this.peerCryptor = new SimpleXorCryptor(this.encryptionKey); break; } } if (receiveCounter != this.PocketReceived) { this.Close( "Protocol 3. Packet lost, Last received packet: " + receiveCounter + ", Expected: " + this.PocketReceived); return(false); } this.PocketReceived++; if (this.neededBytes <= buffer.Length - 10) { Array.Resize( ref this.workingBuffer, this.workingBuffer.Length + this.neededBytes); Array.Copy(buffer, 10, this.workingBuffer, 0, this.neededBytes); Array.Copy( buffer, 10 + this.neededBytes, buffer, 0, (buffer.Length - 10) - this.neededBytes); Array.Resize(ref buffer, (buffer.Length - 10) - this.neededBytes); this.neededBytes = 0; doNext = true; } else { Array.Resize( ref this.workingBuffer, this.workingBuffer.Length + (buffer.Length - 10)); Array.Copy(buffer, 10, this.workingBuffer, 0, buffer.Length - 10); this.neededBytes -= buffer.Length - 10; buffer = new byte[0]; } } } else { if (buffer.Length > 0) { if (this.neededBytes <= buffer.Length) { Array.Resize( ref this.workingBuffer, this.workingBuffer.Length + this.neededBytes); Array.Copy( buffer, 0, this.workingBuffer, this.workingBuffer.Length - this.neededBytes, this.neededBytes); Array.Copy( buffer, this.neededBytes, buffer, 0, buffer.Length - this.neededBytes); Array.Resize(ref buffer, buffer.Length - this.neededBytes); this.neededBytes = 0; doNext = true; } else { Array.Resize( ref this.workingBuffer, this.workingBuffer.Length + buffer.Length); Array.Copy( buffer, 0, this.workingBuffer, this.workingBuffer.Length - buffer.Length, buffer.Length); this.neededBytes -= buffer.Length; buffer = new byte[0]; } } } } } if (buffer.Length == 0 && (this.waitingBuffer.Length > 0 || !syncWait)) { return(this.waitingBuffer.Length > 0); } if (i != i2) { Thread.Sleep(1); } i--; } } return(this.waitingBuffer.Length > 0); } catch (Exception e) { this.Close("Protocol 4. " + e); } return(false); }
// ReSharper disable once RedundantAssignment private bool ReadServerResponse(ref byte[] bytes) { this.currentTimeout = this.NoDataTimeout * 1000; // let make it 60sec string responseHeader = string.Empty; bytes = new byte[0]; while (responseHeader.IndexOf("\r\n\r\n", StringComparison.Ordinal) == -1) { if ((this.ParentClient.UnderlyingSocket != null && !Common.IsSocketConnected(this.ParentClient.UnderlyingSocket)) || !Common.IsSocketConnected(this.UnderlyingSocket)) { this.Close(); return(false); } if (this.UnderlyingSocket.Available > 0) { this.currentTimeout = this.NoDataTimeout * 1000; byte[] response = this.Read(); if (response == null || response.Length <= 0) { this.Close( "No response from server, Read Failure.", null, ErrorRenderer.HttpHeaderCode.C504GatewayTimeout); return(false); } Array.Resize(ref bytes, bytes.Length + response.Length); Array.Copy(response, 0, bytes, bytes.Length - response.Length, response.Length); responseHeader += Encoding.ASCII.GetString(response); } else { if (!this.BusyWrite) { this.currentTimeout--; if (this.currentTimeout == 0) { this.Close( "No response from server, Timeout.", null, ErrorRenderer.HttpHeaderCode.C504GatewayTimeout); return(false); } } Thread.Sleep(1); } } int endOfHeaderIndex = responseHeader.IndexOf("\r\n\r\n", StringComparison.Ordinal) + 4; responseHeader = responseHeader.Substring(0, endOfHeaderIndex); if (!responseHeader.StartsWith("HTTP/1.1 200", StringComparison.InvariantCultureIgnoreCase) && !responseHeader.StartsWith("HTTP/1.0 200", StringComparison.InvariantCultureIgnoreCase)) { this.Close( "Bad server response. Is address of server ", responseHeader.Substring( 0, Math.Min(responseHeader.Length, responseHeader.IndexOf("\r", StringComparison.Ordinal))), ErrorRenderer.HttpHeaderCode.C502BadGateway); return(false); } int headerLenght = Encoding.ASCII.GetByteCount(responseHeader); Array.Copy(bytes, headerLenght, bytes, 0, bytes.Length - headerLenght); Array.Resize(ref bytes, bytes.Length - headerLenght); // --------------------------- We have header. Reading cookies for getting encryption type int indexOfCookies = responseHeader.IndexOf("\r\nSet-Cookie: ", StringComparison.InvariantCultureIgnoreCase); if (indexOfCookies != -1) { int startOfCookies = responseHeader.IndexOf( "=", indexOfCookies, StringComparison.InvariantCultureIgnoreCase) + 1; int endOfCookies = responseHeader.IndexOf( ";", indexOfCookies, StringComparison.InvariantCultureIgnoreCase); this.serverEncryptionType = (Common.EncryptionTypes) int.Parse(responseHeader.Substring(startOfCookies, endOfCookies - startOfCookies)); } if (this.serverEncryptionType == this.encryptionType) { this.peerCryptor = this.cryptor; } else { switch (this.serverEncryptionType) { case Common.EncryptionTypes.None: // Do Nothing. It is OK break; case Common.EncryptionTypes.SimpleXor: this.peerCryptor = new SimpleXorCryptor(this.encryptionKey, false); this.peerCryptor.SetSalt(this.encryptionSaltBytes); break; default: this.Close( "Unsupported encryption method used by server.", null, ErrorRenderer.HttpHeaderCode.C502BadGateway); return(false); } } return(true); }