aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data/MySQL/MySQLEstateData.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Data/MySQL/MySQLEstateData.cs386
1 files changed, 386 insertions, 0 deletions
diff --git a/OpenSim/Data/MySQL/MySQLEstateData.cs b/OpenSim/Data/MySQL/MySQLEstateData.cs
new file mode 100644
index 0000000..eeff31b
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLEstateData.cs
@@ -0,0 +1,386 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Data;
31using System.IO;
32using System.Reflection;
33using System.Threading;
34using libsecondlife;
35using log4net;
36using MySql.Data.MySqlClient;
37using OpenSim.Framework;
38using OpenSim.Region.Environment.Interfaces;
39using OpenSim.Region.Environment.Scenes;
40
41namespace OpenSim.Data.MySQL
42{
43 public class MySQLEstateStore : IEstateDataStore
44 {
45 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private const string m_waitTimeoutSelect = "select @@wait_timeout";
49
50 private MySqlConnection m_connection;
51 private string m_connectionString;
52 private long m_waitTimeout;
53 private long m_waitTimeoutLeeway = 60 * TimeSpan.TicksPerSecond;
54 private long m_lastConnectionUse;
55
56 private FieldInfo[] m_Fields;
57 private Dictionary<string, FieldInfo> m_FieldMap =
58 new Dictionary<string, FieldInfo>();
59
60 public void Initialise(string connectionString)
61 {
62 m_connectionString = connectionString;
63
64 m_log.Info("[ESTATE DB]: MySql - connecting: "+m_connectionString);
65
66 m_connection = new MySqlConnection(m_connectionString);
67 m_connection.Open();
68
69 GetWaitTimeout();
70
71 Assembly assem = GetType().Assembly;
72 Migration m = new Migration(m_connection, assem, "EstateStore");
73 m.Update();
74
75 Type t = typeof(EstateSettings);
76 m_Fields = t.GetFields(BindingFlags.NonPublic |
77 BindingFlags.Instance |
78 BindingFlags.DeclaredOnly);
79
80 foreach (FieldInfo f in m_Fields)
81 if(f.Name.Substring(0, 2) == "m_")
82 m_FieldMap[f.Name.Substring(2)] = f;
83 }
84
85 private string[] FieldList
86 {
87 get { return new List<string>(m_FieldMap.Keys).ToArray(); }
88 }
89
90 protected void GetWaitTimeout()
91 {
92 MySqlCommand cmd = new MySqlCommand(m_waitTimeoutSelect,
93 m_connection);
94
95 using (MySqlDataReader dbReader =
96 cmd.ExecuteReader(CommandBehavior.SingleRow))
97 {
98 if (dbReader.Read())
99 {
100 m_waitTimeout
101 = Convert.ToInt32(dbReader["@@wait_timeout"]) *
102 TimeSpan.TicksPerSecond + m_waitTimeoutLeeway;
103 }
104
105 dbReader.Close();
106 cmd.Dispose();
107 }
108
109 m_lastConnectionUse = System.DateTime.Now.Ticks;
110
111 m_log.DebugFormat(
112 "[REGION DB]: Connection wait timeout {0} seconds",
113 m_waitTimeout / TimeSpan.TicksPerSecond);
114 }
115
116 protected void CheckConnection()
117 {
118 long timeNow = System.DateTime.Now.Ticks;
119 if (timeNow - m_lastConnectionUse > m_waitTimeout ||
120 m_connection.State != ConnectionState.Open)
121 {
122 m_log.DebugFormat("[REGION DB]: Database connection has gone away - reconnecting");
123
124 lock (m_connection)
125 {
126 m_connection.Close();
127 m_connection = new MySqlConnection(m_connectionString);
128 m_connection.Open();
129 }
130 }
131
132 m_lastConnectionUse = timeNow;
133 }
134
135 public EstateSettings LoadEstateSettings(LLUUID regionID)
136 {
137 EstateSettings es = new EstateSettings();
138
139 string sql = "select estate_settings."+String.Join(",estate_settings.", FieldList)+" from estate_map left join estate_settings on estate_map.EstateID = estate_settings.EstateID where estate_settings.EstateID is not null and RegionID = ?RegionID";
140
141 CheckConnection();
142
143 MySqlCommand cmd = m_connection.CreateCommand();
144
145 cmd.CommandText = sql;
146 cmd.Parameters.Add("?RegionID", regionID.ToString());
147
148 IDataReader r = cmd.ExecuteReader();
149
150 if(r.Read())
151 {
152 foreach (string name in FieldList)
153 {
154 if(m_FieldMap[name].GetValue(es) is bool)
155 {
156 int v = Convert.ToInt32(r[name]);
157 if(v != 0)
158 m_FieldMap[name].SetValue(es, true);
159 else
160 m_FieldMap[name].SetValue(es, false);
161 }
162 else
163 {
164 m_FieldMap[name].SetValue(es, r[name]);
165 }
166 }
167 r.Close();
168 }
169 else
170 {
171 // Migration case
172 //
173 r.Close();
174
175 List<string> names = new List<string>(FieldList);
176
177 names.Remove("EstateID");
178
179 sql = "insert into estate_settings ("+String.Join(",", names.ToArray())+") values ( ?"+String.Join(", ?", names.ToArray())+")";
180
181 cmd.CommandText = sql;
182 cmd.Parameters.Clear();
183
184 foreach (string name in FieldList)
185 {
186 if(m_FieldMap[name].GetValue(es) is bool)
187 {
188 if((bool)m_FieldMap[name].GetValue(es))
189 cmd.Parameters.Add("?"+name, "1");
190 else
191 cmd.Parameters.Add("?"+name, "0");
192 }
193 else
194 {
195 cmd.Parameters.Add("?"+name, m_FieldMap[name].GetValue(es).ToString());
196 }
197 }
198
199 cmd.ExecuteNonQuery();
200
201 cmd.CommandText = "select LAST_INSERT_ID() as id";
202 cmd.Parameters.Clear();
203
204 r = cmd.ExecuteReader();
205
206 r.Read();
207
208 es.EstateID = Convert.ToUInt32(r["id"]);
209
210 r.Close();
211
212 cmd.CommandText = "insert into estate_map values (?RegionID, ?EstateID)";
213 cmd.Parameters.Add("?RegionID", regionID.ToString());
214 cmd.Parameters.Add("?EstateID", es.EstateID.ToString());
215
216 // This will throw on dupe key
217 try
218 {
219 cmd.ExecuteNonQuery();
220 }
221 catch (Exception)
222 {
223 }
224
225 // Munge and transfer the ban list
226 //
227 cmd.Parameters.Clear();
228 cmd.CommandText = "insert into estateban select "+es.EstateID.ToString()+", bannedUUID, bannedIp, bannedIpHostMask, '' from regionban where regionban.regionUUID = ?UUID";
229 cmd.Parameters.Add("?UUID", regionID.ToString());
230
231 try
232 {
233 cmd.ExecuteNonQuery();
234 }
235 catch (Exception)
236 {
237 }
238 }
239
240 LoadBanList(es);
241
242 es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
243 es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
244 es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
245 return es;
246 }
247
248 public void StoreEstateSettings(EstateSettings es)
249 {
250 string sql = "replace into estate_settings ("+String.Join(",", FieldList)+") values ( ?"+String.Join(", ?", FieldList)+")";
251
252 CheckConnection();
253
254 MySqlCommand cmd = m_connection.CreateCommand();
255
256 cmd.CommandText = sql;
257
258 foreach (string name in FieldList)
259 {
260 if(m_FieldMap[name].GetValue(es) is bool)
261 {
262 if((bool)m_FieldMap[name].GetValue(es))
263 cmd.Parameters.Add("?"+name, "1");
264 else
265 cmd.Parameters.Add("?"+name, "0");
266 }
267 else
268 {
269 cmd.Parameters.Add("?"+name, m_FieldMap[name].GetValue(es).ToString());
270 }
271 }
272
273 cmd.ExecuteNonQuery();
274
275 SaveBanList(es);
276 SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
277 SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess);
278 SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups);
279 }
280
281 private void LoadBanList(EstateSettings es)
282 {
283 es.ClearBans();
284
285 CheckConnection();
286
287 MySqlCommand cmd = m_connection.CreateCommand();
288
289 cmd.CommandText = "select bannedUUID from estateban where EstateID = ?EstateID";
290 cmd.Parameters.Add("?EstateID", es.EstateID);
291
292 IDataReader r = cmd.ExecuteReader();
293
294 while(r.Read())
295 {
296 EstateBan eb = new EstateBan();
297
298 LLUUID uuid = new LLUUID();
299 LLUUID.TryParse(r["bannedUUID"].ToString(), out uuid);
300
301 eb.bannedUUID = uuid;
302 eb.bannedIP = "0.0.0.0";
303 eb.bannedIPHostMask = "0.0.0.0";
304 es.AddBan(eb);
305 }
306 r.Close();
307 }
308
309 private void SaveBanList(EstateSettings es)
310 {
311 CheckConnection();
312
313 MySqlCommand cmd = m_connection.CreateCommand();
314
315 cmd.CommandText = "delete from estateban where EstateID = ?EstateID";
316 cmd.Parameters.Add("?EstateID", es.EstateID.ToString());
317
318 cmd.ExecuteNonQuery();
319
320 cmd.Parameters.Clear();
321
322 cmd.CommandText = "insert into estateban (EstateID, bannedUUID) values ( ?EstateID, ?bannedUUID )";
323
324 foreach(EstateBan b in es.EstateBans)
325 {
326 cmd.Parameters.Add("?EstateID", es.EstateID.ToString());
327 cmd.Parameters.Add("?bannedUUID", b.bannedUUID.ToString());
328
329 cmd.ExecuteNonQuery();
330 cmd.Parameters.Clear();
331 }
332 }
333
334 void SaveUUIDList(uint EstateID, string table, LLUUID[] data)
335 {
336 CheckConnection();
337
338 MySqlCommand cmd = m_connection.CreateCommand();
339
340 cmd.CommandText = "delete from "+table+" where EstateID = ?EstateID";
341 cmd.Parameters.Add("?EstateID", EstateID.ToString());
342
343 cmd.ExecuteNonQuery();
344
345 cmd.Parameters.Clear();
346
347 cmd.CommandText = "insert into "+table+" (EstateID, uuid) values ( ?EstateID, ?uuid )";
348
349 foreach(LLUUID uuid in data)
350 {
351 cmd.Parameters.Add("?EstateID", EstateID.ToString());
352 cmd.Parameters.Add("?uuid", uuid.ToString());
353
354 cmd.ExecuteNonQuery();
355 cmd.Parameters.Clear();
356 }
357 }
358
359 LLUUID[] LoadUUIDList(uint EstateID, string table)
360 {
361 List<LLUUID> uuids = new List<LLUUID>();
362
363 CheckConnection();
364
365 MySqlCommand cmd = m_connection.CreateCommand();
366
367 cmd.CommandText = "select uuid from "+table+" where EstateID = ?EstateID";
368 cmd.Parameters.Add("?EstateID", EstateID);
369
370 IDataReader r = cmd.ExecuteReader();
371
372 while(r.Read())
373 {
374 EstateBan eb = new EstateBan();
375
376 LLUUID uuid = new LLUUID();
377 LLUUID.TryParse(r["uuid"].ToString(), out uuid);
378
379 uuids.Add(uuid);
380 }
381 r.Close();
382
383 return uuids.ToArray();
384 }
385 }
386}