/// <summary>
        /// WaitCallback method for performing a byte[] scan on an independent thread using System.Treading.QueueUserWorkItem.
        /// </summary>
        /// <exception cref="ArgumentException">Throws argument "o" is not an instance of StreamScanArgs.</exception>
        /// <param name="o">Instance of StreamScanArgs.</param>
        protected virtual void DoStreamScan(object o)
        {
            if (!(o is StreamScanArgs))
            {
                throw new ArgumentException(ResourceManagers.Strings.GetString(STR_DO_BYTE_SCAN_ARG_EX));
            }

            StreamScanArgs scanArgs = (StreamScanArgs)o;

            StreamScan(scanArgs);
        }
        /// <summary>
        /// Scan a byte[] bag.
        /// </summary>
        /// <param name="id">Unique identifier for the buffer (eg. filename, url or database key, etc.)</param>
        /// <param name="stream">Stream to scan</param>
        public override void Scan(string id, Stream stream)
        {
            StreamScanArgs args = new StreamScanArgs(id, stream);

            switch (_threadModel)
            {
            case VirusScanAgent.ThreadingModel.AsynchronousThreadPool:
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoStreamScan), args);
                break;

            case VirusScanAgent.ThreadingModel.SynchronousSingleThread:
                StreamScan(args);
                break;

            default:
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, ResourceManagers.Strings.GetString(STR_SCAN_NOT_SUPPORTED_EX_THREADING), _threadModel));
            }
        }
        /// <summary>
        /// Method scans a byte[] by passing it to clamd over a dynamically allocated port. The real magic happens here.
        /// The ItemScanCompleted event is raised whenever this method completes. If a virus is found, this method raises
        /// the VirusFound event.
        /// </summary>
        /// <param name="args">StreamScanArgs instance.</param>
        protected virtual void StreamScan(StreamScanArgs args)
        {
            string outstr = null;

            try
            {
                using (TcpClient tcpclient = new TcpClient(this.ClamdHost, this.ClamdPort))
                    using (NetworkStream netStream = tcpclient.GetStream())
                        using (StreamWriter outputStream = new StreamWriter(netStream))
                            using (StreamReader inputStream = new StreamReader(netStream))
                            {
                                outputStream.WriteLine(SCAN_VERB);
                                outputStream.Flush();

                                string   portstr    = inputStream.ReadLine();
                                string[] daemonargs = portstr.Split(' ');

                                SendStream(args.Stream, int.Parse(daemonargs[daemonargs.Length - 1], CultureInfo.InvariantCulture));

                                outstr = inputStream.ReadLine();

                                outputStream.Close();
                                inputStream.Close();
                                netStream.Close();
                                tcpclient.Close();
                            }

                if (outstr != null && outstr.IndexOf(FOUND) > -1)
                {
                    this.OnVirusFound(new ScanCompletedEventArgs(args.Id, outstr));
                }

                this.OnItemScanCompleted(new ScanCompletedEventArgs(args.Id, outstr));
                //reset retry counter
                _netRetryCount = 0;
            }
            catch (Exception ex)
            {
                if (ex is SocketException || ex is IOException)
                {
                    if (_netRetryCount < MAX_NET_RETRY)
                    {
                        //increment retry count and try again
                        _netRetryCount++;
                        StreamScan(args);
                    }
                    else
                    {
                        //reset retry count log error and return
                        _netRetryCount = 0;
                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Error(ex);
                        }
                        else
                        {
                            _logger.Error(ex.Message);
                        }
                    }
                }
                else
                {
                    throw;
                }
            }
        }
		/// <summary>
		/// Scan a byte[] bag.
		/// </summary>
		/// <param name="id">Unique identifier for the buffer (eg. filename, url or database key, etc.)</param>
		/// <param name="stream">Stream to scan</param>
		public override void Scan(string id, Stream stream)
		{
			StreamScanArgs args = new StreamScanArgs(id,stream);
			switch(_threadModel)
			{
				case VirusScanAgent.ThreadingModel.AsynchronousThreadPool :
					ThreadPool.QueueUserWorkItem( new WaitCallback( this.DoStreamScan ), args );
					break;
				case VirusScanAgent.ThreadingModel.SynchronousSingleThread :
					StreamScan(args);			
					break;
				default :
					throw new NotSupportedException( string.Format(CultureInfo.CurrentCulture, ResourceManagers.Strings.GetString(STR_SCAN_NOT_SUPPORTED_EX_THREADING), _threadModel) );
			}
		}
		/// <summary>
		/// Method scans a byte[] by passing it to clamd over a dynamically allocated port. The real magic happens here. 
		/// The ItemScanCompleted event is raised whenever this method completes. If a virus is found, this method raises
		/// the VirusFound event.
		/// </summary>
		/// <param name="args">StreamScanArgs instance.</param>
		protected virtual void StreamScan(StreamScanArgs args)
		{
			string outstr = null;
			try
			{
				using ( TcpClient tcpclient = new TcpClient( this.ClamdHost, this.ClamdPort ) )
				using (NetworkStream netStream = tcpclient.GetStream() )
				using (StreamWriter outputStream = new StreamWriter(netStream) )
				using (StreamReader inputStream = new StreamReader(netStream) )
				{
					outputStream.WriteLine( SCAN_VERB );
					outputStream.Flush();
				
					string portstr = inputStream.ReadLine();
					string[] daemonargs = portstr.Split(' ');
				
					SendStream ( args.Stream, int.Parse (daemonargs[daemonargs.Length-1], CultureInfo.InvariantCulture ) );
				
					outstr = inputStream.ReadLine();

					outputStream.Close();
					inputStream.Close();
					netStream.Close();
					tcpclient.Close();
				}

				if(outstr!=null && outstr.IndexOf(FOUND)>-1)
					this.OnVirusFound( new ScanCompletedEventArgs( args.Id, outstr ) );
				
				this.OnItemScanCompleted( new ScanCompletedEventArgs( args.Id, outstr ) );
				//reset retry counter
				_netRetryCount = 0;
			}
			catch(Exception ex)
			{
				if(ex is SocketException || ex is IOException)
				{
					if (_netRetryCount < MAX_NET_RETRY)
					{
						//increment retry count and try again
						_netRetryCount++;
						StreamScan( args );
					}
					else
					{
						//reset retry count log error and return
						_netRetryCount = 0;
						if(_logger.IsDebugEnabled)
							_logger.Error(ex);
						else
							_logger.Error(ex.Message);
					}
				}
				else
					throw;
			}

		}