示例#1
0
        static ServiceAction BuildAction(MethodInfo method,
                                         object service,
                                         Dictionary <string, StateVariableInfo> stateVariables)
        {
            var attributes = method.GetCustomAttributes(typeof(UpnpActionAttribute), false);

            if (attributes.Length != 0)
            {
                var attribute = (UpnpActionAttribute)attributes[0];
                if (Omit(method.DeclaringType, service, attribute.OmitUnless))
                {
                    return(null);
                }
                var name       = string.IsNullOrEmpty(attribute.Name) ? method.Name : attribute.Name;
                var parameters = method.GetParameters();
                var arguments  = new ArgumentInfo[parameters.Length];
                for (var i = 0; i < parameters.Length; i++)
                {
                    arguments[i] = BuildArgumentInfo(parameters[i], name, stateVariables);
                }
                var return_argument = BuildArgumentInfo(method.ReturnParameter, name, stateVariables, true);
                return(new ServiceAction(name, Combine(arguments, return_argument), args => {
                    Trace(name, args.Values);

                    var argument_array = new object[arguments.Length];
                    for (var i = 0; i < arguments.Length; i++)
                    {
                        var argument = arguments[i];
                        if (argument.Argument.Direction == ArgumentDirection.Out)
                        {
                            continue;
                        }

                        string value;
                        if (args.TryGetValue(argument.Argument.Name, out value))
                        {
                            var parameter_type = argument.ParameterInfo.ParameterType;
                            if (parameter_type.IsEnum)
                            {
                                // TODO handle attributes
                                foreach (var enum_value in Enum.GetValues(parameter_type))
                                {
                                    if (Enum.GetName(parameter_type, enum_value) == value)
                                    {
                                        argument_array[i] = enum_value;
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                argument_array[i] = Convert.ChangeType(value, parameter_type);
                            }
                        }
                        else
                        {
                            // TODO throw
                        }
                    }

                    object result;
                    try {
                        result = method.Invoke(service, argument_array);
                    } catch (TargetInvocationException e) {
                        if (e.InnerException is UpnpControlException)
                        {
                            throw e.InnerException;
                        }
                        else
                        {
                            throw new UpnpControlException(
                                UpnpError.Unknown(), "Unexpected exception.", e.InnerException);
                        }
                    }

                    var out_arguments = new Dictionary <string, string> ();
                    for (var i = 0; i < arguments.Length; i++)
                    {
                        if (arguments[i].Argument.Direction == ArgumentDirection.In)
                        {
                            continue;
                        }
                        var value = argument_array[i];
                        out_arguments.Add(arguments[i].Argument.Name, value != null ? value.ToString() : "");
                    }
                    if (return_argument != null)
                    {
                        out_arguments.Add(return_argument.Argument.Name, result.ToString());
                    }

                    Trace(name, out_arguments);

                    return out_arguments;
                }));
            }
            else
            {
                return(null);
            }
        }
示例#2
0
        public IMap <string, string> Invoke(string actionName, IDictionary <string, string> arguments)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);

            request.Method      = "POST";
            request.ContentType = @"text/xml; charset=""utf-8""";
            request.UserAgent   = Protocol.UserAgent;
            request.Headers.Add("SOAPACTION", string.Format(@"""{0}#{1}""", service_type, actionName));
            using (var stream = request.GetRequestStream()) {
                serializer.Serialize(
                    new SoapEnvelope <Arguments> (new Arguments(service_type, actionName, arguments)), stream);
            }

            HttpWebResponse response;
            WebException    exception;

            try {
                response  = Helper.GetResponse(request);
                exception = null;
            } catch (WebException e) {
                response = e.Response as HttpWebResponse;
                if (response == null)
                {
                    Log.Error(string.Format(
                                  "The request for the {0} action request on {1} failed.", actionName, url));
                    throw new UpnpControlException(UpnpError.Unknown(), "The invokation failed.", e);
                }
                exception = e;
            }

            using (response) {
                switch (response.StatusCode)
                {
                case HttpStatusCode.OK:
                    using (var reader = XmlReader.Create(response.GetResponseStream())) {
                        // FIXME this is a workaround for Mono bug 523151
                        reader.MoveToContent();
                        var envelope = deserializer.Deserialize <SoapEnvelope <Arguments> > (reader);
                        if (envelope == null)
                        {
                            Log.Error(string.Format(
                                          "The response to the {0} action request on {1} has no envelope.", actionName, url));
                            throw new UpnpControlException(UpnpError.Unknown(),
                                                           "The service did not provide a valid response (unable to deserialize SOAP envelope).");
                        }
                        else if (envelope.Body == null)
                        {
                            Log.Error(string.Format(
                                          "The response to the {0} action request on {1} " +
                                          "has no envelope body.", actionName, url));
                            throw new UpnpControlException(UpnpError.Unknown(),
                                                           "The service did not provide a valid response " +
                                                           "(unable to deserialize SOAP envelope body).");
                        }
                        return(new Map <string, string> (envelope.Body.Values));
                    }

                case HttpStatusCode.InternalServerError:
                    using (var reader = XmlReader.Create(response.GetResponseStream())) {
                        // FIME this is a workaround for Mono bug 523151
                        reader.MoveToContent();
                        var envelope = deserializer
                                       .Deserialize <SoapEnvelope <XmlShell <SoapFault <XmlShell <UpnpError> > > > > (reader);
                        if (envelope == null)
                        {
                            Log.Error(string.Format(
                                          "The faulty response to the {0} action request " +
                                          "on {1} has no envelope.", actionName, url));
                            throw new UpnpControlException(UpnpError.Unknown(),
                                                           "The invokation failed but the service did not provide valid fault information " +
                                                           "(unable to deserialize SOAP envelope).", exception);
                        }
                        else if (envelope.Body == null)
                        {
                            Log.Error(string.Format(
                                          "The faulty response to the {0} action request on {1} " +
                                          "has no envelope body.", actionName, url));
                            throw new UpnpControlException(UpnpError.Unknown(),
                                                           "The invokation failed but the service did not provide valid fault information " +
                                                           "(unable to deserialize SOAP envelope body).", exception);
                        }
                        else if (envelope.Body.Value.Detail == null || envelope.Body.Value.Detail.Value == null)
                        {
                            Log.Error(string.Format(
                                          "The faulty response to the {0} action request on {1} has no UPnPError. " +
                                          @"The faultcode and faultstring are ""{2}"" and ""{3}"" respectively.",
                                          actionName, url, envelope.Body.Value.FaultCode, envelope.Body.Value.FaultString));
                            throw new UpnpControlException(UpnpError.Unknown(),
                                                           "The invokation failed but the service did not provide valid fault information " +
                                                           "(unable to deserialize a UPnPError from the SOAP envelope).", exception);
                        }
                        Log.Error(string.Format(
                                      "The invokation for the {0} action request on {1} failed: {2}", actionName, url, envelope.Body.Value.Detail.Value));
                        throw new UpnpControlException(envelope.Body.Value.Detail.Value,
                                                       "The invokation failed.", exception);
                    }

                default:
                    Log.Error(string.Format(
                                  "The response to the {0} action request on {1} returned with status code {2}: {3}.",
                                  actionName, url, (int)response.StatusCode, response.StatusDescription));
                    throw new UpnpControlException(UpnpError.Unknown(), "The invokation failed.", exception);
                }
            }
        }
示例#3
0
        protected override void HandleContext(HttpListenerContext context)
        {
            base.HandleContext(context);

            context.Response.ContentType = @"text/xml; charset=""utf-8""";
            context.Response.AddHeader("EXT", string.Empty);

            using (var reader = XmlReader.Create(context.Request.InputStream)) {
                // FIXME this is a workaround for mono bug 523151
                if (reader.MoveToContent() != XmlNodeType.Element)
                {
                    Log.Error(string.Format(
                                  "A control request from {0} to {1} does not have a SOAP envelope.",
                                  context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                SoapEnvelope <Arguments> requestEnvelope;

                try {
                    requestEnvelope = deserializer.Deserialize <SoapEnvelope <Arguments> > (reader);
                } catch (Exception e) {
                    Log.Exception(string.Format(
                                      "Failed to deserialize a control request from {0} to {1}.",
                                      context.Request.RemoteEndPoint, context.Request.Url), e);
                    return;
                }

                if (requestEnvelope == null)
                {
                    Log.Error(string.Format(
                                  "A control request from {0} to {1} does not have a valid SOAP envelope.",
                                  context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                var arguments = requestEnvelope.Body;

                if (arguments == null)
                {
                    Log.Error(string.Format(
                                  "A control request from {0} to {1} does not have a valid argument list.",
                                  context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                if (arguments.ActionName == null)
                {
                    Log.Error(string.Format(
                                  "A control request from {0} to {1} does not have an action name.",
                                  context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                ServiceAction action;

                try {
                    if (actions.TryGetValue(arguments.ActionName, out action))
                    {
                        Log.Information(string.Format("{0} invoked {1} on {2}.",
                                                      context.Request.RemoteEndPoint, arguments.ActionName, context.Request.Url));

                        Arguments result;

                        try {
                            result = new Arguments(
                                service_type, action.Name, action.Execute(arguments.Values), true);
                        } catch (UpnpControlException) {
                            throw;
                        } catch (Exception e) {
                            throw new UpnpControlException(UpnpError.Unknown(), "Unexpected exception.", e);
                        }

                        // TODO If we're allowing consumer code to subclass Argument, then we need to expose that in a
                        // Mono.Upnp.Serializer class. We would then need to put this in a try/catch because custom
                        // serialization code could throw.
                        serializer.Serialize(new SoapEnvelope <Arguments> (result), context.Response.OutputStream);
                    }
                    else
                    {
                        throw new UpnpControlException(UpnpError.InvalidAction(), string.Format(
                                                           "{0} attempted to invoke the non-existant action {1} on {2}.",
                                                           context.Request.RemoteEndPoint, arguments.ActionName, context.Request.Url));
                    }
                } catch (UpnpControlException e) {
                    Log.Exception(e);

                    context.Response.StatusCode        = 500;
                    context.Response.StatusDescription = "Internal Server Error";

                    // TODO This needs to be a try/catch in the future too.
                    serializer.Serialize(new SoapEnvelope <SoapFault <UpnpError> > (
                                             new SoapFault <UpnpError> (e.UpnpError)), context.Response.OutputStream);
                }
            }
        }