private static LicenseState GetLicenseState(Database db, License license, DateTime? buildDate, DateTime now, Dictionary<int, LicenseState> cache, Dictionary<int, string> errors)
        {
            LicenseState licenseState;

            if (cache.TryGetValue(license.LicenseId, out licenseState))
                return licenseState;

            ParsedLicense parsedLicense = ParsedLicenseManager.GetParsedLicense(license.LicenseKey);
            if (parsedLicense == null)
            {
                errors[license.LicenseId] = string.Format("The license key #{0} is invalid.", license.LicenseId);
                return null;
            }

            if (!parsedLicense.IsLicenseServerElligible())
            {
                errors[license.LicenseId] = string.Format("The license #{0}, of type {1}, cannot be used in the license server.",
                    license.LicenseId, parsedLicense.LicenseType);
                return null;
            }


            if ( !(buildDate == null || parsedLicense.SubscriptionEndDate == null || buildDate <= parsedLicense.SubscriptionEndDate ) )
            {
                errors[license.LicenseId] = string.Format("The maintenance subscription of license #{0} ends on {1:d} but the requested version has been built on {2:d}.",
                    license.LicenseId, parsedLicense.SubscriptionEndDate, buildDate);
                return null;
            }

           
            licenseState = new LicenseState(now, db, license, parsedLicense);
            cache.Add(license.LicenseId, licenseState);
            return licenseState;
           
        }
        protected override void OnLoad( EventArgs e )
        {
            Database db = new Database();
            License[] licenses = (from l in db.Licenses orderby l.Priority, l.LicenseId descending select l).ToArray();
            List<LicenseInfo> licenseInfos = new List<LicenseInfo>();

            for ( int i = 0; i < licenses.Length; i++ )
            {
                License license = licenses[i];
                LicenseInfo licenseInfo = new LicenseInfo {LicenseId = license.LicenseId};
                ParsedLicense parsedLicense = ParsedLicenseManager.GetParsedLicense( license.LicenseKey );
                if ( parsedLicense == null )
                {
                    licenseInfo.LicenseType = "INVALID";
                }
                else
                {
                    licenseInfo.LicenseType = parsedLicense.LicenseType.ToString();
                    licenseInfo.MaxUsers = parsedLicense.UserNumber;
                    licenseInfo.CurrentUsers = db.GetActiveLeads( license.LicenseId, VirtualDateTime.UtcNow );
                    licenseInfo.ProductCode = parsedLicense.Product.ToString();
                    licenseInfo.GraceStartTime = license.GraceStartTime;
                    licenseInfo.Status = license.Priority >= 0 ? "Active" : "Disabled";
                    licenseInfo.MaintenanceEndDate = parsedLicense.SubscriptionEndDate;
                }

                licenseInfos.Add( licenseInfo );
            }

            this.noLicensePanel.Visible = licenseInfos.Count == 0;
            this.GridView1.DataSource = licenseInfos;
            this.GridView1.DataBind();
        }
        internal static void CheckAssertions(Database db, License license, DateTime now)
        {
#if FALSE
            db.SubmitChanges();
            Dictionary<int, LicenseState> cache = new Dictionary<int, LicenseState>();
            List<string> errors = new List<string>();
            LicenseState licenseState = GetLicenseState( db, license, now, cache, errors );
            if ( licenseState == null )
                throw new Exception( string.Join( ". ", errors.ToArray() ) );

            
            if ( licenseState.Maximum.HasValue )
            {
                double max = Math.Ceiling(licenseState.Maximum.Value * (100.0 + Settings.Default.GracePeriodPercent) / 100.0);
                if (licenseState.Usage > max)
                    throw new Exception( "Maximum exceeded." );
            }
#endif
        }
        public void ProcessRequest(HttpContext context)
        {
            this.context = context;
            using (Database db = new Database())
            {

                // Parse requested product code.
                string productCode = context.Request.QueryString["product"];
                if (string.IsNullOrEmpty(productCode))
                {
                    this.SetError(400, "Missing query string argument: product.");
                    return;
                }

                // Parse build date.
                string buildDateString = context.Request.QueryString["buildDate"];
                DateTime? buildDate = null;
                if (!string.IsNullOrEmpty(buildDateString))
                {
                    DateTime buildDateNotNull;
                    if (
                        !DateTime.TryParse(buildDateString, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind,
                            out buildDateNotNull))
                    {
                        this.SetError(400, "Cannot parse the argument: buildDate.");
                        return;
                    }

                    buildDate = buildDateNotNull;
                }



                // Parse machine name.
                string machine = context.Request.QueryString["machine"];
                if (string.IsNullOrEmpty(machine))
                {
                    this.SetError(400, "Missing query string argument: machine.");
                    return;
                }

                machine = machine.ToLowerInvariant();


                // Parse user name.
                string userName = context.Request.QueryString["user"];

                if (string.IsNullOrEmpty(userName))
                {
                    this.SetError(400, "Missing query string argument: user.");
                    return;
                }

                userName = userName.ToLowerInvariant();



                bool releaseMutex = false;
                try
                {

                    while (true)
                    {
                        try
                        {

                            if (!mutex.WaitOne(TimeSpan.FromSeconds(Settings.Default.MutexTimeout)))
                            {
                                this.SetError(503, "Service overloaded.");
                                return;
                            }
                            else
                            {
                                releaseMutex = true;
                                break;
                            }

                        }
                        catch (AbandonedMutexException)
                        {
                            try
                            {
                                mutex.ReleaseMutex();
                            }
                            catch
                            {
                            }

                            try
                            {
                                mutex.Close();
                            }
                            catch
                            {
                            }

                            mutex = CreateMutex();
                        }
                    }

                    Stopwatch stopwatch = Stopwatch.StartNew();

                    LicenseLease licenseLease = new LeaseService(true).GetLicenseLease(db, productCode, buildDate, machine, userName, context.User.Identity.Name, VirtualDateTime.UtcNow, errors);

                    if (licenseLease != null)
                    {
                        db.SubmitChanges();

                        string serializedLease = licenseLease.Serialize();
                        context.Response.Write(serializedLease);
                    }
                    else
                    {
                        this.SetError(403, "No license with free capacity. " + string.Join(" ", this.errors.Values));
                    }

                    if (stopwatch.ElapsedMilliseconds > 1000)
                    {
                        context.Trace.Warn(string.Format("Request served in {0}", stopwatch.Elapsed));
                    }
                }
                finally
                {
                    if (releaseMutex)
                    {
                        try
                        {
                            mutex.ReleaseMutex();
                        }
                        catch
                        {

                        }
                    }
                }
            }
        }
        protected override void OnLoad(EventArgs e)
        {
            Database db = new Database();
          

            LicenseId = int.Parse(this.Request.QueryString["id"]);

            Days = int.Parse( this.Request.QueryString["days"] ?? "30" );

            DateTime endDate = VirtualDateTime.UtcNow.Date.AddDays(1);
            DateTime startDate = endDate.AddDays( -Days );

            // Retrieve license information.
            License license = (from l in db.Licenses where l.LicenseId == LicenseId select l).Single();
            ParsedLicense parsedLicense = ParsedLicense.Deserialize(license.LicenseKey);
            if (parsedLicense != null)
            {
                if (parsedLicense.UserNumber.HasValue)
                {
                    this.Maximum = parsedLicense.UserNumber;
                    this.GraceMaximum = this.Maximum.GetValueOrDefault()*(100 + parsedLicense.GetGracePercentOrDefault())/100;
                    this.AxisMaximum = GraceMaximum.GetValueOrDefault();
                }
            }


            var q = from l in db.GetLeaseCountingPoints(LicenseId, startDate, endDate)
                group l by l.Time.Date
                into d
                select
                    new
                    {
                        Date = d.Key,
                        Count = d.Max(point => point.LeaseCount),
                        LastCount = d.OrderByDescending(point => point.Time).First().LeaseCount
                    };

            // Fill the array with data.
            this.Keys = new string[Days];
            this.Values = new string[Days];
            var lastValues = new int?[Days];
            foreach ( var point in q )
            {
                int day = (int) Math.Floor( point.Date.Subtract( startDate ).TotalDays );

                if ( point.Count > this.AxisMaximum )
                {
                    this.AxisMaximum = point.Count;
                }

                if ( day < 0 )
                {
                    this.Values[0] = point.Count.ToString();
                    lastValues[0] = point.LastCount;
                }
                else if ( day < Days )
                {
                    this.Values[day] = point.Count.ToString();
                    lastValues[day] = point.LastCount;
                }
            }

            // Do extrapolation of missing values.
            string lastValue = "0";

            for ( int i = 0; i < Days; i++ )
            {
                DateTime date = startDate.AddDays( i    );
                if (date.DayOfWeek == DayOfWeek.Monday)
                {
                    this.Keys[i] = date.ToString( "MM/dd/yyyy", CultureInfo.InvariantCulture );
                }
                if ( this.Values[i] == null )
                {
                    if (i > 0)
                    {
                        this.Values[i] = lastValue;
                    }
                    else
                    {
                        this.Values[0] = lastValue;
                    }
                }
                if ( lastValues[i] != null )
                {
                    lastValue = lastValues[i].ToString();
                }
            }


            this.AxisMaximum = (int) Math.Ceiling( Math.Ceiling( this.AxisMaximum*1.2 )/10)*10;
        }
 public LicenseState( DateTime time, Database db, License license, ParsedLicense parsedLicense )
 {
     this.time = time;
     this.db = db;
     this.license = license;
     this.ParsedLicense = parsedLicense;
 }
        public Lease GetLease(Database db, string productCode, DateTime? buildDate, string machine, string userName, string authenticatedUserName, DateTime now, Dictionary<int, string> errors, License[] licenses)
        {
            Dictionary<int, LicenseState> licenseStates = new Dictionary<int, LicenseState>();
        
            Settings settings = Settings.Default;

            // Check if we have a lease that we can use.
            foreach (License license in licenses)
            {
                LicenseState licenseState = GetLicenseState( db, license, buildDate, now, licenseStates, errors );
                if ( licenseState == null ) continue;

               
         
                int licenseId = license.LicenseId;
                Lease[] currentLeases = (from l in db.OpenLeases
                                         where
                                             l.LicenseId == licenseId &&
                                             l.StartTime <= now &&
                                             l.EndTime > now &&
                                             l.UserName == userName
                                         orderby l.StartTime
                                         select l).ToArray();

                Dictionary<string, string> machines = new Dictionary<string, string>( StringComparer.OrdinalIgnoreCase );
                foreach (Lease candidateLease in currentLeases)
                {
                    machines[candidateLease.Machine] = candidateLease.Machine;

                    if (candidateLease.Machine != machine)
                        continue;

                    if (candidateLease.EndTime > now.AddDays(settings.MinLeaseDays))
                    {
                        // We have already a good lease.
                        return candidateLease;
                    }
                    else
                    {
                        // Invariant: we can always prolong a lease because licenses are always acquired from
                        // the present moment, therefore taking the current lease into account.
                        // UNLESS it's the end of the license period or the grace period.
                        Lease lease = db.ProlongLease( candidateLease, authenticatedUserName, now );
                        if ( lease == null )
                        {
                            continue;
                        }
                        return lease;
                    }
                }

                // We did not find a lease for the requested machines.
                // See if we can do a new lease that would not increment the number of concurrent users.
                if (machines.Count % Settings.Default.MachinesPerUser != 0)
                {
                    CheckAssertions( db, license, now );
                    Lease lease = db.CreateLease(license, userName, machine, authenticatedUserName, now, licenseState.InExcess);
                    if (lease != null) return lease;
                }
            }

            // We don't have a current lease. Create a new one.
            foreach (License license in licenses)
            {
                LicenseState licenseState = GetLicenseState( db, license, buildDate, now, licenseStates, errors );
                if (licenseState == null) continue;


                if (licenseState.Maximum.HasValue && licenseState.Maximum.Value <= licenseState.Usage 
                    && ( !licenseState.ParsedLicense.ValidTo.HasValue || now < licenseState.ParsedLicense.ValidTo ))
                {
                    // Not enough users for this license.
                    continue;
                }
                
               
                Lease lease = db.CreateLease( license, userName, machine, authenticatedUserName, now, false );
                if (lease != null) return lease;
            }

            // We did not find a suitable license. See if we can use the grace period.
            foreach (License license in licenses)
            {
                LicenseState licenseState = GetLicenseState(db, license, buildDate, now, licenseStates, errors);
              
                if ( licenseState == null ) continue;


                if (license.GraceStartTime == null)
                {
                    license.GraceStartTime = now;
                }

                int graceLimit = (int)Math.Ceiling(licenseState.Maximum.Value * (100.0 + licenseState.ParsedLicense.GetGracePercentOrDefault()) / 100.0);
                DateTime graceEnd = license.GraceStartTime.Value.AddDays(licenseState.ParsedLicense.GetGraceDaysOrDefault());

                if (license.GraceStartTime <= now && graceEnd > now && licenseState.Usage  < graceLimit)
                {
                    // We will use the grace period.

                    // See if we should send a warning message.
                    if (license.GraceLastWarningTime.GetValueOrDefault(DateTime.MinValue).AddDays(settings.GracePeriodWarningDays) < now)
                    {
                        try
                        {
                            string body = string.Format(
                                "The license #{0} has a capacity of {1} concurrent user(s), but {2} users are currently using the product {3}. " +
                                "The grace period has started on {4} and will end on {5}. After this date, additional leases will be denied." +
                                "Please contact PostSharp Technologies to acquire additional licenses.",
                                license.LicenseId, licenseState.Maximum, licenseState.Usage + 1, licenseState.ParsedLicense.Product,
                                license.GraceStartTime, graceEnd);
                            const string subject = "WARNING: licensing capacity exceeded";

                            SendEmail(settings.GracePeriodWarningEmailTo, settings.GracePeriodWarningEmailCC, subject, body);
                            license.GraceLastWarningTime = now;
                        }
                        catch (Exception e)
                        {
                            Trace.TraceError(e.ToString());
                        }
                    }

                    Lease lease = db.CreateLease(license, userName, machine, authenticatedUserName, now, true);
                    if (lease != null) return lease;
                }
            }


            SendEmail(settings.DeniedRequestEmailTo, null, "ERROR: license request denied",
                       string.Format("No license with free capacity was found to satisfy the lease request for the product {0} from " +
                                      "the user '{1}' (authentication: '{2}'), machine '{3}'. " + string.Join(". ", errors.ToArray()),
                                      productCode, userName, authenticatedUserName, machine));

            return null;
        }
        public Lease GetLease( Database db, string productCode, DateTime? buildDate, string machine, string userName, string authenticatedUserName, DateTime now, Dictionary<int,string> errors )
        {
            License[] licenses = (from license in db.Licenses
                                  where license.ProductCode == productCode
                                  orderby license.Priority, license.LicenseId descending 
                                  select license).ToArray();

            return GetLease( db, productCode, buildDate, machine, userName, authenticatedUserName, now, errors, licenses );
        }
        public LicenseLease GetLicenseLease(Database db, string productCode, DateTime? buildDate, string machine, string userName, string authenticatedUserName, DateTime now, Dictionary<int, string> errors)
        {
            Settings settings = Settings.Default;
            
            // Get suitable active licenses.
            License[] licenses = (from license in db.Licenses
                                  where license.ProductCode == productCode && license.Priority >= 0
                                  orderby license.Priority
                                  select license).ToArray();

            // Check if the machine belongs to build server user.
            if ( IsBuildServer( machine ) )
            {
                License buildServerLicense = GetBuildServerLicense( licenses );
                if ( buildServerLicense != null )
                {
                    DateTime endTime = now.AddDays( Settings.Default.NewLeaseDays );
                    LicenseLease buildServerLicenseLease = new LicenseLease( buildServerLicense.LicenseKey, now, endTime, endTime.AddDays( -settings.MinLeaseDays ) );

                    // Lease for build server should not be stored - build server users shouldn't steal developer licenses.
                    return buildServerLicenseLease;
                }

                // try to acquire lease in normal way
            }

            Lease lease = GetLease( db, productCode, buildDate, machine, userName, authenticatedUserName, now, errors, licenses );
            if ( lease == null )
                return null;

            LicenseLease licenseLease = new LicenseLease(lease.License.LicenseKey,
                    lease.StartTime, lease.EndTime, lease.EndTime.AddDays(-settings.MinLeaseDays));

           return licenseLease;
        }