aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/XmlRpcCS
diff options
context:
space:
mode:
authorMW2007-04-25 18:12:06 +0000
committerMW2007-04-25 18:12:06 +0000
commit9ed0a8dbad121b64ca8baca78f28ca58602c47ca (patch)
tree5c0008e0be59cb7ccaaf8ff1b0ea2f272a0548e6 /XmlRpcCS
parentCan now use the xml config file for setting up things like sandbox mode, logi... (diff)
downloadopensim-SC_OLD-9ed0a8dbad121b64ca8baca78f28ca58602c47ca.zip
opensim-SC_OLD-9ed0a8dbad121b64ca8baca78f28ca58602c47ca.tar.gz
opensim-SC_OLD-9ed0a8dbad121b64ca8baca78f28ca58602c47ca.tar.bz2
opensim-SC_OLD-9ed0a8dbad121b64ca8baca78f28ca58602c47ca.tar.xz
updated to use lastest version of libsl but is currently broke when using SL viewer 1.15.02, due to big changes in the message templates.
Diffstat (limited to 'XmlRpcCS')
-rw-r--r--XmlRpcCS/Logger.cs46
-rw-r--r--XmlRpcCS/SimpleHttpRequest.cs204
-rw-r--r--XmlRpcCS/XMLRPC.csproj138
-rw-r--r--XmlRpcCS/XMLRPC.dll.build58
-rw-r--r--XmlRpcCS/XmlRpcBoxcarRequest.cs51
-rw-r--r--XmlRpcCS/XmlRpcClientProxy.cs61
-rw-r--r--XmlRpcCS/XmlRpcDeserializer.cs195
-rw-r--r--XmlRpcCS/XmlRpcErrorCodes.cs51
-rw-r--r--XmlRpcCS/XmlRpcException.cs39
-rw-r--r--XmlRpcCS/XmlRpcExposedAttribute.cs60
-rw-r--r--XmlRpcCS/XmlRpcRequest.cs150
-rw-r--r--XmlRpcCS/XmlRpcRequestDeserializer.cs64
-rw-r--r--XmlRpcCS/XmlRpcRequestSerializer.cs51
-rw-r--r--XmlRpcCS/XmlRpcResponder.cs98
-rw-r--r--XmlRpcCS/XmlRpcResponse.cs85
-rw-r--r--XmlRpcCS/XmlRpcResponseDeserializer.cs65
-rw-r--r--XmlRpcCS/XmlRpcResponseSerializer.cs57
-rw-r--r--XmlRpcCS/XmlRpcSerializer.cs109
-rw-r--r--XmlRpcCS/XmlRpcServer.cs239
-rw-r--r--XmlRpcCS/XmlRpcSystemObject.cs252
-rw-r--r--XmlRpcCS/XmlRpcXmlTokens.cs76
21 files changed, 2149 insertions, 0 deletions
diff --git a/XmlRpcCS/Logger.cs b/XmlRpcCS/Logger.cs
new file mode 100644
index 0000000..ebf804b
--- /dev/null
+++ b/XmlRpcCS/Logger.cs
@@ -0,0 +1,46 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4
5 /// <summary>Define levels of logging.</summary><remarks> This duplicates
6 /// similar enumerations in System.Diagnostics.EventLogEntryType. The
7 /// duplication was merited because .NET Compact Framework lacked the EventLogEntryType enum.</remarks>
8 public enum LogLevel
9 {
10 /// <summary>Information level, log entry for informational reasons only.</summary>
11 Information,
12 /// <summary>Warning level, indicates a possible problem.</summary>
13 Warning,
14 /// <summary>Error level, implies a significant problem.</summary>
15 Error
16 }
17
18 ///<summary>
19 ///Logging singleton with swappable output delegate.
20 ///</summary>
21 ///<remarks>
22 ///This singleton provides a centralized log. The actual WriteEntry calls are passed
23 ///off to a delegate however. Having a delegate do the actual logginh allows you to
24 ///implement different logging mechanism and have them take effect throughout the system.
25 ///</remarks>
26 public class Logger
27 {
28 ///<summary>Delegate definition for logging.</summary>
29 ///<param name="message">The message <c>String</c> to log.</param>
30 ///<param name="level">The <c>LogLevel</c> of your message.</param>
31 public delegate void LoggerDelegate(String message, LogLevel level);
32 ///<summary>The LoggerDelegate that will recieve WriteEntry requests.</summary>
33 static public LoggerDelegate Delegate = null;
34
35 ///<summary>
36 ///Method logging events are sent to.
37 ///</summary>
38 ///<param name="message">The message <c>String</c> to log.</param>
39 ///<param name="level">The <c>LogLevel</c> of your message.</param>
40 static public void WriteEntry(String message, LogLevel level)
41 {
42 if (Delegate != null)
43 Delegate(message, level);
44 }
45 }
46}
diff --git a/XmlRpcCS/SimpleHttpRequest.cs b/XmlRpcCS/SimpleHttpRequest.cs
new file mode 100644
index 0000000..e5326c3
--- /dev/null
+++ b/XmlRpcCS/SimpleHttpRequest.cs
@@ -0,0 +1,204 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.IO;
5 using System.Net.Sockets;
6 using System.Collections;
7
8 ///<summary>Very basic HTTP request handler.</summary>
9 ///<remarks>This class is designed to accept a TcpClient and treat it as an HTTP request.
10 /// It will do some basic header parsing and manage the input and output streams associated
11 /// with the request.</remarks>
12 public class SimpleHttpRequest
13 {
14 private String _httpMethod = null;
15 private String _protocol;
16 private String _filePathFile = null;
17 private String _filePathDir = null;
18 private String __filePath;
19 private TcpClient _client;
20 private StreamReader _input;
21 private StreamWriter _output;
22 private Hashtable _headers;
23
24 /// <summary>A constructor which accepts the TcpClient.</summary>
25 /// <remarks>It creates the associated input and output streams, determines the request type,
26 /// and parses the remaining HTTP header.</remarks>
27 /// <param name="client">The <c>TcpClient</c> associated with the HTTP connection.</param>
28 public SimpleHttpRequest(TcpClient client)
29 {
30 _client = client;
31 _output = new StreamWriter(client.GetStream());
32 _input = new StreamReader(client.GetStream());
33 GetRequestMethod();
34 GetRequestHeaders();
35 }
36
37 /// <summary>The output <c>StreamWriter</c> associated with the request.</summary>
38 public StreamWriter Output
39 {
40 get { return _output; }
41 }
42
43 /// <summary>The input <c>StreamReader</c> associated with the request.</summary>
44 public StreamReader Input
45 {
46 get { return _input; }
47 }
48
49 /// <summary>The <c>TcpClient</c> with the request.</summary>
50 public TcpClient Client
51 {
52 get { return _client; }
53 }
54
55 private String _filePath
56 {
57 get { return __filePath; }
58 set
59 {
60 __filePath = value;
61 _filePathDir = null;
62 _filePathFile = null;
63 }
64 }
65
66 /// <summary>The type of HTTP request (i.e. PUT, GET, etc.).</summary>
67 public String HttpMethod
68 {
69 get { return _httpMethod; }
70 }
71
72 /// <summary>The level of the HTTP protocol.</summary>
73 public String Protocol
74 {
75 get { return _protocol; }
76 }
77
78 /// <summary>The "path" which is part of any HTTP request.</summary>
79 public String FilePath
80 {
81 get { return _filePath; }
82 }
83
84 /// <summary>The file portion of the "path" which is part of any HTTP request.</summary>
85 public String FilePathFile
86 {
87 get
88 {
89 if (_filePathFile != null)
90 return _filePathFile;
91
92 int i = FilePath.LastIndexOf("/");
93
94 if (i == -1)
95 return "";
96
97 i++;
98 _filePathFile = FilePath.Substring(i, FilePath.Length - i);
99 return _filePathFile;
100 }
101 }
102
103 /// <summary>The directory portion of the "path" which is part of any HTTP request.</summary>
104 public String FilePathDir
105 {
106 get
107 {
108 if (_filePathDir != null)
109 return _filePathDir;
110
111 int i = FilePath.LastIndexOf("/");
112
113 if (i == -1)
114 return "";
115
116 i++;
117 _filePathDir = FilePath.Substring(0, i);
118 return _filePathDir;
119 }
120 }
121
122 private void GetRequestMethod()
123 {
124 string req = _input.ReadLine();
125 if (req == null)
126 throw new ApplicationException("Void request.");
127
128 if (0 == String.Compare("GET ", req.Substring(0, 4), true))
129 _httpMethod = "GET";
130 else if (0 == String.Compare("POST ", req.Substring(0, 5), true))
131 _httpMethod = "POST";
132 else
133 throw new InvalidOperationException("Unrecognized method in query: " + req);
134
135 req = req.TrimEnd();
136 int idx = req.IndexOf(' ') + 1;
137 if (idx >= req.Length)
138 throw new ApplicationException("What do you want?");
139
140 string page_protocol = req.Substring(idx);
141 int idx2 = page_protocol.IndexOf(' ');
142 if (idx2 == -1)
143 idx2 = page_protocol.Length;
144
145 _filePath = page_protocol.Substring(0, idx2).Trim();
146 _protocol = page_protocol.Substring(idx2).Trim();
147 }
148
149 private void GetRequestHeaders()
150 {
151 String line;
152 int idx;
153
154 _headers = new Hashtable();
155
156 while ((line = _input.ReadLine()) != "")
157 {
158 if (line == null)
159 {
160 break;
161 }
162
163 idx = line.IndexOf(':');
164 if (idx == -1 || idx == line.Length - 1)
165 {
166 Logger.WriteEntry("Malformed header line: " + line, LogLevel.Information);
167 continue;
168 }
169
170 String key = line.Substring(0, idx);
171 String value = line.Substring(idx + 1);
172
173 try
174 {
175 _headers.Add(key, value);
176 }
177 catch (Exception)
178 {
179 Logger.WriteEntry("Duplicate header key in line: " + line, LogLevel.Information);
180 }
181 }
182 }
183
184 /// <summary>
185 /// Format the object contents into a useful string representation.
186 /// </summary>
187 ///<returns><c>String</c> representation of the <c>SimpleHttpRequest</c> as the <i>HttpMethod FilePath Protocol</i>.</returns>
188 override public String ToString()
189 {
190 return HttpMethod + " " + FilePath + " " + Protocol;
191 }
192
193 /// <summary>
194 /// Close the <c>SimpleHttpRequest</c>. This flushes and closes all associated io streams.
195 /// </summary>
196 public void Close()
197 {
198 _output.Flush();
199 _output.Close();
200 _input.Close();
201 _client.Close();
202 }
203 }
204}
diff --git a/XmlRpcCS/XMLRPC.csproj b/XmlRpcCS/XMLRPC.csproj
new file mode 100644
index 0000000..2c7ef94
--- /dev/null
+++ b/XmlRpcCS/XMLRPC.csproj
@@ -0,0 +1,138 @@
1<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <PropertyGroup>
3 <ProjectType>Local</ProjectType>
4 <ProductVersion>8.0.50727</ProductVersion>
5 <SchemaVersion>2.0</SchemaVersion>
6 <ProjectGuid>{8E81D43C-0000-0000-0000-000000000000}</ProjectGuid>
7 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
8 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
9 <ApplicationIcon></ApplicationIcon>
10 <AssemblyKeyContainerName>
11 </AssemblyKeyContainerName>
12 <AssemblyName>XMLRPC</AssemblyName>
13 <DefaultClientScript>JScript</DefaultClientScript>
14 <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
15 <DefaultTargetSchema>IE50</DefaultTargetSchema>
16 <DelaySign>false</DelaySign>
17 <OutputType>Library</OutputType>
18 <AppDesignerFolder></AppDesignerFolder>
19 <RootNamespace>XMLRPC</RootNamespace>
20 <StartupObject></StartupObject>
21 <FileUpgradeFlags>
22 </FileUpgradeFlags>
23 </PropertyGroup>
24 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
25 <AllowUnsafeBlocks>False</AllowUnsafeBlocks>
26 <BaseAddress>285212672</BaseAddress>
27 <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
28 <ConfigurationOverrideFile>
29 </ConfigurationOverrideFile>
30 <DefineConstants>TRACE;DEBUG</DefineConstants>
31 <DocumentationFile></DocumentationFile>
32 <DebugSymbols>True</DebugSymbols>
33 <FileAlignment>4096</FileAlignment>
34 <Optimize>False</Optimize>
35 <OutputPath>..\bin\</OutputPath>
36 <RegisterForComInterop>False</RegisterForComInterop>
37 <RemoveIntegerChecks>False</RemoveIntegerChecks>
38 <TreatWarningsAsErrors>False</TreatWarningsAsErrors>
39 <WarningLevel>4</WarningLevel>
40 <NoWarn></NoWarn>
41 </PropertyGroup>
42 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
43 <AllowUnsafeBlocks>False</AllowUnsafeBlocks>
44 <BaseAddress>285212672</BaseAddress>
45 <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
46 <ConfigurationOverrideFile>
47 </ConfigurationOverrideFile>
48 <DefineConstants>TRACE</DefineConstants>
49 <DocumentationFile></DocumentationFile>
50 <DebugSymbols>False</DebugSymbols>
51 <FileAlignment>4096</FileAlignment>
52 <Optimize>True</Optimize>
53 <OutputPath>..\bin\</OutputPath>
54 <RegisterForComInterop>False</RegisterForComInterop>
55 <RemoveIntegerChecks>False</RemoveIntegerChecks>
56 <TreatWarningsAsErrors>False</TreatWarningsAsErrors>
57 <WarningLevel>4</WarningLevel>
58 <NoWarn></NoWarn>
59 </PropertyGroup>
60 <ItemGroup>
61 <Reference Include="System" >
62 <HintPath>System.dll</HintPath>
63 <Private>False</Private>
64 </Reference>
65 <Reference Include="System.Xml" >
66 <HintPath>System.Xml.dll</HintPath>
67 <Private>False</Private>
68 </Reference>
69 </ItemGroup>
70 <ItemGroup>
71 </ItemGroup>
72 <ItemGroup>
73 <Compile Include="Logger.cs">
74 <SubType>Code</SubType>
75 </Compile>
76 <Compile Include="SimpleHttpRequest.cs">
77 <SubType>Code</SubType>
78 </Compile>
79 <Compile Include="XmlRpcBoxcarRequest.cs">
80 <SubType>Code</SubType>
81 </Compile>
82 <Compile Include="XmlRpcClientProxy.cs">
83 <SubType>Code</SubType>
84 </Compile>
85 <Compile Include="XmlRpcDeserializer.cs">
86 <SubType>Code</SubType>
87 </Compile>
88 <Compile Include="XmlRpcErrorCodes.cs">
89 <SubType>Code</SubType>
90 </Compile>
91 <Compile Include="XmlRpcException.cs">
92 <SubType>Code</SubType>
93 </Compile>
94 <Compile Include="XmlRpcExposedAttribute.cs">
95 <SubType>Code</SubType>
96 </Compile>
97 <Compile Include="XmlRpcRequest.cs">
98 <SubType>Code</SubType>
99 </Compile>
100 <Compile Include="XmlRpcRequestDeserializer.cs">
101 <SubType>Code</SubType>
102 </Compile>
103 <Compile Include="XmlRpcRequestSerializer.cs">
104 <SubType>Code</SubType>
105 </Compile>
106 <Compile Include="XmlRpcResponder.cs">
107 <SubType>Code</SubType>
108 </Compile>
109 <Compile Include="XmlRpcResponse.cs">
110 <SubType>Code</SubType>
111 </Compile>
112 <Compile Include="XmlRpcResponseDeserializer.cs">
113 <SubType>Code</SubType>
114 </Compile>
115 <Compile Include="XmlRpcResponseSerializer.cs">
116 <SubType>Code</SubType>
117 </Compile>
118 <Compile Include="XmlRpcSerializer.cs">
119 <SubType>Code</SubType>
120 </Compile>
121 <Compile Include="XmlRpcServer.cs">
122 <SubType>Code</SubType>
123 </Compile>
124 <Compile Include="XmlRpcSystemObject.cs">
125 <SubType>Code</SubType>
126 </Compile>
127 <Compile Include="XmlRpcXmlTokens.cs">
128 <SubType>Code</SubType>
129 </Compile>
130 </ItemGroup>
131 <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
132 <PropertyGroup>
133 <PreBuildEvent>
134 </PreBuildEvent>
135 <PostBuildEvent>
136 </PostBuildEvent>
137 </PropertyGroup>
138</Project>
diff --git a/XmlRpcCS/XMLRPC.dll.build b/XmlRpcCS/XMLRPC.dll.build
new file mode 100644
index 0000000..d734d19
--- /dev/null
+++ b/XmlRpcCS/XMLRPC.dll.build
@@ -0,0 +1,58 @@
1<?xml version="1.0" ?>
2<project name="XMLRPC" default="build">
3 <target name="build">
4 <echo message="Build Directory is ${project::get-base-directory()}/${build.dir}" />
5 <mkdir dir="${project::get-base-directory()}/${build.dir}" />
6 <copy todir="${project::get-base-directory()}/${build.dir}">
7 <fileset basedir="${project::get-base-directory()}">
8 </fileset>
9 </copy>
10 <csc target="library" debug="${build.debug}" unsafe="False" define="TRACE;DEBUG" output="${project::get-base-directory()}/${build.dir}/${project::get-name()}.dll">
11 <resources prefix="XMLRPC" dynamicprefix="true" >
12 </resources>
13 <sources failonempty="true">
14 <include name="Logger.cs" />
15 <include name="SimpleHttpRequest.cs" />
16 <include name="XmlRpcBoxcarRequest.cs" />
17 <include name="XmlRpcClientProxy.cs" />
18 <include name="XmlRpcDeserializer.cs" />
19 <include name="XmlRpcErrorCodes.cs" />
20 <include name="XmlRpcException.cs" />
21 <include name="XmlRpcExposedAttribute.cs" />
22 <include name="XmlRpcRequest.cs" />
23 <include name="XmlRpcRequestDeserializer.cs" />
24 <include name="XmlRpcRequestSerializer.cs" />
25 <include name="XmlRpcResponder.cs" />
26 <include name="XmlRpcResponse.cs" />
27 <include name="XmlRpcResponseDeserializer.cs" />
28 <include name="XmlRpcResponseSerializer.cs" />
29 <include name="XmlRpcSerializer.cs" />
30 <include name="XmlRpcServer.cs" />
31 <include name="XmlRpcSystemObject.cs" />
32 <include name="XmlRpcXmlTokens.cs" />
33 </sources>
34 <references basedir="${project::get-base-directory()}">
35 <lib>
36 <include name="${project::get-base-directory()}" />
37 <include name="${project::get-base-directory()}/${build.dir}" />
38 </lib>
39 <include name="System.dll" />
40 <include name="System.Xml.dll" />
41 </references>
42 </csc>
43 <echo message="Copying from [${project::get-base-directory()}/${build.dir}/] to [${project::get-base-directory()}/../bin/" />
44 <mkdir dir="${project::get-base-directory()}/../bin/"/>
45 <copy todir="${project::get-base-directory()}/../bin/">
46 <fileset basedir="${project::get-base-directory()}/${build.dir}/" >
47 <include name="*.dll"/>
48 <include name="*.exe"/>
49 </fileset>
50 </copy>
51 </target>
52 <target name="clean">
53 <delete dir="${bin.dir}" failonerror="false" />
54 <delete dir="${obj.dir}" failonerror="false" />
55 </target>
56 <target name="doc" description="Creates documentation.">
57 </target>
58</project>
diff --git a/XmlRpcCS/XmlRpcBoxcarRequest.cs b/XmlRpcCS/XmlRpcBoxcarRequest.cs
new file mode 100644
index 0000000..f87f7a5
--- /dev/null
+++ b/XmlRpcCS/XmlRpcBoxcarRequest.cs
@@ -0,0 +1,51 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Xml;
7 using System.Net;
8 using System.Text;
9 using System.Reflection;
10
11 /// <summary>Class that collects individual <c>XmlRpcRequest</c> objects and submits them as a <i>boxcarred</i> request.</summary>
12 /// <remarks>A boxcared request is when a number of request are collected before being sent via XML-RPC, and then are sent via
13 /// a single HTTP connection. This results in a speed up from reduced connection time. The results are then retuned collectively
14 /// as well.
15 ///</remarks>
16 /// <seealso cref="XmlRpcRequest"/>
17 public class XmlRpcBoxcarRequest : XmlRpcRequest
18 {
19 /// <summary>ArrayList to collect the requests to boxcar.</summary>
20 public IList Requests = new ArrayList();
21
22 /// <summary>Basic constructor.</summary>
23 public XmlRpcBoxcarRequest()
24 {
25 }
26
27 /// <summary>Returns the <c>String</c> "system.multiCall" which is the server method that handles boxcars.</summary>
28 public override String MethodName
29 {
30 get { return "system.multiCall"; }
31 }
32
33 /// <summary>The <c>ArrayList</c> of boxcarred <paramref>Requests</paramref> as properly formed parameters.</summary>
34 public override IList Params
35 {
36 get {
37 _params.Clear();
38 ArrayList reqArray = new ArrayList();
39 foreach (XmlRpcRequest request in Requests)
40 {
41 Hashtable requestEntry = new Hashtable();
42 requestEntry.Add(XmlRpcXmlTokens.METHOD_NAME, request.MethodName);
43 requestEntry.Add(XmlRpcXmlTokens.PARAMS, request.Params);
44 reqArray.Add(requestEntry);
45 }
46 _params.Add(reqArray);
47 return _params;
48 }
49 }
50 }
51}
diff --git a/XmlRpcCS/XmlRpcClientProxy.cs b/XmlRpcCS/XmlRpcClientProxy.cs
new file mode 100644
index 0000000..f52273a
--- /dev/null
+++ b/XmlRpcCS/XmlRpcClientProxy.cs
@@ -0,0 +1,61 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Runtime.Remoting.Proxies;
5 using System.Runtime.Remoting.Messaging;
6
7 /// <summary>This class provides support for creating local proxies of XML-RPC remote objects</summary>
8 /// <remarks>
9 /// To create a local proxy you need to create a local C# interface and then, via <i>createProxy</i>
10 /// associate that interface with a remote object at a given URL.
11 /// </remarks>
12public class XmlRpcClientProxy : RealProxy
13{
14 private String _remoteObjectName;
15 private String _url;
16 private XmlRpcRequest _client = new XmlRpcRequest();
17
18 /// <summary>Factory method to create proxies.</summary>
19 /// <remarks>
20 /// To create a local proxy you need to create a local C# interface with methods that mirror those of the server object.
21 /// Next, pass that interface into <c>createProxy</c> along with the object name and URL of the remote object and
22 /// cast the resulting object to the specifice interface.
23 /// </remarks>
24 /// <param name="remoteObjectName"><c>String</c> The name of the remote object.</param>
25 /// <param name="url"><c>String</c> The URL of the remote object.</param>
26 /// <param name="anInterface"><c>Type</c> The typeof() of a C# interface.</param>
27 /// <returns><c>Object</c> A proxy for your specified interface. Cast to appropriate type.</returns>
28 public static Object createProxy(String remoteObjectName, String url, Type anInterface)
29 {
30 return new XmlRpcClientProxy(remoteObjectName, url, anInterface).GetTransparentProxy();
31 }
32
33 private XmlRpcClientProxy(String remoteObjectName, String url, Type t) : base(t)
34 {
35 _remoteObjectName = remoteObjectName;
36 _url = url;
37 }
38
39 /// <summary>The local method dispatcher - do not invoke.</summary>
40 override public IMessage Invoke(IMessage msg)
41 {
42 IMethodCallMessage methodMessage = (IMethodCallMessage)msg;
43
44 _client.MethodName = _remoteObjectName + "." + methodMessage.MethodName;
45 _client.Params.Clear();
46 foreach (Object o in methodMessage.Args)
47 _client.Params.Add(o);
48
49 try
50 {
51 Object ret = _client.Invoke(_url);
52 return new ReturnMessage(ret,null,0,
53 methodMessage.LogicalCallContext, methodMessage);
54 }
55 catch (Exception e)
56 {
57 return new ReturnMessage(e, methodMessage);
58 }
59 }
60}
61}
diff --git a/XmlRpcCS/XmlRpcDeserializer.cs b/XmlRpcCS/XmlRpcDeserializer.cs
new file mode 100644
index 0000000..bd736c0
--- /dev/null
+++ b/XmlRpcCS/XmlRpcDeserializer.cs
@@ -0,0 +1,195 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Xml;
7 using System.Globalization;
8
9 /// <summary>Parser context, we maintain contexts in a stack to avoiding recursion. </summary>
10 struct Context
11 {
12 public String Name;
13 public Object Container;
14 }
15
16 /// <summary>Basic XML-RPC data deserializer.</summary>
17 /// <remarks>Uses <c>XmlTextReader</c> to parse the XML data. This level of the class
18 /// only handles the tokens common to both Requests and Responses. This class is not useful in and of itself
19 /// but is designed to be subclassed.</remarks>
20 public class XmlRpcDeserializer : XmlRpcXmlTokens
21 {
22 private static DateTimeFormatInfo _dateFormat = new DateTimeFormatInfo();
23
24 private Object _container;
25 private Stack _containerStack;
26
27 /// <summary>Protected reference to last text.</summary>
28 protected String _text;
29 /// <summary>Protected reference to last deserialized value.</summary>
30 protected Object _value;
31 /// <summary>Protected reference to last name field.</summary>
32 protected String _name;
33
34
35 /// <summary>Basic constructor.</summary>
36 public XmlRpcDeserializer()
37 {
38 Reset();
39 _dateFormat.FullDateTimePattern = ISO_DATETIME;
40 }
41
42 /// <summary>Static method that parses XML data into a response using the Singleton.</summary>
43 /// <param name="xmlData"><c>StreamReader</c> containing an XML-RPC response.</param>
44 /// <returns><c>Object</c> object resulting from the deserialization.</returns>
45 virtual public Object Deserialize(TextReader xmlData)
46 {
47 return null;
48 }
49
50 /// <summary>Protected method to parse a node in an XML-RPC XML stream.</summary>
51 /// <remarks>Method deals with elements common to all XML-RPC data, subclasses of
52 /// this object deal with request/response spefic elements.</remarks>
53 /// <param name="reader"><c>XmlTextReader</c> of the in progress parsing data stream.</param>
54 protected void DeserializeNode(XmlTextReader reader)
55 {
56 switch (reader.NodeType)
57 {
58 case XmlNodeType.Element:
59 if (Logger.Delegate != null)
60 Logger.WriteEntry("START " + reader.Name, LogLevel.Information);
61 switch (reader.Name)
62 {
63 case VALUE:
64 _value = null;
65 _text = null;
66 break;
67 case STRUCT:
68 PushContext();
69 _container = new Hashtable();
70 break;
71 case ARRAY:
72 PushContext();
73 _container = new ArrayList();
74 break;
75 }
76 break;
77 case XmlNodeType.EndElement:
78 if (Logger.Delegate != null)
79 Logger.WriteEntry("END " + reader.Name, LogLevel.Information);
80 switch (reader.Name)
81 {
82 case BASE64:
83 _value = Convert.FromBase64String(_text);
84 break;
85 case BOOLEAN:
86 int val = Int16.Parse(_text);
87 if (val == 0)
88 _value = false;
89 else if (val == 1)
90 _value = true;
91 break;
92 case STRING:
93 _value = _text;
94 break;
95 case DOUBLE:
96 _value = Double.Parse(_text);
97 break;
98 case INT:
99 case ALT_INT:
100 _value = Int32.Parse(_text);
101 break;
102 case DATETIME:
103#if __MONO__
104 _value = DateParse(_text);
105#else
106 _value = DateTime.ParseExact(_text, "F", _dateFormat);
107#endif
108 break;
109 case NAME:
110 _name = _text;
111 break;
112 case VALUE:
113 if (_value == null)
114 _value = _text; // some kits don't use <string> tag, they just do <value>
115
116 if ((_container != null) && (_container is IList)) // in an array? If so add value to it.
117 ((IList)_container).Add(_value);
118 break;
119 case MEMBER:
120 if ((_container != null) && (_container is IDictionary)) // in an struct? If so add value to it.
121 ((IDictionary)_container).Add(_name, _value);
122 break;
123 case ARRAY:
124 case STRUCT:
125 _value = _container;
126 PopContext();
127 break;
128 }
129 break;
130 case XmlNodeType.Text:
131 if (Logger.Delegate != null)
132 Logger.WriteEntry("Text " + reader.Value, LogLevel.Information);
133 _text = reader.Value;
134 break;
135 default:
136 break;
137 }
138 }
139
140 /// <summary>Static method that parses XML in a <c>String</c> into a
141 /// request using the Singleton.</summary>
142 /// <param name="xmlData"><c>String</c> containing an XML-RPC request.</param>
143 /// <returns><c>XmlRpcRequest</c> object resulting from the parse.</returns>
144 public Object Deserialize(String xmlData)
145 {
146 StringReader sr = new StringReader(xmlData);
147 return Deserialize(sr);
148 }
149
150 /// <summary>Pop a Context of the stack, an Array or Struct has closed.</summary>
151 private void PopContext()
152 {
153 Context c = (Context)_containerStack.Pop();
154 _container = c.Container;
155 _name = c.Name;
156 }
157
158 /// <summary>Push a Context on the stack, an Array or Struct has opened.</summary>
159 private void PushContext()
160 {
161 Context context;
162
163 context.Container = _container;
164 context.Name = _name;
165
166 _containerStack.Push(context);
167 }
168
169 /// <summary>Reset the internal state of the deserializer.</summary>
170 protected void Reset()
171 {
172 _text = null;
173 _value = null;
174 _name = null;
175 _container = null;
176 _containerStack = new Stack();
177 }
178
179#if __MONO__
180 private DateTime DateParse(String str)
181 {
182 int year = Int32.Parse(str.Substring(0,4));
183 int month = Int32.Parse(str.Substring(4,2));
184 int day = Int32.Parse(str.Substring(6,2));
185 int hour = Int32.Parse(str.Substring(9,2));
186 int min = Int32.Parse(str.Substring(12,2));
187 int sec = Int32.Parse(str.Substring(15,2));
188 return new DateTime(year,month,day,hour,min,sec);
189 }
190#endif
191
192 }
193}
194
195
diff --git a/XmlRpcCS/XmlRpcErrorCodes.cs b/XmlRpcCS/XmlRpcErrorCodes.cs
new file mode 100644
index 0000000..6dec57d
--- /dev/null
+++ b/XmlRpcCS/XmlRpcErrorCodes.cs
@@ -0,0 +1,51 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4
5 /// <summary>Standard XML-RPC error codes.</summary>
6 public class XmlRpcErrorCodes
7 {
8 /// <summary></summary>
9 public const int PARSE_ERROR_MALFORMED = -32700;
10 /// <summary></summary>
11 public const String PARSE_ERROR_MALFORMED_MSG = "Parse Error, not well formed";
12
13 /// <summary></summary>
14 public const int PARSE_ERROR_ENCODING = -32701;
15 /// <summary></summary>
16 public const String PARSE_ERROR_ENCODING_MSG = "Parse Error, unsupported encoding";
17
18 //
19 // -32702 ---> parse error. invalid character for encoding
20 // -32600 ---> server error. invalid xml-rpc. not conforming to spec.
21 //
22
23 /// <summary></summary>
24 public const int SERVER_ERROR_METHOD = -32601;
25 /// <summary></summary>
26 public const String SERVER_ERROR_METHOD_MSG = "Server Error, requested method not found";
27
28 /// <summary></summary>
29 public const int SERVER_ERROR_PARAMS = -32602;
30 /// <summary></summary>
31 public const String SERVER_ERROR_PARAMS_MSG = "Server Error, invalid method parameters";
32
33 //
34 // -32603 ---> server error. internal xml-rpc error
35 //
36
37 /// <summary></summary>
38 public const int APPLICATION_ERROR = -32500;
39 /// <summary></summary>
40 public const String APPLICATION_ERROR_MSG = "Application Error";
41
42 //
43 // -32400 ---> system error
44 //
45
46 /// <summary></summary>
47 public const int TRANSPORT_ERROR = -32300;
48 /// <summary></summary>
49 public const String TRANSPORT_ERROR_MSG = "Transport Layer Error";
50 }
51}
diff --git a/XmlRpcCS/XmlRpcException.cs b/XmlRpcCS/XmlRpcException.cs
new file mode 100644
index 0000000..fd1f4ae
--- /dev/null
+++ b/XmlRpcCS/XmlRpcException.cs
@@ -0,0 +1,39 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4
5 /// <summary>An XML-RPC Exception.</summary>
6 /// <remarks>Maps a C# exception to an XML-RPC fault. Normal exceptions
7 /// include a message so this adds the code needed by XML-RPC.</remarks>
8 public class XmlRpcException : Exception
9 {
10 private int _code;
11
12 /// <summary>Instantiate an <c>XmlRpcException</c> with a code and message.</summary>
13 /// <param name="code"><c>Int</c> faultCode associated with this exception.</param>
14 /// <param name="message"><c>String</c> faultMessage associated with this exception.</param>
15 public XmlRpcException(int code, String message)
16 : base(message)
17 {
18 _code = code;
19 }
20
21 /// <summary>The value of the faults message, i.e. the faultString.</summary>
22 public String FaultString
23 {
24 get { return Message; }
25 }
26
27 /// <summary>The value of the faults code, i.e. the faultCode.</summary>
28 public int FaultCode
29 {
30 get { return _code; }
31 }
32
33 /// <summary>Format the message to include the code.</summary>
34 override public String ToString()
35 {
36 return "Code: " + FaultCode + " Message: " + base.ToString();
37 }
38 }
39}
diff --git a/XmlRpcCS/XmlRpcExposedAttribute.cs b/XmlRpcCS/XmlRpcExposedAttribute.cs
new file mode 100644
index 0000000..67b27ae
--- /dev/null
+++ b/XmlRpcCS/XmlRpcExposedAttribute.cs
@@ -0,0 +1,60 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Reflection;
5
6 /// <summary>
7 /// Simple tagging attribute to indicate participation is XML-RPC exposure.
8 /// </summary>
9 /// <remarks>
10 /// If present at the class level it indicates that this class does explicitly
11 /// expose methods. If present at the method level it denotes that the method
12 /// is exposed.
13 /// </remarks>
14 [AttributeUsage(
15 AttributeTargets.Class | AttributeTargets.Method,
16 AllowMultiple = false,
17 Inherited = true
18 )]
19 public class XmlRpcExposedAttribute : Attribute
20 {
21 /// <summary>Check if <paramref>obj</paramref> is an object utilizing the XML-RPC exposed Attribute.</summary>
22 /// <param name="obj"><c>Object</c> of a class or method to check for attribute.</param>
23 /// <returns><c>Boolean</c> true if attribute present.</returns>
24 public static Boolean ExposedObject(Object obj)
25 {
26 return IsExposed(obj.GetType());
27 }
28
29 /// <summary>Check if <paramref>obj</paramref>.<paramref>methodName</paramref> is an XML-RPC exposed method.</summary>
30 /// <remarks>A method is considered to be exposed if it exists and, either, the object does not use the XmlRpcExposed attribute,
31 /// or the object does use the XmlRpcExposed attribute and the method has the XmlRpcExposed attribute as well.</remarks>
32 /// <returns><c>Boolean</c> true if the method is exposed.</returns>
33 public static Boolean ExposedMethod(Object obj, String methodName)
34 {
35 Type type = obj.GetType();
36 MethodInfo method = type.GetMethod(methodName);
37
38 if (method == null)
39 throw new MissingMethodException("Method " + methodName + " not found.");
40
41 if (!IsExposed(type))
42 return true;
43
44 return IsExposed(method);
45 }
46
47 /// <summary>Check if <paramref>mi</paramref> is XML-RPC exposed.</summary>
48 /// <param name="mi"><c>MemberInfo</c> of a class or method to check for attribute.</param>
49 /// <returns><c>Boolean</c> true if attribute present.</returns>
50 public static Boolean IsExposed(MemberInfo mi)
51 {
52 foreach (Attribute attr in mi.GetCustomAttributes(true))
53 {
54 if (attr is XmlRpcExposedAttribute)
55 return true;
56 }
57 return false;
58 }
59 }
60}
diff --git a/XmlRpcCS/XmlRpcRequest.cs b/XmlRpcCS/XmlRpcRequest.cs
new file mode 100644
index 0000000..18d2182
--- /dev/null
+++ b/XmlRpcCS/XmlRpcRequest.cs
@@ -0,0 +1,150 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Xml;
7 using System.Net;
8 using System.Text;
9 using System.Reflection;
10 using System.Net.Security;
11 using System.Security.Cryptography.X509Certificates;
12
13 internal class AcceptAllCertificatePolicy : ICertificatePolicy
14 {
15 public AcceptAllCertificatePolicy()
16 {
17 }
18
19 public bool CheckValidationResult(ServicePoint sPoint,
20 System.Security.Cryptography.X509Certificates.X509Certificate cert,
21 WebRequest wRequest, int certProb)
22 {
23 // Always accept
24 return true;
25 }
26 }
27
28 /// <summary>Class supporting the request side of an XML-RPC transaction.</summary>
29 public class XmlRpcRequest
30 {
31 private String _methodName = null;
32 private Encoding _encoding = new ASCIIEncoding();
33 private XmlRpcRequestSerializer _serializer = new XmlRpcRequestSerializer();
34 private XmlRpcResponseDeserializer _deserializer = new XmlRpcResponseDeserializer();
35
36 /// <summary><c>ArrayList</c> containing the parameters.</summary>
37 protected IList _params = null;
38
39 /// <summary>Instantiate an <c>XmlRpcRequest</c></summary>
40 public XmlRpcRequest()
41 {
42 _params = new ArrayList();
43 }
44
45 /// <summary>Instantiate an <c>XmlRpcRequest</c> for a specified method and parameters.</summary>
46 /// <param name="methodName"><c>String</c> designating the <i>object.method</i> on the server the request
47 /// should be directed to.</param>
48 /// <param name="parameters"><c>ArrayList</c> of XML-RPC type parameters to invoke the request with.</param>
49 public XmlRpcRequest(String methodName, IList parameters)
50 {
51 MethodName = methodName;
52 _params = parameters;
53 }
54
55 /// <summary><c>ArrayList</c> conntaining the parameters for the request.</summary>
56 public virtual IList Params
57 {
58 get { return _params; }
59 }
60
61 /// <summary><c>String</c> conntaining the method name, both object and method, that the request will be sent to.</summary>
62 public virtual String MethodName
63 {
64 get { return _methodName; }
65 set { _methodName = value; }
66 }
67
68 /// <summary><c>String</c> object name portion of the method name.</summary>
69 public String MethodNameObject
70 {
71 get
72 {
73 int index = MethodName.IndexOf(".");
74
75 if (index == -1)
76 return MethodName;
77
78 return MethodName.Substring(0, index);
79 }
80 }
81
82 /// <summary><c>String</c> method name portion of the object.method name.</summary>
83 public String MethodNameMethod
84 {
85 get
86 {
87 int index = MethodName.IndexOf(".");
88
89 if (index == -1)
90 return MethodName;
91
92 return MethodName.Substring(index + 1, MethodName.Length - index - 1);
93 }
94 }
95
96 /// <summary>Invoke this request on the server.</summary>
97 /// <param name="url"><c>String</c> The url of the XML-RPC server.</param>
98 /// <returns><c>Object</c> The value returned from the method invocation on the server.</returns>
99 /// <exception cref="XmlRpcException">If an exception generated on the server side.</exception>
100 public Object Invoke(String url)
101 {
102 XmlRpcResponse res = Send(url, 10000);
103
104 if (res.IsFault)
105 throw new XmlRpcException(res.FaultCode, res.FaultString);
106
107 return res.Value;
108 }
109
110 /// <summary>Send the request to the server.</summary>
111 /// <param name="url"><c>String</c> The url of the XML-RPC server.</param>
112 /// <param name="timeout">Milliseconds before the connection times out.</param>
113 /// <returns><c>XmlRpcResponse</c> The response generated.</returns>
114 public XmlRpcResponse Send(String url, int timeout)
115 {
116 // Override SSL authentication mechanisms
117 ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy();
118
119 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
120 if (request == null)
121 throw new XmlRpcException(XmlRpcErrorCodes.TRANSPORT_ERROR,
122 XmlRpcErrorCodes.TRANSPORT_ERROR_MSG + ": Could not create request with " + url);
123 request.Method = "POST";
124 request.ContentType = "text/xml";
125 request.AllowWriteStreamBuffering = true;
126 request.Timeout = timeout;
127
128 Stream stream = request.GetRequestStream();
129 XmlTextWriter xml = new XmlTextWriter(stream, _encoding);
130 _serializer.Serialize(xml, this);
131 xml.Flush();
132 xml.Close();
133
134 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
135 StreamReader input = new StreamReader(response.GetResponseStream());
136
137 XmlRpcResponse resp = (XmlRpcResponse)_deserializer.Deserialize(input);
138 input.Close();
139 response.Close();
140 return resp;
141 }
142
143 /// <summary>Produce <c>String</c> representation of the object.</summary>
144 /// <returns><c>String</c> representation of the object.</returns>
145 override public String ToString()
146 {
147 return _serializer.Serialize(this);
148 }
149 }
150}
diff --git a/XmlRpcCS/XmlRpcRequestDeserializer.cs b/XmlRpcCS/XmlRpcRequestDeserializer.cs
new file mode 100644
index 0000000..0770b7e
--- /dev/null
+++ b/XmlRpcCS/XmlRpcRequestDeserializer.cs
@@ -0,0 +1,64 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.Diagnostics;
6 using System.IO;
7 using System.Xml;
8
9 /// <summary>Class to deserialize XML data representing a request.</summary>
10 public class XmlRpcRequestDeserializer : XmlRpcDeserializer
11 {
12 static private XmlRpcRequestDeserializer _singleton;
13 /// <summary>A static singleton instance of this deserializer.</summary>
14 [Obsolete("This object is now thread safe, just use an instance.", false)]
15 static public XmlRpcRequestDeserializer Singleton
16 {
17 get
18 {
19 if (_singleton == null)
20 _singleton = new XmlRpcRequestDeserializer();
21
22 return _singleton;
23 }
24 }
25
26 /// <summary>Static method that parses XML data into a request using the Singleton.</summary>
27 /// <param name="xmlData"><c>StreamReader</c> containing an XML-RPC request.</param>
28 /// <returns><c>XmlRpcRequest</c> object resulting from the parse.</returns>
29 override public Object Deserialize(TextReader xmlData)
30 {
31 XmlTextReader reader = new XmlTextReader(xmlData);
32 XmlRpcRequest request = new XmlRpcRequest();
33 bool done = false;
34
35 lock (this)
36 {
37 Reset();
38 while (!done && reader.Read())
39 {
40 DeserializeNode(reader); // Parent parse...
41 switch (reader.NodeType)
42 {
43 case XmlNodeType.EndElement:
44 switch (reader.Name)
45 {
46 case METHOD_NAME:
47 request.MethodName = _text;
48 break;
49 case METHOD_CALL:
50 done = true;
51 break;
52 case PARAM:
53 request.Params.Add(_value);
54 _text = null;
55 break;
56 }
57 break;
58 }
59 }
60 }
61 return request;
62 }
63 }
64}
diff --git a/XmlRpcCS/XmlRpcRequestSerializer.cs b/XmlRpcCS/XmlRpcRequestSerializer.cs
new file mode 100644
index 0000000..8099bdb
--- /dev/null
+++ b/XmlRpcCS/XmlRpcRequestSerializer.cs
@@ -0,0 +1,51 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.Xml;
6 using System.IO;
7
8 /// <summary>Class responsible for serializing an XML-RPC request.</summary>
9 /// <remarks>This class handles the request envelope, depending on <c>XmlRpcSerializer</c>
10 /// to serialize the payload.</remarks>
11 /// <seealso cref="XmlRpcSerializer"/>
12 public class XmlRpcRequestSerializer : XmlRpcSerializer
13 {
14 static private XmlRpcRequestSerializer _singleton;
15 /// <summary>A static singleton instance of this deserializer.</summary>
16 static public XmlRpcRequestSerializer Singleton
17 {
18 get
19 {
20 if (_singleton == null)
21 _singleton = new XmlRpcRequestSerializer();
22
23 return _singleton;
24 }
25 }
26
27 /// <summary>Serialize the <c>XmlRpcRequest</c> to the output stream.</summary>
28 /// <param name="output">An <c>XmlTextWriter</c> stream to write data to.</param>
29 /// <param name="obj">An <c>XmlRpcRequest</c> to serialize.</param>
30 /// <seealso cref="XmlRpcRequest"/>
31 override public void Serialize(XmlTextWriter output, Object obj)
32 {
33 XmlRpcRequest request = (XmlRpcRequest)obj;
34 output.WriteStartDocument();
35 output.WriteStartElement(METHOD_CALL);
36 output.WriteElementString(METHOD_NAME, request.MethodName);
37 output.WriteStartElement(PARAMS);
38 foreach (Object param in request.Params)
39 {
40 output.WriteStartElement(PARAM);
41 output.WriteStartElement(VALUE);
42 SerializeObject(output, param);
43 output.WriteEndElement();
44 output.WriteEndElement();
45 }
46
47 output.WriteEndElement();
48 output.WriteEndElement();
49 }
50 }
51}
diff --git a/XmlRpcCS/XmlRpcResponder.cs b/XmlRpcCS/XmlRpcResponder.cs
new file mode 100644
index 0000000..0412568
--- /dev/null
+++ b/XmlRpcCS/XmlRpcResponder.cs
@@ -0,0 +1,98 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Xml;
5 using System.Net.Sockets;
6
7 /// <summary>The class is a container of the context of an XML-RPC dialog on the server side.</summary>
8 /// <remarks>Instances of this class maintain the context for an individual XML-RPC server
9 /// side dialog. Namely they manage an inbound deserializer and an outbound serializer. </remarks>
10 public class XmlRpcResponder
11 {
12 private XmlRpcRequestDeserializer _deserializer = new XmlRpcRequestDeserializer();
13 private XmlRpcResponseSerializer _serializer = new XmlRpcResponseSerializer();
14 private XmlRpcServer _server;
15 private TcpClient _client;
16 private SimpleHttpRequest _httpReq;
17
18 /// <summary>The SimpleHttpRequest based on the TcpClient.</summary>
19 public SimpleHttpRequest HttpReq
20 {
21 get { return _httpReq; }
22 }
23
24 /// <summary>Basic constructor.</summary>
25 /// <param name="server">XmlRpcServer that this XmlRpcResponder services.</param>
26 /// <param name="client">TcpClient with the connection.</param>
27 public XmlRpcResponder(XmlRpcServer server, TcpClient client)
28 {
29 _server = server;
30 _client = client;
31 _httpReq = new SimpleHttpRequest(_client);
32 }
33
34 /// <summary>Call close to insure proper shutdown.</summary>
35 ~XmlRpcResponder()
36 {
37 Close();
38 }
39
40 ///<summary>Respond using this responders HttpReq.</summary>
41 public void Respond()
42 {
43 Respond(HttpReq);
44 }
45
46 /// <summary>Handle an HTTP request containing an XML-RPC request.</summary>
47 /// <remarks>This method deserializes the XML-RPC request, invokes the
48 /// described method, serializes the response (or fault) and sends the XML-RPC response
49 /// back as a valid HTTP page.
50 /// </remarks>
51 /// <param name="httpReq"><c>SimpleHttpRequest</c> containing the request.</param>
52 public void Respond(SimpleHttpRequest httpReq)
53 {
54 XmlRpcRequest xmlRpcReq = (XmlRpcRequest)_deserializer.Deserialize(httpReq.Input);
55 XmlRpcResponse xmlRpcResp = new XmlRpcResponse();
56
57 try
58 {
59 xmlRpcResp.Value = _server.Invoke(xmlRpcReq);
60 }
61 catch (XmlRpcException e)
62 {
63 xmlRpcResp.SetFault(e.FaultCode, e.FaultString);
64 }
65 catch (Exception e2)
66 {
67 xmlRpcResp.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR,
68 XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message);
69 }
70
71 if (Logger.Delegate != null)
72 Logger.WriteEntry(xmlRpcResp.ToString(), LogLevel.Information);
73
74 XmlRpcServer.HttpHeader(httpReq.Protocol, "text/xml", 0, " 200 OK", httpReq.Output);
75 httpReq.Output.Flush();
76 XmlTextWriter xml = new XmlTextWriter(httpReq.Output);
77 _serializer.Serialize(xml, xmlRpcResp);
78 xml.Flush();
79 httpReq.Output.Flush();
80 }
81
82 ///<summary>Close all contained resources, both the HttpReq and client.</summary>
83 public void Close()
84 {
85 if (_httpReq != null)
86 {
87 _httpReq.Close();
88 _httpReq = null;
89 }
90
91 if (_client != null)
92 {
93 _client.Close();
94 _client = null;
95 }
96 }
97 }
98}
diff --git a/XmlRpcCS/XmlRpcResponse.cs b/XmlRpcCS/XmlRpcResponse.cs
new file mode 100644
index 0000000..8ff8354
--- /dev/null
+++ b/XmlRpcCS/XmlRpcResponse.cs
@@ -0,0 +1,85 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Xml;
7
8 /// <summary>Class designed to represent an XML-RPC response.</summary>
9 public class XmlRpcResponse
10 {
11 private Object _value;
12 /// <summary><c>bool</c> indicating if this response represents a fault.</summary>
13 public bool IsFault;
14
15 /// <summary>Basic constructor</summary>
16 public XmlRpcResponse()
17 {
18 Value = null;
19 IsFault = false;
20 }
21
22 /// <summary>Constructor for a fault.</summary>
23 /// <param name="code"><c>int</c> the numeric faultCode value.</param>
24 /// <param name="message"><c>String</c> the faultString value.</param>
25 public XmlRpcResponse(int code, String message)
26 : this()
27 {
28 SetFault(code, message);
29 }
30
31 /// <summary>The data value of the response, may be fault data.</summary>
32 public Object Value
33 {
34 get { return _value; }
35 set
36 {
37 IsFault = false;
38 _value = value;
39 }
40 }
41
42 /// <summary>The faultCode if this is a fault.</summary>
43 public int FaultCode
44 {
45 get
46 {
47 if (!IsFault)
48 return 0;
49 else
50 return (int)((Hashtable)_value)[XmlRpcXmlTokens.FAULT_CODE];
51 }
52 }
53
54 /// <summary>The faultString if this is a fault.</summary>
55 public String FaultString
56 {
57 get
58 {
59 if (!IsFault)
60 return "";
61 else
62 return (String)((Hashtable)_value)[XmlRpcXmlTokens.FAULT_STRING];
63 }
64 }
65
66 /// <summary>Set this response to be a fault.</summary>
67 /// <param name="code"><c>int</c> the numeric faultCode value.</param>
68 /// <param name="message"><c>String</c> the faultString value.</param>
69 public void SetFault(int code, String message)
70 {
71 Hashtable fault = new Hashtable();
72 fault.Add("faultCode", code);
73 fault.Add("faultString", message);
74 Value = fault;
75 IsFault = true;
76 }
77
78 /// <summary>Form a useful string representation of the object, in this case the XML response.</summary>
79 /// <returns><c>String</c> The XML serialized XML-RPC response.</returns>
80 override public String ToString()
81 {
82 return XmlRpcResponseSerializer.Singleton.Serialize(this);
83 }
84 }
85}
diff --git a/XmlRpcCS/XmlRpcResponseDeserializer.cs b/XmlRpcCS/XmlRpcResponseDeserializer.cs
new file mode 100644
index 0000000..032d8a3
--- /dev/null
+++ b/XmlRpcCS/XmlRpcResponseDeserializer.cs
@@ -0,0 +1,65 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Xml;
7
8 /// <summary>Class to deserialize XML data representing a response.</summary>
9 public class XmlRpcResponseDeserializer : XmlRpcDeserializer
10 {
11 static private XmlRpcResponseDeserializer _singleton;
12 /// <summary>A static singleton instance of this deserializer.</summary>
13 [Obsolete("This object is now thread safe, just use an instance.", false)]
14 static public XmlRpcResponseDeserializer Singleton
15 {
16 get
17 {
18 if (_singleton == null)
19 _singleton = new XmlRpcResponseDeserializer();
20
21 return _singleton;
22 }
23 }
24
25 /// <summary>Static method that parses XML data into a response using the Singleton.</summary>
26 /// <param name="xmlData"><c>StreamReader</c> containing an XML-RPC response.</param>
27 /// <returns><c>XmlRpcResponse</c> object resulting from the parse.</returns>
28 override public Object Deserialize(TextReader xmlData)
29 {
30 XmlTextReader reader = new XmlTextReader(xmlData);
31 XmlRpcResponse response = new XmlRpcResponse();
32 bool done = false;
33
34 lock (this)
35 {
36 Reset();
37
38 while (!done && reader.Read())
39 {
40 DeserializeNode(reader); // Parent parse...
41 switch (reader.NodeType)
42 {
43 case XmlNodeType.EndElement:
44 switch (reader.Name)
45 {
46 case FAULT:
47 response.Value = _value;
48 response.IsFault = true;
49 break;
50 case PARAM:
51 response.Value = _value;
52 _value = null;
53 _text = null;
54 break;
55 }
56 break;
57 default:
58 break;
59 }
60 }
61 }
62 return response;
63 }
64 }
65}
diff --git a/XmlRpcCS/XmlRpcResponseSerializer.cs b/XmlRpcCS/XmlRpcResponseSerializer.cs
new file mode 100644
index 0000000..72ca568
--- /dev/null
+++ b/XmlRpcCS/XmlRpcResponseSerializer.cs
@@ -0,0 +1,57 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.Xml;
6
7 /// <summary>Class responsible for serializing an XML-RPC response.</summary>
8 /// <remarks>This class handles the response envelope, depending on XmlRpcSerializer
9 /// to serialize the payload.</remarks>
10 /// <seealso cref="XmlRpcSerializer"/>
11 public class XmlRpcResponseSerializer : XmlRpcSerializer
12 {
13 static private XmlRpcResponseSerializer _singleton;
14 /// <summary>A static singleton instance of this deserializer.</summary>
15 static public XmlRpcResponseSerializer Singleton
16 {
17 get
18 {
19 if (_singleton == null)
20 _singleton = new XmlRpcResponseSerializer();
21
22 return _singleton;
23 }
24 }
25
26 /// <summary>Serialize the <c>XmlRpcResponse</c> to the output stream.</summary>
27 /// <param name="output">An <c>XmlTextWriter</c> stream to write data to.</param>
28 /// <param name="obj">An <c>Object</c> to serialize.</param>
29 /// <seealso cref="XmlRpcResponse"/>
30 override public void Serialize(XmlTextWriter output, Object obj)
31 {
32 XmlRpcResponse response = (XmlRpcResponse)obj;
33
34 output.WriteStartDocument();
35 output.WriteStartElement(METHOD_RESPONSE);
36
37 if (response.IsFault)
38 output.WriteStartElement(FAULT);
39 else
40 {
41 output.WriteStartElement(PARAMS);
42 output.WriteStartElement(PARAM);
43 }
44
45 output.WriteStartElement(VALUE);
46
47 SerializeObject(output, response.Value);
48
49 output.WriteEndElement();
50
51 output.WriteEndElement();
52 if (!response.IsFault)
53 output.WriteEndElement();
54 output.WriteEndElement();
55 }
56 }
57}
diff --git a/XmlRpcCS/XmlRpcSerializer.cs b/XmlRpcCS/XmlRpcSerializer.cs
new file mode 100644
index 0000000..0643d38
--- /dev/null
+++ b/XmlRpcCS/XmlRpcSerializer.cs
@@ -0,0 +1,109 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Xml;
7
8 /// <summary>Base class of classes serializing data to XML-RPC's XML format.</summary>
9 /// <remarks>This class handles the basic type conversions like Integer to &lt;i4&gt;. </remarks>
10 /// <seealso cref="XmlRpcXmlTokens"/>
11 public class XmlRpcSerializer : XmlRpcXmlTokens
12 {
13
14 /// <summary>Serialize the <c>XmlRpcRequest</c> to the output stream.</summary>
15 /// <param name="output">An <c>XmlTextWriter</c> stream to write data to.</param>
16 /// <param name="obj">An <c>Object</c> to serialize.</param>
17 /// <seealso cref="XmlRpcRequest"/>
18 virtual public void Serialize(XmlTextWriter output, Object obj)
19 {
20 }
21
22 /// <summary>Serialize the <c>XmlRpcRequest</c> to a String.</summary>
23 /// <remarks>Note this may represent a real memory hog for a large request.</remarks>
24 /// <param name="obj">An <c>Object</c> to serialize.</param>
25 /// <returns><c>String</c> containing XML-RPC representation of the request.</returns>
26 /// <seealso cref="XmlRpcRequest"/>
27 public String Serialize(Object obj)
28 {
29 StringWriter strBuf = new StringWriter();
30 XmlTextWriter xml = new XmlTextWriter(strBuf);
31 xml.Formatting = Formatting.Indented;
32 xml.Indentation = 4;
33 Serialize(xml, obj);
34 xml.Flush();
35 String returns = strBuf.ToString();
36 xml.Close();
37 return returns;
38 }
39
40 /// <remarks>Serialize the object to the output stream.</remarks>
41 /// <param name="output">An <c>XmlTextWriter</c> stream to write data to.</param>
42 /// <param name="obj">An <c>Object</c> to serialize.</param>
43 public void SerializeObject(XmlTextWriter output, Object obj)
44 {
45 if (obj == null)
46 return;
47
48 if (obj is byte[])
49 {
50 byte[] ba = (byte[])obj;
51 output.WriteStartElement(BASE64);
52 output.WriteBase64(ba, 0, ba.Length);
53 output.WriteEndElement();
54 }
55 else if (obj is String)
56 {
57 output.WriteElementString(STRING, obj.ToString());
58 }
59 else if (obj is Int32)
60 {
61 output.WriteElementString(INT, obj.ToString());
62 }
63 else if (obj is DateTime)
64 {
65 output.WriteElementString(DATETIME, ((DateTime)obj).ToString(ISO_DATETIME));
66 }
67 else if (obj is Double)
68 {
69 output.WriteElementString(DOUBLE, obj.ToString());
70 }
71 else if (obj is Boolean)
72 {
73 output.WriteElementString(BOOLEAN, ((((Boolean)obj) == true) ? "1" : "0"));
74 }
75 else if (obj is IList)
76 {
77 output.WriteStartElement(ARRAY);
78 output.WriteStartElement(DATA);
79 if (((ArrayList)obj).Count > 0)
80 {
81 foreach (Object member in ((IList)obj))
82 {
83 output.WriteStartElement(VALUE);
84 SerializeObject(output, member);
85 output.WriteEndElement();
86 }
87 }
88 output.WriteEndElement();
89 output.WriteEndElement();
90 }
91 else if (obj is IDictionary)
92 {
93 IDictionary h = (IDictionary)obj;
94 output.WriteStartElement(STRUCT);
95 foreach (String key in h.Keys)
96 {
97 output.WriteStartElement(MEMBER);
98 output.WriteElementString(NAME, key);
99 output.WriteStartElement(VALUE);
100 SerializeObject(output, h[key]);
101 output.WriteEndElement();
102 output.WriteEndElement();
103 }
104 output.WriteEndElement();
105 }
106
107 }
108 }
109}
diff --git a/XmlRpcCS/XmlRpcServer.cs b/XmlRpcCS/XmlRpcServer.cs
new file mode 100644
index 0000000..1c226c1
--- /dev/null
+++ b/XmlRpcCS/XmlRpcServer.cs
@@ -0,0 +1,239 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.IO;
6 using System.Net;
7 using System.Net.Sockets;
8 using System.Text;
9 using System.Threading;
10 using System.Xml;
11
12 /// <summary>A restricted HTTP server for use with XML-RPC.</summary>
13 /// <remarks>It only handles POST requests, and only POSTs representing XML-RPC calls.
14 /// In addition to dispatching requests it also provides a registry for request handlers.
15 /// </remarks>
16 public class XmlRpcServer : IEnumerable
17 {
18#pragma warning disable 0414 // disable "private field assigned but not used"
19 const int RESPONDER_COUNT = 10;
20 private TcpListener _myListener;
21 private int _port;
22 private IPAddress _address;
23 private IDictionary _handlers;
24 private XmlRpcSystemObject _system;
25 private WaitCallback _wc;
26#pragma warning restore 0414
27
28 ///<summary>Constructor with port and address.</summary>
29 ///<remarks>This constructor sets up a TcpListener listening on the
30 ///given port and address. It also calls a Thread on the method StartListen().</remarks>
31 ///<param name="address"><c>IPAddress</c> value of the address to listen on.</param>
32 ///<param name="port"><c>Int</c> value of the port to listen on.</param>
33 public XmlRpcServer(IPAddress address, int port)
34 {
35 _port = port;
36 _address = address;
37 _handlers = new Hashtable();
38 _system = new XmlRpcSystemObject(this);
39 _wc = new WaitCallback(WaitCallback);
40 }
41
42 ///<summary>Basic constructor.</summary>
43 ///<remarks>This constructor sets up a TcpListener listening on the
44 ///given port. It also calls a Thread on the method StartListen(). IPAddress.Any
45 ///is assumed as the address here.</remarks>
46 ///<param name="port"><c>Int</c> value of the port to listen on.</param>
47 public XmlRpcServer(int port) : this(IPAddress.Any, port) { }
48
49 /// <summary>Start the server.</summary>
50 public void Start()
51 {
52 try
53 {
54 Stop();
55 //start listing on the given port
56 // IPAddress addr = IPAddress.Parse("127.0.0.1");
57 lock (this)
58 {
59 _myListener = new TcpListener(IPAddress.Any, _port);
60 _myListener.Start();
61 //start the thread which calls the method 'StartListen'
62 Thread th = new Thread(new ThreadStart(StartListen));
63 th.Start();
64 }
65 }
66 catch (Exception e)
67 {
68 Logger.WriteEntry("An Exception Occurred while Listening :" + e.ToString(), LogLevel.Error);
69 }
70 }
71
72 /// <summary>Stop the server.</summary>
73 public void Stop()
74 {
75 try
76 {
77 if (_myListener != null)
78 {
79 lock (this)
80 {
81 _myListener.Stop();
82 _myListener = null;
83 }
84 }
85 }
86 catch (Exception e)
87 {
88 Logger.WriteEntry("An Exception Occurred while stopping :" +
89 e.ToString(), LogLevel.Error);
90 }
91 }
92
93 /// <summary>Get an enumeration of my XML-RPC handlers.</summary>
94 /// <returns><c>IEnumerable</c> the handler enumeration.</returns>
95 public IEnumerator GetEnumerator()
96 {
97 return _handlers.GetEnumerator();
98 }
99
100 /// <summary>Retrieve a handler by name.</summary>
101 /// <param name="name"><c>String</c> naming a handler</param>
102 /// <returns><c>Object</c> that is the handler.</returns>
103 public Object this[String name]
104 {
105 get { return _handlers[name]; }
106 }
107
108 ///<summary>
109 ///This method Accepts new connections and dispatches them when appropriate.
110 ///</summary>
111 public void StartListen()
112 {
113 while (true && _myListener != null)
114 {
115 //Accept a new connection
116 XmlRpcResponder responder = new XmlRpcResponder(this, _myListener.AcceptTcpClient());
117 ThreadPool.QueueUserWorkItem(_wc, responder);
118 }
119 }
120
121
122 ///<summary>
123 ///Add an XML-RPC handler object by name.
124 ///</summary>
125 ///<param name="name"><c>String</c> XML-RPC dispatch name of this object.</param>
126 ///<param name="obj"><c>Object</c> The object that is the XML-RPC handler.</param>
127 public void Add(String name, Object obj)
128 {
129 _handlers.Add(name, obj);
130 }
131
132 ///<summary>Return a C# object.method name for and XML-RPC object.method name pair.</summary>
133 ///<param name="methodName">The XML-RPC object.method.</param>
134 ///<returns><c>String</c> of form object.method for the underlying C# method.</returns>
135 public String MethodName(String methodName)
136 {
137 int dotAt = methodName.LastIndexOf('.');
138
139 if (dotAt == -1)
140 {
141 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
142 XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Bad method name " + methodName);
143 }
144
145 String objectName = methodName.Substring(0, dotAt);
146 Object target = _handlers[objectName];
147
148 if (target == null)
149 {
150 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
151 XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Object " + objectName + " not found");
152 }
153
154 return target.GetType().FullName + "." + methodName.Substring(dotAt + 1);
155 }
156
157 ///<summary>Invoke a method described in a request.</summary>
158 ///<param name="req"><c>XmlRpcRequest</c> containing a method descriptions.</param>
159 /// <seealso cref="XmlRpcSystemObject.Invoke"/>
160 /// <seealso cref="XmlRpcServer.Invoke(String,String,IList)"/>
161 public Object Invoke(XmlRpcRequest req)
162 {
163 return Invoke(req.MethodNameObject, req.MethodNameMethod, req.Params);
164 }
165
166 ///<summary>Invoke a method on a named handler.</summary>
167 ///<param name="objectName"><c>String</c> The name of the handler.</param>
168 ///<param name="methodName"><c>String</c> The name of the method to invoke on the handler.</param>
169 ///<param name="parameters"><c>IList</c> The parameters to invoke the method with.</param>
170 /// <seealso cref="XmlRpcSystemObject.Invoke"/>
171 public Object Invoke(String objectName, String methodName, IList parameters)
172 {
173 Object target = _handlers[objectName];
174
175 if (target == null)
176 {
177 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
178 XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Object " + objectName + " not found");
179 }
180
181 return XmlRpcSystemObject.Invoke(target, methodName, parameters);
182 }
183
184 /// <summary>The method the thread pool invokes when a thread is available to handle an HTTP request.</summary>
185 /// <param name="responder">TcpClient from the socket accept.</param>
186 public void WaitCallback(object responder)
187 {
188 XmlRpcResponder resp = (XmlRpcResponder)responder;
189
190 if (resp.HttpReq.HttpMethod == "POST")
191 {
192 try
193 {
194 resp.Respond();
195 }
196 catch (Exception e)
197 {
198 Logger.WriteEntry("Failed on post: " + e, LogLevel.Error);
199 }
200 }
201 else
202 {
203 Logger.WriteEntry("Only POST methods are supported: " + resp.HttpReq.HttpMethod +
204 " ignored", LogLevel.Error);
205 }
206
207 resp.Close();
208 }
209
210 /// <summary>
211 /// This function send the Header Information to the client (Browser)
212 /// </summary>
213 /// <param name="sHttpVersion">HTTP Version</param>
214 /// <param name="sMIMEHeader">Mime Type</param>
215 /// <param name="iTotBytes">Total Bytes to be sent in the body</param>
216 /// <param name="sStatusCode"></param>
217 /// <param name="output">Socket reference</param>
218 static public void HttpHeader(string sHttpVersion, string sMIMEHeader, long iTotBytes, string sStatusCode, TextWriter output)
219 {
220 String sBuffer = "";
221
222 // if Mime type is not provided set default to text/html
223 if (sMIMEHeader.Length == 0)
224 {
225 sMIMEHeader = "text/html"; // Default Mime Type is text/html
226 }
227
228 sBuffer += sHttpVersion + sStatusCode + "\r\n";
229 sBuffer += "Connection: close\r\n";
230 if (iTotBytes > 0)
231 sBuffer += "Content-Length: " + iTotBytes + "\r\n";
232 sBuffer += "Server: XmlRpcServer \r\n";
233 sBuffer += "Content-Type: " + sMIMEHeader + "\r\n";
234 sBuffer += "\r\n";
235
236 output.Write(sBuffer);
237 }
238 }
239}
diff --git a/XmlRpcCS/XmlRpcSystemObject.cs b/XmlRpcCS/XmlRpcSystemObject.cs
new file mode 100644
index 0000000..5f79951
--- /dev/null
+++ b/XmlRpcCS/XmlRpcSystemObject.cs
@@ -0,0 +1,252 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4 using System.Collections;
5 using System.Reflection;
6
7 /// <summary> XML-RPC System object implementation of extended specifications.</summary>
8 [XmlRpcExposed]
9 public class XmlRpcSystemObject
10 {
11 private XmlRpcServer _server;
12 static private IDictionary _methodHelp = new Hashtable();
13
14 /// <summary>Static <c>IDictionary</c> to hold mappings of method name to associated documentation String</summary>
15 static public IDictionary MethodHelp
16 {
17 get { return _methodHelp; }
18 }
19
20 /// <summary>Constructor.</summary>
21 /// <param name="server"><c>XmlRpcServer</c> server to be the system object for.</param>
22 public XmlRpcSystemObject(XmlRpcServer server)
23 {
24 _server = server;
25 server.Add("system", this);
26 _methodHelp.Add(this.GetType().FullName + ".methodHelp", "Return a string description.");
27 }
28
29 /// <summary>Invoke a method on a given object.</summary>
30 /// <remarks>Using reflection, and respecting the <c>XmlRpcExposed</c> attribute,
31 /// invoke the <paramref>methodName</paramref> method on the <paramref>target</paramref>
32 /// instance with the <paramref>parameters</paramref> provided. All this packages other <c>Invoke</c> methods
33 /// end up calling this.</remarks>
34 /// <returns><c>Object</c> the value the invoked method returns.</returns>
35 /// <exception cref="XmlRpcException">If method does not exist, is not exposed, parameters invalid, or invocation
36 /// results in an exception. Note, the <c>XmlRpcException.Code</c> will indicate cause.</exception>
37 static public Object Invoke(Object target, String methodName, IList parameters)
38 {
39 if (target == null)
40 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
41 XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Invalid target object.");
42
43 Type type = target.GetType();
44 MethodInfo method = type.GetMethod(methodName);
45
46 try
47 {
48 if (!XmlRpcExposedAttribute.ExposedMethod(target, methodName))
49 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
50 XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Method " + methodName + " is not exposed.");
51 }
52 catch (MissingMethodException me)
53 {
54 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
55 XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": " + me.Message);
56 }
57
58 Object[] args = new Object[parameters.Count];
59
60 int index = 0;
61 foreach (Object arg in parameters)
62 {
63 args[index] = arg;
64 index++;
65 }
66
67 try
68 {
69 Object retValue = method.Invoke(target, args);
70 if (retValue == null)
71 throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
72 XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": Method returned NULL.");
73 return retValue;
74 }
75 catch (XmlRpcException e)
76 {
77 throw e;
78 }
79 catch (ArgumentException ae)
80 {
81 Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + ae.Message,
82 LogLevel.Information);
83 String call = methodName + "( ";
84 foreach (Object o in args)
85 {
86 call += o.GetType().Name;
87 call += " ";
88 }
89 call += ")";
90 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
91 XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement type mismatch invoking " + call);
92 }
93 catch (TargetParameterCountException tpce)
94 {
95 Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + tpce.Message,
96 LogLevel.Information);
97 throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
98 XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement count mismatch invoking " + methodName);
99 }
100 catch (TargetInvocationException tie)
101 {
102 throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
103 XmlRpcErrorCodes.APPLICATION_ERROR_MSG + " Invoked method " + methodName + ": " + tie.Message);
104 }
105 }
106
107 /// <summary>List methods available on all handlers of this server.</summary>
108 /// <returns><c>IList</c> An array of <c>Strings</c>, each <c>String</c> will have form "object.method".</returns>
109 [XmlRpcExposed]
110 public IList listMethods()
111 {
112 IList methods = new ArrayList();
113 Boolean considerExposure;
114
115 foreach (DictionaryEntry handlerEntry in _server)
116 {
117 considerExposure = XmlRpcExposedAttribute.IsExposed(handlerEntry.Value.GetType());
118
119 foreach (MemberInfo mi in handlerEntry.Value.GetType().GetMembers())
120 {
121 if (mi.MemberType != MemberTypes.Method)
122 continue;
123
124 if (!((MethodInfo)mi).IsPublic)
125 continue;
126
127 if (considerExposure && !XmlRpcExposedAttribute.IsExposed(mi))
128 continue;
129
130 methods.Add(handlerEntry.Key + "." + mi.Name);
131 }
132 }
133
134 return methods;
135 }
136
137 /// <summary>Given a method name return the possible signatures for it.</summary>
138 /// <param name="name"><c>String</c> The object.method name to look up.</param>
139 /// <returns><c>IList</c> Of arrays of signatures.</returns>
140 [XmlRpcExposed]
141 public IList methodSignature(String name)
142 {
143 IList signatures = new ArrayList();
144 int index = name.IndexOf('.');
145
146 if (index < 0)
147 return signatures;
148
149 String oName = name.Substring(0, index);
150 Object obj = _server[oName];
151
152 if (obj == null)
153 return signatures;
154
155 MemberInfo[] mi = obj.GetType().GetMember(name.Substring(index + 1));
156
157 if (mi == null || mi.Length != 1) // for now we want a single signature
158 return signatures;
159
160 MethodInfo method;
161
162 try
163 {
164 method = (MethodInfo)mi[0];
165 }
166 catch (Exception e)
167 {
168 Logger.WriteEntry("Attempted methodSignature call on " + mi[0] + " caused: " + e,
169 LogLevel.Information);
170 return signatures;
171 }
172
173 if (!method.IsPublic)
174 return signatures;
175
176 IList signature = new ArrayList();
177 signature.Add(method.ReturnType.Name);
178
179 foreach (ParameterInfo param in method.GetParameters())
180 {
181 signature.Add(param.ParameterType.Name);
182 }
183
184
185 signatures.Add(signature);
186
187 return signatures;
188 }
189
190 /// <summary>Help for given method signature. Not implemented yet.</summary>
191 /// <param name="name"><c>String</c> The object.method name to look up.</param>
192 /// <returns><c>String</c> help text. Rich HTML text.</returns>
193 [XmlRpcExposed]
194 public String methodHelp(String name)
195 {
196 String help = null;
197
198 try
199 {
200 help = (String)_methodHelp[_server.MethodName(name)];
201 }
202 catch (XmlRpcException e)
203 {
204 throw e;
205 }
206 catch (Exception) { /* ignored */ };
207
208 if (help == null)
209 help = "No help available for: " + name;
210
211 return help;
212 }
213
214 /// <summary>Boxcarring support method.</summary>
215 /// <param name="calls"><c>IList</c> of calls</param>
216 /// <returns><c>ArrayList</c> of results/faults.</returns>
217 [XmlRpcExposed]
218 public IList multiCall(IList calls)
219 {
220 IList responses = new ArrayList();
221 XmlRpcResponse fault = new XmlRpcResponse();
222
223 foreach (IDictionary call in calls)
224 {
225 try
226 {
227 XmlRpcRequest req = new XmlRpcRequest((String)call[XmlRpcXmlTokens.METHOD_NAME],
228 (ArrayList)call[XmlRpcXmlTokens.PARAMS]);
229 Object results = _server.Invoke(req);
230 IList response = new ArrayList();
231 response.Add(results);
232 responses.Add(response);
233 }
234 catch (XmlRpcException e)
235 {
236 fault.SetFault(e.FaultCode, e.FaultString);
237 responses.Add(fault.Value);
238 }
239 catch (Exception e2)
240 {
241 fault.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR,
242 XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message);
243 responses.Add(fault.Value);
244 }
245 }
246
247 return responses;
248 }
249
250 }
251}
252
diff --git a/XmlRpcCS/XmlRpcXmlTokens.cs b/XmlRpcCS/XmlRpcXmlTokens.cs
new file mode 100644
index 0000000..50788bd
--- /dev/null
+++ b/XmlRpcCS/XmlRpcXmlTokens.cs
@@ -0,0 +1,76 @@
1namespace Nwc.XmlRpc
2{
3 using System;
4
5 /// <summary>Class collecting <c>String</c> tokens that are part of XML-RPC files.</summary>
6 public class XmlRpcXmlTokens
7 {
8 /// <summary>C# formatting string to describe an ISO 8601 date.</summary>
9 public const String ISO_DATETIME = "yyyyMMdd\\THH\\:mm\\:ss";
10 /// <summary>Base64 field indicator.</summary>
11 /// <remarks>Corresponds to the &lt;base64&gt; tag.</remarks>
12 public const String BASE64 = "base64";
13 /// <summary>String field indicator.</summary>
14 /// <remarks>Corresponds to the &lt;string&gt; tag.</remarks>
15 public const String STRING = "string";
16 /// <summary>Integer field integer.</summary>
17 /// <remarks>Corresponds to the &lt;i4&gt; tag.</remarks>
18 public const String INT = "i4";
19 /// <summary>Alternate integer field indicator.</summary>
20 /// <remarks>Corresponds to the &lt;int&gt; tag.</remarks>
21 public const String ALT_INT = "int";
22 /// <summary>Date field indicator.</summary>
23 /// <remarks>Corresponds to the &lt;dateTime.iso8601&gt; tag.</remarks>
24 public const String DATETIME = "dateTime.iso8601";
25 /// <summary>Boolean field indicator.</summary>
26 /// <remarks>Corresponds to the &lt;boolean&gt; tag.</remarks>
27 public const String BOOLEAN = "boolean";
28 /// <summary>Value token.</summary>
29 /// <remarks>Corresponds to the &lt;value&gt; tag.</remarks>
30 public const String VALUE = "value";
31 /// <summary>Name token.</summary>
32 /// <remarks>Corresponds to the &lt;name&gt; tag.</remarks>
33 public const String NAME = "name";
34 /// <summary>Array field indicator..</summary>
35 /// <remarks>Corresponds to the &lt;array&gt; tag.</remarks>
36 public const String ARRAY = "array";
37 /// <summary>Data token.</summary>
38 /// <remarks>Corresponds to the &lt;data&gt; tag.</remarks>
39 public const String DATA = "data";
40 /// <summary>Member token.</summary>
41 /// <remarks>Corresponds to the &lt;member&gt; tag.</remarks>
42 public const String MEMBER = "member";
43 /// <summary>Stuct field indicator.</summary>
44 /// <remarks>Corresponds to the &lt;struct&gt; tag.</remarks>
45 public const String STRUCT = "struct";
46 /// <summary>Double field indicator.</summary>
47 /// <remarks>Corresponds to the &lt;double&gt; tag.</remarks>
48 public const String DOUBLE = "double";
49 /// <summary>Param token.</summary>
50 /// <remarks>Corresponds to the &lt;param&gt; tag.</remarks>
51 public const String PARAM = "param";
52 /// <summary>Params token.</summary>
53 /// <remarks>Corresponds to the &lt;params&gt; tag.</remarks>
54 public const String PARAMS = "params";
55 /// <summary>MethodCall token.</summary>
56 /// <remarks>Corresponds to the &lt;methodCall&gt; tag.</remarks>
57 public const String METHOD_CALL = "methodCall";
58 /// <summary>MethodName token.</summary>
59 /// <remarks>Corresponds to the &lt;methodName&gt; tag.</remarks>
60 public const String METHOD_NAME = "methodName";
61 /// <summary>MethodResponse token</summary>
62 /// <remarks>Corresponds to the &lt;methodResponse&gt; tag.</remarks>
63 public const String METHOD_RESPONSE = "methodResponse";
64 /// <summary>Fault response token.</summary>
65 /// <remarks>Corresponds to the &lt;fault&gt; tag.</remarks>
66 public const String FAULT = "fault";
67 /// <summary>FaultCode token.</summary>
68 /// <remarks>Corresponds to the &lt;faultCode&gt; tag.</remarks>
69 public const String FAULT_CODE = "faultCode";
70 /// <summary>FaultString token.</summary>
71 /// <remarks>Corresponds to the &lt;faultString&gt; tag.</remarks>
72 public const String FAULT_STRING = "faultString";
73 }
74}
75
76