예제 #1
0
        public static bool TryParse(string versionStr, out UPnPVersion result)
        {
            result = null;
            int dotIndex = versionStr.IndexOf('.');

            if (dotIndex < 0)
            {
                dotIndex = versionStr.IndexOf(',');
            }
            if (!versionStr.StartsWith(VERSION_PREFIX) || dotIndex < VERSION_PREFIX.Length + 1)
            {
                return(false);
            }
            int verMax;

            if (!int.TryParse(versionStr.Substring(VERSION_PREFIX.Length, dotIndex - VERSION_PREFIX.Length), out verMax))
            {
                return(false);
            }
            int verMin;

            if (!int.TryParse(versionStr.Substring(dotIndex + 1), out verMin))
            {
                return(false);
            }
            result = new UPnPVersion(verMax, verMin);
            return(true);
        }
예제 #2
0
    /// <summary>
    /// Encodes a call of the specified <paramref name="action"/> with the given <paramref name="inParamValues"/> and
    /// returns the resulting SOAP XML string.
    /// </summary>
    /// <param name="action">Action to be called.</param>
    /// <param name="inParamValues">List of parameter values which must match the action's signature.
    /// Can be <c>null</c> if the parameter list is empty.</param>
    /// <param name="upnpVersion">UPnP version to use for the encoding.</param>
    /// <returns>XML string which contains the SOAP document.</returns>
    public static string EncodeCall(CpAction action, IList<object> inParamValues, UPnPVersion upnpVersion)
    {
      bool targetSupportsUPnP11 = upnpVersion.VerMin >= 1;
      StringBuilder result = new StringBuilder(5000);
      using (StringWriterWithEncoding stringWriter = new StringWriterWithEncoding(result, UPnPConsts.UTF8_NO_BOM))
      using (XmlWriter writer = XmlWriter.Create(stringWriter, UPnPConfiguration.DEFAULT_XML_WRITER_SETTINGS))
      {
        SoapHelper.WriteSoapEnvelopeStart(writer, true);
        writer.WriteStartElement("u", action.Name, action.ParentService.ServiceTypeVersion_URN);

        // Check input parameters
        IList<CpArgument> formalArguments = action.InArguments;
        if (inParamValues == null)
          inParamValues = EMPTY_OBJECT_LIST;
        if (inParamValues.Count != formalArguments.Count)
          throw new ArgumentException("Invalid argument count");
        for (int i = 0; i < formalArguments.Count; i++)
        {
          CpArgument argument = formalArguments[i];
          object value = inParamValues[i];
          writer.WriteStartElement(argument.Name);
          argument.SoapSerializeArgument(value, !targetSupportsUPnP11, writer);
          writer.WriteEndElement(); // argument.Name
        }
        SoapHelper.WriteSoapEnvelopeEndAndClose(writer);
      }
      return result.ToString();
    }
예제 #3
0
 public static bool TryParseFromUserAgent(string userAgentHeader, out UPnPVersion upnpVersion)
 {
   upnpVersion = null;
   if (string.IsNullOrEmpty(userAgentHeader))
     return false;
   // The specification says the userAgentHeader string should contain three tokens, separated by ' '.
   // Unfortunately, some devices send tokens separated by ", ". Others only send two tokens. We try to handle all situations correctly here.
   string[] versionInfos = userAgentHeader.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
   string upnpVersionInfo = versionInfos.FirstOrDefault(v => v.StartsWith(VERSION_PREFIX));
   if (upnpVersionInfo == null)
     return false;
   return TryParse(upnpVersionInfo, out upnpVersion);
 }
예제 #4
0
 public static bool TryParse(string versionStr, out UPnPVersion result)
 {
   result = null;
   int dotIndex = versionStr.IndexOf('.');
   if (!versionStr.StartsWith(VERSION_PREFIX) || dotIndex < VERSION_PREFIX.Length + 1)
     return false;
   int verMax;
   if (!int.TryParse(versionStr.Substring(VERSION_PREFIX.Length, dotIndex - VERSION_PREFIX.Length), out verMax))
     return false;
   int verMin;
   if (!int.TryParse(versionStr.Substring(dotIndex + 1), out verMin))
     return false;
   result = new UPnPVersion(verMax, verMin);
   return true;
 }
예제 #5
0
        public static bool TryParseFromUserAgent(string userAgentHeader, out UPnPVersion upnpVersion)
        {
            upnpVersion = null;
            if (string.IsNullOrEmpty(userAgentHeader))
            {
                return(false);
            }
            // The specification says the userAgentHeader string should contain three tokens, separated by ' '.
            // Unfortunately, some devices send tokens separated by ", ". Others only send two tokens. We try to handle all situations correctly here.
            string[] versionInfos    = userAgentHeader.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
            string   upnpVersionInfo = versionInfos.FirstOrDefault(v => v.StartsWith(VERSION_PREFIX));

            if (upnpVersionInfo == null)
            {
                return(false);
            }
            return(TryParse(upnpVersionInfo, out upnpVersion));
        }
예제 #6
0
 protected RootEntry GetOrCreateRootEntry(string deviceUUID, string descriptionLocation, UPnPVersion upnpVersion, string osVersion,
     string productVersion, DateTime expirationTime, EndpointConfiguration endpoint, HTTPVersion httpVersion, int searchPort, out bool wasAdded)
 {
   // Because the order of the UDP advertisement packets isn't guaranteed (and even not really specified by the UPnP specification),
   // in the general case it is not possible to find the correct root entry for each advertisement message.
   // - We cannot search by root device UUID because the upnp:rootdevice message might not be the first message, so before that message, we don't know the root device ID and
   //   thus we cannot use the root device id as unique key to find the root entry
   // - We cannot use the device description because for multi-homed devices, more than one device description can belong to the same root device
   //
   // Assume the message arrive in an order so that device A over network interface N1 is announced first. Second, device B over network interface N2 is announced.
   // In that case, we cannot judge if those two devices belong to the same root device or not.
   //
   // To face that situation, we first add all advertised devices to _pendingDeviceEntries. When a upnp:rootdevice message is received,
   // we either simply move the root entry from _pendingDeviceEntries into _cpData.DeviceEntries or we merge the pending entry with an already existing
   // entry in _cpData.DeviceEntries. At that time the merge is possible because we then have the root device id for both root entries.
   lock (_cpData.SyncObj)
   {
     RootEntry result = GetRootEntryByContainedDeviceUUID(deviceUUID) ?? GetRootEntryByDescriptionLocation(descriptionLocation);
     if (result != null)
     {
       result.ExpirationTime = expirationTime;
       wasAdded = false;
     }
     else
     {
       result = new RootEntry(_cpData.SyncObj, upnpVersion, osVersion, productVersion, expirationTime);
       _pendingDeviceEntries.Add(result);
       wasAdded = true;
     }
     return result;
   }
 }
예제 #7
0
 /// <summary>
 /// Takes the XML document provided by the given <paramref name="body"/> stream, parses it in the given
 /// <paramref name="contentEncoding"/> and provides the action result to the appropriate receiver.
 /// </summary>
 /// <param name="body">Body stream of the SOAP XML action result message.</param>
 /// <param name="contentEncoding">Encoding of the body stream.</param>
 /// <param name="action">Action which was called before.</param>
 /// <param name="clientState">State object which was given in the action call and which will be returned to the client.</param>
 /// <param name="upnpVersion">UPnP version of the UPnP server.</param>
 public static void HandleResult(Stream body, Encoding contentEncoding, CpAction action, object clientState, UPnPVersion upnpVersion)
 {
   bool sourceSupportsUPnP11 = upnpVersion.VerMin >= 1;
   IList<object> outParameterValues;
   try
   {
     if (!body.CanRead)
     {
       UPnPConfiguration.LOGGER.Error("SOAPHandler: Empty action result document");
       action.ActionErrorResultPresent(new UPnPError(501, "Invalid server result"), clientState);
       return;
     }
     using (TextReader textReader = new StreamReader(body, contentEncoding))
       outParameterValues = ParseResult(textReader, action, sourceSupportsUPnP11);
   }
   catch (Exception e)
   {
     UPnPConfiguration.LOGGER.Error("SOAPHandler: Error parsing action result document", e);
     action.ActionErrorResultPresent(new UPnPError(501, "Invalid server result"), clientState);
     return;
   }
   try
   {
     // Invoke action result
     action.ActionResultPresent(outParameterValues, clientState);
   }
   catch (Exception e)
   {
     UPnPConfiguration.LOGGER.Error("UPnP subsystem: Error invoking action '{0}'", e, action.FullQualifiedName);
   }
 }
예제 #8
0
 protected static void HandleVariableChangeNotification(XmlReader reader, CpService service, UPnPVersion upnpVersion)
 {
   string variableName = reader.LocalName;
   CpStateVariable stateVariable;
   if (!service.StateVariables.TryGetValue(variableName, out stateVariable))
     // We don't know that variable - this is an error case but we won't raise an exception here
     return;
   object value = stateVariable.DataType.SoapDeserializeValue(reader, upnpVersion.VerMin == 0);
   service.InvokeStateVariableChanged(stateVariable, value);
 }
예제 #9
0
 public static HttpStatusCode HandleEventNotification(Stream stream, Encoding streamEncoding, CpService service,
     UPnPVersion upnpVersion)
 {
   try
   {
     // Parse XML document
     using (StreamReader streamReader = new StreamReader(stream, streamEncoding))
       using (XmlReader reader = XmlReader.Create(streamReader, UPnPConfiguration.DEFAULT_XML_READER_SETTINGS))
       {
         reader.MoveToContent();
         reader.ReadStartElement("propertyset", UPnPConsts.NS_UPNP_EVENT);
         while (reader.LocalName == "property" && reader.NamespaceURI == UPnPConsts.NS_UPNP_EVENT)
         {
           reader.ReadStartElement("property", UPnPConsts.NS_UPNP_EVENT);
           HandleVariableChangeNotification(reader, service, upnpVersion);
           reader.ReadEndElement(); // property
         }
         reader.Close();
       }
     return HttpStatusCode.OK;
   }
   catch (Exception e)
   {
     UPnPConfiguration.LOGGER.Warn("GENAClientController: Error handling event notification", e);
     return HttpStatusCode.BadRequest;
   }
 }
예제 #10
0
 public GENAClientController(CPData cpData, DeviceConnection connection, EndpointConfiguration endpoint, UPnPVersion upnpVersion)
 {
   _cpData = cpData;
   _connection = connection;
   _endpoint = endpoint;
   _upnpVersion = upnpVersion;
   _eventNotificationPath = "/" + Guid.NewGuid();
   IPAddress address = endpoint.EndPointIPAddress;
   _eventNotificationEndpoint = new IPEndPoint(address, address.AddressFamily == AddressFamily.InterNetwork ?
       cpData.HttpPortV4 : cpData.HttpPortV6);
   _subscriptionRenewalTimer = new Timer(OnSubscriptionRenewalTimerElapsed);
 }