public static object[] GetDynamicValues(Message msg, Type[] types) { //TODO: this validation check should provide better information, eg. message dump or a stack trace if (Protocol.Verbose) { if (Signature.GetSig(types) != msg.Signature) { Console.Error.WriteLine("Warning: The signature of the message does not match that of the handler"); } } object[] vals = new object[types.Length]; if (msg.Body != null) { MessageReader reader = new MessageReader(msg); for (int i = 0; i != types.Length; i++) { object arg; reader.GetValue(types[i], out arg); vals[i] = arg; } } return(vals); }
internal void HandleMessage(Message msg) { //TODO: support disconnection situations properly and move this check elsewhere if (msg == null) { throw new ArgumentNullException("msg", "Cannot handle a null message; maybe the bus was disconnected"); } { //TODO: don't store replies unless they are expected (right now all replies are expected as we don't support NoReplyExpected) object reply_serial; if (msg.Header.Fields.TryGetValue(FieldCode.ReplySerial, out reply_serial)) { replies[(uint)reply_serial] = msg; return; } } switch (msg.Header.MessageType) { case MessageType.MethodCall: MethodCall method_call = new MethodCall(msg); HandleMethodCall(method_call); break; case MessageType.Signal: //HandleSignal (msg); lock (Inbound) Inbound.Enqueue(msg); break; case MessageType.Error: //TODO: better exception handling Error error = new Error(msg); string errMsg = String.Empty; if (msg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(msg); reader.GetValue(out errMsg); } //throw new Exception ("Remote Error: Signature='" + msg.Signature.Value + "' " + error.ErrorName + ": " + errMsg); //if (Protocol.Verbose) Console.Error.WriteLine("Remote Error: Signature='" + msg.Signature.Value + "' " + error.ErrorName + ": " + errMsg); break; case MessageType.Invalid: default: throw new Exception("Invalid message received: MessageType='" + msg.Header.MessageType + "'"); } }
public void Invoke(MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception) { outArgs = new object[0]; retVal = null; exception = null; MethodInfo mi = methodBase as MethodInfo; if (mi != null && mi.IsSpecialName && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) { string[] parts = methodName.Split(new char[] { '_' }, 2); string ename = parts[1]; Delegate dlg = (Delegate)inArgs[0]; MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Interface = Mapper.GetInterfaceName(mi); rule.Member = ename; rule.Path = object_path; if (parts[0] == "add") { if (conn.Handlers.ContainsKey(rule)) { conn.Handlers[rule] = Delegate.Combine(conn.Handlers[rule], dlg); } else { conn.Handlers[rule] = dlg; conn.AddMatch(rule.ToString()); } } else if (parts[0] == "remove") { conn.Handlers[rule] = Delegate.Remove(conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch(rule.ToString()); conn.Handlers.Remove(rule); } } return; } Type[] inTypes = Mapper.GetTypes(ArgDirection.In, mi.GetParameters()); Signature inSig = Signature.GetSig(inTypes); MethodCall method_call; Message callMsg; //build the outbound method call message { //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced string iface = null; if (mi != null) { iface = Mapper.GetInterfaceName(mi); } //map property accessors //TODO: this needs to be done properly, not with simple String.Replace //note that IsSpecialName is also for event accessors, but we already handled those and returned if (mi != null && mi.IsSpecialName) { methodName = methodName.Replace("get_", "Get"); methodName = methodName.Replace("set_", "Set"); } method_call = new MethodCall(object_path, iface, methodName, bus_name, inSig); callMsg = method_call.message; if (inArgs != null && inArgs.Length != 0) { MessageWriter writer = new MessageWriter(Connection.NativeEndianness); writer.connection = conn; for (int i = 0; i != inTypes.Length; i++) { writer.Write(inTypes[i], inArgs[i]); } callMsg.Body = writer.ToArray(); } } //TODO: complete out parameter support Type[] outParmTypes = Mapper.GetTypes(ArgDirection.Out, mi.GetParameters()); Signature outParmSig = Signature.GetSig(outParmTypes); if (outParmSig != Signature.Empty) { throw new Exception("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); } Type[] outTypes = new Type[1]; outTypes[0] = mi.ReturnType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send(callMsg); return; } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig(outTypes); callMsg.Header.Fields[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock(callMsg); //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues(retMsg, outTypes); if (retVals.Length != 0) { retVal = retVals[retVals.Length - 1]; } break; case MessageType.Error: //TODO: typed exceptions Error error = new Error(retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(retMsg); reader.GetValue(out errMsg); } exception = new Exception(error.ErrorName + ": " + errMsg); break; default: throw new Exception("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return; }
/* * Queue<Message> Outbound = new Queue<Message> (); * * public void Flush () * { * //should just iterate the enumerator here * while (Outbound.Count != 0) { * Message msg = Outbound.Dequeue (); * WriteMessage (msg); * } * } * * public bool ReadWrite (int timeout_milliseconds) * { * //TODO * * return true; * } * * public bool ReadWrite () * { * return ReadWrite (-1); * } * * public bool Dispatch () * { * //TODO * Message msg = Inbound.Dequeue (); * //HandleMessage (msg); * * return true; * } * * public bool ReadWriteDispatch (int timeout_milliseconds) * { * //TODO * return Dispatch (); * } * * public bool ReadWriteDispatch () * { * return ReadWriteDispatch (-1); * } */ internal Message ReadMessage() { //FIXME: fix reading algorithm to work in one step //this code is a bit silly and inefficient //hopefully it's at least correct and avoids polls for now int read; byte[] buf = new byte[16]; read = ns.Read(buf, 0, 16); if (read == 0) { return(null); } if (read != 16) { throw new Exception("Header read length mismatch: " + read + " of expected " + "16"); } MemoryStream ms = new MemoryStream(); ms.Write(buf, 0, 16); EndianFlag endianness = (EndianFlag)buf[0]; MessageReader reader = new MessageReader(endianness, buf); //discard the endian byte as we've already read it byte tmp; reader.GetValue(out tmp); //discard message type and flags, which we don't care about here reader.GetValue(out tmp); reader.GetValue(out tmp); byte version; reader.GetValue(out version); if (version < Protocol.MinVersion || version > Protocol.MaxVersion) { throw new NotSupportedException("Protocol version '" + version.ToString() + "' is not supported"); } if (Protocol.Verbose) { if (version != Protocol.Version) { Console.Error.WriteLine("Warning: Protocol version '" + version.ToString() + "' is not explicitly supported but may be compatible"); } } uint bodyLength, serial, headerLength; reader.GetValue(out bodyLength); reader.GetValue(out serial); reader.GetValue(out headerLength); //TODO: remove this limitation if (bodyLength > Int32.MaxValue || headerLength > Int32.MaxValue) { throw new NotImplementedException("Long messages are not yet supported"); } int bodyLen = (int)bodyLength; int toRead = (int)headerLength; toRead = Protocol.Padded((int)toRead, 8); buf = new byte[toRead]; read = ns.Read(buf, 0, toRead); if (read != toRead) { throw new Exception("Read length mismatch: " + read + " of expected " + toRead); } ms.Write(buf, 0, buf.Length); Message msg = new Message(); msg.Connection = this; msg.HeaderData = ms.ToArray(); //read the body if (bodyLen != 0) { //FIXME //msg.Body = new byte[(int)msg.Header->Length]; byte[] body = new byte[bodyLen]; //int len = ns.Read (msg.Body, 0, msg.Body.Length); int len = ns.Read(body, 0, bodyLen); //if (len != msg.Body.Length) if (len != bodyLen) { throw new Exception("Message body size mismatch"); } //msg.Body = new MemoryStream (body); msg.Body = body; } //this needn't be done here msg.ParseHeader(); return(msg); }
public void Invoke (MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception) { outArgs = new object[0]; retVal = null; exception = null; MethodInfo mi = methodBase as MethodInfo; if (mi != null && mi.IsSpecialName && (methodName.StartsWith ("add_") || methodName.StartsWith ("remove_"))) { string[] parts = methodName.Split (new char[]{'_'}, 2); string ename = parts[1]; Delegate dlg = (Delegate)inArgs[0]; MatchRule rule = new MatchRule (); rule.MessageType = MessageType.Signal; rule.Interface = Mapper.GetInterfaceName (mi); rule.Member = ename; rule.Path = object_path; if (parts[0] == "add") { if (conn.Handlers.ContainsKey (rule)) conn.Handlers[rule] = Delegate.Combine (conn.Handlers[rule], dlg); else { conn.Handlers[rule] = dlg; conn.AddMatch (rule.ToString ()); } } else if (parts[0] == "remove") { conn.Handlers[rule] = Delegate.Remove (conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch (rule.ToString ()); conn.Handlers.Remove (rule); } } return; } Type[] inTypes = Mapper.GetTypes (ArgDirection.In, mi.GetParameters ()); Signature inSig = Signature.GetSig (inTypes); MethodCall method_call; Message callMsg; //build the outbound method call message { //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced string iface = null; if (mi != null) iface = Mapper.GetInterfaceName (mi); //map property accessors //TODO: this needs to be done properly, not with simple String.Replace //note that IsSpecialName is also for event accessors, but we already handled those and returned if (mi != null && mi.IsSpecialName) { methodName = methodName.Replace ("get_", "Get"); methodName = methodName.Replace ("set_", "Set"); } method_call = new MethodCall (object_path, iface, methodName, bus_name, inSig); callMsg = method_call.message; if (inArgs != null && inArgs.Length != 0) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); writer.connection = conn; for (int i = 0 ; i != inTypes.Length ; i++) writer.Write (inTypes[i], inArgs[i]); callMsg.Body = writer.ToArray (); } } //TODO: complete out parameter support Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); Signature outParmSig = Signature.GetSig (outParmTypes); if (outParmSig != Signature.Empty) throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); Type[] outTypes = new Type[1]; outTypes[0] = mi.ReturnType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send (callMsg); return; } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig (outTypes); callMsg.Header.Fields[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock (callMsg); //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes); if (retVals.Length != 0) retVal = retVals[retVals.Length - 1]; break; case MessageType.Error: //TODO: typed exceptions Error error = new Error (retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith ("s")) { MessageReader reader = new MessageReader (retMsg); reader.GetValue (out errMsg); } exception = new Exception (error.ErrorName + ": " + errMsg); break; default: throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return; }
public static object[] GetDynamicValues (Message msg, Type[] types) { //TODO: this validation check should provide better information, eg. message dump or a stack trace if (Protocol.Verbose) { if (Signature.GetSig (types) != msg.Signature) Console.Error.WriteLine ("Warning: The signature of the message does not match that of the handler"); } object[] vals = new object[types.Length]; if (msg.Body != null) { MessageReader reader = new MessageReader (msg); for (int i = 0 ; i != types.Length ; i++) { object arg; reader.GetValue (types[i], out arg); vals[i] = arg; } } return vals; }