diff options
author | teravus | 2013-10-09 22:21:25 -0500 |
---|---|---|
committer | teravus | 2013-10-09 22:21:25 -0500 |
commit | 75f63ecfcd885ae71bca130ee0db1ecc997b86cd (patch) | |
tree | d7eea5746c154ed8b6b6e9a4bd0c1b0ba98cc320 | |
parent | * Remove a test *cleanup* (diff) | |
download | opensim-SC_OLD-75f63ecfcd885ae71bca130ee0db1ecc997b86cd.zip opensim-SC_OLD-75f63ecfcd885ae71bca130ee0db1ecc997b86cd.tar.gz opensim-SC_OLD-75f63ecfcd885ae71bca130ee0db1ecc997b86cd.tar.bz2 opensim-SC_OLD-75f63ecfcd885ae71bca130ee0db1ecc997b86cd.tar.xz |
* Add a session concurrency option per key. Allows developer/config to specify number of concurrent requests on a service.
4 files changed, 102 insertions, 23 deletions
diff --git a/OpenSim/Framework/BasicDOSProtector.cs b/OpenSim/Framework/BasicDOSProtector.cs index b470161..89bfa94 100644 --- a/OpenSim/Framework/BasicDOSProtector.cs +++ b/OpenSim/Framework/BasicDOSProtector.cs | |||
@@ -43,9 +43,11 @@ namespace OpenSim.Framework | |||
43 | private readonly BasicDosProtectorOptions _options; | 43 | private readonly BasicDosProtectorOptions _options; |
44 | private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker | 44 | private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker |
45 | private readonly Dictionary<string, int> _tempBlocked; // blocked list | 45 | private readonly Dictionary<string, int> _tempBlocked; // blocked list |
46 | private readonly Dictionary<string, int> _sessions; | ||
46 | private readonly System.Timers.Timer _forgetTimer; // Cleanup timer | 47 | private readonly System.Timers.Timer _forgetTimer; // Cleanup timer |
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim(); | 49 | private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim(); |
50 | private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim(); | ||
49 | public BasicDOSProtector(BasicDosProtectorOptions options) | 51 | public BasicDOSProtector(BasicDosProtectorOptions options) |
50 | { | 52 | { |
51 | _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true); | 53 | _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true); |
@@ -53,13 +55,14 @@ namespace OpenSim.Framework | |||
53 | _options = options; | 55 | _options = options; |
54 | _deeperInspection = new Dictionary<string, CircularBuffer<int>>(); | 56 | _deeperInspection = new Dictionary<string, CircularBuffer<int>>(); |
55 | _tempBlocked = new Dictionary<string, int>(); | 57 | _tempBlocked = new Dictionary<string, int>(); |
58 | _sessions = new Dictionary<string, int>(); | ||
56 | _forgetTimer = new System.Timers.Timer(); | 59 | _forgetTimer = new System.Timers.Timer(); |
57 | _forgetTimer.Elapsed += delegate | 60 | _forgetTimer.Elapsed += delegate |
58 | { | 61 | { |
59 | _forgetTimer.Enabled = false; | 62 | _forgetTimer.Enabled = false; |
60 | 63 | ||
61 | List<string> removes = new List<string>(); | 64 | List<string> removes = new List<string>(); |
62 | _lockSlim.EnterReadLock(); | 65 | _blockLockSlim.EnterReadLock(); |
63 | foreach (string str in _tempBlocked.Keys) | 66 | foreach (string str in _tempBlocked.Keys) |
64 | { | 67 | { |
65 | if ( | 68 | if ( |
@@ -67,26 +70,27 @@ namespace OpenSim.Framework | |||
67 | _tempBlocked[str]) > 0) | 70 | _tempBlocked[str]) > 0) |
68 | removes.Add(str); | 71 | removes.Add(str); |
69 | } | 72 | } |
70 | _lockSlim.ExitReadLock(); | 73 | _blockLockSlim.ExitReadLock(); |
71 | lock (_deeperInspection) | 74 | lock (_deeperInspection) |
72 | { | 75 | { |
73 | _lockSlim.EnterWriteLock(); | 76 | _blockLockSlim.EnterWriteLock(); |
74 | for (int i = 0; i < removes.Count; i++) | 77 | for (int i = 0; i < removes.Count; i++) |
75 | { | 78 | { |
76 | _tempBlocked.Remove(removes[i]); | 79 | _tempBlocked.Remove(removes[i]); |
77 | _deeperInspection.Remove(removes[i]); | 80 | _deeperInspection.Remove(removes[i]); |
81 | _sessions.Remove(removes[i]); | ||
78 | } | 82 | } |
79 | _lockSlim.ExitWriteLock(); | 83 | _blockLockSlim.ExitWriteLock(); |
80 | } | 84 | } |
81 | foreach (string str in removes) | 85 | foreach (string str in removes) |
82 | { | 86 | { |
83 | m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", | 87 | m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", |
84 | _options.ReportingName, str); | 88 | _options.ReportingName, str); |
85 | } | 89 | } |
86 | _lockSlim.EnterReadLock(); | 90 | _blockLockSlim.EnterReadLock(); |
87 | if (_tempBlocked.Count > 0) | 91 | if (_tempBlocked.Count > 0) |
88 | _forgetTimer.Enabled = true; | 92 | _forgetTimer.Enabled = true; |
89 | _lockSlim.ExitReadLock(); | 93 | _blockLockSlim.ExitReadLock(); |
90 | }; | 94 | }; |
91 | 95 | ||
92 | _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; | 96 | _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; |
@@ -100,9 +104,9 @@ namespace OpenSim.Framework | |||
100 | public bool IsBlocked(string key) | 104 | public bool IsBlocked(string key) |
101 | { | 105 | { |
102 | bool ret = false; | 106 | bool ret = false; |
103 | _lockSlim.EnterReadLock(); | 107 | _blockLockSlim.EnterReadLock(); |
104 | ret = _tempBlocked.ContainsKey(key); | 108 | ret = _tempBlocked.ContainsKey(key); |
105 | _lockSlim.ExitReadLock(); | 109 | _blockLockSlim.ExitReadLock(); |
106 | return ret; | 110 | return ret; |
107 | } | 111 | } |
108 | 112 | ||
@@ -119,20 +123,58 @@ namespace OpenSim.Framework | |||
119 | 123 | ||
120 | string clientstring = key; | 124 | string clientstring = key; |
121 | 125 | ||
122 | _lockSlim.EnterReadLock(); | 126 | _blockLockSlim.EnterReadLock(); |
123 | if (_tempBlocked.ContainsKey(clientstring)) | 127 | if (_tempBlocked.ContainsKey(clientstring)) |
124 | { | 128 | { |
125 | _lockSlim.ExitReadLock(); | 129 | _blockLockSlim.ExitReadLock(); |
126 | 130 | ||
127 | if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) | 131 | if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) |
128 | return false; | 132 | return false; |
129 | else | 133 | else |
130 | throw new System.Security.SecurityException("Throttled"); | 134 | throw new System.Security.SecurityException("Throttled"); |
131 | } | 135 | } |
132 | _lockSlim.ExitReadLock(); | 136 | |
137 | _blockLockSlim.ExitReadLock(); | ||
133 | 138 | ||
134 | _generalRequestTimes.Put(Util.EnvironmentTickCount()); | 139 | lock (_generalRequestTimes) |
140 | _generalRequestTimes.Put(Util.EnvironmentTickCount()); | ||
135 | 141 | ||
142 | if (_options.MaxConcurrentSessions > 0) | ||
143 | { | ||
144 | int sessionscount = 0; | ||
145 | |||
146 | _sessionLockSlim.EnterReadLock(); | ||
147 | if (_sessions.ContainsKey(key)) | ||
148 | sessionscount = _sessions[key]; | ||
149 | _sessionLockSlim.ExitReadLock(); | ||
150 | |||
151 | if (sessionscount > _options.MaxConcurrentSessions) | ||
152 | { | ||
153 | // Add to blocking and cleanup methods | ||
154 | lock (_deeperInspection) | ||
155 | { | ||
156 | _blockLockSlim.EnterWriteLock(); | ||
157 | if (!_tempBlocked.ContainsKey(clientstring)) | ||
158 | { | ||
159 | _tempBlocked.Add(clientstring, | ||
160 | Util.EnvironmentTickCount() + | ||
161 | (int) _options.ForgetTimeSpan.TotalMilliseconds); | ||
162 | _forgetTimer.Enabled = true; | ||
163 | m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds based on concurrency, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); | ||
164 | |||
165 | } | ||
166 | else | ||
167 | _tempBlocked[clientstring] = Util.EnvironmentTickCount() + | ||
168 | (int) _options.ForgetTimeSpan.TotalMilliseconds; | ||
169 | _blockLockSlim.ExitWriteLock(); | ||
170 | |||
171 | } | ||
172 | |||
173 | |||
174 | } | ||
175 | else | ||
176 | ProcessConcurrency(key, endpoint); | ||
177 | } | ||
136 | if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && | 178 | if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && |
137 | (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < | 179 | (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < |
138 | _options.RequestTimeSpan.TotalMilliseconds)) | 180 | _options.RequestTimeSpan.TotalMilliseconds)) |
@@ -147,6 +189,29 @@ namespace OpenSim.Framework | |||
147 | } | 189 | } |
148 | return true; | 190 | return true; |
149 | } | 191 | } |
192 | private void ProcessConcurrency(string key, string endpoint) | ||
193 | { | ||
194 | _sessionLockSlim.EnterWriteLock(); | ||
195 | if (_sessions.ContainsKey(key)) | ||
196 | _sessions[key] = _sessions[key] + 1; | ||
197 | else | ||
198 | _sessions.Add(key,1); | ||
199 | _sessionLockSlim.ExitWriteLock(); | ||
200 | } | ||
201 | public void ProcessEnd(string key, string endpoint) | ||
202 | { | ||
203 | _sessionLockSlim.EnterWriteLock(); | ||
204 | if (_sessions.ContainsKey(key)) | ||
205 | { | ||
206 | _sessions[key]--; | ||
207 | if (_sessions[key] <= 0) | ||
208 | _sessions.Remove(key); | ||
209 | } | ||
210 | else | ||
211 | _sessions.Add(key, 1); | ||
212 | |||
213 | _sessionLockSlim.ExitWriteLock(); | ||
214 | } | ||
150 | 215 | ||
151 | /// <summary> | 216 | /// <summary> |
152 | /// At this point, the rate limiting code needs to track 'per user' velocity. | 217 | /// At this point, the rate limiting code needs to track 'per user' velocity. |
@@ -169,12 +234,12 @@ namespace OpenSim.Framework | |||
169 | _options.RequestTimeSpan.TotalMilliseconds)) | 234 | _options.RequestTimeSpan.TotalMilliseconds)) |
170 | { | 235 | { |
171 | //Looks like we're over the limit | 236 | //Looks like we're over the limit |
172 | _lockSlim.EnterWriteLock(); | 237 | _blockLockSlim.EnterWriteLock(); |
173 | if (!_tempBlocked.ContainsKey(clientstring)) | 238 | if (!_tempBlocked.ContainsKey(clientstring)) |
174 | _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); | 239 | _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); |
175 | else | 240 | else |
176 | _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; | 241 | _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; |
177 | _lockSlim.ExitWriteLock(); | 242 | _blockLockSlim.ExitWriteLock(); |
178 | 243 | ||
179 | m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); | 244 | m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); |
180 | 245 | ||
@@ -205,5 +270,6 @@ namespace OpenSim.Framework | |||
205 | public bool AllowXForwardedFor; | 270 | public bool AllowXForwardedFor; |
206 | public string ReportingName = "BASICDOSPROTECTOR"; | 271 | public string ReportingName = "BASICDOSPROTECTOR"; |
207 | public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod; | 272 | public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod; |
273 | public int MaxConcurrentSessions; | ||
208 | } | 274 | } |
209 | } | 275 | } |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs index 9b8b8c2..1b88545 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs | |||
@@ -55,12 +55,14 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
55 | { | 55 | { |
56 | byte[] result; | 56 | byte[] result; |
57 | RequestsReceived++; | 57 | RequestsReceived++; |
58 | 58 | string clientstring = GetClientString(httpRequest); | |
59 | if (_dosProtector.Process(GetClientString(httpRequest), GetRemoteAddr(httpRequest))) | 59 | string endpoint = GetRemoteAddr(httpRequest); |
60 | if (_dosProtector.Process(clientstring, endpoint)) | ||
60 | result = ProcessRequest(path, request, httpRequest, httpResponse); | 61 | result = ProcessRequest(path, request, httpRequest, httpResponse); |
61 | else | 62 | else |
62 | result = ThrottledRequest(path, request, httpRequest, httpResponse); | 63 | result = ThrottledRequest(path, request, httpRequest, httpResponse); |
63 | 64 | if (_options.MaxConcurrentSessions > 0) | |
65 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
64 | 66 | ||
65 | RequestsHandled++; | 67 | RequestsHandled++; |
66 | 68 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs index 39c98b4..cd4b8ff 100644 --- a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs | |||
@@ -47,10 +47,18 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
47 | } | 47 | } |
48 | public Hashtable Process(Hashtable request) | 48 | public Hashtable Process(Hashtable request) |
49 | { | 49 | { |
50 | if (_dosProtector.Process(GetClientString(request), GetRemoteAddr(request))) | 50 | Hashtable process = null; |
51 | return _normalMethod(request); | 51 | string clientstring= GetClientString(request); |
52 | string endpoint = GetRemoteAddr(request); | ||
53 | if (_dosProtector.Process(clientstring, endpoint)) | ||
54 | process = _normalMethod(request); | ||
52 | else | 55 | else |
53 | return _throttledMethod(request); | 56 | process = _throttledMethod(request); |
57 | |||
58 | if (_options.MaxConcurrentSessions>0) | ||
59 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
60 | |||
61 | return process; | ||
54 | } | 62 | } |
55 | 63 | ||
56 | private string GetRemoteAddr(Hashtable request) | 64 | private string GetRemoteAddr(Hashtable request) |
diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs index bc7efb6..f212208 100644 --- a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs | |||
@@ -53,11 +53,14 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
53 | { | 53 | { |
54 | 54 | ||
55 | XmlRpcResponse resp = null; | 55 | XmlRpcResponse resp = null; |
56 | if (_dosProtector.Process(GetClientString(request, client), GetEndPoint(request, client))) | 56 | string clientstring = GetClientString(request, client); |
57 | string endpoint = GetEndPoint(request, client); | ||
58 | if (_dosProtector.Process(clientstring, endpoint)) | ||
57 | resp = _normalMethod(request, client); | 59 | resp = _normalMethod(request, client); |
58 | else | 60 | else |
59 | resp = _throttledMethod(request, client); | 61 | resp = _throttledMethod(request, client); |
60 | 62 | if (_options.MaxConcurrentSessions > 0) | |
63 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
61 | return resp; | 64 | return resp; |
62 | } | 65 | } |
63 | 66 | ||