프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

markus / Rhino.Licensing / LicensingService.cs @ 42d49521

이력 | 보기 | 이력해설 | 다운로드 (8.42 KB)

1
namespace Rhino.Licensing
2
{
3
    using System;
4
    using System.Collections.Generic;
5
    using System.Diagnostics;
6
    using System.IO;
7
    using System.ServiceModel;
8
    using System.Linq;
9

    
10
    /// <summary>
11
    /// Licensing server implementation.
12
    /// Because we use this service behavior, we don't have to worry 
13
    /// about multi threading issues. it is not something that we 
14
    /// expect to have to deal with huge load, anyway.
15
    /// </summary>
16
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
17
    public class LicensingService : ILicensingService
18
    {
19
        private readonly List<LicenseValidator> availableLicenses = new List<LicenseValidator>();
20
        private readonly Dictionary<string, KeyValuePair<DateTime, LicenseValidator>> leasedLicenses = new Dictionary<string, KeyValuePair<DateTime, LicenseValidator>>();
21
        private readonly string state;
22

    
23
        /// <summary>
24
        /// Creates a new instance of <seealso cref="LicensingService"/>.
25
        /// </summary>
26
        public LicensingService()
27
        {
28
            if (SoftwarePublicKey == null)
29
                throw new InvalidOperationException("SoftwarePublicKey must be set before starting the service");
30

    
31
            if (LicenseServerPrivateKey == null)
32
                throw new InvalidOperationException("LicenseServerPrivateKey must be set before starting the service");
33

    
34
            var licensesDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Licenses");
35
            state = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "licenseServer.state");
36

    
37
            EnsureLicenseDirectoryExists(licensesDirectory);
38

    
39
            ReadAvailableLicenses(licensesDirectory);
40

    
41
            ReadInitialState();
42
        }
43

    
44
        /// <summary>
45
        /// Gets or Sets the public key of the product
46
        /// </summary>
47
        public static string SoftwarePublicKey
48
        {
49
            get; set;
50
        }
51

    
52
        /// <summary>
53
        /// Gets or Sets the private key of the license server
54
        /// </summary>
55
        public static string LicenseServerPrivateKey
56
        {
57
            get; set;
58
        }
59

    
60
        private static void EnsureLicenseDirectoryExists(string licensesDirectory)
61
        {
62
            if (Directory.Exists(licensesDirectory) == false)
63
            {
64
                try
65
                {
66
                    Directory.CreateDirectory(licensesDirectory);
67
                }
68
                catch (Exception e)
69
                {
70
                    throw new DirectoryNotFoundException("Could not find licenses directory: " + licensesDirectory, e);
71
                }
72
            }
73
        }
74

    
75
        private void ReadAvailableLicenses(string licensesDirectory)
76
        {
77
            foreach (var license in Directory.GetFiles(licensesDirectory, "*.xml"))
78
            {
79
                var set = new HashSet<Guid>();
80
                var validator = new LicenseValidator(SoftwarePublicKey, license)
81
                {
82
                    DisableFloatingLicenses = true
83
                };
84
                try
85
                {
86
                    validator.AssertValidLicense();
87
                    Debug.WriteLine("Found license for " + validator.Name + " of type: " + validator.LicenseType);
88
                    if (validator.LicenseType == LicenseType.Standard &&
89
                        // this prevent a simple cheating of simply copying the same
90
                        // license file several times
91
                        set.Add(validator.UserId))
92
                    {
93
                        availableLicenses.Add(validator);
94
                        Debug.WriteLine("Accepting license for: " + validator.Name + " " + validator.UserId);
95
                    }
96
                }
97
                catch
98
                {
99
                    continue;
100
                }
101
            }
102
        }
103

    
104
        private void ReadInitialState()
105
        {
106
            try
107
            {
108
                using (var file = new FileStream(state, FileMode.OpenOrCreate, FileAccess.ReadWrite))
109
                {
110
                    ReadState(file);
111
                }
112
            }
113
            catch (AccessViolationException e)
114
            {
115
                throw new AccessViolationException("Could not open file '" + state + "' for read/write, please grant read/write access to the file.", e);
116
            }
117
            catch (Exception e)
118
            {
119
                throw new InvalidOperationException("Could not understand file '" + state + "'.", e);
120
            }
121
        }
122

    
123
        private void ReadState(Stream stream)
124
        {
125
            try
126
            {
127
                using (var binaryReader = new BinaryReader(stream))
128
                {
129
                    while (true)
130
                    {
131
                        var identifier = binaryReader.ReadString();
132
                        var time = DateTime.FromBinary(binaryReader.ReadInt64());
133
                        var userId = new Guid(binaryReader.ReadBytes(16));
134

    
135
                        var licenseValidator = availableLicenses.FirstOrDefault(x => x.UserId == userId);
136
                        if (licenseValidator == null)
137
                            continue;
138

    
139
                        leasedLicenses[identifier] = new KeyValuePair<DateTime, LicenseValidator>(time, licenseValidator);
140
                        availableLicenses.Remove(licenseValidator);
141
                    }
142
                }
143
            }
144
            catch (EndOfStreamException)
145
            {
146
            }
147
        }
148

    
149
        private void WriteState(Stream stream)
150
        {
151
            using (var binaryWriter = new BinaryWriter(stream))
152
            {
153
                foreach (var pair in leasedLicenses)
154
                {
155
                    binaryWriter.Write(pair.Key);
156
                    binaryWriter.Write(pair.Value.Key.ToBinary());
157
                    binaryWriter.Write(pair.Value.Value.UserId.ToByteArray());
158
                }
159
                binaryWriter.Flush();
160
                stream.Flush();
161
            }
162
        }
163

    
164

    
165
		/// <summary>
166
        /// Leases a new license to the client machine.
167
        /// </summary>
168
        /// <param name="machine">client machine name</param>
169
        /// <param name="user">user name</param>
170
        /// <param name="id">Id of the license holder</param>
171
        /// <returns></returns>
172
		public string LeaseLicense(
173
			string machine,
174
			string user,
175
			Guid id)
176
		{
177
			KeyValuePair<DateTime, LicenseValidator> value;
178
			var identifier = machine + @"\" + user + ": " + id;
179
			if (leasedLicenses.TryGetValue(identifier, out value))
180
			{
181
				Debug.WriteLine(id + " is already leased, so extending lease");
182
				var licenseValidator = value.Value;
183
				return GenerateLicenseAndRenewLease(identifier, id, licenseValidator, value.Value.LicenseAttributes);
184
			}
185
			if (availableLicenses.Count > 0)
186
			{
187
				var availableLicense = availableLicenses[availableLicenses.Count - 1];
188
				availableLicenses.RemoveAt(availableLicenses.Count - 1);
189
				Debug.WriteLine("Found available license to give, leasing it");
190
				return GenerateLicenseAndRenewLease(identifier, id, availableLicense, availableLicense.LicenseAttributes);
191
			}
192
			foreach (var kvp in leasedLicenses)
193
			{
194
				if ((DateTime.UtcNow - kvp.Value.Key).TotalMinutes < 45)
195
					continue;
196
				leasedLicenses.Remove(kvp.Key);
197
				Debug.WriteLine("Found expired leased license, leasing it");
198
				return GenerateLicenseAndRenewLease(identifier, id, kvp.Value.Value, kvp.Value.Value.LicenseAttributes);
199
			}
200
			Debug.WriteLine("Could not find license to lease");
201
			return null;
202
		}
203

    
204
		private string GenerateLicenseAndRenewLease(string identifier, Guid id, LicenseValidator licenseValidator, IDictionary<string, string> attributes)
205
		{
206
			leasedLicenses[identifier] = new KeyValuePair<DateTime, LicenseValidator>(DateTime.UtcNow.AddMinutes(30), licenseValidator);
207
			using (var file = new FileStream(state, FileMode.Create, FileAccess.ReadWrite))
208
			{
209
				WriteState(file);
210
			}
211
			return GenerateLicense(id, licenseValidator, attributes);
212
		}
213

    
214
		private static string GenerateLicense(Guid id, LicenseValidator validator, IDictionary<string, string> attributes)
215
		{
216
			var generator = new LicenseGenerator(LicenseServerPrivateKey);
217
			return generator.Generate(validator.Name, id, DateTime.UtcNow.AddMinutes(45), attributes ,LicenseType.Floating);
218
		}
219

    
220
        /// <summary>
221
        /// 
222
        /// </summary>
223
        /// <param name="key"></param>
224
        /// <returns></returns>
225
        public string GetLicense(string key)
226
        {
227
            throw new NotImplementedException();
228
        }
229
    }
230
}
클립보드 이미지 추가 (최대 크기: 500 MB)