/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if(m_IsDisposed){ return; } m_IsDisposed = true; m_pOwner = null; m_pBuffer = null; m_pException = null; this.Completed = null; }
/// <summary> /// Default constructor. /// </summary> /// <param name="stream">Source stream.</param> /// <param name="access">Specifies stream access mode.</param> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception> public QuotedPrintableStream(SmartStream stream,FileAccess access) { if(stream == null){ throw new ArgumentNullException("stream"); } m_pStream = stream; m_AccessMode = access; m_pDecodedBuffer = new byte[32000]; m_pEncodedBuffer = new byte[78]; }
/// <summary> /// Cleans up any resources being used. /// </summary> public override void Dispose() { if(m_IsDisposed){ return; } if(!m_IsTerminated){ try{ Disconnect(); } catch{ // Skip disconnect errors. } } m_IsDisposed = true; // We must call disposed event before we release events. try{ OnDisposed(); } catch{ // We never should get exception here, user should handle it, just skip it. } m_pLocalEP = null; m_pRemoteEP = null; m_pCertificate = null; if(m_pTcpStream != null){ m_pTcpStream.Dispose(); } m_pTcpStream = null; m_pTags = null; // Release events. this.IdleTimeout = null; this.Disonnected = null; this.Disposed = null; }
/// <summary> /// Starts period-terminated data reading. /// </summary> /// <param name="stream">Owner SmartStream.</param> /// <returns>Returns true if read line completed synchronously, false if asynchronous operation pending.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception> internal bool Start(SmartStream stream) { if(stream == null){ throw new ArgumentNullException("stream"); } m_pOwner = stream; // Clear old data, if any. m_IsCompleted = false; m_BytesStored = 0; m_LinesStored = 0; m_pException = null; m_IsCompletedSync = DoRead(); return m_IsCompletedSync; }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if(m_IsDisposed){ return; } m_IsDisposed = true; m_pOwner = null; m_pStream = null; m_pReadLineOP.Dispose(); m_pReadLineOP = null; m_pException = null; this.Completed = null; }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner stream.</param> /// <param name="buffer">Buffer where to store data.</param> /// <param name="offset">The location in <b>buffer</b> to begin storing the data.</param> /// <param name="maxSize">Maximum number of bytes to read.</param> /// <param name="callback">The AsyncCallback delegate that is executed when asynchronous operation completes.</param> /// <param name="asyncState">User-defined object that qualifies or contains information about an asynchronous operation.</param> public ReadAsyncOperation(SmartStream owner,byte[] buffer,int offset,int maxSize,AsyncCallback callback,object asyncState) { if(owner == null){ throw new ArgumentNullException("owner"); } if(buffer == null){ throw new ArgumentNullException("buffer"); } if(offset < 0){ throw new ArgumentOutOfRangeException("offset","Argument 'offset' value must be >= 0."); } if(offset > buffer.Length){ throw new ArgumentOutOfRangeException("offset","Argument 'offset' value must be < buffer.Length."); } if(maxSize < 0){ throw new ArgumentOutOfRangeException("maxSize","Argument 'maxSize' value must be >= 0."); } if(offset + maxSize > buffer.Length){ throw new ArgumentOutOfRangeException("maxSize","Argument 'maxSize' is bigger than than argument 'buffer' can store."); } m_pOwner = owner; m_pBuffer = buffer; m_OffsetInBuffer = offset; m_MaxSize = maxSize; m_pAsyncCallback = callback; m_pAsyncState = asyncState; m_pAsyncWaitHandle = new AutoResetEvent(false); DoRead(); }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner stream.</param> /// <param name="storeStream">Stream where to store readed data.</param> /// <param name="count">Number of bytes to read from source stream.</param> /// <param name="callback">The AsyncCallback delegate that is executed when asynchronous operation completes.</param> /// <param name="asyncState">User-defined object that qualifies or contains information about an asynchronous operation.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>storeStream</b> is null reference.</exception> /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception> public ReadToStreamAsyncOperation(SmartStream owner,Stream storeStream,long count,AsyncCallback callback,object asyncState) { if(owner == null){ throw new ArgumentNullException("owner"); } if(storeStream == null){ throw new ArgumentNullException("storeStream"); } if(count < 0){ throw new ArgumentException("Argument 'count' must be >= 0."); } m_pOwner = owner; m_pStoreStream = storeStream; m_Count = count; m_pAsyncCallback = callback; m_pAsyncState = asyncState; m_pAsyncWaitHandle = new AutoResetEvent(false); if(m_Count == 0){ Completed(); } else{ DoDataReading(); } }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner stream.</param> /// <param name="terminator">Data terminator.</param> /// <param name="storeStream">Stream where to store readed header.</param> /// <param name="maxCount">Maximum number of bytes to read. Value 0 means not limited.</param> /// <param name="exceededAction">Specifies how this method behaves when maximum line size exceeded.</param> /// <param name="callback">The AsyncCallback delegate that is executed when asynchronous operation completes.</param> /// <param name="asyncState">User-defined object that qualifies or contains information about an asynchronous operation.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b>,<b>terminator</b> or <b>storeStream</b> is null reference.</exception> public ReadToTerminatorAsyncOperation(SmartStream owner,string terminator,Stream storeStream,long maxCount,SizeExceededAction exceededAction,AsyncCallback callback,object asyncState) { if(owner == null){ throw new ArgumentNullException("owner"); } if(terminator == null){ throw new ArgumentNullException("terminator"); } if(storeStream == null){ throw new ArgumentNullException("storeStream"); } if(maxCount < 0){ throw new ArgumentException("Argument 'maxCount' must be >= 0."); } m_pOwner = owner; m_Terminator = terminator; m_pTerminatorBytes = Encoding.ASCII.GetBytes(terminator); m_pStoreStream = storeStream; m_MaxCount = maxCount; m_SizeExceededAction = exceededAction; m_pAsyncCallback = callback; m_pAsyncState = asyncState; m_pAsyncWaitHandle = new AutoResetEvent(false); m_pLineBuffer = new byte[32000]; // Start reading data. #pragma warning disable m_pOwner.BeginReadLine(m_pLineBuffer,0,m_pLineBuffer.Length - 2,m_SizeExceededAction,new AsyncCallback(this.ReadLine_Completed),null); #pragma warning restore }
/// <summary> /// Disconnects connection. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="InvalidOperationException">Is raised when TCP client is not connected.</exception> public override void Disconnect() { if(m_IsDisposed){ throw new ObjectDisposedException("TCP_Client"); } if(!m_IsConnected){ throw new InvalidOperationException("TCP client is not connected."); } m_IsConnected = false; m_pLocalEP = null; m_pRemoteEP = null; m_pTcpStream.Dispose(); m_IsSecure = false; m_pTcpStream = null; LogAddText("Disconnected."); }
/// <summary> /// Starts reading line. /// </summary> /// <param name="async">If true then this method can complete asynchronously. If false, this method completed always syncronously.</param> /// <param name="stream">Owner SmartStream.</param> /// <returns>Returns true if read line completed synchronously, false if asynchronous operation pending.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception> internal bool Start(bool async,SmartStream stream) { if(stream == null){ throw new ArgumentNullException("stream"); } m_pOwner = stream; // Clear old data, if any. m_IsCompleted = false; m_BytesInBuffer = 0; m_LastByte = -1; m_pException = null; m_IsCompletedSync = DoLineReading(async); return m_IsCompletedSync; }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { if(m_State == AsyncOP_State.Disposed){ return; } SetState(AsyncOP_State.Disposed); m_pException = null; m_pStream = null; m_pOwner = null; m_pReadLineOP = null; this.CompletedAsync = null; }
/// <summary> /// Default constructor. /// </summary> /// <param name="stream">Source stream. Reading starts from stream current location.</param> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception> public WritePeriodTerminatedAsyncOP(Stream stream) { if(stream == null){ throw new ArgumentNullException("stream"); } m_pStream = new SmartStream(stream,false); }
/// <summary> /// Starts operation processing. /// </summary> /// <param name="owner">Owner SmartStream.</param> /// <returns>Returns true if asynchronous operation in progress or false if operation completed synchronously.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> internal bool Start(SmartStream owner) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pOwner = owner; SetState(AsyncOP_State.Active); BeginReadData(); // Set flag rise CompletedAsync event flag. The event is raised when async op completes. // If already completed sync, that flag has no effect. lock(m_pLock){ m_RiseCompleted = true; return m_State == AsyncOP_State.Active; } }
/// <summary> /// Initializes session. This method is called from TCP_Server when new session created. /// </summary> /// <param name="server">Owner TCP server.</param> /// <param name="socket">Connected socket.</param> /// <param name="hostName">Local host name.</param> /// <param name="ssl">Specifies if session should switch to SSL.</param> /// <param name="certificate">SSL certificate.</param> internal void Init(object server,Socket socket,string hostName,bool ssl,X509Certificate certificate) { // NOTE: We may not raise any event here ! m_pServer = server; m_LocalHostName = hostName; m_ID = Guid.NewGuid().ToString(); m_ConnectTime = DateTime.Now; m_pLocalEP = (IPEndPoint)socket.LocalEndPoint; m_pRemoteEP = (IPEndPoint)socket.RemoteEndPoint; m_pCertificate = certificate; socket.ReceiveBufferSize = 32000; socket.SendBufferSize = 32000; if(ssl){ m_pTcpStream = new SmartStream(new NetworkStream(socket,true),true); SwitchToSecure(); } else{ m_pTcpStream = new SmartStream(new NetworkStream(socket,true),true); } }
/// <summary> /// Switches session to secure connection. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="InvalidOperationException">Is raised when connection is already secure or when SSL certificate is not specified.</exception> public void SwitchToSecure() { if(m_IsDisposed){ throw new ObjectDisposedException("TCP_ServerSession"); } if(m_IsSecure){ throw new InvalidOperationException("Session is already SSL/TLS."); } if(m_pCertificate == null){ throw new InvalidOperationException("There is no certificate specified."); } // FIX ME: if ssl switching fails, it closes source stream or otherwise if ssl successful, source stream leaks. SslStream sslStream = new SslStream(m_pTcpStream.SourceStream); sslStream.AuthenticateAsServer(m_pCertificate); // Close old stream, but leave source stream open. m_pTcpStream.IsOwner = false; m_pTcpStream.Dispose(); m_IsSecure = true; m_pTcpStream = new SmartStream(sslStream,true); }
/// <summary> /// Switches session to secure connection. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="InvalidOperationException">Is raised when TCP client is not connected or is already secure.</exception> protected void SwitchToSecure() { if(m_IsDisposed){ throw new ObjectDisposedException("TCP_Client"); } if(!m_IsConnected){ throw new InvalidOperationException("TCP client is not connected."); } if(m_IsSecure){ throw new InvalidOperationException("TCP client is already secure."); } LogAddText("Switching to SSL."); // FIX ME: if ssl switching fails, it closes source stream or otherwise if ssl successful, source stream leaks. SslStream sslStream = new SslStream(m_pTcpStream.SourceStream,true,this.RemoteCertificateValidationCallback); sslStream.AuthenticateAsClient("dummy"); // Close old stream, but leave source stream open. m_pTcpStream.IsOwner = false; m_pTcpStream.Dispose(); m_IsSecure = true; m_pTcpStream = new SmartStream(sslStream,true); }
/// <summary> /// Default constructor. /// </summary> /// <param name="owner">Owner stream.</param> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> public BufferReadAsyncOP(SmartStream owner) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pOwner = owner; }
/// <summary> /// Starts operation processing. /// </summary> /// <param name="owner">Owner SmartStream.</param> /// <returns>Returns true if asynchronous operation in progress or false if operation completed synchronously.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> internal bool Start(SmartStream owner) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pOwner = owner; SetState(AsyncOP_State.Active); try{ // Read line. m_pReadLineOP = new ReadLineAsyncOP(new byte[32000],SizeExceededAction.ThrowException); m_pReadLineOP.Completed += delegate(object s,EventArgs<ReadLineAsyncOP> e){ ReadLineCompleted(m_pReadLineOP); }; if(m_pStream.ReadLine(m_pReadLineOP,true)){ ReadLineCompleted(m_pReadLineOP); } } catch(Exception x){ m_pException = x; SetState(AsyncOP_State.Completed); m_pReadLineOP.Dispose(); } // Set flag rise CompletedAsync event flag. The event is raised when async op completes. // If already completed sync, that flag has no effect. lock(m_pLock){ m_RiseCompleted = true; return m_State == AsyncOP_State.Active; } }
/// <summary> /// Reads header from source <b>stream</b> and writes it to stream. /// </summary> /// <param name="stream">Stream from where to read header.</param> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null.</exception> public void WriteHeader(Stream stream) { if(m_IsDisposed){ throw new ObjectDisposedException(this.GetType().Name); } if(stream == null){ throw new ArgumentNullException("stream"); } SmartStream reader = new SmartStream(stream,false); reader.ReadHeader(this,0,SizeExceededAction.ThrowException); }
/// <summary> /// Completes command reading operation. /// </summary> /// <param name="op">Operation.</param> /// <returns>Returns true if server should start reading next command.</returns> private bool ProcessCmd(SmartStream.ReadLineAsyncOP op) { bool readNextCommand = true; try{ // We are already disposed. if(this.IsDisposed){ return false; } // Check errors. if(op.Error != null){ OnError(op.Error); } // Remote host shut-down(Socket.ShutDown) socket. if(op.BytesInBuffer == 0){ LogAddText("The remote host '" + this.RemoteEndPoint.ToString() + "' shut down socket."); Dispose(); return false; } string[] cmd_args = Encoding.UTF8.GetString(op.Buffer,0,op.LineBytesInBuffer).Split(new char[]{' '},2); string cmd = cmd_args[0].ToUpperInvariant(); string args = cmd_args.Length == 2 ? cmd_args[1] : ""; // Log. if(this.Server.Logger != null){ // Hide password from log. if(cmd == "PASS"){ this.Server.Logger.AddRead(this.ID,this.AuthenticatedUserIdentity,op.BytesInBuffer,"PASS <***REMOVED***>",this.LocalEndPoint,this.RemoteEndPoint); } else{ this.Server.Logger.AddRead(this.ID,this.AuthenticatedUserIdentity,op.BytesInBuffer,op.LineUtf8,this.LocalEndPoint,this.RemoteEndPoint); } } if(cmd == "STLS"){ STLS(args); } else if(cmd == "USER"){ USER(args); } else if(cmd == "PASS"){ PASS(args); } else if(cmd == "PASS"){ PASS(args); } else if(cmd == "AUTH"){ AUTH(args); } else if(cmd == "STAT"){ STAT(args); } else if(cmd == "LIST"){ LIST(args); } else if(cmd == "UIDL"){ UIDL(args); } else if(cmd == "TOP"){ TOP(args); } else if(cmd == "RETR"){ RETR(args); } else if(cmd == "DELE"){ DELE(args); } else if(cmd == "NOOP"){ NOOP(args); } else if(cmd == "RSET"){ RSET(args); } else if(cmd == "DELE"){ DELE(args); } else if(cmd == "CAPA"){ CAPA(args); } else if(cmd == "QUIT"){ QUIT(args); } else{ m_BadCommands++; // Maximum allowed bad commands exceeded. if(this.Server.MaxBadCommands != 0 && m_BadCommands > this.Server.MaxBadCommands){ WriteLine("-ERR Too many bad commands, closing transmission channel."); Disconnect(); return false; } WriteLine("-ERR Error: command '" + cmd + "' not recognized."); } } catch(Exception x){ OnError(x); } return readNextCommand; }