diff options
Diffstat (limited to '')
-rw-r--r-- | XmlRpcCS/XmlRpcServer.cs | 239 |
1 files changed, 239 insertions, 0 deletions
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 @@ | |||
1 | namespace 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 | } | ||