Click here to Skip to main content
15,886,110 members
Articles / Web Development / HTML

My own Mailinator in 5 minutes

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
19 Nov 2012CPOL6 min read 31.6K   405   13  
A simple Mailinator clone developed in five minutes with the NetFluid framework
using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.DNS.Client
{
    /// <summary>
    /// This class implements DNS client cache.
    /// </summary>
    public class DNS_ClientCache
    {
        #region class CacheEntry

        /// <summary>
        /// This class represents DNS cache entry.
        /// </summary>
        private class CacheEntry
        {
            private DnsServerResponse m_pResponse = null;
            private DateTime          m_Expires;

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="response">DNS server response.</param>
            /// <param name="expires">Time when cache entry expires.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
            public CacheEntry(DnsServerResponse response,DateTime expires)
            {
                if(response == null){
                    throw new ArgumentNullException("response");
                }

                m_pResponse = response;
                m_Expires   = expires;
            }


            #region Properties implementation

            /// <summary>
            /// Gets DNS server response.
            /// </summary>
            public DnsServerResponse Response
            {
                get{ return m_pResponse; }
            }

            /// <summary>
            /// Gets time when cache entry expires.
            /// </summary>
            public DateTime Expires
            {
                get{ return m_Expires; }
            }

            #endregion
        }

        #endregion

        private Dictionary<string,CacheEntry> m_pCache              = null;
        private int                           m_MaxCacheTtl         = 86400;
        private int                           m_MaxNegativeCacheTtl = 900;
        private TimerEx                       m_pTimerTimeout       = null;

        /// <summary>
        /// Default constructor.
        /// </summary>
        internal DNS_ClientCache()
        {
            m_pCache = new Dictionary<string,CacheEntry>();

            m_pTimerTimeout = new TimerEx(60000);
            m_pTimerTimeout.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerTimeout_Elapsed);
            m_pTimerTimeout.Start();
        }

        #region method Dispose

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        internal void Dispose()
        {
            m_pCache = null;

            m_pTimerTimeout.Dispose();
            m_pTimerTimeout = null;
        }

        #endregion


        #region Events handling

        #region method m_pTimerTimeout_Elapsed

        /// <summary>
        /// Is called when cache expired entries check timer triggers.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimerTimeout_Elapsed(object sender,System.Timers.ElapsedEventArgs e)
        {
            lock(m_pCache){
                // Copy entries to new array.
                List<KeyValuePair<string,CacheEntry>> values = new List<KeyValuePair<string,CacheEntry>>();
                foreach(KeyValuePair<string,CacheEntry> entry in m_pCache){
                    values.Add(entry);
                }

                // Remove expired cache entries.
                foreach(KeyValuePair<string,CacheEntry> entry in values){
                    if(DateTime.Now > entry.Value.Expires){
                        m_pCache.Remove(entry.Key);
                    }
                }
            }
        }

        #endregion

        #endregion


        #region method GetFromCache

        /// <summary>
		/// Gets DNS server cached response or null if no cached result.
		/// </summary>
		/// <param name="qname">Query name.</param>
		/// <param name="qtype">Query type.</param>
		/// <returns>Returns DNS server cached response or null if no cached result.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>qname</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		public DnsServerResponse GetFromCache(string qname,int qtype)
		{
            if(qname == null){
                throw new ArgumentNullException("qname");
            }
            if(qname == string.Empty){
                throw new ArgumentException("Argument 'qname' value must be specified.","qname");
            }

            CacheEntry entry = null;
            if(m_pCache.TryGetValue(qname + qtype,out entry)){
                // Cache entry has expired.
                if(DateTime.Now > entry.Expires){
                    return null;
                }
                else{
                    return entry.Response;
                }
            }
            else{
                return null;
            }
		}

		#endregion

        #region method AddToCache

		/// <summary>
		/// Adds dns records to cache. If old entry exists, it is replaced.
		/// </summary>
		/// <param name="qname">Query name.</param>
		/// <param name="qtype">Query type.</param>
		/// <param name="response">DNS server response.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>qname</b> or <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		public void AddToCache(string qname,int qtype,DnsServerResponse response)
		{
            if(qname == null){
                throw new ArgumentNullException("qname");
            }
            if(qname == string.Empty){
                throw new ArgumentException("Argument 'qname' value must be specified.","qname");
            }
			if(response == null){
				throw new ArgumentNullException("response");
			}

	        lock(m_pCache){
			    // Remove old cache entry, if any.
				if(m_pCache.ContainsKey(qname + qtype)){
				    m_pCache.Remove(qname + qtype);
			    }

                if(response.ResponseCode == DNS_RCode.NO_ERROR){
                    int ttl = m_MaxCacheTtl;
                    // Search smallest DNS record TTL and use it.
                    foreach(DNS_rr rr in response.AllAnswers){
                        if(rr.TTL < ttl){
                            ttl = rr.TTL;
                        }
                    }

                    m_pCache.Add(qname + qtype,new CacheEntry(response,DateTime.Now.AddSeconds(ttl)));
                }
                else{
                    m_pCache.Add(qname + qtype,new CacheEntry(response,DateTime.Now.AddSeconds(m_MaxNegativeCacheTtl)));
                }
			}
		}

		#endregion

        #region method ClearCache

		/// <summary>
		/// Clears DNS cache.
		/// </summary>
		public void ClearCache()
		{
			lock(m_pCache){
				m_pCache.Clear();
			}
		}

		#endregion


        #region Properties implementation

        /// <summary>
        /// Gets or sets maximum number of seconds to cache positive DNS responses.
        /// </summary>
        public int MaxCacheTtl
        {
            get{ return m_MaxCacheTtl; }

            set{ m_MaxCacheTtl = value; }
        }

        /// <summary>
        /// Gets or sets maximum number of seconds to cache negative DNS responses.
        /// </summary>
        public int MaxNegativeCacheTtl
        {
            get{ return m_MaxNegativeCacheTtl; }

            set{ m_MaxNegativeCacheTtl = value; }
        }

        /// <summary>
        /// Gets number of DNS queries cached.
        /// </summary>
        public int Count
        {
            get{ return m_pCache.Count; }
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Genny Mobility
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions