Esempio n. 1
0
        /// <summary>
        /// Gets permission to attempt a send of a message.
        /// </summary>
        /// <param name="ipAddress">The IP Address we wan't to send from.</param>
        /// <param name="mxRecord">The MX Record of the destination.</param>
        /// <returns>TRUE if we can send FALSE if we should throttle.</returns>
        public bool TryGetSendAuth(VirtualMTA ipAddress, MXRecord mxRecord)
        {
            int mxPatternID     = -1;
            int maxMessagesHour = OutboundRuleManager.GetMaxMessagesDestinationHour(ipAddress, mxRecord, out mxPatternID);

            // If the Max messages is -1 then unlimited so can just return true here.
            // No need for any logging or calculating.
            if (maxMessagesHour == -1)
            {
                return(true);
            }

            // Create or get this outbound IP/mx pattern send history.
            ThrottleManager.MxPatternThrottlingSendHistory mxSndHist = null;
            if (!this._sendHistory.TryGetValue(ipAddress.IPAddress.ToString(), out mxSndHist))
            {
                mxSndHist = new ThrottleManager.MxPatternThrottlingSendHistory();
                this._sendHistory.AddOrUpdate(ipAddress.IPAddress.ToString(), mxSndHist, (string s, ThrottleManager.MxPatternThrottlingSendHistory sh) => mxSndHist);
            }
            //this._sendHistory.GetOrAdd(ipAddress.IPAddress.ToString(), new ThrottleManager.MxPatternThrottlingSendHistory());
            List <DateTime> sndHistory = mxSndHist.GetOrAdd(mxPatternID, new List <DateTime>());

            // Only calculate if needed.
            if (mxSndHist.IntervalValuesNeedRecalcTimestamp <= DateTime.UtcNow)
            {
                int maxMessages = 0;
                int maxMessagesIntervalMinute = 0;
                while (maxMessages < 1 && maxMessagesIntervalMinute <= 60)
                {
                    maxMessagesIntervalMinute++;
                    maxMessages = (int)Math.Floor((double)maxMessagesHour / 60d * (double)maxMessagesIntervalMinute);
                }

                mxSndHist.IntervalMaxMessages = maxMessages;
                mxSndHist.IntervalMinutes     = maxMessagesIntervalMinute;
                mxSndHist.IntervalValuesNeedRecalcTimestamp = DateTime.UtcNow.AddMinutes(MtaParameters.MTA_CACHE_MINUTES);
            }


            lock (sndHistory)
            {
                // Remove sends that happened over "Interval" minute(s) ago.
                DateTime sendsAfterTimestamp = DateTime.UtcNow.AddMinutes((double)(mxSndHist.IntervalMinutes * -1));
                sndHistory.RemoveAll((DateTime d) => d <= sendsAfterTimestamp);

                // Check for throttling
                if (sndHistory.Count < mxSndHist.IntervalMaxMessages)
                {
                    // Not hit throttle limit yet.
                    // Log send and return true.
                    sndHistory.Add(DateTime.UtcNow);
                    return(true);
                }
                else
                {
                    // THROTTLED!
                    return(false);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Keeps the send history clean by removing old values.
        /// This should only be called on background thread as it will run forever.
        /// </summary>
        private void DoSendHistoryCleaning()
        {
            while (true)
            {
                // Stopwatch is used to time the cleaning process.
                Stopwatch timer = new Stopwatch();
                timer.Start();
                // Loop through all outbound IPs send history
                foreach (KeyValuePair <string, ThrottleManager.MxPatternThrottlingSendHistory> ipHistory in this._sendHistory)
                {
                    ThrottleManager.MxPatternThrottlingSendHistory ipMxPtnHistory = ipHistory.Value;
                    // Loop through each MX Pattern within each outbound IP
                    foreach (KeyValuePair <int, List <DateTime> > mxPatternHistory in ipMxPtnHistory)
                    {
                        // Lock the ArrayList that contains the send history.
                        lock (mxPatternHistory.Value)
                        {
                            // ArrayList will hold the position of elements to remove from mxPatternHistory.Value
                            ArrayList toRemove = new ArrayList();

                            // Go through every log send and check that it hasn't expired.
                            for (int i = 0; i < mxPatternHistory.Value.Count; i++)
                            {
                                if (mxPatternHistory.Value[i].AddMinutes((double)ipMxPtnHistory.IntervalMinutes) < DateTime.UtcNow)
                                {
                                    toRemove.Add(i);
                                }
                            }

                            // Remove send history that is no longer required.
                            for (int z = toRemove.Count - 1; z >= 0; z--)
                            {
                                mxPatternHistory.Value.RemoveAt((int)toRemove[z]);
                            }
                        }
                    }
                }

                // We don't wan't to have the cleaner thread running indefinitely if there isn't anything
                // to do. Sleep thread so it only runs once every 15 seconds. Unless it's taking longer than
                // 15 seconds to clean in which case go again instantly.
                timer.Stop();
                TimeSpan ts = (TimeSpan.FromSeconds(15) - timer.Elapsed);
                if (ts > TimeSpan.FromSeconds(0))
                {
                    Thread.Sleep(ts);
                }
            }
        }