From 3376b82501000692d6dac24b051af738cdaf2737 Mon Sep 17 00:00:00 2001
From: MW
Date: Thu, 24 May 2007 12:16:50 +0000
Subject: Some more code refactoring, plus a restructuring of the directories
so that the Grid servers can be a separate solution to the region server.
---
Common-Source/XmlRpcCS/Logger.cs | 46 ++++
Common-Source/XmlRpcCS/SimpleHttpRequest.cs | 204 +++++++++++++++++
Common-Source/XmlRpcCS/XMLRPC.csproj | 138 +++++++++++
Common-Source/XmlRpcCS/XMLRPC.csproj.user | 12 +
Common-Source/XmlRpcCS/XMLRPC.dll.build | 58 +++++
Common-Source/XmlRpcCS/XmlRpcBoxcarRequest.cs | 51 +++++
Common-Source/XmlRpcCS/XmlRpcClientProxy.cs | 61 +++++
Common-Source/XmlRpcCS/XmlRpcDeserializer.cs | 195 ++++++++++++++++
Common-Source/XmlRpcCS/XmlRpcErrorCodes.cs | 51 +++++
Common-Source/XmlRpcCS/XmlRpcException.cs | 39 ++++
Common-Source/XmlRpcCS/XmlRpcExposedAttribute.cs | 60 +++++
Common-Source/XmlRpcCS/XmlRpcRequest.cs | 150 ++++++++++++
.../XmlRpcCS/XmlRpcRequestDeserializer.cs | 64 ++++++
Common-Source/XmlRpcCS/XmlRpcRequestSerializer.cs | 51 +++++
Common-Source/XmlRpcCS/XmlRpcResponder.cs | 98 ++++++++
Common-Source/XmlRpcCS/XmlRpcResponse.cs | 85 +++++++
.../XmlRpcCS/XmlRpcResponseDeserializer.cs | 65 ++++++
Common-Source/XmlRpcCS/XmlRpcResponseSerializer.cs | 57 +++++
Common-Source/XmlRpcCS/XmlRpcSerializer.cs | 109 +++++++++
Common-Source/XmlRpcCS/XmlRpcServer.cs | 239 +++++++++++++++++++
Common-Source/XmlRpcCS/XmlRpcSystemObject.cs | 252 +++++++++++++++++++++
Common-Source/XmlRpcCS/XmlRpcXmlTokens.cs | 76 +++++++
22 files changed, 2161 insertions(+)
create mode 100644 Common-Source/XmlRpcCS/Logger.cs
create mode 100644 Common-Source/XmlRpcCS/SimpleHttpRequest.cs
create mode 100644 Common-Source/XmlRpcCS/XMLRPC.csproj
create mode 100644 Common-Source/XmlRpcCS/XMLRPC.csproj.user
create mode 100644 Common-Source/XmlRpcCS/XMLRPC.dll.build
create mode 100644 Common-Source/XmlRpcCS/XmlRpcBoxcarRequest.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcClientProxy.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcDeserializer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcErrorCodes.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcException.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcExposedAttribute.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcRequest.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcRequestDeserializer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcRequestSerializer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcResponder.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcResponse.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcResponseDeserializer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcResponseSerializer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcSerializer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcServer.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcSystemObject.cs
create mode 100644 Common-Source/XmlRpcCS/XmlRpcXmlTokens.cs
(limited to 'Common-Source/XmlRpcCS')
diff --git a/Common-Source/XmlRpcCS/Logger.cs b/Common-Source/XmlRpcCS/Logger.cs
new file mode 100644
index 0000000..ebf804b
--- /dev/null
+++ b/Common-Source/XmlRpcCS/Logger.cs
@@ -0,0 +1,46 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+
+ /// Define levels of logging. This duplicates
+ /// similar enumerations in System.Diagnostics.EventLogEntryType. The
+ /// duplication was merited because .NET Compact Framework lacked the EventLogEntryType enum.
+ public enum LogLevel
+ {
+ /// Information level, log entry for informational reasons only.
+ Information,
+ /// Warning level, indicates a possible problem.
+ Warning,
+ /// Error level, implies a significant problem.
+ Error
+ }
+
+ ///
+ ///Logging singleton with swappable output delegate.
+ ///
+ ///
+ ///This singleton provides a centralized log. The actual WriteEntry calls are passed
+ ///off to a delegate however. Having a delegate do the actual logginh allows you to
+ ///implement different logging mechanism and have them take effect throughout the system.
+ ///
+ public class Logger
+ {
+ ///Delegate definition for logging.
+ ///The message String to log.
+ ///The LogLevel of your message.
+ public delegate void LoggerDelegate(String message, LogLevel level);
+ ///The LoggerDelegate that will recieve WriteEntry requests.
+ static public LoggerDelegate Delegate = null;
+
+ ///
+ ///Method logging events are sent to.
+ ///
+ ///The message String to log.
+ ///The LogLevel of your message.
+ static public void WriteEntry(String message, LogLevel level)
+ {
+ if (Delegate != null)
+ Delegate(message, level);
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/SimpleHttpRequest.cs b/Common-Source/XmlRpcCS/SimpleHttpRequest.cs
new file mode 100644
index 0000000..e5326c3
--- /dev/null
+++ b/Common-Source/XmlRpcCS/SimpleHttpRequest.cs
@@ -0,0 +1,204 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.IO;
+ using System.Net.Sockets;
+ using System.Collections;
+
+ ///Very basic HTTP request handler.
+ ///This class is designed to accept a TcpClient and treat it as an HTTP request.
+ /// It will do some basic header parsing and manage the input and output streams associated
+ /// with the request.
+ public class SimpleHttpRequest
+ {
+ private String _httpMethod = null;
+ private String _protocol;
+ private String _filePathFile = null;
+ private String _filePathDir = null;
+ private String __filePath;
+ private TcpClient _client;
+ private StreamReader _input;
+ private StreamWriter _output;
+ private Hashtable _headers;
+
+ /// A constructor which accepts the TcpClient.
+ /// It creates the associated input and output streams, determines the request type,
+ /// and parses the remaining HTTP header.
+ /// The TcpClient associated with the HTTP connection.
+ public SimpleHttpRequest(TcpClient client)
+ {
+ _client = client;
+ _output = new StreamWriter(client.GetStream());
+ _input = new StreamReader(client.GetStream());
+ GetRequestMethod();
+ GetRequestHeaders();
+ }
+
+ /// The output StreamWriter associated with the request.
+ public StreamWriter Output
+ {
+ get { return _output; }
+ }
+
+ /// The input StreamReader associated with the request.
+ public StreamReader Input
+ {
+ get { return _input; }
+ }
+
+ /// The TcpClient with the request.
+ public TcpClient Client
+ {
+ get { return _client; }
+ }
+
+ private String _filePath
+ {
+ get { return __filePath; }
+ set
+ {
+ __filePath = value;
+ _filePathDir = null;
+ _filePathFile = null;
+ }
+ }
+
+ /// The type of HTTP request (i.e. PUT, GET, etc.).
+ public String HttpMethod
+ {
+ get { return _httpMethod; }
+ }
+
+ /// The level of the HTTP protocol.
+ public String Protocol
+ {
+ get { return _protocol; }
+ }
+
+ /// The "path" which is part of any HTTP request.
+ public String FilePath
+ {
+ get { return _filePath; }
+ }
+
+ /// The file portion of the "path" which is part of any HTTP request.
+ public String FilePathFile
+ {
+ get
+ {
+ if (_filePathFile != null)
+ return _filePathFile;
+
+ int i = FilePath.LastIndexOf("/");
+
+ if (i == -1)
+ return "";
+
+ i++;
+ _filePathFile = FilePath.Substring(i, FilePath.Length - i);
+ return _filePathFile;
+ }
+ }
+
+ /// The directory portion of the "path" which is part of any HTTP request.
+ public String FilePathDir
+ {
+ get
+ {
+ if (_filePathDir != null)
+ return _filePathDir;
+
+ int i = FilePath.LastIndexOf("/");
+
+ if (i == -1)
+ return "";
+
+ i++;
+ _filePathDir = FilePath.Substring(0, i);
+ return _filePathDir;
+ }
+ }
+
+ private void GetRequestMethod()
+ {
+ string req = _input.ReadLine();
+ if (req == null)
+ throw new ApplicationException("Void request.");
+
+ if (0 == String.Compare("GET ", req.Substring(0, 4), true))
+ _httpMethod = "GET";
+ else if (0 == String.Compare("POST ", req.Substring(0, 5), true))
+ _httpMethod = "POST";
+ else
+ throw new InvalidOperationException("Unrecognized method in query: " + req);
+
+ req = req.TrimEnd();
+ int idx = req.IndexOf(' ') + 1;
+ if (idx >= req.Length)
+ throw new ApplicationException("What do you want?");
+
+ string page_protocol = req.Substring(idx);
+ int idx2 = page_protocol.IndexOf(' ');
+ if (idx2 == -1)
+ idx2 = page_protocol.Length;
+
+ _filePath = page_protocol.Substring(0, idx2).Trim();
+ _protocol = page_protocol.Substring(idx2).Trim();
+ }
+
+ private void GetRequestHeaders()
+ {
+ String line;
+ int idx;
+
+ _headers = new Hashtable();
+
+ while ((line = _input.ReadLine()) != "")
+ {
+ if (line == null)
+ {
+ break;
+ }
+
+ idx = line.IndexOf(':');
+ if (idx == -1 || idx == line.Length - 1)
+ {
+ Logger.WriteEntry("Malformed header line: " + line, LogLevel.Information);
+ continue;
+ }
+
+ String key = line.Substring(0, idx);
+ String value = line.Substring(idx + 1);
+
+ try
+ {
+ _headers.Add(key, value);
+ }
+ catch (Exception)
+ {
+ Logger.WriteEntry("Duplicate header key in line: " + line, LogLevel.Information);
+ }
+ }
+ }
+
+ ///
+ /// Format the object contents into a useful string representation.
+ ///
+ ///String representation of the SimpleHttpRequest as the HttpMethod FilePath Protocol.
+ override public String ToString()
+ {
+ return HttpMethod + " " + FilePath + " " + Protocol;
+ }
+
+ ///
+ /// Close the SimpleHttpRequest. This flushes and closes all associated io streams.
+ ///
+ public void Close()
+ {
+ _output.Flush();
+ _output.Close();
+ _input.Close();
+ _client.Close();
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XMLRPC.csproj b/Common-Source/XmlRpcCS/XMLRPC.csproj
new file mode 100644
index 0000000..2c7ef94
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XMLRPC.csproj
@@ -0,0 +1,138 @@
+
+
+ Local
+ 8.0.50727
+ 2.0
+ {8E81D43C-0000-0000-0000-000000000000}
+ Debug
+ AnyCPU
+
+
+
+ XMLRPC
+ JScript
+ Grid
+ IE50
+ false
+ Library
+
+ XMLRPC
+
+
+
+
+
+ False
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+
+
+
+ False
+ 285212672
+ False
+
+
+ TRACE
+
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+
+
+
+
+ System.dll
+ False
+
+
+ System.Xml.dll
+ False
+
+
+
+
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+
+
+
+
+
+
+
+
diff --git a/Common-Source/XmlRpcCS/XMLRPC.csproj.user b/Common-Source/XmlRpcCS/XMLRPC.csproj.user
new file mode 100644
index 0000000..d47d65d
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XMLRPC.csproj.user
@@ -0,0 +1,12 @@
+
+
+ Debug
+ AnyCPU
+ C:\New Folder\second-life-viewer\opensim-dailys2\opensim15-07\bin\
+ 8.0.50727
+ ProjectFiles
+ 0
+
+
+
+
diff --git a/Common-Source/XmlRpcCS/XMLRPC.dll.build b/Common-Source/XmlRpcCS/XMLRPC.dll.build
new file mode 100644
index 0000000..d734d19
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XMLRPC.dll.build
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Common-Source/XmlRpcCS/XmlRpcBoxcarRequest.cs b/Common-Source/XmlRpcCS/XmlRpcBoxcarRequest.cs
new file mode 100644
index 0000000..f87f7a5
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcBoxcarRequest.cs
@@ -0,0 +1,51 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Xml;
+ using System.Net;
+ using System.Text;
+ using System.Reflection;
+
+ /// Class that collects individual XmlRpcRequest objects and submits them as a boxcarred request.
+ /// A boxcared request is when a number of request are collected before being sent via XML-RPC, and then are sent via
+ /// a single HTTP connection. This results in a speed up from reduced connection time. The results are then retuned collectively
+ /// as well.
+ ///
+ ///
+ public class XmlRpcBoxcarRequest : XmlRpcRequest
+ {
+ /// ArrayList to collect the requests to boxcar.
+ public IList Requests = new ArrayList();
+
+ /// Basic constructor.
+ public XmlRpcBoxcarRequest()
+ {
+ }
+
+ /// Returns the String "system.multiCall" which is the server method that handles boxcars.
+ public override String MethodName
+ {
+ get { return "system.multiCall"; }
+ }
+
+ /// The ArrayList of boxcarred Requests as properly formed parameters.
+ public override IList Params
+ {
+ get {
+ _params.Clear();
+ ArrayList reqArray = new ArrayList();
+ foreach (XmlRpcRequest request in Requests)
+ {
+ Hashtable requestEntry = new Hashtable();
+ requestEntry.Add(XmlRpcXmlTokens.METHOD_NAME, request.MethodName);
+ requestEntry.Add(XmlRpcXmlTokens.PARAMS, request.Params);
+ reqArray.Add(requestEntry);
+ }
+ _params.Add(reqArray);
+ return _params;
+ }
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcClientProxy.cs b/Common-Source/XmlRpcCS/XmlRpcClientProxy.cs
new file mode 100644
index 0000000..f52273a
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcClientProxy.cs
@@ -0,0 +1,61 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Runtime.Remoting.Proxies;
+ using System.Runtime.Remoting.Messaging;
+
+ /// This class provides support for creating local proxies of XML-RPC remote objects
+ ///
+ /// To create a local proxy you need to create a local C# interface and then, via createProxy
+ /// associate that interface with a remote object at a given URL.
+ ///
+public class XmlRpcClientProxy : RealProxy
+{
+ private String _remoteObjectName;
+ private String _url;
+ private XmlRpcRequest _client = new XmlRpcRequest();
+
+ /// Factory method to create proxies.
+ ///
+ /// To create a local proxy you need to create a local C# interface with methods that mirror those of the server object.
+ /// Next, pass that interface into createProxy along with the object name and URL of the remote object and
+ /// cast the resulting object to the specifice interface.
+ ///
+ /// String The name of the remote object.
+ /// String The URL of the remote object.
+ /// Type The typeof() of a C# interface.
+ /// Object A proxy for your specified interface. Cast to appropriate type.
+ public static Object createProxy(String remoteObjectName, String url, Type anInterface)
+ {
+ return new XmlRpcClientProxy(remoteObjectName, url, anInterface).GetTransparentProxy();
+ }
+
+ private XmlRpcClientProxy(String remoteObjectName, String url, Type t) : base(t)
+ {
+ _remoteObjectName = remoteObjectName;
+ _url = url;
+ }
+
+ /// The local method dispatcher - do not invoke.
+ override public IMessage Invoke(IMessage msg)
+ {
+ IMethodCallMessage methodMessage = (IMethodCallMessage)msg;
+
+ _client.MethodName = _remoteObjectName + "." + methodMessage.MethodName;
+ _client.Params.Clear();
+ foreach (Object o in methodMessage.Args)
+ _client.Params.Add(o);
+
+ try
+ {
+ Object ret = _client.Invoke(_url);
+ return new ReturnMessage(ret,null,0,
+ methodMessage.LogicalCallContext, methodMessage);
+ }
+ catch (Exception e)
+ {
+ return new ReturnMessage(e, methodMessage);
+ }
+ }
+}
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcDeserializer.cs b/Common-Source/XmlRpcCS/XmlRpcDeserializer.cs
new file mode 100644
index 0000000..bd736c0
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcDeserializer.cs
@@ -0,0 +1,195 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Xml;
+ using System.Globalization;
+
+ /// Parser context, we maintain contexts in a stack to avoiding recursion.
+ struct Context
+ {
+ public String Name;
+ public Object Container;
+ }
+
+ /// Basic XML-RPC data deserializer.
+ /// Uses XmlTextReader to parse the XML data. This level of the class
+ /// only handles the tokens common to both Requests and Responses. This class is not useful in and of itself
+ /// but is designed to be subclassed.
+ public class XmlRpcDeserializer : XmlRpcXmlTokens
+ {
+ private static DateTimeFormatInfo _dateFormat = new DateTimeFormatInfo();
+
+ private Object _container;
+ private Stack _containerStack;
+
+ /// Protected reference to last text.
+ protected String _text;
+ /// Protected reference to last deserialized value.
+ protected Object _value;
+ /// Protected reference to last name field.
+ protected String _name;
+
+
+ /// Basic constructor.
+ public XmlRpcDeserializer()
+ {
+ Reset();
+ _dateFormat.FullDateTimePattern = ISO_DATETIME;
+ }
+
+ /// Static method that parses XML data into a response using the Singleton.
+ /// StreamReader containing an XML-RPC response.
+ /// Object object resulting from the deserialization.
+ virtual public Object Deserialize(TextReader xmlData)
+ {
+ return null;
+ }
+
+ /// Protected method to parse a node in an XML-RPC XML stream.
+ /// Method deals with elements common to all XML-RPC data, subclasses of
+ /// this object deal with request/response spefic elements.
+ /// XmlTextReader of the in progress parsing data stream.
+ protected void DeserializeNode(XmlTextReader reader)
+ {
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.Element:
+ if (Logger.Delegate != null)
+ Logger.WriteEntry("START " + reader.Name, LogLevel.Information);
+ switch (reader.Name)
+ {
+ case VALUE:
+ _value = null;
+ _text = null;
+ break;
+ case STRUCT:
+ PushContext();
+ _container = new Hashtable();
+ break;
+ case ARRAY:
+ PushContext();
+ _container = new ArrayList();
+ break;
+ }
+ break;
+ case XmlNodeType.EndElement:
+ if (Logger.Delegate != null)
+ Logger.WriteEntry("END " + reader.Name, LogLevel.Information);
+ switch (reader.Name)
+ {
+ case BASE64:
+ _value = Convert.FromBase64String(_text);
+ break;
+ case BOOLEAN:
+ int val = Int16.Parse(_text);
+ if (val == 0)
+ _value = false;
+ else if (val == 1)
+ _value = true;
+ break;
+ case STRING:
+ _value = _text;
+ break;
+ case DOUBLE:
+ _value = Double.Parse(_text);
+ break;
+ case INT:
+ case ALT_INT:
+ _value = Int32.Parse(_text);
+ break;
+ case DATETIME:
+#if __MONO__
+ _value = DateParse(_text);
+#else
+ _value = DateTime.ParseExact(_text, "F", _dateFormat);
+#endif
+ break;
+ case NAME:
+ _name = _text;
+ break;
+ case VALUE:
+ if (_value == null)
+ _value = _text; // some kits don't use tag, they just do
+
+ if ((_container != null) && (_container is IList)) // in an array? If so add value to it.
+ ((IList)_container).Add(_value);
+ break;
+ case MEMBER:
+ if ((_container != null) && (_container is IDictionary)) // in an struct? If so add value to it.
+ ((IDictionary)_container).Add(_name, _value);
+ break;
+ case ARRAY:
+ case STRUCT:
+ _value = _container;
+ PopContext();
+ break;
+ }
+ break;
+ case XmlNodeType.Text:
+ if (Logger.Delegate != null)
+ Logger.WriteEntry("Text " + reader.Value, LogLevel.Information);
+ _text = reader.Value;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /// Static method that parses XML in a String into a
+ /// request using the Singleton.
+ /// String containing an XML-RPC request.
+ /// XmlRpcRequest object resulting from the parse.
+ public Object Deserialize(String xmlData)
+ {
+ StringReader sr = new StringReader(xmlData);
+ return Deserialize(sr);
+ }
+
+ /// Pop a Context of the stack, an Array or Struct has closed.
+ private void PopContext()
+ {
+ Context c = (Context)_containerStack.Pop();
+ _container = c.Container;
+ _name = c.Name;
+ }
+
+ /// Push a Context on the stack, an Array or Struct has opened.
+ private void PushContext()
+ {
+ Context context;
+
+ context.Container = _container;
+ context.Name = _name;
+
+ _containerStack.Push(context);
+ }
+
+ /// Reset the internal state of the deserializer.
+ protected void Reset()
+ {
+ _text = null;
+ _value = null;
+ _name = null;
+ _container = null;
+ _containerStack = new Stack();
+ }
+
+#if __MONO__
+ private DateTime DateParse(String str)
+ {
+ int year = Int32.Parse(str.Substring(0,4));
+ int month = Int32.Parse(str.Substring(4,2));
+ int day = Int32.Parse(str.Substring(6,2));
+ int hour = Int32.Parse(str.Substring(9,2));
+ int min = Int32.Parse(str.Substring(12,2));
+ int sec = Int32.Parse(str.Substring(15,2));
+ return new DateTime(year,month,day,hour,min,sec);
+ }
+#endif
+
+ }
+}
+
+
diff --git a/Common-Source/XmlRpcCS/XmlRpcErrorCodes.cs b/Common-Source/XmlRpcCS/XmlRpcErrorCodes.cs
new file mode 100644
index 0000000..6dec57d
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcErrorCodes.cs
@@ -0,0 +1,51 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+
+ /// Standard XML-RPC error codes.
+ public class XmlRpcErrorCodes
+ {
+ ///
+ public const int PARSE_ERROR_MALFORMED = -32700;
+ ///
+ public const String PARSE_ERROR_MALFORMED_MSG = "Parse Error, not well formed";
+
+ ///
+ public const int PARSE_ERROR_ENCODING = -32701;
+ ///
+ public const String PARSE_ERROR_ENCODING_MSG = "Parse Error, unsupported encoding";
+
+ //
+ // -32702 ---> parse error. invalid character for encoding
+ // -32600 ---> server error. invalid xml-rpc. not conforming to spec.
+ //
+
+ ///
+ public const int SERVER_ERROR_METHOD = -32601;
+ ///
+ public const String SERVER_ERROR_METHOD_MSG = "Server Error, requested method not found";
+
+ ///
+ public const int SERVER_ERROR_PARAMS = -32602;
+ ///
+ public const String SERVER_ERROR_PARAMS_MSG = "Server Error, invalid method parameters";
+
+ //
+ // -32603 ---> server error. internal xml-rpc error
+ //
+
+ ///
+ public const int APPLICATION_ERROR = -32500;
+ ///
+ public const String APPLICATION_ERROR_MSG = "Application Error";
+
+ //
+ // -32400 ---> system error
+ //
+
+ ///
+ public const int TRANSPORT_ERROR = -32300;
+ ///
+ public const String TRANSPORT_ERROR_MSG = "Transport Layer Error";
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcException.cs b/Common-Source/XmlRpcCS/XmlRpcException.cs
new file mode 100644
index 0000000..fd1f4ae
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcException.cs
@@ -0,0 +1,39 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+
+ /// An XML-RPC Exception.
+ /// Maps a C# exception to an XML-RPC fault. Normal exceptions
+ /// include a message so this adds the code needed by XML-RPC.
+ public class XmlRpcException : Exception
+ {
+ private int _code;
+
+ /// Instantiate an XmlRpcException with a code and message.
+ /// Int faultCode associated with this exception.
+ /// String faultMessage associated with this exception.
+ public XmlRpcException(int code, String message)
+ : base(message)
+ {
+ _code = code;
+ }
+
+ /// The value of the faults message, i.e. the faultString.
+ public String FaultString
+ {
+ get { return Message; }
+ }
+
+ /// The value of the faults code, i.e. the faultCode.
+ public int FaultCode
+ {
+ get { return _code; }
+ }
+
+ /// Format the message to include the code.
+ override public String ToString()
+ {
+ return "Code: " + FaultCode + " Message: " + base.ToString();
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcExposedAttribute.cs b/Common-Source/XmlRpcCS/XmlRpcExposedAttribute.cs
new file mode 100644
index 0000000..67b27ae
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcExposedAttribute.cs
@@ -0,0 +1,60 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Reflection;
+
+ ///
+ /// Simple tagging attribute to indicate participation is XML-RPC exposure.
+ ///
+ ///
+ /// If present at the class level it indicates that this class does explicitly
+ /// expose methods. If present at the method level it denotes that the method
+ /// is exposed.
+ ///
+ [AttributeUsage(
+ AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = false,
+ Inherited = true
+ )]
+ public class XmlRpcExposedAttribute : Attribute
+ {
+ /// Check if obj is an object utilizing the XML-RPC exposed Attribute.
+ /// Object of a class or method to check for attribute.
+ /// Boolean true if attribute present.
+ public static Boolean ExposedObject(Object obj)
+ {
+ return IsExposed(obj.GetType());
+ }
+
+ /// Check if obj.methodName is an XML-RPC exposed method.
+ /// A method is considered to be exposed if it exists and, either, the object does not use the XmlRpcExposed attribute,
+ /// or the object does use the XmlRpcExposed attribute and the method has the XmlRpcExposed attribute as well.
+ /// Boolean true if the method is exposed.
+ public static Boolean ExposedMethod(Object obj, String methodName)
+ {
+ Type type = obj.GetType();
+ MethodInfo method = type.GetMethod(methodName);
+
+ if (method == null)
+ throw new MissingMethodException("Method " + methodName + " not found.");
+
+ if (!IsExposed(type))
+ return true;
+
+ return IsExposed(method);
+ }
+
+ /// Check if mi is XML-RPC exposed.
+ /// MemberInfo of a class or method to check for attribute.
+ /// Boolean true if attribute present.
+ public static Boolean IsExposed(MemberInfo mi)
+ {
+ foreach (Attribute attr in mi.GetCustomAttributes(true))
+ {
+ if (attr is XmlRpcExposedAttribute)
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcRequest.cs b/Common-Source/XmlRpcCS/XmlRpcRequest.cs
new file mode 100644
index 0000000..18d2182
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcRequest.cs
@@ -0,0 +1,150 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Xml;
+ using System.Net;
+ using System.Text;
+ using System.Reflection;
+ using System.Net.Security;
+ using System.Security.Cryptography.X509Certificates;
+
+ internal class AcceptAllCertificatePolicy : ICertificatePolicy
+ {
+ public AcceptAllCertificatePolicy()
+ {
+ }
+
+ public bool CheckValidationResult(ServicePoint sPoint,
+ System.Security.Cryptography.X509Certificates.X509Certificate cert,
+ WebRequest wRequest, int certProb)
+ {
+ // Always accept
+ return true;
+ }
+ }
+
+ /// Class supporting the request side of an XML-RPC transaction.
+ public class XmlRpcRequest
+ {
+ private String _methodName = null;
+ private Encoding _encoding = new ASCIIEncoding();
+ private XmlRpcRequestSerializer _serializer = new XmlRpcRequestSerializer();
+ private XmlRpcResponseDeserializer _deserializer = new XmlRpcResponseDeserializer();
+
+ /// ArrayList containing the parameters.
+ protected IList _params = null;
+
+ /// Instantiate an XmlRpcRequest
+ public XmlRpcRequest()
+ {
+ _params = new ArrayList();
+ }
+
+ /// Instantiate an XmlRpcRequest for a specified method and parameters.
+ /// String designating the object.method on the server the request
+ /// should be directed to.
+ /// ArrayList of XML-RPC type parameters to invoke the request with.
+ public XmlRpcRequest(String methodName, IList parameters)
+ {
+ MethodName = methodName;
+ _params = parameters;
+ }
+
+ /// ArrayList conntaining the parameters for the request.
+ public virtual IList Params
+ {
+ get { return _params; }
+ }
+
+ /// String conntaining the method name, both object and method, that the request will be sent to.
+ public virtual String MethodName
+ {
+ get { return _methodName; }
+ set { _methodName = value; }
+ }
+
+ /// String object name portion of the method name.
+ public String MethodNameObject
+ {
+ get
+ {
+ int index = MethodName.IndexOf(".");
+
+ if (index == -1)
+ return MethodName;
+
+ return MethodName.Substring(0, index);
+ }
+ }
+
+ /// String method name portion of the object.method name.
+ public String MethodNameMethod
+ {
+ get
+ {
+ int index = MethodName.IndexOf(".");
+
+ if (index == -1)
+ return MethodName;
+
+ return MethodName.Substring(index + 1, MethodName.Length - index - 1);
+ }
+ }
+
+ /// Invoke this request on the server.
+ /// String The url of the XML-RPC server.
+ /// Object The value returned from the method invocation on the server.
+ /// If an exception generated on the server side.
+ public Object Invoke(String url)
+ {
+ XmlRpcResponse res = Send(url, 10000);
+
+ if (res.IsFault)
+ throw new XmlRpcException(res.FaultCode, res.FaultString);
+
+ return res.Value;
+ }
+
+ /// Send the request to the server.
+ /// String The url of the XML-RPC server.
+ /// Milliseconds before the connection times out.
+ /// XmlRpcResponse The response generated.
+ public XmlRpcResponse Send(String url, int timeout)
+ {
+ // Override SSL authentication mechanisms
+ ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy();
+
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
+ if (request == null)
+ throw new XmlRpcException(XmlRpcErrorCodes.TRANSPORT_ERROR,
+ XmlRpcErrorCodes.TRANSPORT_ERROR_MSG + ": Could not create request with " + url);
+ request.Method = "POST";
+ request.ContentType = "text/xml";
+ request.AllowWriteStreamBuffering = true;
+ request.Timeout = timeout;
+
+ Stream stream = request.GetRequestStream();
+ XmlTextWriter xml = new XmlTextWriter(stream, _encoding);
+ _serializer.Serialize(xml, this);
+ xml.Flush();
+ xml.Close();
+
+ HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+ StreamReader input = new StreamReader(response.GetResponseStream());
+
+ XmlRpcResponse resp = (XmlRpcResponse)_deserializer.Deserialize(input);
+ input.Close();
+ response.Close();
+ return resp;
+ }
+
+ /// Produce String representation of the object.
+ /// String representation of the object.
+ override public String ToString()
+ {
+ return _serializer.Serialize(this);
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcRequestDeserializer.cs b/Common-Source/XmlRpcCS/XmlRpcRequestDeserializer.cs
new file mode 100644
index 0000000..0770b7e
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcRequestDeserializer.cs
@@ -0,0 +1,64 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Xml;
+
+ /// Class to deserialize XML data representing a request.
+ public class XmlRpcRequestDeserializer : XmlRpcDeserializer
+ {
+ static private XmlRpcRequestDeserializer _singleton;
+ /// A static singleton instance of this deserializer.
+ [Obsolete("This object is now thread safe, just use an instance.", false)]
+ static public XmlRpcRequestDeserializer Singleton
+ {
+ get
+ {
+ if (_singleton == null)
+ _singleton = new XmlRpcRequestDeserializer();
+
+ return _singleton;
+ }
+ }
+
+ /// Static method that parses XML data into a request using the Singleton.
+ /// StreamReader containing an XML-RPC request.
+ /// XmlRpcRequest object resulting from the parse.
+ override public Object Deserialize(TextReader xmlData)
+ {
+ XmlTextReader reader = new XmlTextReader(xmlData);
+ XmlRpcRequest request = new XmlRpcRequest();
+ bool done = false;
+
+ lock (this)
+ {
+ Reset();
+ while (!done && reader.Read())
+ {
+ DeserializeNode(reader); // Parent parse...
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.EndElement:
+ switch (reader.Name)
+ {
+ case METHOD_NAME:
+ request.MethodName = _text;
+ break;
+ case METHOD_CALL:
+ done = true;
+ break;
+ case PARAM:
+ request.Params.Add(_value);
+ _text = null;
+ break;
+ }
+ break;
+ }
+ }
+ }
+ return request;
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcRequestSerializer.cs b/Common-Source/XmlRpcCS/XmlRpcRequestSerializer.cs
new file mode 100644
index 0000000..8099bdb
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcRequestSerializer.cs
@@ -0,0 +1,51 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.Xml;
+ using System.IO;
+
+ /// Class responsible for serializing an XML-RPC request.
+ /// This class handles the request envelope, depending on XmlRpcSerializer
+ /// to serialize the payload.
+ ///
+ public class XmlRpcRequestSerializer : XmlRpcSerializer
+ {
+ static private XmlRpcRequestSerializer _singleton;
+ /// A static singleton instance of this deserializer.
+ static public XmlRpcRequestSerializer Singleton
+ {
+ get
+ {
+ if (_singleton == null)
+ _singleton = new XmlRpcRequestSerializer();
+
+ return _singleton;
+ }
+ }
+
+ /// Serialize the XmlRpcRequest to the output stream.
+ /// An XmlTextWriter stream to write data to.
+ /// An XmlRpcRequest to serialize.
+ ///
+ override public void Serialize(XmlTextWriter output, Object obj)
+ {
+ XmlRpcRequest request = (XmlRpcRequest)obj;
+ output.WriteStartDocument();
+ output.WriteStartElement(METHOD_CALL);
+ output.WriteElementString(METHOD_NAME, request.MethodName);
+ output.WriteStartElement(PARAMS);
+ foreach (Object param in request.Params)
+ {
+ output.WriteStartElement(PARAM);
+ output.WriteStartElement(VALUE);
+ SerializeObject(output, param);
+ output.WriteEndElement();
+ output.WriteEndElement();
+ }
+
+ output.WriteEndElement();
+ output.WriteEndElement();
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcResponder.cs b/Common-Source/XmlRpcCS/XmlRpcResponder.cs
new file mode 100644
index 0000000..0412568
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcResponder.cs
@@ -0,0 +1,98 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Xml;
+ using System.Net.Sockets;
+
+ /// The class is a container of the context of an XML-RPC dialog on the server side.
+ /// Instances of this class maintain the context for an individual XML-RPC server
+ /// side dialog. Namely they manage an inbound deserializer and an outbound serializer.
+ public class XmlRpcResponder
+ {
+ private XmlRpcRequestDeserializer _deserializer = new XmlRpcRequestDeserializer();
+ private XmlRpcResponseSerializer _serializer = new XmlRpcResponseSerializer();
+ private XmlRpcServer _server;
+ private TcpClient _client;
+ private SimpleHttpRequest _httpReq;
+
+ /// The SimpleHttpRequest based on the TcpClient.
+ public SimpleHttpRequest HttpReq
+ {
+ get { return _httpReq; }
+ }
+
+ /// Basic constructor.
+ /// XmlRpcServer that this XmlRpcResponder services.
+ /// TcpClient with the connection.
+ public XmlRpcResponder(XmlRpcServer server, TcpClient client)
+ {
+ _server = server;
+ _client = client;
+ _httpReq = new SimpleHttpRequest(_client);
+ }
+
+ /// Call close to insure proper shutdown.
+ ~XmlRpcResponder()
+ {
+ Close();
+ }
+
+ ///Respond using this responders HttpReq.
+ public void Respond()
+ {
+ Respond(HttpReq);
+ }
+
+ /// Handle an HTTP request containing an XML-RPC request.
+ /// This method deserializes the XML-RPC request, invokes the
+ /// described method, serializes the response (or fault) and sends the XML-RPC response
+ /// back as a valid HTTP page.
+ ///
+ /// SimpleHttpRequest containing the request.
+ public void Respond(SimpleHttpRequest httpReq)
+ {
+ XmlRpcRequest xmlRpcReq = (XmlRpcRequest)_deserializer.Deserialize(httpReq.Input);
+ XmlRpcResponse xmlRpcResp = new XmlRpcResponse();
+
+ try
+ {
+ xmlRpcResp.Value = _server.Invoke(xmlRpcReq);
+ }
+ catch (XmlRpcException e)
+ {
+ xmlRpcResp.SetFault(e.FaultCode, e.FaultString);
+ }
+ catch (Exception e2)
+ {
+ xmlRpcResp.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR,
+ XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message);
+ }
+
+ if (Logger.Delegate != null)
+ Logger.WriteEntry(xmlRpcResp.ToString(), LogLevel.Information);
+
+ XmlRpcServer.HttpHeader(httpReq.Protocol, "text/xml", 0, " 200 OK", httpReq.Output);
+ httpReq.Output.Flush();
+ XmlTextWriter xml = new XmlTextWriter(httpReq.Output);
+ _serializer.Serialize(xml, xmlRpcResp);
+ xml.Flush();
+ httpReq.Output.Flush();
+ }
+
+ ///Close all contained resources, both the HttpReq and client.
+ public void Close()
+ {
+ if (_httpReq != null)
+ {
+ _httpReq.Close();
+ _httpReq = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Close();
+ _client = null;
+ }
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcResponse.cs b/Common-Source/XmlRpcCS/XmlRpcResponse.cs
new file mode 100644
index 0000000..8ff8354
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcResponse.cs
@@ -0,0 +1,85 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Xml;
+
+ /// Class designed to represent an XML-RPC response.
+ public class XmlRpcResponse
+ {
+ private Object _value;
+ /// bool indicating if this response represents a fault.
+ public bool IsFault;
+
+ /// Basic constructor
+ public XmlRpcResponse()
+ {
+ Value = null;
+ IsFault = false;
+ }
+
+ /// Constructor for a fault.
+ /// int the numeric faultCode value.
+ /// String the faultString value.
+ public XmlRpcResponse(int code, String message)
+ : this()
+ {
+ SetFault(code, message);
+ }
+
+ /// The data value of the response, may be fault data.
+ public Object Value
+ {
+ get { return _value; }
+ set
+ {
+ IsFault = false;
+ _value = value;
+ }
+ }
+
+ /// The faultCode if this is a fault.
+ public int FaultCode
+ {
+ get
+ {
+ if (!IsFault)
+ return 0;
+ else
+ return (int)((Hashtable)_value)[XmlRpcXmlTokens.FAULT_CODE];
+ }
+ }
+
+ /// The faultString if this is a fault.
+ public String FaultString
+ {
+ get
+ {
+ if (!IsFault)
+ return "";
+ else
+ return (String)((Hashtable)_value)[XmlRpcXmlTokens.FAULT_STRING];
+ }
+ }
+
+ /// Set this response to be a fault.
+ /// int the numeric faultCode value.
+ /// String the faultString value.
+ public void SetFault(int code, String message)
+ {
+ Hashtable fault = new Hashtable();
+ fault.Add("faultCode", code);
+ fault.Add("faultString", message);
+ Value = fault;
+ IsFault = true;
+ }
+
+ /// Form a useful string representation of the object, in this case the XML response.
+ /// String The XML serialized XML-RPC response.
+ override public String ToString()
+ {
+ return XmlRpcResponseSerializer.Singleton.Serialize(this);
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcResponseDeserializer.cs b/Common-Source/XmlRpcCS/XmlRpcResponseDeserializer.cs
new file mode 100644
index 0000000..032d8a3
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcResponseDeserializer.cs
@@ -0,0 +1,65 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Xml;
+
+ /// Class to deserialize XML data representing a response.
+ public class XmlRpcResponseDeserializer : XmlRpcDeserializer
+ {
+ static private XmlRpcResponseDeserializer _singleton;
+ /// A static singleton instance of this deserializer.
+ [Obsolete("This object is now thread safe, just use an instance.", false)]
+ static public XmlRpcResponseDeserializer Singleton
+ {
+ get
+ {
+ if (_singleton == null)
+ _singleton = new XmlRpcResponseDeserializer();
+
+ return _singleton;
+ }
+ }
+
+ /// Static method that parses XML data into a response using the Singleton.
+ /// StreamReader containing an XML-RPC response.
+ /// XmlRpcResponse object resulting from the parse.
+ override public Object Deserialize(TextReader xmlData)
+ {
+ XmlTextReader reader = new XmlTextReader(xmlData);
+ XmlRpcResponse response = new XmlRpcResponse();
+ bool done = false;
+
+ lock (this)
+ {
+ Reset();
+
+ while (!done && reader.Read())
+ {
+ DeserializeNode(reader); // Parent parse...
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.EndElement:
+ switch (reader.Name)
+ {
+ case FAULT:
+ response.Value = _value;
+ response.IsFault = true;
+ break;
+ case PARAM:
+ response.Value = _value;
+ _value = null;
+ _text = null;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return response;
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcResponseSerializer.cs b/Common-Source/XmlRpcCS/XmlRpcResponseSerializer.cs
new file mode 100644
index 0000000..72ca568
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcResponseSerializer.cs
@@ -0,0 +1,57 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.Xml;
+
+ /// Class responsible for serializing an XML-RPC response.
+ /// This class handles the response envelope, depending on XmlRpcSerializer
+ /// to serialize the payload.
+ ///
+ public class XmlRpcResponseSerializer : XmlRpcSerializer
+ {
+ static private XmlRpcResponseSerializer _singleton;
+ /// A static singleton instance of this deserializer.
+ static public XmlRpcResponseSerializer Singleton
+ {
+ get
+ {
+ if (_singleton == null)
+ _singleton = new XmlRpcResponseSerializer();
+
+ return _singleton;
+ }
+ }
+
+ /// Serialize the XmlRpcResponse to the output stream.
+ /// An XmlTextWriter stream to write data to.
+ /// An Object to serialize.
+ ///
+ override public void Serialize(XmlTextWriter output, Object obj)
+ {
+ XmlRpcResponse response = (XmlRpcResponse)obj;
+
+ output.WriteStartDocument();
+ output.WriteStartElement(METHOD_RESPONSE);
+
+ if (response.IsFault)
+ output.WriteStartElement(FAULT);
+ else
+ {
+ output.WriteStartElement(PARAMS);
+ output.WriteStartElement(PARAM);
+ }
+
+ output.WriteStartElement(VALUE);
+
+ SerializeObject(output, response.Value);
+
+ output.WriteEndElement();
+
+ output.WriteEndElement();
+ if (!response.IsFault)
+ output.WriteEndElement();
+ output.WriteEndElement();
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcSerializer.cs b/Common-Source/XmlRpcCS/XmlRpcSerializer.cs
new file mode 100644
index 0000000..0643d38
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcSerializer.cs
@@ -0,0 +1,109 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Xml;
+
+ /// Base class of classes serializing data to XML-RPC's XML format.
+ /// This class handles the basic type conversions like Integer to <i4>.
+ ///
+ public class XmlRpcSerializer : XmlRpcXmlTokens
+ {
+
+ /// Serialize the XmlRpcRequest to the output stream.
+ /// An XmlTextWriter stream to write data to.
+ /// An Object to serialize.
+ ///
+ virtual public void Serialize(XmlTextWriter output, Object obj)
+ {
+ }
+
+ /// Serialize the XmlRpcRequest to a String.
+ /// Note this may represent a real memory hog for a large request.
+ /// An Object to serialize.
+ /// String containing XML-RPC representation of the request.
+ ///
+ public String Serialize(Object obj)
+ {
+ StringWriter strBuf = new StringWriter();
+ XmlTextWriter xml = new XmlTextWriter(strBuf);
+ xml.Formatting = Formatting.Indented;
+ xml.Indentation = 4;
+ Serialize(xml, obj);
+ xml.Flush();
+ String returns = strBuf.ToString();
+ xml.Close();
+ return returns;
+ }
+
+ /// Serialize the object to the output stream.
+ /// An XmlTextWriter stream to write data to.
+ /// An Object to serialize.
+ public void SerializeObject(XmlTextWriter output, Object obj)
+ {
+ if (obj == null)
+ return;
+
+ if (obj is byte[])
+ {
+ byte[] ba = (byte[])obj;
+ output.WriteStartElement(BASE64);
+ output.WriteBase64(ba, 0, ba.Length);
+ output.WriteEndElement();
+ }
+ else if (obj is String)
+ {
+ output.WriteElementString(STRING, obj.ToString());
+ }
+ else if (obj is Int32)
+ {
+ output.WriteElementString(INT, obj.ToString());
+ }
+ else if (obj is DateTime)
+ {
+ output.WriteElementString(DATETIME, ((DateTime)obj).ToString(ISO_DATETIME));
+ }
+ else if (obj is Double)
+ {
+ output.WriteElementString(DOUBLE, obj.ToString());
+ }
+ else if (obj is Boolean)
+ {
+ output.WriteElementString(BOOLEAN, ((((Boolean)obj) == true) ? "1" : "0"));
+ }
+ else if (obj is IList)
+ {
+ output.WriteStartElement(ARRAY);
+ output.WriteStartElement(DATA);
+ if (((ArrayList)obj).Count > 0)
+ {
+ foreach (Object member in ((IList)obj))
+ {
+ output.WriteStartElement(VALUE);
+ SerializeObject(output, member);
+ output.WriteEndElement();
+ }
+ }
+ output.WriteEndElement();
+ output.WriteEndElement();
+ }
+ else if (obj is IDictionary)
+ {
+ IDictionary h = (IDictionary)obj;
+ output.WriteStartElement(STRUCT);
+ foreach (String key in h.Keys)
+ {
+ output.WriteStartElement(MEMBER);
+ output.WriteElementString(NAME, key);
+ output.WriteStartElement(VALUE);
+ SerializeObject(output, h[key]);
+ output.WriteEndElement();
+ output.WriteEndElement();
+ }
+ output.WriteEndElement();
+ }
+
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcServer.cs b/Common-Source/XmlRpcCS/XmlRpcServer.cs
new file mode 100644
index 0000000..1c226c1
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcServer.cs
@@ -0,0 +1,239 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.IO;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Text;
+ using System.Threading;
+ using System.Xml;
+
+ /// A restricted HTTP server for use with XML-RPC.
+ /// It only handles POST requests, and only POSTs representing XML-RPC calls.
+ /// In addition to dispatching requests it also provides a registry for request handlers.
+ ///
+ public class XmlRpcServer : IEnumerable
+ {
+#pragma warning disable 0414 // disable "private field assigned but not used"
+ const int RESPONDER_COUNT = 10;
+ private TcpListener _myListener;
+ private int _port;
+ private IPAddress _address;
+ private IDictionary _handlers;
+ private XmlRpcSystemObject _system;
+ private WaitCallback _wc;
+#pragma warning restore 0414
+
+ ///Constructor with port and address.
+ ///This constructor sets up a TcpListener listening on the
+ ///given port and address. It also calls a Thread on the method StartListen().
+ ///IPAddress value of the address to listen on.
+ ///Int value of the port to listen on.
+ public XmlRpcServer(IPAddress address, int port)
+ {
+ _port = port;
+ _address = address;
+ _handlers = new Hashtable();
+ _system = new XmlRpcSystemObject(this);
+ _wc = new WaitCallback(WaitCallback);
+ }
+
+ ///Basic constructor.
+ ///This constructor sets up a TcpListener listening on the
+ ///given port. It also calls a Thread on the method StartListen(). IPAddress.Any
+ ///is assumed as the address here.
+ ///Int value of the port to listen on.
+ public XmlRpcServer(int port) : this(IPAddress.Any, port) { }
+
+ /// Start the server.
+ public void Start()
+ {
+ try
+ {
+ Stop();
+ //start listing on the given port
+ // IPAddress addr = IPAddress.Parse("127.0.0.1");
+ lock (this)
+ {
+ _myListener = new TcpListener(IPAddress.Any, _port);
+ _myListener.Start();
+ //start the thread which calls the method 'StartListen'
+ Thread th = new Thread(new ThreadStart(StartListen));
+ th.Start();
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.WriteEntry("An Exception Occurred while Listening :" + e.ToString(), LogLevel.Error);
+ }
+ }
+
+ /// Stop the server.
+ public void Stop()
+ {
+ try
+ {
+ if (_myListener != null)
+ {
+ lock (this)
+ {
+ _myListener.Stop();
+ _myListener = null;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.WriteEntry("An Exception Occurred while stopping :" +
+ e.ToString(), LogLevel.Error);
+ }
+ }
+
+ /// Get an enumeration of my XML-RPC handlers.
+ /// IEnumerable the handler enumeration.
+ public IEnumerator GetEnumerator()
+ {
+ return _handlers.GetEnumerator();
+ }
+
+ /// Retrieve a handler by name.
+ /// String naming a handler
+ /// Object that is the handler.
+ public Object this[String name]
+ {
+ get { return _handlers[name]; }
+ }
+
+ ///
+ ///This method Accepts new connections and dispatches them when appropriate.
+ ///
+ public void StartListen()
+ {
+ while (true && _myListener != null)
+ {
+ //Accept a new connection
+ XmlRpcResponder responder = new XmlRpcResponder(this, _myListener.AcceptTcpClient());
+ ThreadPool.QueueUserWorkItem(_wc, responder);
+ }
+ }
+
+
+ ///
+ ///Add an XML-RPC handler object by name.
+ ///
+ ///String XML-RPC dispatch name of this object.
+ ///Object The object that is the XML-RPC handler.
+ public void Add(String name, Object obj)
+ {
+ _handlers.Add(name, obj);
+ }
+
+ ///Return a C# object.method name for and XML-RPC object.method name pair.
+ ///The XML-RPC object.method.
+ ///String of form object.method for the underlying C# method.
+ public String MethodName(String methodName)
+ {
+ int dotAt = methodName.LastIndexOf('.');
+
+ if (dotAt == -1)
+ {
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
+ XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Bad method name " + methodName);
+ }
+
+ String objectName = methodName.Substring(0, dotAt);
+ Object target = _handlers[objectName];
+
+ if (target == null)
+ {
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
+ XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Object " + objectName + " not found");
+ }
+
+ return target.GetType().FullName + "." + methodName.Substring(dotAt + 1);
+ }
+
+ ///Invoke a method described in a request.
+ ///XmlRpcRequest containing a method descriptions.
+ ///
+ ///
+ public Object Invoke(XmlRpcRequest req)
+ {
+ return Invoke(req.MethodNameObject, req.MethodNameMethod, req.Params);
+ }
+
+ ///Invoke a method on a named handler.
+ ///String The name of the handler.
+ ///String The name of the method to invoke on the handler.
+ ///IList The parameters to invoke the method with.
+ ///
+ public Object Invoke(String objectName, String methodName, IList parameters)
+ {
+ Object target = _handlers[objectName];
+
+ if (target == null)
+ {
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
+ XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Object " + objectName + " not found");
+ }
+
+ return XmlRpcSystemObject.Invoke(target, methodName, parameters);
+ }
+
+ /// The method the thread pool invokes when a thread is available to handle an HTTP request.
+ /// TcpClient from the socket accept.
+ public void WaitCallback(object responder)
+ {
+ XmlRpcResponder resp = (XmlRpcResponder)responder;
+
+ if (resp.HttpReq.HttpMethod == "POST")
+ {
+ try
+ {
+ resp.Respond();
+ }
+ catch (Exception e)
+ {
+ Logger.WriteEntry("Failed on post: " + e, LogLevel.Error);
+ }
+ }
+ else
+ {
+ Logger.WriteEntry("Only POST methods are supported: " + resp.HttpReq.HttpMethod +
+ " ignored", LogLevel.Error);
+ }
+
+ resp.Close();
+ }
+
+ ///
+ /// This function send the Header Information to the client (Browser)
+ ///
+ /// HTTP Version
+ /// Mime Type
+ /// Total Bytes to be sent in the body
+ ///
+ /// Socket reference
+ static public void HttpHeader(string sHttpVersion, string sMIMEHeader, long iTotBytes, string sStatusCode, TextWriter output)
+ {
+ String sBuffer = "";
+
+ // if Mime type is not provided set default to text/html
+ if (sMIMEHeader.Length == 0)
+ {
+ sMIMEHeader = "text/html"; // Default Mime Type is text/html
+ }
+
+ sBuffer += sHttpVersion + sStatusCode + "\r\n";
+ sBuffer += "Connection: close\r\n";
+ if (iTotBytes > 0)
+ sBuffer += "Content-Length: " + iTotBytes + "\r\n";
+ sBuffer += "Server: XmlRpcServer \r\n";
+ sBuffer += "Content-Type: " + sMIMEHeader + "\r\n";
+ sBuffer += "\r\n";
+
+ output.Write(sBuffer);
+ }
+ }
+}
diff --git a/Common-Source/XmlRpcCS/XmlRpcSystemObject.cs b/Common-Source/XmlRpcCS/XmlRpcSystemObject.cs
new file mode 100644
index 0000000..5f79951
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcSystemObject.cs
@@ -0,0 +1,252 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+ using System.Collections;
+ using System.Reflection;
+
+ /// XML-RPC System object implementation of extended specifications.
+ [XmlRpcExposed]
+ public class XmlRpcSystemObject
+ {
+ private XmlRpcServer _server;
+ static private IDictionary _methodHelp = new Hashtable();
+
+ /// Static IDictionary to hold mappings of method name to associated documentation String
+ static public IDictionary MethodHelp
+ {
+ get { return _methodHelp; }
+ }
+
+ /// Constructor.
+ /// XmlRpcServer server to be the system object for.
+ public XmlRpcSystemObject(XmlRpcServer server)
+ {
+ _server = server;
+ server.Add("system", this);
+ _methodHelp.Add(this.GetType().FullName + ".methodHelp", "Return a string description.");
+ }
+
+ /// Invoke a method on a given object.
+ /// Using reflection, and respecting the XmlRpcExposed attribute,
+ /// invoke the methodName method on the target
+ /// instance with the parameters provided. All this packages other Invoke methods
+ /// end up calling this.
+ /// Object the value the invoked method returns.
+ /// If method does not exist, is not exposed, parameters invalid, or invocation
+ /// results in an exception. Note, the XmlRpcException.Code will indicate cause.
+ static public Object Invoke(Object target, String methodName, IList parameters)
+ {
+ if (target == null)
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
+ XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Invalid target object.");
+
+ Type type = target.GetType();
+ MethodInfo method = type.GetMethod(methodName);
+
+ try
+ {
+ if (!XmlRpcExposedAttribute.ExposedMethod(target, methodName))
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
+ XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Method " + methodName + " is not exposed.");
+ }
+ catch (MissingMethodException me)
+ {
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
+ XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": " + me.Message);
+ }
+
+ Object[] args = new Object[parameters.Count];
+
+ int index = 0;
+ foreach (Object arg in parameters)
+ {
+ args[index] = arg;
+ index++;
+ }
+
+ try
+ {
+ Object retValue = method.Invoke(target, args);
+ if (retValue == null)
+ throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
+ XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": Method returned NULL.");
+ return retValue;
+ }
+ catch (XmlRpcException e)
+ {
+ throw e;
+ }
+ catch (ArgumentException ae)
+ {
+ Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + ae.Message,
+ LogLevel.Information);
+ String call = methodName + "( ";
+ foreach (Object o in args)
+ {
+ call += o.GetType().Name;
+ call += " ";
+ }
+ call += ")";
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
+ XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement type mismatch invoking " + call);
+ }
+ catch (TargetParameterCountException tpce)
+ {
+ Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + tpce.Message,
+ LogLevel.Information);
+ throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
+ XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement count mismatch invoking " + methodName);
+ }
+ catch (TargetInvocationException tie)
+ {
+ throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
+ XmlRpcErrorCodes.APPLICATION_ERROR_MSG + " Invoked method " + methodName + ": " + tie.Message);
+ }
+ }
+
+ /// List methods available on all handlers of this server.
+ /// IList An array of Strings, each String will have form "object.method".
+ [XmlRpcExposed]
+ public IList listMethods()
+ {
+ IList methods = new ArrayList();
+ Boolean considerExposure;
+
+ foreach (DictionaryEntry handlerEntry in _server)
+ {
+ considerExposure = XmlRpcExposedAttribute.IsExposed(handlerEntry.Value.GetType());
+
+ foreach (MemberInfo mi in handlerEntry.Value.GetType().GetMembers())
+ {
+ if (mi.MemberType != MemberTypes.Method)
+ continue;
+
+ if (!((MethodInfo)mi).IsPublic)
+ continue;
+
+ if (considerExposure && !XmlRpcExposedAttribute.IsExposed(mi))
+ continue;
+
+ methods.Add(handlerEntry.Key + "." + mi.Name);
+ }
+ }
+
+ return methods;
+ }
+
+ /// Given a method name return the possible signatures for it.
+ /// String The object.method name to look up.
+ /// IList Of arrays of signatures.
+ [XmlRpcExposed]
+ public IList methodSignature(String name)
+ {
+ IList signatures = new ArrayList();
+ int index = name.IndexOf('.');
+
+ if (index < 0)
+ return signatures;
+
+ String oName = name.Substring(0, index);
+ Object obj = _server[oName];
+
+ if (obj == null)
+ return signatures;
+
+ MemberInfo[] mi = obj.GetType().GetMember(name.Substring(index + 1));
+
+ if (mi == null || mi.Length != 1) // for now we want a single signature
+ return signatures;
+
+ MethodInfo method;
+
+ try
+ {
+ method = (MethodInfo)mi[0];
+ }
+ catch (Exception e)
+ {
+ Logger.WriteEntry("Attempted methodSignature call on " + mi[0] + " caused: " + e,
+ LogLevel.Information);
+ return signatures;
+ }
+
+ if (!method.IsPublic)
+ return signatures;
+
+ IList signature = new ArrayList();
+ signature.Add(method.ReturnType.Name);
+
+ foreach (ParameterInfo param in method.GetParameters())
+ {
+ signature.Add(param.ParameterType.Name);
+ }
+
+
+ signatures.Add(signature);
+
+ return signatures;
+ }
+
+ /// Help for given method signature. Not implemented yet.
+ /// String The object.method name to look up.
+ /// String help text. Rich HTML text.
+ [XmlRpcExposed]
+ public String methodHelp(String name)
+ {
+ String help = null;
+
+ try
+ {
+ help = (String)_methodHelp[_server.MethodName(name)];
+ }
+ catch (XmlRpcException e)
+ {
+ throw e;
+ }
+ catch (Exception) { /* ignored */ };
+
+ if (help == null)
+ help = "No help available for: " + name;
+
+ return help;
+ }
+
+ /// Boxcarring support method.
+ /// IList of calls
+ /// ArrayList of results/faults.
+ [XmlRpcExposed]
+ public IList multiCall(IList calls)
+ {
+ IList responses = new ArrayList();
+ XmlRpcResponse fault = new XmlRpcResponse();
+
+ foreach (IDictionary call in calls)
+ {
+ try
+ {
+ XmlRpcRequest req = new XmlRpcRequest((String)call[XmlRpcXmlTokens.METHOD_NAME],
+ (ArrayList)call[XmlRpcXmlTokens.PARAMS]);
+ Object results = _server.Invoke(req);
+ IList response = new ArrayList();
+ response.Add(results);
+ responses.Add(response);
+ }
+ catch (XmlRpcException e)
+ {
+ fault.SetFault(e.FaultCode, e.FaultString);
+ responses.Add(fault.Value);
+ }
+ catch (Exception e2)
+ {
+ fault.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR,
+ XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message);
+ responses.Add(fault.Value);
+ }
+ }
+
+ return responses;
+ }
+
+ }
+}
+
diff --git a/Common-Source/XmlRpcCS/XmlRpcXmlTokens.cs b/Common-Source/XmlRpcCS/XmlRpcXmlTokens.cs
new file mode 100644
index 0000000..50788bd
--- /dev/null
+++ b/Common-Source/XmlRpcCS/XmlRpcXmlTokens.cs
@@ -0,0 +1,76 @@
+namespace Nwc.XmlRpc
+{
+ using System;
+
+ /// Class collecting String tokens that are part of XML-RPC files.
+ public class XmlRpcXmlTokens
+ {
+ /// C# formatting string to describe an ISO 8601 date.
+ public const String ISO_DATETIME = "yyyyMMdd\\THH\\:mm\\:ss";
+ /// Base64 field indicator.
+ /// Corresponds to the <base64> tag.
+ public const String BASE64 = "base64";
+ /// String field indicator.
+ /// Corresponds to the <string> tag.
+ public const String STRING = "string";
+ /// Integer field integer.
+ /// Corresponds to the <i4> tag.
+ public const String INT = "i4";
+ /// Alternate integer field indicator.
+ /// Corresponds to the <int> tag.
+ public const String ALT_INT = "int";
+ /// Date field indicator.
+ /// Corresponds to the <dateTime.iso8601> tag.
+ public const String DATETIME = "dateTime.iso8601";
+ /// Boolean field indicator.
+ /// Corresponds to the <boolean> tag.
+ public const String BOOLEAN = "boolean";
+ /// Value token.
+ /// Corresponds to the <value> tag.
+ public const String VALUE = "value";
+ /// Name token.
+ /// Corresponds to the <name> tag.
+ public const String NAME = "name";
+ /// Array field indicator..
+ /// Corresponds to the <array> tag.
+ public const String ARRAY = "array";
+ /// Data token.
+ /// Corresponds to the <data> tag.
+ public const String DATA = "data";
+ /// Member token.
+ /// Corresponds to the <member> tag.
+ public const String MEMBER = "member";
+ /// Stuct field indicator.
+ /// Corresponds to the <struct> tag.
+ public const String STRUCT = "struct";
+ /// Double field indicator.
+ /// Corresponds to the <double> tag.
+ public const String DOUBLE = "double";
+ /// Param token.
+ /// Corresponds to the <param> tag.
+ public const String PARAM = "param";
+ /// Params token.
+ /// Corresponds to the <params> tag.
+ public const String PARAMS = "params";
+ /// MethodCall token.
+ /// Corresponds to the <methodCall> tag.
+ public const String METHOD_CALL = "methodCall";
+ /// MethodName token.
+ /// Corresponds to the <methodName> tag.
+ public const String METHOD_NAME = "methodName";
+ /// MethodResponse token
+ /// Corresponds to the <methodResponse> tag.
+ public const String METHOD_RESPONSE = "methodResponse";
+ /// Fault response token.
+ /// Corresponds to the <fault> tag.
+ public const String FAULT = "fault";
+ /// FaultCode token.
+ /// Corresponds to the <faultCode> tag.
+ public const String FAULT_CODE = "faultCode";
+ /// FaultString token.
+ /// Corresponds to the <faultString> tag.
+ public const String FAULT_STRING = "faultString";
+ }
+}
+
+
--
cgit v1.1