Mono.Zeroconf – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
4  
5 using System;
6 using System.Reflection;
7 using System.Reflection.Emit;
8 using System.Collections.Generic;
9  
10 namespace NDesk.DBus
11 {
12 class BusObject
13 {
14 protected Connection conn;
15 string bus_name;
16 ObjectPath object_path;
17  
18 //protected BusObject ()
19 public BusObject ()
20 {
21 }
22  
23 public BusObject (Connection conn, string bus_name, ObjectPath object_path)
24 {
25 this.conn = conn;
26 this.bus_name = bus_name;
27 this.object_path = object_path;
28 }
29  
30 public Connection Connection
31 {
32 get {
33 return conn;
34 }
35 }
36  
37 public string BusName
38 {
39 get {
40 return bus_name;
41 }
42 }
43  
44 public ObjectPath Path
45 {
46 get {
47 return object_path;
48 }
49 }
50  
51 public void ToggleSignal (string iface, string member, Delegate dlg, bool adding)
52 {
53 MatchRule rule = new MatchRule ();
54 rule.MessageType = MessageType.Signal;
55 rule.Interface = iface;
56 rule.Member = member;
57 rule.Path = object_path;
58  
59 if (adding) {
60 if (conn.Handlers.ContainsKey (rule))
61 conn.Handlers[rule] = Delegate.Combine (conn.Handlers[rule], dlg);
62 else {
63 conn.Handlers[rule] = dlg;
64 conn.AddMatch (rule.ToString ());
65 }
66 } else {
67 conn.Handlers[rule] = Delegate.Remove (conn.Handlers[rule], dlg);
68 if (conn.Handlers[rule] == null) {
69 conn.RemoveMatch (rule.ToString ());
70 conn.Handlers.Remove (rule);
71 }
72 }
73 }
74  
75 public void SendSignal (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception)
76 {
77 exception = null;
78  
79 //TODO: don't ignore retVal, exception etc.
80  
81 Signature outSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr);
82  
83 Signal signal = new Signal (object_path, iface, member);
84 signal.message.Signature = outSig;
85  
86 Message signalMsg = signal.message;
87 signalMsg.Body = writer.ToArray ();
88  
89 conn.Send (signalMsg);
90 }
91  
92 public object SendMethodCall (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception)
93 {
94 exception = null;
95  
96 //TODO: don't ignore retVal, exception etc.
97  
98 Signature inSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr);
99  
100 MethodCall method_call = new MethodCall (object_path, iface, member, bus_name, inSig);
101  
102 Message callMsg = method_call.message;
103 callMsg.Body = writer.ToArray ();
104  
105 //Invoke Code::
106  
107 //TODO: complete out parameter support
108 /*
109 Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ());
110 Signature outParmSig = Signature.GetSig (outParmTypes);
111  
112 if (outParmSig != Signature.Empty)
113 throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'");
114 */
115  
116 Type[] outTypes = new Type[1];
117 outTypes[0] = retType;
118  
119 //we default to always requiring replies for now, even though unnecessary
120 //this is to make sure errors are handled synchronously
121 //TODO: don't hard code this
122 bool needsReply = true;
123  
124 //if (mi.ReturnType == typeof (void))
125 // needsReply = false;
126  
127 callMsg.ReplyExpected = needsReply;
128 callMsg.Signature = inSig;
129  
130 if (!needsReply) {
131 conn.Send (callMsg);
132 return null;
133 }
134  
135 #if PROTO_REPLY_SIGNATURE
136 if (needsReply) {
137 Signature outSig = Signature.GetSig (outTypes);
138 callMsg.Header.Fields[FieldCode.ReplySignature] = outSig;
139 }
140 #endif
141  
142 Message retMsg = conn.SendWithReplyAndBlock (callMsg);
143  
144 object retVal = null;
145  
146 //handle the reply message
147 switch (retMsg.Header.MessageType) {
148 case MessageType.MethodReturn:
149 object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes);
150 if (retVals.Length != 0)
151 retVal = retVals[retVals.Length - 1];
152 break;
153 case MessageType.Error:
154 //TODO: typed exceptions
155 Error error = new Error (retMsg);
156 string errMsg = String.Empty;
157 if (retMsg.Signature.Value.StartsWith ("s")) {
158 MessageReader reader = new MessageReader (retMsg);
159 errMsg = reader.ReadString ();
160 }
161 exception = new Exception (error.ErrorName + ": " + errMsg);
162 break;
163 default:
164 throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error");
165 }
166  
167 return retVal;
168 }
169  
170 public void Invoke (MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception)
171 {
172 outArgs = new object[0];
173 retVal = null;
174 exception = null;
175  
176 MethodInfo mi = methodBase as MethodInfo;
177  
178 if (mi != null && mi.IsSpecialName && (methodName.StartsWith ("add_") || methodName.StartsWith ("remove_"))) {
179 string[] parts = methodName.Split (new char[]{'_'}, 2);
180 string ename = parts[1];
181 Delegate dlg = (Delegate)inArgs[0];
182  
183 ToggleSignal (Mapper.GetInterfaceName (mi), ename, dlg, parts[0] == "add");
184  
185 return;
186 }
187  
188 Type[] inTypes = Mapper.GetTypes (ArgDirection.In, mi.GetParameters ());
189 Signature inSig = Signature.GetSig (inTypes);
190  
191 MethodCall method_call;
192 Message callMsg;
193  
194 //build the outbound method call message
195 {
196 //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced
197 string iface = null;
198 if (mi != null)
199 iface = Mapper.GetInterfaceName (mi);
200  
201 //map property accessors
202 //TODO: this needs to be done properly, not with simple String.Replace
203 //note that IsSpecialName is also for event accessors, but we already handled those and returned
204 if (mi != null && mi.IsSpecialName) {
205 methodName = methodName.Replace ("get_", "Get");
206 methodName = methodName.Replace ("set_", "Set");
207 }
208  
209 method_call = new MethodCall (object_path, iface, methodName, bus_name, inSig);
210  
211 callMsg = method_call.message;
212  
213 if (inArgs != null && inArgs.Length != 0) {
214 MessageWriter writer = new MessageWriter (Connection.NativeEndianness);
215 writer.connection = conn;
216  
217 for (int i = 0 ; i != inTypes.Length ; i++)
218 writer.Write (inTypes[i], inArgs[i]);
219  
220 callMsg.Body = writer.ToArray ();
221 }
222 }
223  
224 //TODO: complete out parameter support
225 /*
226 Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ());
227 Signature outParmSig = Signature.GetSig (outParmTypes);
228  
229 if (outParmSig != Signature.Empty)
230 throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'");
231 */
232  
233 Type[] outTypes = new Type[1];
234 outTypes[0] = mi.ReturnType;
235  
236 //we default to always requiring replies for now, even though unnecessary
237 //this is to make sure errors are handled synchronously
238 //TODO: don't hard code this
239 bool needsReply = true;
240  
241 //if (mi.ReturnType == typeof (void))
242 // needsReply = false;
243  
244 callMsg.ReplyExpected = needsReply;
245 callMsg.Signature = inSig;
246  
247 if (!needsReply) {
248 conn.Send (callMsg);
249 return;
250 }
251  
252 #if PROTO_REPLY_SIGNATURE
253 if (needsReply) {
254 Signature outSig = Signature.GetSig (outTypes);
255 callMsg.Header.Fields[FieldCode.ReplySignature] = outSig;
256 }
257 #endif
258  
259 Message retMsg = conn.SendWithReplyAndBlock (callMsg);
260  
261 //handle the reply message
262 switch (retMsg.Header.MessageType) {
263 case MessageType.MethodReturn:
264 object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes);
265 if (retVals.Length != 0)
266 retVal = retVals[retVals.Length - 1];
267 break;
268 case MessageType.Error:
269 //TODO: typed exceptions
270 Error error = new Error (retMsg);
271 string errMsg = String.Empty;
272 if (retMsg.Signature.Value.StartsWith ("s")) {
273 MessageReader reader = new MessageReader (retMsg);
274 errMsg = reader.ReadString ();
275 }
276 exception = new Exception (error.ErrorName + ": " + errMsg);
277 break;
278 default:
279 throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error");
280 }
281  
282 return;
283 }
284  
285 public static object GetObject (Connection conn, string bus_name, ObjectPath object_path, Type declType)
286 {
287 Type proxyType = TypeImplementer.GetImplementation (declType);
288  
289 BusObject inst = (BusObject)Activator.CreateInstance (proxyType);
290 inst.conn = conn;
291 inst.bus_name = bus_name;
292 inst.object_path = object_path;
293  
294 return inst;
295 }
296  
297 public Delegate GetHookupDelegate (EventInfo ei)
298 {
299 DynamicMethod hookupMethod = TypeImplementer.GetHookupMethod (ei);
300 Delegate d = hookupMethod.CreateDelegate (ei.EventHandlerType, this);
301 return d;
302 }
303 }
304 }