diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Console/RemoteConsole.cs | 358 |
1 files changed, 348 insertions, 10 deletions
diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 73209be..da8556a 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs | |||
@@ -26,30 +26,43 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Xml; | ||
30 | using System.Collections; | ||
29 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
30 | using System.Diagnostics; | 32 | using System.Diagnostics; |
31 | using System.Reflection; | 33 | using System.Reflection; |
32 | using System.Text; | 34 | using System.Text; |
33 | using System.Threading; | 35 | using System.Threading; |
36 | using OpenMetaverse; | ||
34 | using Nini.Config; | 37 | using Nini.Config; |
35 | using OpenSim.Framework.Servers.HttpServer; | 38 | using OpenSim.Framework.Servers.HttpServer; |
36 | using log4net; | 39 | using log4net; |
37 | 40 | ||
38 | namespace OpenSim.Framework.Console | 41 | namespace OpenSim.Framework.Console |
39 | { | 42 | { |
43 | public class ConsoleConnection | ||
44 | { | ||
45 | public int last; | ||
46 | public long lastLineSeen; | ||
47 | } | ||
48 | |||
40 | // A console that uses REST interfaces | 49 | // A console that uses REST interfaces |
41 | // | 50 | // |
42 | public class RemoteConsole : CommandConsole | 51 | public class RemoteConsole : CommandConsole |
43 | { | 52 | { |
44 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 53 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | 54 | ||
46 | // private IHttpServer m_Server = null; | 55 | private IHttpServer m_Server = null; |
47 | // private IConfigSource m_Config = null; | 56 | private IConfigSource m_Config = null; |
48 | 57 | ||
49 | private List<string> m_Scrollback = new List<string>(); | 58 | private List<string> m_Scrollback = new List<string>(); |
50 | private ManualResetEvent m_DataEvent = new ManualResetEvent(false); | 59 | private ManualResetEvent m_DataEvent = new ManualResetEvent(false); |
51 | private List<string> m_InputData = new List<string>(); | 60 | private List<string> m_InputData = new List<string>(); |
52 | private uint m_LineNumber = 1; | 61 | private long m_LineNumber = 0; |
62 | private Dictionary<UUID, ConsoleConnection> m_Connections = | ||
63 | new Dictionary<UUID, ConsoleConnection>(); | ||
64 | private string m_UserName = String.Empty; | ||
65 | private string m_Password = String.Empty; | ||
53 | 66 | ||
54 | public RemoteConsole(string defaultPrompt) : base(defaultPrompt) | 67 | public RemoteConsole(string defaultPrompt) : base(defaultPrompt) |
55 | { | 68 | { |
@@ -57,12 +70,23 @@ namespace OpenSim.Framework.Console | |||
57 | 70 | ||
58 | public void ReadConfig(IConfigSource config) | 71 | public void ReadConfig(IConfigSource config) |
59 | { | 72 | { |
60 | // m_Config = config; | 73 | m_Config = config; |
74 | |||
75 | IConfig netConfig = m_Config.Configs["Network"]; | ||
76 | if (netConfig == null) | ||
77 | return; | ||
78 | |||
79 | m_UserName = netConfig.GetString("ConsoleUser", String.Empty); | ||
80 | m_Password = netConfig.GetString("ConsolePass", String.Empty); | ||
61 | } | 81 | } |
62 | 82 | ||
63 | public void SetServer(IHttpServer server) | 83 | public void SetServer(IHttpServer server) |
64 | { | 84 | { |
65 | // m_Server = server; | 85 | m_Server = server; |
86 | |||
87 | m_Server.AddHTTPHandler("/StartSession/", HandleHttpStartSession); | ||
88 | m_Server.AddHTTPHandler("/CloseSession/", HandleHttpCloseSession); | ||
89 | m_Server.AddHTTPHandler("/SessionCommand/", HandleHttpSessionCommand); | ||
66 | } | 90 | } |
67 | 91 | ||
68 | public override void Output(string text, string level) | 92 | public override void Output(string text, string level) |
@@ -71,16 +95,19 @@ namespace OpenSim.Framework.Console | |||
71 | { | 95 | { |
72 | while (m_Scrollback.Count >= 1000) | 96 | while (m_Scrollback.Count >= 1000) |
73 | m_Scrollback.RemoveAt(0); | 97 | m_Scrollback.RemoveAt(0); |
74 | m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text); | ||
75 | m_LineNumber++; | 98 | m_LineNumber++; |
99 | m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text); | ||
76 | } | 100 | } |
77 | System.Console.Write(text); | 101 | System.Console.WriteLine(text.Trim()); |
102 | } | ||
103 | |||
104 | public override void Output(string text) | ||
105 | { | ||
106 | Output(text, "normal"); | ||
78 | } | 107 | } |
79 | 108 | ||
80 | public override string ReadLine(string p, bool isCommand, bool e) | 109 | public override string ReadLine(string p, bool isCommand, bool e) |
81 | { | 110 | { |
82 | System.Console.Write("{0}", prompt); | ||
83 | |||
84 | m_DataEvent.WaitOne(); | 111 | m_DataEvent.WaitOne(); |
85 | 112 | ||
86 | lock (m_InputData) | 113 | lock (m_InputData) |
@@ -115,5 +142,316 @@ namespace OpenSim.Framework.Console | |||
115 | return cmdinput; | 142 | return cmdinput; |
116 | } | 143 | } |
117 | } | 144 | } |
145 | |||
146 | private void DoExpire() | ||
147 | { | ||
148 | List<UUID> expired = new List<UUID>(); | ||
149 | |||
150 | lock (m_Connections) | ||
151 | { | ||
152 | foreach (KeyValuePair<UUID, ConsoleConnection> kvp in m_Connections) | ||
153 | { | ||
154 | if (System.Environment.TickCount - kvp.Value.last > 500000) | ||
155 | expired.Add(kvp.Key); | ||
156 | } | ||
157 | |||
158 | foreach (UUID id in expired) | ||
159 | { | ||
160 | m_Connections.Remove(id); | ||
161 | CloseConnection(id); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | private Hashtable HandleHttpStartSession(Hashtable request) | ||
167 | { | ||
168 | DoExpire(); | ||
169 | |||
170 | Hashtable post = DecodePostString(request["body"].ToString()); | ||
171 | Hashtable reply = new Hashtable(); | ||
172 | |||
173 | reply["str_response_string"] = ""; | ||
174 | reply["int_response_code"] = 401; | ||
175 | reply["content_type"] = "text/plain"; | ||
176 | |||
177 | if (m_UserName == String.Empty) | ||
178 | return reply; | ||
179 | |||
180 | if (post["USER"] == null || post["PASS"] == null) | ||
181 | return reply; | ||
182 | |||
183 | if (m_UserName != post["USER"].ToString() || | ||
184 | m_Password != post["PASS"].ToString()) | ||
185 | { | ||
186 | return reply; | ||
187 | } | ||
188 | |||
189 | ConsoleConnection c = new ConsoleConnection(); | ||
190 | c.last = System.Environment.TickCount; | ||
191 | c.lastLineSeen = 0; | ||
192 | |||
193 | UUID sessionID = UUID.Random(); | ||
194 | |||
195 | lock (m_Connections) | ||
196 | { | ||
197 | m_Connections[sessionID] = c; | ||
198 | } | ||
199 | |||
200 | string uri = "/ReadResponses/" + sessionID.ToString() + "/"; | ||
201 | |||
202 | m_Server.AddPollServiceHTTPHandler(uri, HandleHttpCloseSession, | ||
203 | new PollServiceEventArgs(HasEvents, GetEvents, NoEvents, | ||
204 | sessionID)); | ||
205 | |||
206 | XmlDocument xmldoc = new XmlDocument(); | ||
207 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
208 | "", ""); | ||
209 | |||
210 | xmldoc.AppendChild(xmlnode); | ||
211 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
212 | ""); | ||
213 | |||
214 | xmldoc.AppendChild(rootElement); | ||
215 | |||
216 | XmlElement id = xmldoc.CreateElement("", "SessionID", ""); | ||
217 | id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString())); | ||
218 | |||
219 | rootElement.AppendChild(id); | ||
220 | rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc)); | ||
221 | |||
222 | reply["str_response_string"] = xmldoc.InnerXml; | ||
223 | reply["int_response_code"] = 200; | ||
224 | reply["content_type"] = "text/xml"; | ||
225 | |||
226 | return reply; | ||
227 | } | ||
228 | |||
229 | private Hashtable HandleHttpCloseSession(Hashtable request) | ||
230 | { | ||
231 | DoExpire(); | ||
232 | |||
233 | Hashtable post = DecodePostString(request["body"].ToString()); | ||
234 | Hashtable reply = new Hashtable(); | ||
235 | |||
236 | reply["str_response_string"] = ""; | ||
237 | reply["int_response_code"] = 404; | ||
238 | reply["content_type"] = "text/plain"; | ||
239 | |||
240 | if (post["ID"] == null) | ||
241 | return reply; | ||
242 | |||
243 | UUID id; | ||
244 | if (!UUID.TryParse(post["ID"].ToString(), out id)) | ||
245 | return reply; | ||
246 | |||
247 | lock (m_Connections) | ||
248 | { | ||
249 | if (m_Connections.ContainsKey(id)) | ||
250 | { | ||
251 | m_Connections.Remove(id); | ||
252 | CloseConnection(id); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | XmlDocument xmldoc = new XmlDocument(); | ||
257 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
258 | "", ""); | ||
259 | |||
260 | xmldoc.AppendChild(xmlnode); | ||
261 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
262 | ""); | ||
263 | |||
264 | xmldoc.AppendChild(rootElement); | ||
265 | |||
266 | XmlElement res = xmldoc.CreateElement("", "Result", ""); | ||
267 | res.AppendChild(xmldoc.CreateTextNode("OK")); | ||
268 | |||
269 | rootElement.AppendChild(res); | ||
270 | |||
271 | reply["str_response_string"] = xmldoc.InnerXml; | ||
272 | reply["int_response_code"] = 200; | ||
273 | reply["content_type"] = "text/plain"; | ||
274 | |||
275 | return reply; | ||
276 | } | ||
277 | |||
278 | private Hashtable HandleHttpSessionCommand(Hashtable request) | ||
279 | { | ||
280 | DoExpire(); | ||
281 | |||
282 | Hashtable post = DecodePostString(request["body"].ToString()); | ||
283 | Hashtable reply = new Hashtable(); | ||
284 | |||
285 | reply["str_response_string"] = ""; | ||
286 | reply["int_response_code"] = 404; | ||
287 | reply["content_type"] = "text/plain"; | ||
288 | |||
289 | if (post["ID"] == null) | ||
290 | return reply; | ||
291 | |||
292 | UUID id; | ||
293 | if (!UUID.TryParse(post["ID"].ToString(), out id)) | ||
294 | return reply; | ||
295 | |||
296 | if (post["COMMAND"] == null || post["COMMAND"].ToString() == String.Empty) | ||
297 | return reply; | ||
298 | |||
299 | lock (m_InputData) | ||
300 | { | ||
301 | m_DataEvent.Set(); | ||
302 | m_InputData.Add(post["COMMAND"].ToString()); | ||
303 | } | ||
304 | |||
305 | XmlDocument xmldoc = new XmlDocument(); | ||
306 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
307 | "", ""); | ||
308 | |||
309 | xmldoc.AppendChild(xmlnode); | ||
310 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
311 | ""); | ||
312 | |||
313 | xmldoc.AppendChild(rootElement); | ||
314 | |||
315 | XmlElement res = xmldoc.CreateElement("", "Result", ""); | ||
316 | res.AppendChild(xmldoc.CreateTextNode("OK")); | ||
317 | |||
318 | rootElement.AppendChild(res); | ||
319 | |||
320 | reply["str_response_string"] = xmldoc.InnerXml; | ||
321 | reply["int_response_code"] = 200; | ||
322 | reply["content_type"] = "text/plain"; | ||
323 | |||
324 | return reply; | ||
325 | } | ||
326 | |||
327 | private Hashtable DecodePostString(string data) | ||
328 | { | ||
329 | Hashtable result = new Hashtable(); | ||
330 | |||
331 | string[] terms = data.Split(new char[] {'&'}); | ||
332 | |||
333 | foreach (string term in terms) | ||
334 | { | ||
335 | string[] elems = term.Split(new char[] {'='}); | ||
336 | if (elems.Length == 0) | ||
337 | continue; | ||
338 | |||
339 | string name = System.Web.HttpUtility.UrlDecode(elems[0]); | ||
340 | string value = String.Empty; | ||
341 | |||
342 | if (elems.Length > 1) | ||
343 | value = System.Web.HttpUtility.UrlDecode(elems[1]); | ||
344 | |||
345 | result[name] = value; | ||
346 | } | ||
347 | |||
348 | return result; | ||
349 | } | ||
350 | |||
351 | public void CloseConnection(UUID id) | ||
352 | { | ||
353 | try | ||
354 | { | ||
355 | string uri = "/ReadResponses/" + id.ToString() + "/"; | ||
356 | |||
357 | m_Server.RemovePollServiceHTTPHandler("", uri); | ||
358 | } | ||
359 | catch (Exception) | ||
360 | { | ||
361 | } | ||
362 | } | ||
363 | |||
364 | private bool HasEvents(UUID sessionID) | ||
365 | { | ||
366 | ConsoleConnection c = null; | ||
367 | |||
368 | lock (m_Connections) | ||
369 | { | ||
370 | if (!m_Connections.ContainsKey(sessionID)) | ||
371 | return false; | ||
372 | c = m_Connections[sessionID]; | ||
373 | } | ||
374 | c.last = System.Environment.TickCount; | ||
375 | if (c.lastLineSeen < m_LineNumber) | ||
376 | return true; | ||
377 | return false; | ||
378 | } | ||
379 | |||
380 | private Hashtable GetEvents(UUID sessionID, string request) | ||
381 | { | ||
382 | ConsoleConnection c = null; | ||
383 | |||
384 | lock (m_Connections) | ||
385 | { | ||
386 | if (!m_Connections.ContainsKey(sessionID)) | ||
387 | return NoEvents(); | ||
388 | c = m_Connections[sessionID]; | ||
389 | } | ||
390 | c.last = System.Environment.TickCount; | ||
391 | if (c.lastLineSeen >= m_LineNumber) | ||
392 | return NoEvents(); | ||
393 | |||
394 | Hashtable result = new Hashtable(); | ||
395 | |||
396 | XmlDocument xmldoc = new XmlDocument(); | ||
397 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
398 | "", ""); | ||
399 | |||
400 | xmldoc.AppendChild(xmlnode); | ||
401 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
402 | ""); | ||
403 | |||
404 | lock (m_Scrollback) | ||
405 | { | ||
406 | long startLine = m_LineNumber - m_Scrollback.Count; | ||
407 | long sendStart = startLine; | ||
408 | if (sendStart < c.lastLineSeen) | ||
409 | sendStart = c.lastLineSeen; | ||
410 | |||
411 | for (long i = sendStart ; i < m_LineNumber ; i++) | ||
412 | { | ||
413 | XmlElement res = xmldoc.CreateElement("", "Line", ""); | ||
414 | long line = i + 1; | ||
415 | res.SetAttribute("Number", line.ToString()); | ||
416 | res.AppendChild(xmldoc.CreateTextNode(m_Scrollback[(int)(i - startLine)])); | ||
417 | |||
418 | rootElement.AppendChild(res); | ||
419 | } | ||
420 | } | ||
421 | c.lastLineSeen = m_LineNumber; | ||
422 | |||
423 | xmldoc.AppendChild(rootElement); | ||
424 | |||
425 | result["str_response_string"] = xmldoc.InnerXml; | ||
426 | result["int_response_code"] = 200; | ||
427 | result["content_type"] = "application/xml"; | ||
428 | result["keepalive"] = false; | ||
429 | result["reusecontext"] = false; | ||
430 | |||
431 | return result; | ||
432 | } | ||
433 | |||
434 | private Hashtable NoEvents() | ||
435 | { | ||
436 | Hashtable result = new Hashtable(); | ||
437 | |||
438 | XmlDocument xmldoc = new XmlDocument(); | ||
439 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
440 | "", ""); | ||
441 | |||
442 | xmldoc.AppendChild(xmlnode); | ||
443 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
444 | ""); | ||
445 | |||
446 | xmldoc.AppendChild(rootElement); | ||
447 | |||
448 | result["str_response_string"] = xmldoc.InnerXml; | ||
449 | result["int_response_code"] = 200; | ||
450 | result["content_type"] = "text/xml"; | ||
451 | result["keepalive"] = false; | ||
452 | result["reusecontext"] = false; | ||
453 | |||
454 | return result; | ||
455 | } | ||
118 | } | 456 | } |
119 | } | 457 | } |