Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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 + "'");
            }
        }
Ejemplo n.º 3
0
        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;
        }
Ejemplo n.º 4
0
        /*
         * 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);
        }
Ejemplo n.º 5
0
		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;
		}
Ejemplo n.º 6
0
		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;
		}